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 ******************************************************************/
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
;
100 DPRINT ("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
|
120 FILE_OPEN_FOR_BACKUP_INTENT
,
124 FILE_ATTRIBUTE_NORMAL
,
125 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
127 FILE_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT
,
131 RtlFreeHeap (RtlGetProcessHeap (),
135 if (!NT_SUCCESS(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 DPRINT ("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 DPRINT("Reparse points not supported, try with less options\n");
223 goto OpenTemplateDir
;
227 DPRINT1("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 DPRINT1("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 DPRINT1("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 DPRINT1("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 DPRINT1("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 DPRINT1("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 DPRINT("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
;
528 DPRINT("lpPathName %S\n", lpPathName
);
530 if (!RtlDosPathNameToNtPathName_U (lpPathName
,
536 InitializeObjectAttributes(&ObjectAttributes
,
538 OBJ_CASE_INSENSITIVE
,
542 DPRINT("NtPathU '%S'\n", NtPathU
.Buffer
);
544 Status
= NtCreateFile (&DirectoryHandle
,
549 FILE_ATTRIBUTE_DIRECTORY
, /* 0x7 */
552 FILE_DIRECTORY_FILE
, /* 0x204021 */
556 RtlFreeHeap (RtlGetProcessHeap (),
560 if (!NT_SUCCESS(Status
))
563 SetLastErrorByStatus (Status
);
567 FileDispInfo
.DeleteFile
= TRUE
;
569 Status
= NtSetInformationFile (DirectoryHandle
,
572 sizeof(FILE_DISPOSITION_INFORMATION
),
573 FileDispositionInformation
);
574 NtClose(DirectoryHandle
);
576 if (!NT_SUCCESS(Status
))
578 SetLastErrorByStatus (Status
);
598 WCHAR BufferW
[MAX_PATH
];
601 LPWSTR FilePartW
= NULL
;
603 DPRINT("GetFullPathNameA(lpFileName %s, nBufferLength %d, lpBuffer %p, "
604 "lpFilePart %p)\n",lpFileName
,nBufferLength
,lpBuffer
,lpFilePart
);
608 SetLastError(ERROR_INVALID_PARAMETER
);
612 if (!(FileNameW
= FilenameA2W(lpFileName
, FALSE
)))
615 ret
= GetFullPathNameW(FileNameW
, MAX_PATH
, BufferW
, &FilePartW
);
622 SetLastError(ERROR_FILENAME_EXCED_RANGE
);
626 ret
= FilenameW2A_FitOrFail(lpBuffer
, nBufferLength
, BufferW
, ret
+1);
628 if (ret
< nBufferLength
&& lpFilePart
)
630 /* if the path closed with '\', FilePart is NULL */
634 *lpFilePart
= (FilePartW
- BufferW
) + lpBuffer
;
637 DPRINT("GetFullPathNameA ret: lpBuffer %s lpFilePart %s\n",
638 lpBuffer
, (lpFilePart
== NULL
) ? "NULL" : *lpFilePart
);
658 DPRINT("GetFullPathNameW(lpFileName %S, nBufferLength %d, lpBuffer %p, "
659 "lpFilePart %p)\n",lpFileName
,nBufferLength
,lpBuffer
,lpFilePart
);
661 Length
= RtlGetFullPathName_U ((LPWSTR
)lpFileName
,
662 nBufferLength
* sizeof(WCHAR
),
666 DPRINT("GetFullPathNameW ret: lpBuffer %S lpFilePart %S Length %ld\n",
667 lpBuffer
, (lpFilePart
== NULL
) ? L
"NULL" : *lpFilePart
, Length
/ sizeof(WCHAR
));
669 return Length
/sizeof(WCHAR
);
674 * NOTE: Copied from Wine.
686 WCHAR ShortPathW
[MAX_PATH
];
691 SetLastError(ERROR_INVALID_PARAMETER
);
695 if (!(LongPathW
= FilenameA2W(longpath
, FALSE
)))
698 ret
= GetShortPathNameW(LongPathW
, ShortPathW
, MAX_PATH
);
705 SetLastError(ERROR_FILENAME_EXCED_RANGE
);
709 return FilenameW2A_FitOrFail(shortpath
, shortlen
, ShortPathW
, ret
+1);
714 * NOTE: Copied from Wine.
725 WCHAR tmpshortpath
[MAX_PATH
];
727 DWORD sp
= 0, lp
= 0;
729 WIN32_FIND_DATAW wfd
;
732 WCHAR ustr_buf
[8+1+3+1];
734 DPRINT("GetShortPathNameW: %S\n",longpath
);
738 SetLastError(ERROR_INVALID_PARAMETER
);
743 SetLastError(ERROR_BAD_PATHNAME
);
747 /* check for drive letter */
748 if (longpath
[1] == ':' )
750 tmpshortpath
[0] = longpath
[0];
751 tmpshortpath
[1] = ':';
755 ustr
.Buffer
= ustr_buf
;
757 ustr
.MaximumLength
= sizeof(ustr_buf
);
761 /* check for path delimiters and reproduce them */
762 if (longpath
[lp
] == '\\' || longpath
[lp
] == '/')
764 if (!sp
|| tmpshortpath
[sp
-1] != '\\')
766 /* strip double "\\" */
767 tmpshortpath
[sp
] = '\\';
770 tmpshortpath
[sp
] = 0; /* terminate string */
775 for (p
= longpath
+ lp
; *p
&& *p
!= '/' && *p
!= '\\'; p
++);
776 tmplen
= p
- (longpath
+ lp
);
777 lstrcpynW(tmpshortpath
+ sp
, longpath
+ lp
, tmplen
+ 1);
778 /* Check, if the current element is a valid dos name */
779 if (tmplen
<= 8+1+3+1)
782 memcpy(ustr_buf
, longpath
+ lp
, tmplen
* sizeof(WCHAR
));
783 ustr_buf
[tmplen
] = '\0';
784 ustr
.Length
= (USHORT
)tmplen
* sizeof(WCHAR
);
785 if (RtlIsNameLegalDOS8Dot3(&ustr
, NULL
, &spaces
) && !spaces
)
793 /* Check if the file exists and use the existing short file name */
794 goit
= FindFirstFileW(tmpshortpath
, &wfd
);
795 if (goit
== INVALID_HANDLE_VALUE
) goto notfound
;
797 lstrcpyW(tmpshortpath
+ sp
, wfd
.cAlternateFileName
);
798 sp
+= lstrlenW(tmpshortpath
+ sp
);
801 tmpshortpath
[sp
] = 0;
803 tmplen
= lstrlenW(tmpshortpath
) + 1;
804 if (tmplen
<= shortlen
)
806 lstrcpyW(shortpath
, tmpshortpath
);
807 tmplen
--; /* length without 0 */
813 SetLastError ( ERROR_FILE_NOT_FOUND
);
832 UNICODE_STRING PathU
= {0};
833 UNICODE_STRING FileNameU
= {0};
834 UNICODE_STRING ExtensionU
= {0};
835 UNICODE_STRING BufferU
= {0};
837 ANSI_STRING FileName
;
838 ANSI_STRING Extension
;
842 NTSTATUS Status
= STATUS_SUCCESS
;
844 RtlInitAnsiString (&Path
,
846 RtlInitAnsiString (&FileName
,
848 RtlInitAnsiString (&Extension
,
851 /* convert ansi (or oem) strings to unicode */
854 Status
= RtlAnsiStringToUnicodeString (&PathU
,
857 if (!NT_SUCCESS(Status
))
860 Status
= RtlAnsiStringToUnicodeString (&FileNameU
,
863 if (!NT_SUCCESS(Status
))
866 Status
= RtlAnsiStringToUnicodeString (&ExtensionU
,
869 if (!NT_SUCCESS(Status
))
874 Status
= RtlOemStringToUnicodeString (&PathU
,
877 if (!NT_SUCCESS(Status
))
879 Status
= RtlOemStringToUnicodeString (&FileNameU
,
882 if (!NT_SUCCESS(Status
))
885 Status
= RtlOemStringToUnicodeString (&ExtensionU
,
888 if (!NT_SUCCESS(Status
))
892 BufferU
.MaximumLength
= (USHORT
)nBufferLength
* sizeof(WCHAR
);
893 BufferU
.Buffer
= RtlAllocateHeap (RtlGetProcessHeap (),
895 BufferU
.MaximumLength
);
896 if (BufferU
.Buffer
== NULL
)
898 Status
= STATUS_NO_MEMORY
;
902 Buffer
.MaximumLength
= (USHORT
)nBufferLength
;
903 Buffer
.Buffer
= lpBuffer
;
905 RetValue
= SearchPathW (NULL
== lpPath
? NULL
: PathU
.Buffer
,
906 NULL
== lpFileName
? NULL
: FileNameU
.Buffer
,
907 NULL
== lpExtension
? NULL
: ExtensionU
.Buffer
,
914 BufferU
.Length
= wcslen(BufferU
.Buffer
) * sizeof(WCHAR
);
915 /* convert ansi (or oem) string to unicode */
917 RtlUnicodeStringToAnsiString (&Buffer
,
921 RtlUnicodeStringToOemString (&Buffer
,
924 /* nul-terminate ascii string */
925 Buffer
.Buffer
[BufferU
.Length
/ sizeof(WCHAR
)] = '\0';
927 if (NULL
!= lpFilePart
&& BufferU
.Length
!= 0)
929 *lpFilePart
= strrchr (lpBuffer
, '\\') + 1;
934 RtlFreeHeap (RtlGetProcessHeap (),
937 RtlFreeHeap (RtlGetProcessHeap (),
940 RtlFreeHeap (RtlGetProcessHeap (),
943 RtlFreeHeap (RtlGetProcessHeap (),
947 if (!NT_SUCCESS(Status
))
949 SetLastErrorByStatus(Status
);
971 * FUNCTION: Searches for the specified file
973 * lpPath = Points to a null-terminated string that specified the
974 * path to be searched. If this parameters is NULL then
975 * the following directories are searched
976 * The directory from which the application loaded
977 * The current directory
978 * The system directory
979 * The 16-bit system directory
980 * The windows directory
981 * The directories listed in the PATH environment
983 * lpFileName = Specifies the filename to search for
984 * lpExtension = Points to the null-terminated string that specifies
985 * an extension to be added to the filename when
986 * searching for the file. The first character of the
987 * filename extension must be a period (.). The
988 * extension is only added if the specified filename
989 * doesn't end with an extension
991 * If the filename extension is not required or if the
992 * filename contains an extension, this parameters can be
994 * nBufferLength = The length in characters of the buffer for output
995 * lpBuffer = Points to the buffer for the valid path and filename of
997 * lpFilePart = Points to the last component of the valid path and
999 * RETURNS: On success, the length, in characters, of the string copied to the
1006 PWCHAR EnvironmentBufferW
= NULL
;
1007 PWCHAR AppPathW
= NULL
;
1013 DPRINT("SearchPath\n");
1015 HasExtension
= FALSE
;
1016 p
= lpFileName
+ wcslen(lpFileName
);
1017 while (lpFileName
< p
&&
1018 L
'\\' != *(p
- 1) &&
1022 HasExtension
= HasExtension
|| L
'.' == *(p
- 1);
1027 if (HasExtension
|| NULL
== lpExtension
)
1029 Name
= (PWCHAR
) lpFileName
;
1033 Name
= RtlAllocateHeap(GetProcessHeap(),
1034 HEAP_GENERATE_EXCEPTIONS
,
1035 (wcslen(lpFileName
) + wcslen(lpExtension
) + 1)
1039 SetLastError(ERROR_OUTOFMEMORY
);
1042 wcscat(wcscpy(Name
, lpFileName
), lpExtension
);
1044 if (RtlDoesFileExists_U(Name
))
1046 retCode
= RtlGetFullPathName_U (Name
,
1047 nBufferLength
* sizeof(WCHAR
),
1051 if (Name
!= lpFileName
)
1053 RtlFreeHeap(GetProcessHeap(), 0, Name
);
1061 AppPathW
= (PWCHAR
) RtlAllocateHeap(RtlGetProcessHeap(),
1062 HEAP_GENERATE_EXCEPTIONS
|HEAP_ZERO_MEMORY
,
1063 MAX_PATH
* sizeof(WCHAR
));
1064 if (AppPathW
== NULL
)
1066 SetLastError(ERROR_OUTOFMEMORY
);
1071 wcscat (AppPathW
, NtCurrentPeb()->ProcessParameters
->ImagePathName
.Buffer
);
1073 len
= wcslen (AppPathW
);
1075 while (len
&& AppPathW
[len
- 1] != L
'\\')
1078 if (len
) AppPathW
[len
-1] = L
'\0';
1080 len
= GetEnvironmentVariableW(L
"PATH", &Buffer
, 0);
1081 len
+= 1 + GetCurrentDirectoryW(0, &Buffer
);
1082 len
+= 1 + GetSystemDirectoryW(&Buffer
, 0);
1083 len
+= 1 + GetWindowsDirectoryW(&Buffer
, 0);
1084 len
+= 1 + wcslen(AppPathW
) * sizeof(WCHAR
);
1086 EnvironmentBufferW
= (PWCHAR
) RtlAllocateHeap(RtlGetProcessHeap(),
1087 HEAP_GENERATE_EXCEPTIONS
|HEAP_ZERO_MEMORY
,
1088 len
* sizeof(WCHAR
));
1089 if (EnvironmentBufferW
== NULL
)
1091 RtlFreeHeap(RtlGetProcessHeap(), 0, AppPathW
);
1092 SetLastError(ERROR_OUTOFMEMORY
);
1096 pos
= GetCurrentDirectoryW(len
, EnvironmentBufferW
);
1097 EnvironmentBufferW
[pos
++] = L
';';
1098 EnvironmentBufferW
[pos
] = 0;
1099 pos
+= GetSystemDirectoryW(&EnvironmentBufferW
[pos
], len
- pos
);
1100 EnvironmentBufferW
[pos
++] = L
';';
1101 EnvironmentBufferW
[pos
] = 0;
1102 pos
+= GetWindowsDirectoryW(&EnvironmentBufferW
[pos
], len
- pos
);
1103 EnvironmentBufferW
[pos
++] = L
';';
1104 EnvironmentBufferW
[pos
] = 0;
1105 pos
+= GetEnvironmentVariableW(L
"PATH", &EnvironmentBufferW
[pos
], len
- pos
);
1106 EnvironmentBufferW
[pos
++] = L
';';
1107 EnvironmentBufferW
[pos
] = 0;
1108 wcscat (EnvironmentBufferW
, AppPathW
);
1110 RtlFreeHeap (RtlGetProcessHeap (),
1114 lpPath
= EnvironmentBufferW
;
1118 retCode
= RtlDosSearchPath_U ((PWCHAR
)lpPath
, (PWCHAR
)lpFileName
, (PWCHAR
)lpExtension
,
1119 nBufferLength
* sizeof(WCHAR
), lpBuffer
, lpFilePart
);
1121 if (EnvironmentBufferW
!= NULL
)
1123 RtlFreeHeap(GetProcessHeap(), 0, EnvironmentBufferW
);
1127 SetLastError(ERROR_FILE_NOT_FOUND
);
1130 return retCode
/ sizeof(WCHAR
);
1142 UNICODE_STRING PathName
;
1144 RtlInitUnicodeString(&PathName
, lpPathName
);
1146 RtlEnterCriticalSection(&DllLock
);
1147 if(PathName
.Length
> 0)
1149 if(PathName
.Length
+ sizeof(WCHAR
) <= DllDirectory
.MaximumLength
)
1151 RtlCopyUnicodeString(&DllDirectory
, &PathName
);
1155 RtlFreeUnicodeString(&DllDirectory
);
1156 if(!(DllDirectory
.Buffer
= (PWSTR
)RtlAllocateHeap(RtlGetProcessHeap(),
1158 PathName
.Length
+ sizeof(WCHAR
))))
1160 RtlLeaveCriticalSection(&DllLock
);
1161 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1164 DllDirectory
.Length
= 0;
1165 DllDirectory
.MaximumLength
= PathName
.Length
+ sizeof(WCHAR
);
1167 RtlCopyUnicodeString(&DllDirectory
, &PathName
);
1172 RtlFreeUnicodeString(&DllDirectory
);
1174 RtlLeaveCriticalSection(&DllLock
);
1185 LPCSTR lpPathName
/* can be NULL */
1188 PWCHAR PathNameW
=NULL
;
1192 if (!(PathNameW
= FilenameA2W(lpPathName
, FALSE
)))
1196 return SetDllDirectoryW(PathNameW
);
1205 DWORD nBufferLength
,
1211 RtlEnterCriticalSection(&DllLock
);
1212 if(nBufferLength
> 0)
1214 Ret
= DllDirectory
.Length
/ sizeof(WCHAR
);
1215 if(Ret
> nBufferLength
- 1)
1217 Ret
= nBufferLength
- 1;
1222 RtlCopyMemory(lpBuffer
, DllDirectory
.Buffer
, Ret
* sizeof(WCHAR
));
1224 lpBuffer
[Ret
] = L
'\0';
1228 /* include termination character, even if the string is empty! */
1229 Ret
= (DllDirectory
.Length
/ sizeof(WCHAR
)) + 1;
1231 RtlLeaveCriticalSection(&DllLock
);
1242 DWORD nBufferLength
,
1246 WCHAR BufferW
[MAX_PATH
];
1249 ret
= GetDllDirectoryW(MAX_PATH
, BufferW
);
1256 SetLastError(ERROR_FILENAME_EXCED_RANGE
);
1260 return FilenameW2A_FitOrFail(lpBuffer
, nBufferLength
, BufferW
, ret
+1);
1268 NeedCurrentDirectoryForExePathW(LPCWSTR ExeName
)
1270 return (wcschr(ExeName
,
1279 NeedCurrentDirectoryForExePathA(LPCSTR ExeName
)
1281 return (strchr(ExeName
,
1289 /***********************************************************************
1292 * GetLongPathNameW (KERNEL32.@)
1295 * observed (Win2000):
1296 * shortpath=NULL: LastError=ERROR_INVALID_PARAMETER, ret=0
1297 * shortpath="": LastError=ERROR_PATH_NOT_FOUND, ret=0
1299 DWORD STDCALL
GetLongPathNameW( LPCWSTR shortpath
, LPWSTR longpath
, DWORD longlen
)
1301 #define MAX_PATHNAME_LEN 1024
1303 WCHAR tmplongpath
[MAX_PATHNAME_LEN
];
1305 DWORD sp
= 0, lp
= 0;
1307 BOOL unixabsolute
= (shortpath
[0] == '/');
1308 WIN32_FIND_DATAW wfd
;
1313 SetLastError(ERROR_INVALID_PARAMETER
);
1318 SetLastError(ERROR_PATH_NOT_FOUND
);
1322 DPRINT("GetLongPathNameW(%s,%p,%ld)\n", shortpath
, longpath
, longlen
);
1324 if (shortpath
[0] == '\\' && shortpath
[1] == '\\')
1326 DPRINT1("ERR: UNC pathname %s\n", shortpath
);
1327 lstrcpynW( longpath
, shortpath
, longlen
);
1328 return wcslen(longpath
);
1331 /* check for drive letter */
1332 if (!unixabsolute
&& shortpath
[1] == ':' )
1334 tmplongpath
[0] = shortpath
[0];
1335 tmplongpath
[1] = ':';
1339 while (shortpath
[sp
])
1341 /* check for path delimiters and reproduce them */
1342 if (shortpath
[sp
] == '\\' || shortpath
[sp
] == '/')
1344 if (!lp
|| tmplongpath
[lp
-1] != '\\')
1346 /* strip double "\\" */
1347 tmplongpath
[lp
++] = '\\';
1349 tmplongpath
[lp
] = 0; /* terminate string */
1355 if (sp
== 0 && p
[0] == '.' && (p
[1] == '/' || p
[1] == '\\'))
1357 tmplongpath
[lp
++] = *p
++;
1358 tmplongpath
[lp
++] = *p
++;
1360 for (; *p
&& *p
!= '/' && *p
!= '\\'; p
++);
1361 tmplen
= p
- (shortpath
+ sp
);
1362 lstrcpynW(tmplongpath
+ lp
, shortpath
+ sp
, tmplen
+ 1);
1363 /* Check if the file exists and use the existing file name */
1364 goit
= FindFirstFileW(tmplongpath
, &wfd
);
1365 if (goit
== INVALID_HANDLE_VALUE
)
1367 DPRINT("not found %s!\n", tmplongpath
);
1368 SetLastError ( ERROR_FILE_NOT_FOUND
);
1372 wcscpy(tmplongpath
+ lp
, wfd
.cFileName
);
1373 lp
+= wcslen(tmplongpath
+ lp
);
1376 tmplen
= wcslen(shortpath
) - 1;
1377 if ((shortpath
[tmplen
] == '/' || shortpath
[tmplen
] == '\\') &&
1378 (tmplongpath
[lp
- 1] != '/' && tmplongpath
[lp
- 1] != '\\'))
1379 tmplongpath
[lp
++] = shortpath
[tmplen
];
1380 tmplongpath
[lp
] = 0;
1382 tmplen
= wcslen(tmplongpath
) + 1;
1383 if (tmplen
<= longlen
)
1385 wcscpy(longpath
, tmplongpath
);
1386 DPRINT("returning %s\n", longpath
);
1387 tmplen
--; /* length without 0 */
1395 /***********************************************************************
1396 * GetLongPathNameA (KERNEL32.@)
1398 DWORD STDCALL
GetLongPathNameA( LPCSTR shortpath
, LPSTR longpath
, DWORD longlen
)
1401 WCHAR longpathW
[MAX_PATH
];
1404 DPRINT("GetLongPathNameA %s, %i\n",shortpath
,longlen
);
1406 if (!(shortpathW
= FilenameA2W( shortpath
, FALSE
)))
1409 ret
= GetLongPathNameW(shortpathW
, longpathW
, MAX_PATH
);
1414 SetLastError(ERROR_FILENAME_EXCED_RANGE
);
1418 return FilenameW2A_FitOrFail(longpath
, longlen
, longpathW
, ret
+1 );