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 DllDirectory
= {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 SetLastErrorByStatus(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 SetLastErrorByStatus(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 SetLastErrorByStatus (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 SetLastErrorByStatus (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
);
604 SetLastError(ERROR_INVALID_PARAMETER
);
608 if (!(FileNameW
= FilenameA2W(lpFileName
, FALSE
)))
611 ret
= GetFullPathNameW(FileNameW
, MAX_PATH
, BufferW
, &FilePartW
);
618 SetLastError(ERROR_FILENAME_EXCED_RANGE
);
622 ret
= FilenameW2A_FitOrFail(lpBuffer
, nBufferLength
, BufferW
, ret
+1);
624 if (ret
< nBufferLength
&& lpFilePart
)
626 /* if the path closed with '\', FilePart is NULL */
630 *lpFilePart
= (FilePartW
- BufferW
) + lpBuffer
;
633 TRACE("GetFullPathNameA ret: lpBuffer %s lpFilePart %s\n",
634 lpBuffer
, (lpFilePart
== NULL
) ? "NULL" : *lpFilePart
);
654 TRACE("GetFullPathNameW(lpFileName %S, nBufferLength %d, lpBuffer %p, "
655 "lpFilePart %p)\n",lpFileName
,nBufferLength
,lpBuffer
,lpFilePart
);
657 Length
= RtlGetFullPathName_U ((LPWSTR
)lpFileName
,
658 nBufferLength
* sizeof(WCHAR
),
662 TRACE("GetFullPathNameW ret: lpBuffer %S lpFilePart %S Length %ld\n",
663 lpBuffer
, (lpFilePart
== NULL
) ? L
"NULL" : *lpFilePart
, Length
/ sizeof(WCHAR
));
665 return Length
/sizeof(WCHAR
);
670 * NOTE: Copied from Wine.
682 WCHAR ShortPathW
[MAX_PATH
];
687 SetLastError(ERROR_INVALID_PARAMETER
);
691 if (!(LongPathW
= FilenameA2W(longpath
, FALSE
)))
694 ret
= GetShortPathNameW(LongPathW
, ShortPathW
, MAX_PATH
);
701 SetLastError(ERROR_FILENAME_EXCED_RANGE
);
705 return FilenameW2A_FitOrFail(shortpath
, shortlen
, ShortPathW
, ret
+1);
710 * NOTE: Copied from Wine.
721 WCHAR tmpshortpath
[MAX_PATH
];
723 DWORD sp
= 0, lp
= 0;
725 WIN32_FIND_DATAW wfd
;
728 WCHAR ustr_buf
[8+1+3+1];
730 TRACE("GetShortPathNameW: %S\n",longpath
);
734 SetLastError(ERROR_INVALID_PARAMETER
);
739 SetLastError(ERROR_BAD_PATHNAME
);
743 /* check for drive letter */
744 if (longpath
[0] != '/' && longpath
[1] == ':' )
746 tmpshortpath
[0] = longpath
[0];
747 tmpshortpath
[1] = ':';
751 ustr
.Buffer
= ustr_buf
;
753 ustr
.MaximumLength
= sizeof(ustr_buf
);
757 /* check for path delimiters and reproduce them */
758 if (longpath
[lp
] == '\\' || longpath
[lp
] == '/')
760 if (!sp
|| tmpshortpath
[sp
-1] != '\\')
762 /* strip double "\\" */
763 tmpshortpath
[sp
] = '\\';
766 tmpshortpath
[sp
] = 0; /* terminate string */
771 for (p
= longpath
+ lp
; *p
&& *p
!= '/' && *p
!= '\\'; p
++);
772 tmplen
= p
- (longpath
+ lp
);
773 lstrcpynW(tmpshortpath
+ sp
, longpath
+ lp
, tmplen
+ 1);
774 /* Check, if the current element is a valid dos name */
778 memcpy(ustr_buf
, longpath
+ lp
, tmplen
* sizeof(WCHAR
));
779 ustr_buf
[tmplen
] = '\0';
780 ustr
.Length
= (USHORT
)tmplen
* sizeof(WCHAR
);
781 if (RtlIsNameLegalDOS8Dot3(&ustr
, NULL
, &spaces
) && !spaces
)
789 /* Check if the file exists and use the existing short file name */
790 goit
= FindFirstFileW(tmpshortpath
, &wfd
);
791 if (goit
== INVALID_HANDLE_VALUE
) goto notfound
;
793 lstrcpyW(tmpshortpath
+ sp
, wfd
.cAlternateFileName
);
794 sp
+= lstrlenW(tmpshortpath
+ sp
);
797 tmpshortpath
[sp
] = 0;
799 tmplen
= lstrlenW(tmpshortpath
) + 1;
800 if (tmplen
<= shortlen
)
802 lstrcpyW(shortpath
, tmpshortpath
);
803 tmplen
--; /* length without 0 */
809 SetLastError ( ERROR_FILE_NOT_FOUND
);
828 UNICODE_STRING PathU
= { 0, 0, NULL
};
829 UNICODE_STRING FileNameU
= { 0, 0, NULL
};
830 UNICODE_STRING ExtensionU
= { 0, 0, NULL
};
831 UNICODE_STRING BufferU
= { 0, 0, NULL
};
833 ANSI_STRING FileName
;
834 ANSI_STRING Extension
;
838 NTSTATUS Status
= STATUS_SUCCESS
;
842 SetLastError(ERROR_INVALID_PARAMETER
);
846 RtlInitAnsiString (&Path
,
848 RtlInitAnsiString (&FileName
,
850 RtlInitAnsiString (&Extension
,
853 /* convert ansi (or oem) strings to unicode */
856 Status
= RtlAnsiStringToUnicodeString (&PathU
,
859 if (!NT_SUCCESS(Status
))
862 Status
= RtlAnsiStringToUnicodeString (&FileNameU
,
865 if (!NT_SUCCESS(Status
))
868 Status
= RtlAnsiStringToUnicodeString (&ExtensionU
,
871 if (!NT_SUCCESS(Status
))
876 Status
= RtlOemStringToUnicodeString (&PathU
,
879 if (!NT_SUCCESS(Status
))
881 Status
= RtlOemStringToUnicodeString (&FileNameU
,
884 if (!NT_SUCCESS(Status
))
887 Status
= RtlOemStringToUnicodeString (&ExtensionU
,
890 if (!NT_SUCCESS(Status
))
894 BufferU
.MaximumLength
= min(nBufferLength
* sizeof(WCHAR
), USHRT_MAX
);
895 BufferU
.Buffer
= RtlAllocateHeap (RtlGetProcessHeap (),
897 BufferU
.MaximumLength
);
898 if (BufferU
.Buffer
== NULL
)
900 Status
= STATUS_NO_MEMORY
;
904 Buffer
.MaximumLength
= min(nBufferLength
, USHRT_MAX
);
905 Buffer
.Buffer
= lpBuffer
;
907 RetValue
= SearchPathW (NULL
== lpPath
? NULL
: PathU
.Buffer
,
908 NULL
== lpFileName
? NULL
: FileNameU
.Buffer
,
909 NULL
== lpExtension
? NULL
: ExtensionU
.Buffer
,
916 BufferU
.Length
= wcslen(BufferU
.Buffer
) * sizeof(WCHAR
);
917 /* convert ansi (or oem) string to unicode */
919 Status
= RtlUnicodeStringToAnsiString(&Buffer
,
923 Status
= RtlUnicodeStringToOemString(&Buffer
,
927 if (NT_SUCCESS(Status
) && Buffer
.Buffer
)
929 /* nul-terminate ascii string */
930 Buffer
.Buffer
[BufferU
.Length
/ sizeof(WCHAR
)] = '\0';
932 if (NULL
!= lpFilePart
&& BufferU
.Length
!= 0)
934 *lpFilePart
= strrchr (lpBuffer
, '\\') + 1;
940 RtlFreeHeap (RtlGetProcessHeap (),
943 RtlFreeHeap (RtlGetProcessHeap (),
946 RtlFreeHeap (RtlGetProcessHeap (),
949 RtlFreeHeap (RtlGetProcessHeap (),
953 if (!NT_SUCCESS(Status
))
955 SetLastErrorByStatus(Status
);
963 /***********************************************************************
964 * ContainsPath (Wine name: contains_pathW)
966 * Check if the file name contains a path; helper for SearchPathW.
967 * A relative path is not considered a path unless it starts with ./ or ../
971 ContainsPath(LPCWSTR name
)
973 if (RtlDetermineDosPathNameType_U(name
) != RtlPathTypeRelative
) return TRUE
;
974 if (name
[0] != '.') return FALSE
;
975 if (name
[1] == '/' || name
[1] == '\\' || name
[1] == '\0') return TRUE
;
976 return (name
[1] == '.' && (name
[2] == '/' || name
[2] == '\\'));
985 SearchPathW(LPCWSTR lpPath
,
994 if (!lpFileName
|| !lpFileName
[0])
996 SetLastError(ERROR_INVALID_PARAMETER
);
1000 /* If the name contains an explicit path, ignore the path */
1001 if (ContainsPath(lpFileName
))
1003 /* try first without extension */
1004 if (RtlDoesFileExists_U(lpFileName
))
1005 return GetFullPathNameW(lpFileName
, nBufferLength
, lpBuffer
, lpFilePart
);
1009 LPCWSTR p
= wcsrchr(lpFileName
, '.');
1010 if (p
&& !strchr((const char *)p
, '/') && !wcschr( p
, '\\' ))
1011 lpExtension
= NULL
; /* Ignore the specified extension */
1014 /* Allocate a buffer for the file name and extension */
1018 DWORD len
= wcslen(lpFileName
) + wcslen(lpExtension
);
1020 if (!(tmp
= RtlAllocateHeap(RtlGetProcessHeap(), 0, (len
+ 1) * sizeof(WCHAR
))))
1022 SetLastError(ERROR_OUTOFMEMORY
);
1025 wcscpy(tmp
, lpFileName
);
1026 wcscat(tmp
, lpExtension
);
1027 if (RtlDoesFileExists_U(tmp
))
1028 ret
= GetFullPathNameW(tmp
, nBufferLength
, lpBuffer
, lpFilePart
);
1029 RtlFreeHeap(RtlGetProcessHeap(), 0, tmp
);
1032 else if (lpPath
&& lpPath
[0]) /* search in the specified path */
1034 ret
= RtlDosSearchPath_U(lpPath
,
1037 nBufferLength
* sizeof(WCHAR
),
1039 lpFilePart
) / sizeof(WCHAR
);
1041 else /* search in the default path */
1043 WCHAR
*DllPath
= GetDllLoadPath(NULL
);
1047 ret
= RtlDosSearchPath_U(DllPath
,
1050 nBufferLength
* sizeof(WCHAR
),
1052 lpFilePart
) / sizeof(WCHAR
);
1053 RtlFreeHeap(RtlGetProcessHeap(), 0, DllPath
);
1057 SetLastError(ERROR_OUTOFMEMORY
);
1062 if (!ret
) SetLastError(ERROR_FILE_NOT_FOUND
);
1076 UNICODE_STRING PathName
;
1078 RtlInitUnicodeString(&PathName
, lpPathName
);
1080 RtlEnterCriticalSection(&DllLock
);
1081 if(PathName
.Length
> 0)
1083 if(PathName
.Length
+ sizeof(WCHAR
) <= DllDirectory
.MaximumLength
)
1085 RtlCopyUnicodeString(&DllDirectory
, &PathName
);
1089 RtlFreeUnicodeString(&DllDirectory
);
1090 if(!(DllDirectory
.Buffer
= (PWSTR
)RtlAllocateHeap(RtlGetProcessHeap(),
1092 PathName
.Length
+ sizeof(WCHAR
))))
1094 RtlLeaveCriticalSection(&DllLock
);
1095 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1098 DllDirectory
.Length
= 0;
1099 DllDirectory
.MaximumLength
= PathName
.Length
+ sizeof(WCHAR
);
1101 RtlCopyUnicodeString(&DllDirectory
, &PathName
);
1106 RtlFreeUnicodeString(&DllDirectory
);
1108 RtlLeaveCriticalSection(&DllLock
);
1119 LPCSTR lpPathName
/* can be NULL */
1122 PWCHAR PathNameW
=NULL
;
1126 if (!(PathNameW
= FilenameA2W(lpPathName
, FALSE
)))
1130 return SetDllDirectoryW(PathNameW
);
1139 DWORD nBufferLength
,
1145 RtlEnterCriticalSection(&DllLock
);
1146 if(nBufferLength
> 0)
1148 Ret
= DllDirectory
.Length
/ sizeof(WCHAR
);
1149 if(Ret
> nBufferLength
- 1)
1151 Ret
= nBufferLength
- 1;
1156 RtlCopyMemory(lpBuffer
, DllDirectory
.Buffer
, Ret
* sizeof(WCHAR
));
1158 lpBuffer
[Ret
] = L
'\0';
1162 /* include termination character, even if the string is empty! */
1163 Ret
= (DllDirectory
.Length
/ sizeof(WCHAR
)) + 1;
1165 RtlLeaveCriticalSection(&DllLock
);
1176 DWORD nBufferLength
,
1180 WCHAR BufferW
[MAX_PATH
];
1183 ret
= GetDllDirectoryW(MAX_PATH
, BufferW
);
1190 SetLastError(ERROR_FILENAME_EXCED_RANGE
);
1194 return FilenameW2A_FitOrFail(lpBuffer
, nBufferLength
, BufferW
, ret
+1);
1202 NeedCurrentDirectoryForExePathW(LPCWSTR ExeName
)
1204 static const WCHAR env_name
[] = {'N','o','D','e','f','a','u','l','t',
1205 'C','u','r','r','e','n','t',
1206 'D','i','r','e','c','t','o','r','y',
1207 'I','n','E','x','e','P','a','t','h',0};
1210 /* MSDN mentions some 'registry location'. We do not use registry. */
1211 FIXME("(%s): partial stub\n", debugstr_w(ExeName
));
1213 if (wcschr(ExeName
, L
'\\'))
1216 /* Check the existence of the variable, not value */
1217 if (!GetEnvironmentVariableW( env_name
, &env_val
, 1 ))
1228 NeedCurrentDirectoryForExePathA(LPCSTR ExeName
)
1232 if (!(ExeNameW
= FilenameA2W(ExeName
, FALSE
)))
1235 return NeedCurrentDirectoryForExePathW(ExeNameW
);
1242 /***********************************************************************
1245 * GetLongPathNameW (KERNEL32.@)
1248 * observed (Win2000):
1249 * shortpath=NULL: LastError=ERROR_INVALID_PARAMETER, ret=0
1250 * shortpath="": LastError=ERROR_PATH_NOT_FOUND, ret=0
1252 DWORD WINAPI
GetLongPathNameW( LPCWSTR shortpath
, LPWSTR longpath
, DWORD longlen
)
1254 #define MAX_PATHNAME_LEN 1024
1256 WCHAR tmplongpath
[MAX_PATHNAME_LEN
];
1258 DWORD sp
= 0, lp
= 0;
1261 WIN32_FIND_DATAW wfd
;
1266 SetLastError(ERROR_INVALID_PARAMETER
);
1271 SetLastError(ERROR_PATH_NOT_FOUND
);
1275 TRACE("GetLongPathNameW(%s,%p,%ld)\n", shortpath
, longpath
, longlen
);
1277 if (shortpath
[0] == '\\' && shortpath
[1] == '\\')
1279 WARN("ERR: UNC pathname %s\n", shortpath
);
1280 lstrcpynW( longpath
, shortpath
, longlen
);
1281 return wcslen(longpath
);
1283 unixabsolute
= (shortpath
[0] == '/');
1284 /* check for drive letter */
1285 if (!unixabsolute
&& shortpath
[1] == ':' )
1287 tmplongpath
[0] = shortpath
[0];
1288 tmplongpath
[1] = ':';
1292 while (shortpath
[sp
])
1294 /* check for path delimiters and reproduce them */
1295 if (shortpath
[sp
] == '\\' || shortpath
[sp
] == '/')
1297 if (!lp
|| tmplongpath
[lp
-1] != '\\')
1299 /* strip double "\\" */
1300 tmplongpath
[lp
++] = '\\';
1302 tmplongpath
[lp
] = 0; /* terminate string */
1308 if (sp
== 0 && p
[0] == '.' && (p
[1] == '/' || p
[1] == '\\'))
1310 tmplongpath
[lp
++] = *p
++;
1311 tmplongpath
[lp
++] = *p
++;
1313 for (; *p
&& *p
!= '/' && *p
!= '\\'; p
++);
1314 tmplen
= p
- (shortpath
+ sp
);
1315 lstrcpynW(tmplongpath
+ lp
, shortpath
+ sp
, tmplen
+ 1);
1316 /* Check if the file exists and use the existing file name */
1317 goit
= FindFirstFileW(tmplongpath
, &wfd
);
1318 if (goit
== INVALID_HANDLE_VALUE
)
1320 TRACE("not found %s!\n", tmplongpath
);
1321 SetLastError ( ERROR_FILE_NOT_FOUND
);
1325 wcscpy(tmplongpath
+ lp
, wfd
.cFileName
);
1326 lp
+= wcslen(tmplongpath
+ lp
);
1329 tmplen
= wcslen(shortpath
) - 1;
1330 if ((shortpath
[tmplen
] == '/' || shortpath
[tmplen
] == '\\') &&
1331 (tmplongpath
[lp
- 1] != '/' && tmplongpath
[lp
- 1] != '\\'))
1332 tmplongpath
[lp
++] = shortpath
[tmplen
];
1333 tmplongpath
[lp
] = 0;
1335 tmplen
= wcslen(tmplongpath
) + 1;
1336 if (tmplen
<= longlen
)
1338 wcscpy(longpath
, tmplongpath
);
1339 TRACE("returning %s\n", longpath
);
1340 tmplen
--; /* length without 0 */
1348 /***********************************************************************
1349 * GetLongPathNameA (KERNEL32.@)
1351 DWORD WINAPI
GetLongPathNameA( LPCSTR shortpath
, LPSTR longpath
, DWORD longlen
)
1354 WCHAR longpathW
[MAX_PATH
];
1357 TRACE("GetLongPathNameA %s, %i\n",shortpath
,longlen
);
1359 if (!(shortpathW
= FilenameA2W( shortpath
, FALSE
)))
1362 ret
= GetLongPathNameW(shortpathW
, longpathW
, MAX_PATH
);
1367 SetLastError(ERROR_FILENAME_EXCED_RANGE
);
1371 return FilenameW2A_FitOrFail(longpath
, longlen
, longpathW
, ret
+1 );