3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/kernel32/file/dir.c
6 * PURPOSE: Directory functions
7 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
13 * NOTES: Changed to using ZwCreateFile
16 /* INCLUDES ******************************************************************/
21 DEBUG_CHANNEL(kernel32file
);
23 UNICODE_STRING BaseDllDirectory
= {0, 0, NULL
};
25 /* FUNCTIONS *****************************************************************/
34 LPSECURITY_ATTRIBUTES lpSecurityAttributes
39 if (!(PathNameW
= FilenameA2W(lpPathName
, FALSE
)))
42 return CreateDirectoryW (PathNameW
,
43 lpSecurityAttributes
);
53 LPCSTR lpTemplateDirectory
,
54 LPCSTR lpNewDirectory
,
55 LPSECURITY_ATTRIBUTES lpSecurityAttributes
)
57 PWCHAR TemplateDirectoryW
;
61 if (!(TemplateDirectoryW
= FilenameA2W(lpTemplateDirectory
, TRUE
)))
64 if (!(NewDirectoryW
= FilenameA2W(lpNewDirectory
, FALSE
)))
66 RtlFreeHeap (RtlGetProcessHeap (),
72 ret
= CreateDirectoryExW (TemplateDirectoryW
,
74 lpSecurityAttributes
);
76 RtlFreeHeap (RtlGetProcessHeap (),
91 LPSECURITY_ATTRIBUTES lpSecurityAttributes
94 OBJECT_ATTRIBUTES ObjectAttributes
;
95 IO_STATUS_BLOCK IoStatusBlock
;
96 UNICODE_STRING NtPathU
;
97 HANDLE DirectoryHandle
= NULL
;
100 TRACE ("lpPathName %S lpSecurityAttributes %p\n",
101 lpPathName
, lpSecurityAttributes
);
103 if (!RtlDosPathNameToNtPathName_U (lpPathName
,
108 SetLastError(ERROR_PATH_NOT_FOUND
);
112 InitializeObjectAttributes(&ObjectAttributes
,
114 OBJ_CASE_INSENSITIVE
,
116 (lpSecurityAttributes
? lpSecurityAttributes
->lpSecurityDescriptor
: NULL
));
118 Status
= NtCreateFile (&DirectoryHandle
,
119 FILE_LIST_DIRECTORY
| SYNCHRONIZE
,
123 FILE_ATTRIBUTE_NORMAL
,
124 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
126 FILE_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
| FILE_OPEN_FOR_BACKUP_INTENT
,
130 RtlFreeHeap (RtlGetProcessHeap (),
134 if (!NT_SUCCESS(Status
))
136 WARN("NtCreateFile failed with Status %lx\n", Status
);
137 BaseSetLastNTError(Status
);
141 NtClose (DirectoryHandle
);
153 LPCWSTR lpTemplateDirectory
,
154 LPCWSTR lpNewDirectory
,
155 LPSECURITY_ATTRIBUTES lpSecurityAttributes
158 OBJECT_ATTRIBUTES ObjectAttributes
;
159 IO_STATUS_BLOCK IoStatusBlock
;
160 UNICODE_STRING NtPathU
, NtTemplatePathU
;
161 HANDLE DirectoryHandle
= NULL
;
162 HANDLE TemplateHandle
= NULL
;
163 FILE_EA_INFORMATION EaInformation
;
164 FILE_BASIC_INFORMATION FileBasicInfo
;
166 ULONG OpenOptions
, CreateOptions
;
167 ACCESS_MASK DesiredAccess
;
168 BOOLEAN ReparsePoint
= FALSE
;
169 PVOID EaBuffer
= NULL
;
172 OpenOptions
= FILE_DIRECTORY_FILE
| FILE_OPEN_REPARSE_POINT
|
173 FILE_OPEN_FOR_BACKUP_INTENT
;
174 CreateOptions
= FILE_DIRECTORY_FILE
| FILE_OPEN_FOR_BACKUP_INTENT
;
175 DesiredAccess
= FILE_LIST_DIRECTORY
| SYNCHRONIZE
| FILE_WRITE_ATTRIBUTES
|
176 FILE_READ_ATTRIBUTES
;
178 TRACE ("lpTemplateDirectory %ws lpNewDirectory %ws lpSecurityAttributes %p\n",
179 lpTemplateDirectory
, lpNewDirectory
, lpSecurityAttributes
);
182 * Translate the template directory path
185 if (!RtlDosPathNameToNtPathName_U (lpTemplateDirectory
,
190 SetLastError(ERROR_PATH_NOT_FOUND
);
194 InitializeObjectAttributes(&ObjectAttributes
,
196 OBJ_CASE_INSENSITIVE
,
201 * Open the template directory
205 Status
= NtOpenFile (&TemplateHandle
,
206 FILE_LIST_DIRECTORY
| FILE_READ_ATTRIBUTES
| FILE_READ_EA
,
209 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
211 if (!NT_SUCCESS(Status
))
213 if (Status
== STATUS_INVALID_PARAMETER
&&
214 (OpenOptions
& FILE_OPEN_REPARSE_POINT
))
216 /* Some FSs (FAT) don't support reparse points, try opening
217 the directory without FILE_OPEN_REPARSE_POINT */
218 OpenOptions
&= ~FILE_OPEN_REPARSE_POINT
;
220 TRACE("Reparse points not supported, try with less options\n");
223 goto OpenTemplateDir
;
227 WARN("Failed to open the template directory: 0x%x\n", Status
);
228 goto CleanupNoNtPath
;
233 * Translate the new directory path and check if they're the same
236 if (!RtlDosPathNameToNtPathName_U (lpNewDirectory
,
241 Status
= STATUS_OBJECT_PATH_NOT_FOUND
;
242 goto CleanupNoNtPath
;
245 if (RtlEqualUnicodeString(&NtPathU
,
249 WARN("Both directory paths are the same!\n");
250 Status
= STATUS_OBJECT_NAME_INVALID
;
254 InitializeObjectAttributes(&ObjectAttributes
,
256 OBJ_CASE_INSENSITIVE
,
258 (lpSecurityAttributes
? lpSecurityAttributes
->lpSecurityDescriptor
: NULL
));
261 * Query the basic file attributes from the template directory
264 /* Make sure FILE_ATTRIBUTE_NORMAL is used in case the information
265 isn't set by the FS */
266 FileBasicInfo
.FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
267 Status
= NtQueryInformationFile(TemplateHandle
,
270 sizeof(FILE_BASIC_INFORMATION
),
271 FileBasicInformation
);
272 if (!NT_SUCCESS(Status
))
274 WARN("Failed to query the basic directory attributes\n");
278 /* clear the reparse point attribute if present. We're going to set the
279 reparse point later which will cause the attribute to be set */
280 if (FileBasicInfo
.FileAttributes
& FILE_ATTRIBUTE_REPARSE_POINT
)
282 FileBasicInfo
.FileAttributes
&= ~FILE_ATTRIBUTE_REPARSE_POINT
;
284 /* writing the extended attributes requires the FILE_WRITE_DATA
286 DesiredAccess
|= FILE_WRITE_DATA
;
288 CreateOptions
|= FILE_OPEN_REPARSE_POINT
;
293 * Read the Extended Attributes if present
298 Status
= NtQueryInformationFile(TemplateHandle
,
301 sizeof(FILE_EA_INFORMATION
),
303 if (NT_SUCCESS(Status
) && (EaInformation
.EaSize
!= 0))
305 EaBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
307 EaInformation
.EaSize
);
308 if (EaBuffer
== NULL
)
310 Status
= STATUS_INSUFFICIENT_RESOURCES
;
314 Status
= NtQueryEaFile(TemplateHandle
,
317 EaInformation
.EaSize
,
324 if (NT_SUCCESS(Status
))
326 /* we successfully read the extended attributes */
327 EaLength
= EaInformation
.EaSize
;
332 RtlFreeHeap(RtlGetProcessHeap(),
337 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
339 /* unless we just allocated not enough memory, break the loop
340 and just continue without copying extended attributes */
347 /* failure or no extended attributes present, break the loop */
352 if (!NT_SUCCESS(Status
))
354 WARN("Querying the EA data failed: 0x%x\n", Status
);
359 * Create the new directory
362 Status
= NtCreateFile (&DirectoryHandle
,
367 FileBasicInfo
.FileAttributes
,
368 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
373 if (!NT_SUCCESS(Status
))
376 (Status
== STATUS_INVALID_PARAMETER
|| Status
== STATUS_ACCESS_DENIED
))
378 /* The FS doesn't seem to support reparse points... */
379 WARN("Cannot copy the hardlink, destination doesn\'t support reparse points!\n");
388 * Copy the reparse point
391 PREPARSE_GUID_DATA_BUFFER ReparseDataBuffer
=
392 (PREPARSE_GUID_DATA_BUFFER
)RtlAllocateHeap(RtlGetProcessHeap(),
394 MAXIMUM_REPARSE_DATA_BUFFER_SIZE
);
396 if (ReparseDataBuffer
== NULL
)
398 Status
= STATUS_INSUFFICIENT_RESOURCES
;
402 /* query the size of the reparse data buffer structure */
403 Status
= NtFsControlFile(TemplateHandle
,
408 FSCTL_GET_REPARSE_POINT
,
412 MAXIMUM_REPARSE_DATA_BUFFER_SIZE
);
413 if (NT_SUCCESS(Status
))
415 /* write the reparse point */
416 Status
= NtFsControlFile(DirectoryHandle
,
421 FSCTL_SET_REPARSE_POINT
,
423 MAXIMUM_REPARSE_DATA_BUFFER_SIZE
,
428 RtlFreeHeap(RtlGetProcessHeap(),
432 if (!NT_SUCCESS(Status
))
434 /* fail, we were unable to read the reparse point data! */
435 WARN("Querying or setting the reparse point failed: 0x%x\n", Status
);
442 * Copy alternate file streams, if existing
445 /* FIXME - enumerate and copy the file streams */
449 * We successfully created the directory and copied all information
450 * from the template directory
452 Status
= STATUS_SUCCESS
;
455 RtlFreeHeap (RtlGetProcessHeap (),
460 if (TemplateHandle
!= NULL
)
462 NtClose(TemplateHandle
);
465 RtlFreeHeap (RtlGetProcessHeap (),
467 NtTemplatePathU
.Buffer
);
469 /* free the he extended attributes buffer */
470 if (EaBuffer
!= NULL
)
472 RtlFreeHeap (RtlGetProcessHeap (),
477 if (DirectoryHandle
!= NULL
)
479 NtClose(DirectoryHandle
);
482 if (!NT_SUCCESS(Status
))
484 BaseSetLastNTError(Status
);
503 TRACE("RemoveDirectoryA(%s)\n",lpPathName
);
505 if (!(PathNameW
= FilenameA2W(lpPathName
, FALSE
)))
508 return RemoveDirectoryW (PathNameW
);
521 FILE_DISPOSITION_INFORMATION FileDispInfo
;
522 OBJECT_ATTRIBUTES ObjectAttributes
;
523 IO_STATUS_BLOCK IoStatusBlock
;
524 UNICODE_STRING NtPathU
;
525 HANDLE DirectoryHandle
= NULL
;
528 TRACE("lpPathName %S\n", lpPathName
);
530 if (!RtlDosPathNameToNtPathName_U (lpPathName
,
535 SetLastError(ERROR_PATH_NOT_FOUND
);
539 InitializeObjectAttributes(&ObjectAttributes
,
541 OBJ_CASE_INSENSITIVE
,
545 TRACE("NtPathU '%S'\n", NtPathU
.Buffer
);
547 Status
= NtOpenFile(&DirectoryHandle
,
548 DELETE
| SYNCHRONIZE
,
551 FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
,
552 FILE_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
);
554 RtlFreeUnicodeString(&NtPathU
);
556 if (!NT_SUCCESS(Status
))
558 WARN("Status 0x%08x\n", Status
);
559 BaseSetLastNTError (Status
);
563 FileDispInfo
.DeleteFile
= TRUE
;
565 Status
= NtSetInformationFile (DirectoryHandle
,
568 sizeof(FILE_DISPOSITION_INFORMATION
),
569 FileDispositionInformation
);
570 NtClose(DirectoryHandle
);
572 if (!NT_SUCCESS(Status
))
574 BaseSetLastNTError (Status
);
594 WCHAR BufferW
[MAX_PATH
];
597 LPWSTR FilePartW
= NULL
;
599 TRACE("GetFullPathNameA(lpFileName %s, nBufferLength %d, lpBuffer %p, "
600 "lpFilePart %p)\n",lpFileName
,nBufferLength
,lpBuffer
,lpFilePart
);
602 if (!(FileNameW
= FilenameA2W(lpFileName
, FALSE
)))
605 ret
= GetFullPathNameW(FileNameW
, MAX_PATH
, BufferW
, &FilePartW
);
612 SetLastError(ERROR_FILENAME_EXCED_RANGE
);
616 ret
= FilenameW2A_FitOrFail(lpBuffer
, nBufferLength
, BufferW
, ret
+1);
618 if (ret
< nBufferLength
&& lpFilePart
)
620 /* if the path closed with '\', FilePart is NULL */
624 *lpFilePart
= (FilePartW
- BufferW
) + lpBuffer
;
627 TRACE("GetFullPathNameA ret: lpBuffer %s lpFilePart %s\n",
628 lpBuffer
, (lpFilePart
== NULL
) ? "NULL" : *lpFilePart
);
648 TRACE("GetFullPathNameW(lpFileName %S, nBufferLength %d, lpBuffer %p, "
649 "lpFilePart %p)\n",lpFileName
,nBufferLength
,lpBuffer
,lpFilePart
);
651 Length
= RtlGetFullPathName_U ((LPWSTR
)lpFileName
,
652 nBufferLength
* sizeof(WCHAR
),
656 TRACE("GetFullPathNameW ret: lpBuffer %S lpFilePart %S Length %ld\n",
657 lpBuffer
, (lpFilePart
== NULL
) ? L
"NULL" : *lpFilePart
, Length
/ sizeof(WCHAR
));
661 #if (WINVER >= _WIN32_WINNT_WIN7)
662 SetLastError(ERROR_INVALID_PARAMETER
);
667 return Length
/sizeof(WCHAR
);
672 * NOTE: Copied from Wine.
684 WCHAR ShortPathW
[MAX_PATH
];
689 SetLastError(ERROR_INVALID_PARAMETER
);
693 if (!(LongPathW
= FilenameA2W(longpath
, FALSE
)))
696 ret
= GetShortPathNameW(LongPathW
, ShortPathW
, MAX_PATH
);
703 SetLastError(ERROR_FILENAME_EXCED_RANGE
);
707 return FilenameW2A_FitOrFail(shortpath
, shortlen
, ShortPathW
, ret
+1);
712 * NOTE: Copied from Wine.
723 WCHAR tmpshortpath
[MAX_PATH
];
725 DWORD sp
= 0, lp
= 0;
727 WIN32_FIND_DATAW wfd
;
730 WCHAR ustr_buf
[8+1+3+1];
732 TRACE("GetShortPathNameW: %S\n",longpath
);
736 SetLastError(ERROR_INVALID_PARAMETER
);
741 SetLastError(ERROR_BAD_PATHNAME
);
745 /* check for drive letter */
746 if (longpath
[0] != '/' && longpath
[1] == ':' )
748 tmpshortpath
[0] = longpath
[0];
749 tmpshortpath
[1] = ':';
753 ustr
.Buffer
= ustr_buf
;
755 ustr
.MaximumLength
= sizeof(ustr_buf
);
759 /* check for path delimiters and reproduce them */
760 if (longpath
[lp
] == '\\' || longpath
[lp
] == '/')
762 if (!sp
|| tmpshortpath
[sp
-1] != '\\')
764 /* strip double "\\" */
765 tmpshortpath
[sp
] = '\\';
768 tmpshortpath
[sp
] = 0; /* terminate string */
773 for (p
= longpath
+ lp
; *p
&& *p
!= '/' && *p
!= '\\'; p
++);
774 tmplen
= p
- (longpath
+ lp
);
775 lstrcpynW(tmpshortpath
+ sp
, longpath
+ lp
, tmplen
+ 1);
776 /* Check, if the current element is a valid dos name */
780 memcpy(ustr_buf
, longpath
+ lp
, tmplen
* sizeof(WCHAR
));
781 ustr_buf
[tmplen
] = '\0';
782 ustr
.Length
= (USHORT
)tmplen
* sizeof(WCHAR
);
783 if (RtlIsNameLegalDOS8Dot3(&ustr
, NULL
, &spaces
) && !spaces
)
791 /* Check if the file exists and use the existing short file name */
792 goit
= FindFirstFileW(tmpshortpath
, &wfd
);
793 if (goit
== INVALID_HANDLE_VALUE
) goto notfound
;
795 lstrcpyW(tmpshortpath
+ sp
, wfd
.cAlternateFileName
);
796 sp
+= lstrlenW(tmpshortpath
+ sp
);
799 tmpshortpath
[sp
] = 0;
801 tmplen
= lstrlenW(tmpshortpath
) + 1;
802 if (tmplen
<= shortlen
)
804 lstrcpyW(shortpath
, tmpshortpath
);
805 tmplen
--; /* length without 0 */
811 SetLastError ( ERROR_FILE_NOT_FOUND
);
830 UNICODE_STRING PathU
= { 0, 0, NULL
};
831 UNICODE_STRING FileNameU
= { 0, 0, NULL
};
832 UNICODE_STRING ExtensionU
= { 0, 0, NULL
};
833 UNICODE_STRING BufferU
= { 0, 0, NULL
};
835 ANSI_STRING FileName
;
836 ANSI_STRING Extension
;
840 NTSTATUS Status
= STATUS_SUCCESS
;
844 SetLastError(ERROR_INVALID_PARAMETER
);
848 RtlInitAnsiString (&Path
,
850 RtlInitAnsiString (&FileName
,
852 RtlInitAnsiString (&Extension
,
855 /* convert ansi (or oem) strings to unicode */
858 Status
= RtlAnsiStringToUnicodeString (&PathU
,
861 if (!NT_SUCCESS(Status
))
864 Status
= RtlAnsiStringToUnicodeString (&FileNameU
,
867 if (!NT_SUCCESS(Status
))
870 Status
= RtlAnsiStringToUnicodeString (&ExtensionU
,
873 if (!NT_SUCCESS(Status
))
878 Status
= RtlOemStringToUnicodeString (&PathU
,
881 if (!NT_SUCCESS(Status
))
883 Status
= RtlOemStringToUnicodeString (&FileNameU
,
886 if (!NT_SUCCESS(Status
))
889 Status
= RtlOemStringToUnicodeString (&ExtensionU
,
892 if (!NT_SUCCESS(Status
))
896 BufferU
.MaximumLength
= min(nBufferLength
* sizeof(WCHAR
), USHRT_MAX
);
897 BufferU
.Buffer
= RtlAllocateHeap (RtlGetProcessHeap (),
899 BufferU
.MaximumLength
);
900 if (BufferU
.Buffer
== NULL
)
902 Status
= STATUS_NO_MEMORY
;
906 Buffer
.MaximumLength
= min(nBufferLength
, USHRT_MAX
);
907 Buffer
.Buffer
= lpBuffer
;
909 RetValue
= SearchPathW (NULL
== lpPath
? NULL
: PathU
.Buffer
,
910 NULL
== lpFileName
? NULL
: FileNameU
.Buffer
,
911 NULL
== lpExtension
? NULL
: ExtensionU
.Buffer
,
918 BufferU
.Length
= wcslen(BufferU
.Buffer
) * sizeof(WCHAR
);
919 /* convert ansi (or oem) string to unicode */
921 Status
= RtlUnicodeStringToAnsiString(&Buffer
,
925 Status
= RtlUnicodeStringToOemString(&Buffer
,
929 if (NT_SUCCESS(Status
) && Buffer
.Buffer
)
931 /* nul-terminate ascii string */
932 Buffer
.Buffer
[BufferU
.Length
/ sizeof(WCHAR
)] = '\0';
934 if (NULL
!= lpFilePart
&& BufferU
.Length
!= 0)
936 *lpFilePart
= strrchr (lpBuffer
, '\\') + 1;
942 RtlFreeHeap (RtlGetProcessHeap (),
945 RtlFreeHeap (RtlGetProcessHeap (),
948 RtlFreeHeap (RtlGetProcessHeap (),
951 RtlFreeHeap (RtlGetProcessHeap (),
955 if (!NT_SUCCESS(Status
))
957 BaseSetLastNTError(Status
);
965 /***********************************************************************
966 * ContainsPath (Wine name: contains_pathW)
968 * Check if the file name contains a path; helper for SearchPathW.
969 * A relative path is not considered a path unless it starts with ./ or ../
973 ContainsPath(LPCWSTR name
)
975 if (RtlDetermineDosPathNameType_U(name
) != RtlPathTypeRelative
) return TRUE
;
976 if (name
[0] != '.') return FALSE
;
977 if (name
[1] == '/' || name
[1] == '\\' || name
[1] == '\0') return TRUE
;
978 return (name
[1] == '.' && (name
[2] == '/' || name
[2] == '\\'));
987 SearchPathW(LPCWSTR lpPath
,
996 if (!lpFileName
|| !lpFileName
[0])
998 SetLastError(ERROR_INVALID_PARAMETER
);
1002 /* If the name contains an explicit path, ignore the path */
1003 if (ContainsPath(lpFileName
))
1005 /* try first without extension */
1006 if (RtlDoesFileExists_U(lpFileName
))
1007 return GetFullPathNameW(lpFileName
, nBufferLength
, lpBuffer
, lpFilePart
);
1011 LPCWSTR p
= wcsrchr(lpFileName
, '.');
1012 if (p
&& !strchr((const char *)p
, '/') && !wcschr( p
, '\\' ))
1013 lpExtension
= NULL
; /* Ignore the specified extension */
1016 /* Allocate a buffer for the file name and extension */
1020 DWORD len
= wcslen(lpFileName
) + wcslen(lpExtension
);
1022 if (!(tmp
= RtlAllocateHeap(RtlGetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
))))
1024 SetLastError(ERROR_OUTOFMEMORY
);
1027 wcscpy(tmp
, lpFileName
);
1028 wcscat(tmp
, lpExtension
);
1029 if (RtlDoesFileExists_U(tmp
))
1030 ret
= GetFullPathNameW(tmp
, nBufferLength
, lpBuffer
, lpFilePart
);
1031 RtlFreeHeap(RtlGetProcessHeap(), 0, tmp
);
1034 else if (lpPath
&& lpPath
[0]) /* search in the specified path */
1036 ret
= RtlDosSearchPath_U(lpPath
,
1039 nBufferLength
* sizeof(WCHAR
),
1041 lpFilePart
) / sizeof(WCHAR
);
1043 else /* search in the default path */
1045 WCHAR
*DllPath
= GetDllLoadPath(NULL
);
1049 ret
= RtlDosSearchPath_U(DllPath
,
1052 nBufferLength
* sizeof(WCHAR
),
1054 lpFilePart
) / sizeof(WCHAR
);
1055 RtlFreeHeap(RtlGetProcessHeap(), 0, DllPath
);
1059 SetLastError(ERROR_OUTOFMEMORY
);
1064 if (!ret
) SetLastError(ERROR_FILE_NOT_FOUND
);
1078 UNICODE_STRING PathName
;
1080 RtlInitUnicodeString(&PathName
, lpPathName
);
1082 RtlEnterCriticalSection(&BaseDllDirectoryLock
);
1083 if(PathName
.Length
> 0)
1085 if(PathName
.Length
+ sizeof(WCHAR
) <= BaseDllDirectory
.MaximumLength
)
1087 RtlCopyUnicodeString(&BaseDllDirectory
, &PathName
);
1091 RtlFreeUnicodeString(&BaseDllDirectory
);
1092 if(!(BaseDllDirectory
.Buffer
= (PWSTR
)RtlAllocateHeap(RtlGetProcessHeap(),
1094 PathName
.Length
+ sizeof(WCHAR
))))
1096 RtlLeaveCriticalSection(&BaseDllDirectoryLock
);
1097 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1100 BaseDllDirectory
.Length
= 0;
1101 BaseDllDirectory
.MaximumLength
= PathName
.Length
+ sizeof(WCHAR
);
1103 RtlCopyUnicodeString(&BaseDllDirectory
, &PathName
);
1108 RtlFreeUnicodeString(&BaseDllDirectory
);
1110 RtlLeaveCriticalSection(&BaseDllDirectoryLock
);
1121 LPCSTR lpPathName
/* can be NULL */
1124 PWCHAR PathNameW
=NULL
;
1128 if (!(PathNameW
= FilenameA2W(lpPathName
, FALSE
)))
1132 return SetDllDirectoryW(PathNameW
);
1141 DWORD nBufferLength
,
1147 RtlEnterCriticalSection(&BaseDllDirectoryLock
);
1148 if(nBufferLength
> 0)
1150 Ret
= BaseDllDirectory
.Length
/ sizeof(WCHAR
);
1151 if(Ret
> nBufferLength
- 1)
1153 Ret
= nBufferLength
- 1;
1158 RtlCopyMemory(lpBuffer
, BaseDllDirectory
.Buffer
, Ret
* sizeof(WCHAR
));
1160 lpBuffer
[Ret
] = L
'\0';
1164 /* include termination character, even if the string is empty! */
1165 Ret
= (BaseDllDirectory
.Length
/ sizeof(WCHAR
)) + 1;
1167 RtlLeaveCriticalSection(&BaseDllDirectoryLock
);
1178 DWORD nBufferLength
,
1182 WCHAR BufferW
[MAX_PATH
];
1185 ret
= GetDllDirectoryW(MAX_PATH
, BufferW
);
1192 SetLastError(ERROR_FILENAME_EXCED_RANGE
);
1196 return FilenameW2A_FitOrFail(lpBuffer
, nBufferLength
, BufferW
, ret
+1);
1204 NeedCurrentDirectoryForExePathW(LPCWSTR ExeName
)
1206 static const WCHAR env_name
[] = {'N','o','D','e','f','a','u','l','t',
1207 'C','u','r','r','e','n','t',
1208 'D','i','r','e','c','t','o','r','y',
1209 'I','n','E','x','e','P','a','t','h',0};
1212 /* MSDN mentions some 'registry location'. We do not use registry. */
1213 FIXME("(%s): partial stub\n", debugstr_w(ExeName
));
1215 if (wcschr(ExeName
, L
'\\'))
1218 /* Check the existence of the variable, not value */
1219 if (!GetEnvironmentVariableW( env_name
, &env_val
, 1 ))
1230 NeedCurrentDirectoryForExePathA(LPCSTR ExeName
)
1234 if (!(ExeNameW
= FilenameA2W(ExeName
, FALSE
)))
1237 return NeedCurrentDirectoryForExePathW(ExeNameW
);
1244 /***********************************************************************
1247 * GetLongPathNameW (KERNEL32.@)
1250 * observed (Win2000):
1251 * shortpath=NULL: LastError=ERROR_INVALID_PARAMETER, ret=0
1252 * shortpath="": LastError=ERROR_PATH_NOT_FOUND, ret=0
1254 DWORD WINAPI
GetLongPathNameW( LPCWSTR shortpath
, LPWSTR longpath
, DWORD longlen
)
1256 #define MAX_PATHNAME_LEN 1024
1258 WCHAR tmplongpath
[MAX_PATHNAME_LEN
];
1260 DWORD sp
= 0, lp
= 0;
1263 WIN32_FIND_DATAW wfd
;
1268 SetLastError(ERROR_INVALID_PARAMETER
);
1273 SetLastError(ERROR_PATH_NOT_FOUND
);
1277 TRACE("GetLongPathNameW(%s,%p,%ld)\n", shortpath
, longpath
, longlen
);
1279 if (shortpath
[0] == '\\' && shortpath
[1] == '\\')
1281 WARN("ERR: UNC pathname %s\n", shortpath
);
1282 lstrcpynW( longpath
, shortpath
, longlen
);
1283 return wcslen(longpath
);
1285 unixabsolute
= (shortpath
[0] == '/');
1286 /* check for drive letter */
1287 if (!unixabsolute
&& shortpath
[1] == ':' )
1289 tmplongpath
[0] = shortpath
[0];
1290 tmplongpath
[1] = ':';
1294 while (shortpath
[sp
])
1296 /* check for path delimiters and reproduce them */
1297 if (shortpath
[sp
] == '\\' || shortpath
[sp
] == '/')
1299 if (!lp
|| tmplongpath
[lp
-1] != '\\')
1301 /* strip double "\\" */
1302 tmplongpath
[lp
++] = '\\';
1304 tmplongpath
[lp
] = 0; /* terminate string */
1310 if (sp
== 0 && p
[0] == '.' && (p
[1] == '/' || p
[1] == '\\'))
1312 tmplongpath
[lp
++] = *p
++;
1313 tmplongpath
[lp
++] = *p
++;
1315 for (; *p
&& *p
!= '/' && *p
!= '\\'; p
++);
1316 tmplen
= p
- (shortpath
+ sp
);
1317 lstrcpynW(tmplongpath
+ lp
, shortpath
+ sp
, tmplen
+ 1);
1318 /* Check if the file exists and use the existing file name */
1319 goit
= FindFirstFileW(tmplongpath
, &wfd
);
1320 if (goit
== INVALID_HANDLE_VALUE
)
1322 TRACE("not found %s!\n", tmplongpath
);
1323 SetLastError ( ERROR_FILE_NOT_FOUND
);
1327 wcscpy(tmplongpath
+ lp
, wfd
.cFileName
);
1328 lp
+= wcslen(tmplongpath
+ lp
);
1331 tmplen
= wcslen(shortpath
) - 1;
1332 if ((shortpath
[tmplen
] == '/' || shortpath
[tmplen
] == '\\') &&
1333 (tmplongpath
[lp
- 1] != '/' && tmplongpath
[lp
- 1] != '\\'))
1334 tmplongpath
[lp
++] = shortpath
[tmplen
];
1335 tmplongpath
[lp
] = 0;
1337 tmplen
= wcslen(tmplongpath
) + 1;
1338 if (tmplen
<= longlen
)
1340 wcscpy(longpath
, tmplongpath
);
1341 TRACE("returning %s\n", longpath
);
1342 tmplen
--; /* length without 0 */
1350 /***********************************************************************
1351 * GetLongPathNameA (KERNEL32.@)
1353 DWORD WINAPI
GetLongPathNameA( LPCSTR shortpath
, LPSTR longpath
, DWORD longlen
)
1356 WCHAR longpathW
[MAX_PATH
];
1359 TRACE("GetLongPathNameA %s, %i\n",shortpath
,longlen
);
1361 if (!(shortpathW
= FilenameA2W( shortpath
, FALSE
)))
1364 ret
= GetLongPathNameW(shortpathW
, longpathW
, MAX_PATH
);
1369 SetLastError(ERROR_FILENAME_EXCED_RANGE
);
1373 return FilenameW2A_FitOrFail(longpath
, longlen
, longpathW
, ret
+1 );