xref: /reactos/dll/win32/kernel32/client/file/dir.c (revision 9393fc32)
1*c2c66affSColin Finck /*
2*c2c66affSColin Finck  * COPYRIGHT:       See COPYING in the top level directory
3*c2c66affSColin Finck  * PROJECT:         ReactOS system libraries
4*c2c66affSColin Finck  * FILE:            dll/win32/kernel32/client/file/dir.c
5*c2c66affSColin Finck  * PURPOSE:         Directory functions
6*c2c66affSColin Finck  * PROGRAMMER:      Pierre Schweitzer (pierre@reactos.org)
7*c2c66affSColin Finck  */
8*c2c66affSColin Finck 
9*c2c66affSColin Finck /* INCLUDES ******************************************************************/
10*c2c66affSColin Finck 
11*c2c66affSColin Finck #include <k32.h>
12*c2c66affSColin Finck #define NDEBUG
13*c2c66affSColin Finck #include <debug.h>
14*c2c66affSColin Finck 
15*c2c66affSColin Finck /* Short File Name length in chars (8.3) */
16*c2c66affSColin Finck #define SFN_LENGTH 12
17*c2c66affSColin Finck 
18*c2c66affSColin Finck /* Match a volume name like:
19*c2c66affSColin Finck  * \\?\Volume{GUID}
20*c2c66affSColin Finck  */
21*c2c66affSColin Finck #define IS_VOLUME_NAME(s, l)                       \
22*c2c66affSColin Finck   ((l == 96 || (l == 98 && s[48] == '\\')) &&      \
23*c2c66affSColin Finck    s[0] == '\\'&& (s[1] == '?' || s[1] == '\\') && \
24*c2c66affSColin Finck    s[2] == '?' && s[3] == '\\' && s[4] == 'V' &&   \
25*c2c66affSColin Finck    s[5] == 'o' && s[6] == 'l' && s[7] == 'u' &&    \
26*c2c66affSColin Finck    s[8] == 'm' && s[9] == 'e' && s[10] == '{' &&   \
27*c2c66affSColin Finck    s[19] == '-' && s[24] == '-' && s[29] == '-' && \
28*c2c66affSColin Finck    s[34] == '-' && s[47] == '}')
29*c2c66affSColin Finck 
30*c2c66affSColin Finck /* FUNCTIONS *****************************************************************/
31*c2c66affSColin Finck 
32*c2c66affSColin Finck /*
33*c2c66affSColin Finck  * @implemented
34*c2c66affSColin Finck  */
35*c2c66affSColin Finck BOOL
36*c2c66affSColin Finck WINAPI
CreateDirectoryA(IN LPCSTR lpPathName,IN LPSECURITY_ATTRIBUTES lpSecurityAttributes)37*c2c66affSColin Finck CreateDirectoryA(IN LPCSTR lpPathName,
38*c2c66affSColin Finck                  IN LPSECURITY_ATTRIBUTES lpSecurityAttributes)
39*c2c66affSColin Finck {
40*c2c66affSColin Finck     PUNICODE_STRING PathNameW;
41*c2c66affSColin Finck 
42*c2c66affSColin Finck     PathNameW = Basep8BitStringToStaticUnicodeString(lpPathName);
43*c2c66affSColin Finck     if (!PathNameW)
44*c2c66affSColin Finck     {
45*c2c66affSColin Finck         return FALSE;
46*c2c66affSColin Finck     }
47*c2c66affSColin Finck 
48*c2c66affSColin Finck     return CreateDirectoryW(PathNameW->Buffer,
49*c2c66affSColin Finck                             lpSecurityAttributes);
50*c2c66affSColin Finck }
51*c2c66affSColin Finck 
52*c2c66affSColin Finck /*
53*c2c66affSColin Finck  * @implemented
54*c2c66affSColin Finck  */
55*c2c66affSColin Finck BOOL
56*c2c66affSColin Finck WINAPI
CreateDirectoryExA(IN LPCSTR lpTemplateDirectory,IN LPCSTR lpNewDirectory,IN LPSECURITY_ATTRIBUTES lpSecurityAttributes)57*c2c66affSColin Finck CreateDirectoryExA(IN LPCSTR lpTemplateDirectory,
58*c2c66affSColin Finck                    IN LPCSTR lpNewDirectory,
59*c2c66affSColin Finck                    IN LPSECURITY_ATTRIBUTES lpSecurityAttributes)
60*c2c66affSColin Finck {
61*c2c66affSColin Finck     PUNICODE_STRING TemplateDirectoryW;
62*c2c66affSColin Finck     UNICODE_STRING NewDirectoryW;
63*c2c66affSColin Finck     BOOL ret;
64*c2c66affSColin Finck 
65*c2c66affSColin Finck     TemplateDirectoryW = Basep8BitStringToStaticUnicodeString(lpTemplateDirectory);
66*c2c66affSColin Finck     if (!TemplateDirectoryW)
67*c2c66affSColin Finck     {
68*c2c66affSColin Finck         return FALSE;
69*c2c66affSColin Finck     }
70*c2c66affSColin Finck 
71*c2c66affSColin Finck     if (!Basep8BitStringToDynamicUnicodeString(&NewDirectoryW, lpNewDirectory))
72*c2c66affSColin Finck     {
73*c2c66affSColin Finck         return FALSE;
74*c2c66affSColin Finck     }
75*c2c66affSColin Finck 
76*c2c66affSColin Finck     ret = CreateDirectoryExW(TemplateDirectoryW->Buffer,
77*c2c66affSColin Finck                              NewDirectoryW.Buffer,
78*c2c66affSColin Finck                              lpSecurityAttributes);
79*c2c66affSColin Finck 
80*c2c66affSColin Finck     RtlFreeUnicodeString(&NewDirectoryW);
81*c2c66affSColin Finck 
82*c2c66affSColin Finck     return ret;
83*c2c66affSColin Finck }
84*c2c66affSColin Finck 
85*c2c66affSColin Finck /*
86*c2c66affSColin Finck  * @implemented
87*c2c66affSColin Finck  */
88*c2c66affSColin Finck BOOL
89*c2c66affSColin Finck WINAPI
CreateDirectoryW(IN LPCWSTR lpPathName,IN LPSECURITY_ATTRIBUTES lpSecurityAttributes)90*c2c66affSColin Finck CreateDirectoryW(IN LPCWSTR lpPathName,
91*c2c66affSColin Finck                  IN LPSECURITY_ATTRIBUTES lpSecurityAttributes)
92*c2c66affSColin Finck {
93*c2c66affSColin Finck     DWORD Length;
94*c2c66affSColin Finck     NTSTATUS Status;
95*c2c66affSColin Finck     HANDLE DirectoryHandle;
96*c2c66affSColin Finck     UNICODE_STRING NtPathU;
97*c2c66affSColin Finck     PWSTR PathUBuffer, FilePart;
98*c2c66affSColin Finck     IO_STATUS_BLOCK IoStatusBlock;
99*c2c66affSColin Finck     RTL_RELATIVE_NAME_U RelativeName;
100*c2c66affSColin Finck     OBJECT_ATTRIBUTES ObjectAttributes;
101*c2c66affSColin Finck 
102*c2c66affSColin Finck     /* Get relative name */
103*c2c66affSColin Finck     if (!RtlDosPathNameToRelativeNtPathName_U(lpPathName, &NtPathU, NULL, &RelativeName))
104*c2c66affSColin Finck     {
105*c2c66affSColin Finck         SetLastError(ERROR_PATH_NOT_FOUND);
106*c2c66affSColin Finck         return FALSE;
107*c2c66affSColin Finck     }
108*c2c66affSColin Finck 
109*c2c66affSColin Finck     /* Check if path length is < MAX_PATH (with space for file name).
110*c2c66affSColin Finck      * If not, prefix is required.
111*c2c66affSColin Finck      */
112*c2c66affSColin Finck     if (NtPathU.Length > (MAX_PATH - SFN_LENGTH) * sizeof(WCHAR) && lpPathName[0] != L'\\' &&
113*c2c66affSColin Finck         lpPathName[1] != L'\\' && lpPathName[2] != L'?' && lpPathName[3] != L'\\')
114*c2c66affSColin Finck     {
115*c2c66affSColin Finck         /* Get file name position and full path length */
116*c2c66affSColin Finck         Length = GetFullPathNameW(lpPathName, 0, NULL, &FilePart);
117*c2c66affSColin Finck         if (Length == 0)
118*c2c66affSColin Finck         {
119*c2c66affSColin Finck             RtlReleaseRelativeName(&RelativeName);
120*c2c66affSColin Finck             RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathU.Buffer);
121*c2c66affSColin Finck             SetLastError(ERROR_FILENAME_EXCED_RANGE);
122*c2c66affSColin Finck             return FALSE;
123*c2c66affSColin Finck         }
124*c2c66affSColin Finck 
125*c2c66affSColin Finck         /* Keep place for 8.3 file name */
126*c2c66affSColin Finck         Length += SFN_LENGTH;
127*c2c66affSColin Finck         /* No prefix, so, must be smaller than MAX_PATH */
128*c2c66affSColin Finck         if (Length > MAX_PATH)
129*c2c66affSColin Finck         {
130*c2c66affSColin Finck             RtlReleaseRelativeName(&RelativeName);
131*c2c66affSColin Finck             RtlFreeHeap(GetProcessHeap(), 0, NtPathU.Buffer);
132*c2c66affSColin Finck             SetLastError(ERROR_FILENAME_EXCED_RANGE);
133*c2c66affSColin Finck             return FALSE;
134*c2c66affSColin Finck         }
135*c2c66affSColin Finck     }
136*c2c66affSColin Finck 
137*c2c66affSColin Finck     /* Save buffer to allow later freeing */
138*c2c66affSColin Finck     PathUBuffer = NtPathU.Buffer;
139*c2c66affSColin Finck 
140*c2c66affSColin Finck     /* If we have relative name (and root dir), use them instead */
141*c2c66affSColin Finck     if (RelativeName.RelativeName.Length != 0)
142*c2c66affSColin Finck     {
143*c2c66affSColin Finck         NtPathU.Length = RelativeName.RelativeName.Length;
144*c2c66affSColin Finck         NtPathU.MaximumLength = RelativeName.RelativeName.MaximumLength;
145*c2c66affSColin Finck         NtPathU.Buffer = RelativeName.RelativeName.Buffer;
146*c2c66affSColin Finck     }
147*c2c66affSColin Finck     else
148*c2c66affSColin Finck     {
149*c2c66affSColin Finck         RelativeName.ContainingDirectory = NULL;
150*c2c66affSColin Finck     }
151*c2c66affSColin Finck 
152*c2c66affSColin Finck     InitializeObjectAttributes(&ObjectAttributes,
153*c2c66affSColin Finck                                &NtPathU,
154*c2c66affSColin Finck                                OBJ_CASE_INSENSITIVE,
155*c2c66affSColin Finck                                RelativeName.ContainingDirectory,
156*c2c66affSColin Finck                                (lpSecurityAttributes ? lpSecurityAttributes->lpSecurityDescriptor : NULL));
157*c2c66affSColin Finck 
158*c2c66affSColin Finck     Status = NtCreateFile(&DirectoryHandle,
159*c2c66affSColin Finck                           FILE_LIST_DIRECTORY | SYNCHRONIZE,
160*c2c66affSColin Finck                           &ObjectAttributes,
161*c2c66affSColin Finck                           &IoStatusBlock,
162*c2c66affSColin Finck                           NULL,
163*c2c66affSColin Finck                           FILE_ATTRIBUTE_NORMAL,
164*c2c66affSColin Finck                           FILE_SHARE_READ | FILE_SHARE_WRITE,
165*c2c66affSColin Finck                           FILE_CREATE,
166*c2c66affSColin Finck                           FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT,
167*c2c66affSColin Finck                           NULL,
168*c2c66affSColin Finck                           0);
169*c2c66affSColin Finck 
170*c2c66affSColin Finck     RtlReleaseRelativeName(&RelativeName);
171*c2c66affSColin Finck     RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
172*c2c66affSColin Finck 
173*c2c66affSColin Finck     if (NT_SUCCESS(Status))
174*c2c66affSColin Finck     {
175*c2c66affSColin Finck         NtClose(DirectoryHandle);
176*c2c66affSColin Finck         return TRUE;
177*c2c66affSColin Finck     }
178*c2c66affSColin Finck 
179*c2c66affSColin Finck     if (RtlIsDosDeviceName_U(lpPathName))
180*c2c66affSColin Finck     {
181*c2c66affSColin Finck         Status = STATUS_NOT_A_DIRECTORY;
182*c2c66affSColin Finck     }
183*c2c66affSColin Finck 
184*c2c66affSColin Finck     BaseSetLastNTError(Status);
185*c2c66affSColin Finck     return FALSE;
186*c2c66affSColin Finck }
187*c2c66affSColin Finck 
188*c2c66affSColin Finck /*
189*c2c66affSColin Finck  * @implemented
190*c2c66affSColin Finck  */
191*c2c66affSColin Finck BOOL
192*c2c66affSColin Finck WINAPI
CreateDirectoryExW(IN LPCWSTR lpTemplateDirectory,IN LPCWSTR lpNewDirectory,IN LPSECURITY_ATTRIBUTES lpSecurityAttributes)193*c2c66affSColin Finck CreateDirectoryExW(IN LPCWSTR lpTemplateDirectory,
194*c2c66affSColin Finck                    IN LPCWSTR lpNewDirectory,
195*c2c66affSColin Finck                    IN LPSECURITY_ATTRIBUTES lpSecurityAttributes)
196*c2c66affSColin Finck {
197*c2c66affSColin Finck     DWORD Length;
198*c2c66affSColin Finck     NTSTATUS Status;
199*c2c66affSColin Finck     PVOID EaBuffer = NULL;
200*c2c66affSColin Finck     BOOL ReparsePoint = FALSE;
201*c2c66affSColin Finck     IO_STATUS_BLOCK IoStatusBlock;
202*c2c66affSColin Finck     FILE_EA_INFORMATION FileEaInfo;
203*c2c66affSColin Finck     ULONG EaLength = 0, StreamSize;
204*c2c66affSColin Finck     OBJECT_ATTRIBUTES ObjectAttributes;
205*c2c66affSColin Finck     FILE_BASIC_INFORMATION FileBasicInfo;
206*c2c66affSColin Finck     PREPARSE_DATA_BUFFER ReparseDataBuffer;
207*c2c66affSColin Finck     HANDLE TemplateHandle, DirectoryHandle;
208*c2c66affSColin Finck     PFILE_STREAM_INFORMATION FileStreamInfo;
209*c2c66affSColin Finck     FILE_ATTRIBUTE_TAG_INFORMATION FileTagInfo;
210*c2c66affSColin Finck     UNICODE_STRING NtPathU, NtTemplatePathU, NewDirectory;
211*c2c66affSColin Finck     RTL_RELATIVE_NAME_U RelativeName, TemplateRelativeName;
212*c2c66affSColin Finck     PWSTR TemplateBuffer, PathUBuffer, FilePart, SubstituteName;
213*c2c66affSColin Finck 
214*c2c66affSColin Finck     /* Get relative name of the template */
215*c2c66affSColin Finck     if (!RtlDosPathNameToRelativeNtPathName_U(lpTemplateDirectory, &NtTemplatePathU, NULL, &TemplateRelativeName))
216*c2c66affSColin Finck     {
217*c2c66affSColin Finck         SetLastError(ERROR_PATH_NOT_FOUND);
218*c2c66affSColin Finck         return FALSE;
219*c2c66affSColin Finck     }
220*c2c66affSColin Finck 
221*c2c66affSColin Finck     /* Save buffer for further freeing */
222*c2c66affSColin Finck     TemplateBuffer = NtTemplatePathU.Buffer;
223*c2c66affSColin Finck 
224*c2c66affSColin Finck     /* If we have relative name (and root dir), use them instead */
225*c2c66affSColin Finck     if (TemplateRelativeName.RelativeName.Length != 0)
226*c2c66affSColin Finck     {
227*c2c66affSColin Finck         NtTemplatePathU.Length = TemplateRelativeName.RelativeName.Length;
228*c2c66affSColin Finck         NtTemplatePathU.MaximumLength = TemplateRelativeName.RelativeName.MaximumLength;
229*c2c66affSColin Finck         NtTemplatePathU.Buffer = TemplateRelativeName.RelativeName.Buffer;
230*c2c66affSColin Finck     }
231*c2c66affSColin Finck     else
232*c2c66affSColin Finck     {
233*c2c66affSColin Finck         TemplateRelativeName.ContainingDirectory = NULL;
234*c2c66affSColin Finck     }
235*c2c66affSColin Finck 
236*c2c66affSColin Finck     InitializeObjectAttributes(&ObjectAttributes,
237*c2c66affSColin Finck                                &NtTemplatePathU,
238*c2c66affSColin Finck                                OBJ_CASE_INSENSITIVE,
239*c2c66affSColin Finck                                NULL,
240*c2c66affSColin Finck                                NULL);
241*c2c66affSColin Finck 
242*c2c66affSColin Finck     /* Open template directory */
243*c2c66affSColin Finck     Status = NtOpenFile(&TemplateHandle,
244*c2c66affSColin Finck                         FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES | FILE_READ_EA,
245*c2c66affSColin Finck                         &ObjectAttributes,
246*c2c66affSColin Finck                         &IoStatusBlock,
247*c2c66affSColin Finck                         FILE_SHARE_READ | FILE_SHARE_WRITE,
248*c2c66affSColin Finck                         FILE_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT | FILE_OPEN_FOR_BACKUP_INTENT);
249*c2c66affSColin Finck     if (!NT_SUCCESS(Status))
250*c2c66affSColin Finck     {
251*c2c66affSColin Finck         if (Status != STATUS_INVALID_PARAMETER)
252*c2c66affSColin Finck         {
253*c2c66affSColin Finck             RtlReleaseRelativeName(&TemplateRelativeName);
254*c2c66affSColin Finck             RtlFreeHeap(RtlGetProcessHeap(), 0, TemplateBuffer);
255*c2c66affSColin Finck             BaseSetLastNTError(Status);
256*c2c66affSColin Finck             return FALSE;
257*c2c66affSColin Finck         }
258*c2c66affSColin Finck 
259*c2c66affSColin Finck OpenWithoutReparseSupport:
260*c2c66affSColin Finck         /* Opening failed due to lacking reparse points support in the FSD, try without */
261*c2c66affSColin Finck         Status = NtOpenFile(&TemplateHandle,
262*c2c66affSColin Finck                             FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES | FILE_READ_EA,
263*c2c66affSColin Finck                             &ObjectAttributes,
264*c2c66affSColin Finck                             &IoStatusBlock,
265*c2c66affSColin Finck                             FILE_SHARE_READ | FILE_SHARE_WRITE,
266*c2c66affSColin Finck                             FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT);
267*c2c66affSColin Finck 
268*c2c66affSColin Finck         if (!NT_SUCCESS(Status))
269*c2c66affSColin Finck         {
270*c2c66affSColin Finck             RtlReleaseRelativeName(&TemplateRelativeName);
271*c2c66affSColin Finck             RtlFreeHeap(RtlGetProcessHeap(), 0, TemplateBuffer);
272*c2c66affSColin Finck             BaseSetLastNTError(Status);
273*c2c66affSColin Finck             return FALSE;
274*c2c66affSColin Finck         }
275*c2c66affSColin Finck 
276*c2c66affSColin Finck         /* Request file attributes */
277*c2c66affSColin Finck         FileBasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
278*c2c66affSColin Finck         Status = NtQueryInformationFile(TemplateHandle,
279*c2c66affSColin Finck                                         &IoStatusBlock,
280*c2c66affSColin Finck                                         &FileBasicInfo,
281*c2c66affSColin Finck                                         sizeof(FileBasicInfo),
282*c2c66affSColin Finck                                         FileBasicInformation);
283*c2c66affSColin Finck         if (!NT_SUCCESS(Status))
284*c2c66affSColin Finck         {
285*c2c66affSColin Finck             RtlReleaseRelativeName(&TemplateRelativeName);
286*c2c66affSColin Finck             RtlFreeHeap(RtlGetProcessHeap(), 0, TemplateBuffer);
287*c2c66affSColin Finck             CloseHandle(TemplateHandle);
288*c2c66affSColin Finck             BaseSetLastNTError(Status);
289*c2c66affSColin Finck             return FALSE;
290*c2c66affSColin Finck 
291*c2c66affSColin Finck         }
292*c2c66affSColin Finck     }
293*c2c66affSColin Finck     else
294*c2c66affSColin Finck     {
295*c2c66affSColin Finck         /* Request file attributes */
296*c2c66affSColin Finck         FileBasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
297*c2c66affSColin Finck         Status = NtQueryInformationFile(TemplateHandle,
298*c2c66affSColin Finck                                         &IoStatusBlock,
299*c2c66affSColin Finck                                         &FileBasicInfo,
300*c2c66affSColin Finck                                         sizeof(FileBasicInfo),
301*c2c66affSColin Finck                                         FileBasicInformation);
302*c2c66affSColin Finck         if (!NT_SUCCESS(Status))
303*c2c66affSColin Finck         {
304*c2c66affSColin Finck             RtlReleaseRelativeName(&TemplateRelativeName);
305*c2c66affSColin Finck             RtlFreeHeap(RtlGetProcessHeap(), 0, TemplateBuffer);
306*c2c66affSColin Finck             CloseHandle(TemplateHandle);
307*c2c66affSColin Finck             BaseSetLastNTError(Status);
308*c2c66affSColin Finck             return FALSE;
309*c2c66affSColin Finck 
310*c2c66affSColin Finck         }
311*c2c66affSColin Finck 
312*c2c66affSColin Finck         /* If it is a reparse point, then get information about it */
313*c2c66affSColin Finck         if (FileBasicInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
314*c2c66affSColin Finck         {
315*c2c66affSColin Finck             Status = NtQueryInformationFile(TemplateHandle,
316*c2c66affSColin Finck                                             &IoStatusBlock,
317*c2c66affSColin Finck                                             &FileTagInfo,
318*c2c66affSColin Finck                                             sizeof(FileTagInfo),
319*c2c66affSColin Finck                                             FileAttributeTagInformation);
320*c2c66affSColin Finck             if (!NT_SUCCESS(Status))
321*c2c66affSColin Finck             {
322*c2c66affSColin Finck                 RtlReleaseRelativeName(&TemplateRelativeName);
323*c2c66affSColin Finck                 RtlFreeHeap(RtlGetProcessHeap(), 0, TemplateBuffer);
324*c2c66affSColin Finck                 CloseHandle(TemplateHandle);
325*c2c66affSColin Finck                 BaseSetLastNTError(Status);
326*c2c66affSColin Finck                 return FALSE;
327*c2c66affSColin Finck             }
328*c2c66affSColin Finck 
329*c2c66affSColin Finck             /* Only mount points are supported, retry without if anything different */
330*c2c66affSColin Finck             if (FileTagInfo.ReparseTag != IO_REPARSE_TAG_MOUNT_POINT)
331*c2c66affSColin Finck             {
332*c2c66affSColin Finck                 CloseHandle(TemplateHandle);
333*c2c66affSColin Finck                 goto OpenWithoutReparseSupport;
334*c2c66affSColin Finck             }
335*c2c66affSColin Finck 
336*c2c66affSColin Finck             /* Mark we are playing with a reparse point */
337*c2c66affSColin Finck             ReparsePoint = TRUE;
338*c2c66affSColin Finck         }
339*c2c66affSColin Finck     }
340*c2c66affSColin Finck 
341*c2c66affSColin Finck     /* Get relative name of the directory */
342*c2c66affSColin Finck     if (!RtlDosPathNameToRelativeNtPathName_U(lpNewDirectory, &NtPathU, NULL, &RelativeName))
343*c2c66affSColin Finck     {
344*c2c66affSColin Finck         RtlReleaseRelativeName(&TemplateRelativeName);
345*c2c66affSColin Finck         RtlFreeHeap(RtlGetProcessHeap(), 0, TemplateBuffer);
346*c2c66affSColin Finck         NtClose(TemplateHandle);
347*c2c66affSColin Finck         SetLastError(ERROR_PATH_NOT_FOUND);
348*c2c66affSColin Finck         return FALSE;
349*c2c66affSColin Finck     }
350*c2c66affSColin Finck 
351*c2c66affSColin Finck     /* Save its buffer for further freeing */
352*c2c66affSColin Finck     PathUBuffer = NtPathU.Buffer;
353*c2c66affSColin Finck 
354*c2c66affSColin Finck     /* Template & directory can't be the same */
355*c2c66affSColin Finck     if (RtlEqualUnicodeString(&NtPathU,
356*c2c66affSColin Finck                               &NtTemplatePathU,
357*c2c66affSColin Finck                               TRUE))
358*c2c66affSColin Finck     {
359*c2c66affSColin Finck         RtlReleaseRelativeName(&RelativeName);
360*c2c66affSColin Finck         RtlReleaseRelativeName(&TemplateRelativeName);
361*c2c66affSColin Finck         RtlFreeHeap(RtlGetProcessHeap(), 0, TemplateBuffer);
362*c2c66affSColin Finck         RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
363*c2c66affSColin Finck         NtClose(TemplateHandle);
364*c2c66affSColin Finck         SetLastError(ERROR_INVALID_NAME);
365*c2c66affSColin Finck         return FALSE;
366*c2c66affSColin Finck     }
367*c2c66affSColin Finck 
368*c2c66affSColin Finck     RtlReleaseRelativeName(&TemplateRelativeName);
369*c2c66affSColin Finck     RtlFreeHeap(RtlGetProcessHeap(), 0, TemplateBuffer);
370*c2c66affSColin Finck 
371*c2c66affSColin Finck     /* Check if path length is < MAX_PATH (with space for file name).
372*c2c66affSColin Finck      * If not, prefix is required.
373*c2c66affSColin Finck      */
374*c2c66affSColin Finck     if (NtPathU.Length > (MAX_PATH - SFN_LENGTH) * sizeof(WCHAR) && lpNewDirectory[0] != L'\\' &&
375*c2c66affSColin Finck         lpNewDirectory[1] != L'\\' && lpNewDirectory[2] != L'?' && lpNewDirectory[3] != L'\\')
376*c2c66affSColin Finck     {
377*c2c66affSColin Finck         /* Get file name position and full path length */
378*c2c66affSColin Finck         Length = GetFullPathNameW(lpNewDirectory, 0, NULL, &FilePart);
379*c2c66affSColin Finck         if (Length == 0)
380*c2c66affSColin Finck         {
381*c2c66affSColin Finck             RtlReleaseRelativeName(&RelativeName);
382*c2c66affSColin Finck             RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
383*c2c66affSColin Finck             CloseHandle(TemplateHandle);
384*c2c66affSColin Finck             SetLastError(ERROR_FILENAME_EXCED_RANGE);
385*c2c66affSColin Finck             return FALSE;
386*c2c66affSColin Finck         }
387*c2c66affSColin Finck 
388*c2c66affSColin Finck         /* Keep place for 8.3 file name */
389*c2c66affSColin Finck         Length += SFN_LENGTH;
390*c2c66affSColin Finck         /* No prefix, so, must be smaller than MAX_PATH */
391*c2c66affSColin Finck         if (Length > MAX_PATH)
392*c2c66affSColin Finck         {
393*c2c66affSColin Finck             RtlReleaseRelativeName(&RelativeName);
394*c2c66affSColin Finck             RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
395*c2c66affSColin Finck             CloseHandle(TemplateHandle);
396*c2c66affSColin Finck             SetLastError(ERROR_FILENAME_EXCED_RANGE);
397*c2c66affSColin Finck             return FALSE;
398*c2c66affSColin Finck         }
399*c2c66affSColin Finck     }
400*c2c66affSColin Finck 
401*c2c66affSColin Finck     /* If we have relative name (and root dir), use them instead */
402*c2c66affSColin Finck     if (RelativeName.RelativeName.Length != 0)
403*c2c66affSColin Finck     {
404*c2c66affSColin Finck         NtPathU.Length = RelativeName.RelativeName.Length;
405*c2c66affSColin Finck         NtPathU.MaximumLength = RelativeName.RelativeName.MaximumLength;
406*c2c66affSColin Finck         NtPathU.Buffer = RelativeName.RelativeName.Buffer;
407*c2c66affSColin Finck     }
408*c2c66affSColin Finck     else
409*c2c66affSColin Finck     {
410*c2c66affSColin Finck         RelativeName.ContainingDirectory = NULL;
411*c2c66affSColin Finck     }
412*c2c66affSColin Finck 
413*c2c66affSColin Finck     /* Get extended attributes */
414*c2c66affSColin Finck     Status = NtQueryInformationFile(TemplateHandle,
415*c2c66affSColin Finck                                     &IoStatusBlock,
416*c2c66affSColin Finck                                     &FileEaInfo,
417*c2c66affSColin Finck                                     sizeof(FileEaInfo),
418*c2c66affSColin Finck                                     FileEaInformation);
419*c2c66affSColin Finck     if (!NT_SUCCESS(Status))
420*c2c66affSColin Finck     {
421*c2c66affSColin Finck         RtlReleaseRelativeName(&RelativeName);
422*c2c66affSColin Finck         RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
423*c2c66affSColin Finck         CloseHandle(TemplateHandle);
424*c2c66affSColin Finck         BaseSetLastNTError(Status);
425*c2c66affSColin Finck         return FALSE;
426*c2c66affSColin Finck     }
427*c2c66affSColin Finck 
428*c2c66affSColin Finck     /* Start reading extended attributes */
429*c2c66affSColin Finck     if (FileEaInfo.EaSize != 0)
430*c2c66affSColin Finck     {
431*c2c66affSColin Finck         for (EaLength = FileEaInfo.EaSize * 2; ; EaLength = EaLength * 2)
432*c2c66affSColin Finck         {
433*c2c66affSColin Finck             /* Allocate buffer for reading */
434*c2c66affSColin Finck             EaBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, EaLength);
435*c2c66affSColin Finck             if (!EaBuffer)
436*c2c66affSColin Finck             {
437*c2c66affSColin Finck                 RtlReleaseRelativeName(&RelativeName);
438*c2c66affSColin Finck                 RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
439*c2c66affSColin Finck                 CloseHandle(TemplateHandle);
440*c2c66affSColin Finck                 BaseSetLastNTError(STATUS_NO_MEMORY);
441*c2c66affSColin Finck                 return FALSE;
442*c2c66affSColin Finck             }
443*c2c66affSColin Finck 
444*c2c66affSColin Finck             /* Query EAs */
445*c2c66affSColin Finck             Status = NtQueryEaFile(TemplateHandle,
446*c2c66affSColin Finck                                    &IoStatusBlock,
447*c2c66affSColin Finck                                    EaBuffer,
448*c2c66affSColin Finck                                    EaLength,
449*c2c66affSColin Finck                                    FALSE,
450*c2c66affSColin Finck                                    NULL,
451*c2c66affSColin Finck                                    0,
452*c2c66affSColin Finck                                    NULL,
453*c2c66affSColin Finck                                    TRUE);
454*c2c66affSColin Finck             if (!NT_SUCCESS(Status))
455*c2c66affSColin Finck             {
456*c2c66affSColin Finck                 RtlFreeHeap(RtlGetProcessHeap(), 0, EaBuffer);
457*c2c66affSColin Finck                 IoStatusBlock.Information = 0;
458*c2c66affSColin Finck             }
459*c2c66affSColin Finck 
460*c2c66affSColin Finck             /* If we don't fail because of too small buffer, stop here */
461*c2c66affSColin Finck             if (Status != STATUS_BUFFER_OVERFLOW &&
462*c2c66affSColin Finck                 Status != STATUS_BUFFER_TOO_SMALL)
463*c2c66affSColin Finck             {
464*c2c66affSColin Finck                 EaLength = IoStatusBlock.Information;
465*c2c66affSColin Finck                 break;
466*c2c66affSColin Finck             }
467*c2c66affSColin Finck         }
468*c2c66affSColin Finck     }
469*c2c66affSColin Finck 
470*c2c66affSColin Finck     InitializeObjectAttributes(&ObjectAttributes,
471*c2c66affSColin Finck                                &NtPathU,
472*c2c66affSColin Finck                                OBJ_CASE_INSENSITIVE,
473*c2c66affSColin Finck                                RelativeName.ContainingDirectory,
474*c2c66affSColin Finck                                (lpSecurityAttributes ? lpSecurityAttributes->lpSecurityDescriptor : NULL));
475*c2c66affSColin Finck 
476*c2c66affSColin Finck     /* Ensure attributes are valid */
477*c2c66affSColin Finck     FileBasicInfo.FileAttributes &= FILE_ATTRIBUTE_VALID_FLAGS;
478*c2c66affSColin Finck 
479*c2c66affSColin Finck     /* Create the new directory */
480*c2c66affSColin Finck     Status = NtCreateFile(&DirectoryHandle,
481*c2c66affSColin Finck                           FILE_LIST_DIRECTORY | SYNCHRONIZE | FILE_WRITE_ATTRIBUTES |
482*c2c66affSColin Finck                           FILE_READ_ATTRIBUTES | (FileBasicInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ? FILE_ADD_FILE : 0),
483*c2c66affSColin Finck                           &ObjectAttributes,
484*c2c66affSColin Finck                           &IoStatusBlock,
485*c2c66affSColin Finck                           NULL,
486*c2c66affSColin Finck                           FileBasicInfo.FileAttributes,
487*c2c66affSColin Finck                           FILE_SHARE_READ | FILE_SHARE_WRITE,
488*c2c66affSColin Finck                           FILE_CREATE,
489*c2c66affSColin Finck                           FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
490*c2c66affSColin Finck                           FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT,
491*c2c66affSColin Finck                           EaBuffer,
492*c2c66affSColin Finck                           EaLength);
493*c2c66affSColin Finck     if (!NT_SUCCESS(Status))
494*c2c66affSColin Finck     {
495*c2c66affSColin Finck         if (Status == STATUS_INVALID_PARAMETER || Status == STATUS_ACCESS_DENIED)
496*c2c66affSColin Finck         {
497*c2c66affSColin Finck             /* If creation failed, it might be because FSD doesn't support reparse points
498*c2c66affSColin Finck              * Retry without asking for such support in case template is not a reparse point
499*c2c66affSColin Finck              */
500*c2c66affSColin Finck             if (!ReparsePoint)
501*c2c66affSColin Finck             {
502*c2c66affSColin Finck                 Status = NtCreateFile(&DirectoryHandle,
503*c2c66affSColin Finck                                       FILE_LIST_DIRECTORY | SYNCHRONIZE |
504*c2c66affSColin Finck                                       FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES,
505*c2c66affSColin Finck                                       &ObjectAttributes,
506*c2c66affSColin Finck                                       &IoStatusBlock,
507*c2c66affSColin Finck                                       NULL,
508*c2c66affSColin Finck                                       FileBasicInfo.FileAttributes,
509*c2c66affSColin Finck                                       FILE_SHARE_READ | FILE_SHARE_WRITE,
510*c2c66affSColin Finck                                       FILE_CREATE,
511*c2c66affSColin Finck                                       FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
512*c2c66affSColin Finck                                       FILE_OPEN_FOR_BACKUP_INTENT,
513*c2c66affSColin Finck                                       EaBuffer,
514*c2c66affSColin Finck                                       EaLength);
515*c2c66affSColin Finck             }
516*c2c66affSColin Finck             else
517*c2c66affSColin Finck             {
518*c2c66affSColin Finck                 RtlReleaseRelativeName(&RelativeName);
519*c2c66affSColin Finck                 RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
520*c2c66affSColin Finck                 if (EaBuffer)
521*c2c66affSColin Finck                 {
522*c2c66affSColin Finck                     RtlFreeHeap(RtlGetProcessHeap(), 0, EaBuffer);
523*c2c66affSColin Finck                 }
524*c2c66affSColin Finck                 CloseHandle(TemplateHandle);
525*c2c66affSColin Finck                 BaseSetLastNTError(Status);
526*c2c66affSColin Finck                 return FALSE;
527*c2c66affSColin Finck             }
528*c2c66affSColin Finck         }
529*c2c66affSColin Finck     }
530*c2c66affSColin Finck 
531*c2c66affSColin Finck     RtlReleaseRelativeName(&RelativeName);
532*c2c66affSColin Finck     RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
533*c2c66affSColin Finck     if (EaBuffer)
534*c2c66affSColin Finck     {
535*c2c66affSColin Finck         RtlFreeHeap(RtlGetProcessHeap(), 0, EaBuffer);
536*c2c66affSColin Finck     }
537*c2c66affSColin Finck 
538*c2c66affSColin Finck     if (!NT_SUCCESS(Status))
539*c2c66affSColin Finck     {
540*c2c66affSColin Finck         NtClose(TemplateHandle);
541*c2c66affSColin Finck         if (RtlIsDosDeviceName_U(lpNewDirectory))
542*c2c66affSColin Finck         {
543*c2c66affSColin Finck             Status = STATUS_NOT_A_DIRECTORY;
544*c2c66affSColin Finck         }
545*c2c66affSColin Finck         BaseSetLastNTError(Status);
546*c2c66affSColin Finck         return FALSE;
547*c2c66affSColin Finck     }
548*c2c66affSColin Finck 
549*c2c66affSColin Finck     /* If template is a reparse point, copy reparse data */
550*c2c66affSColin Finck     if (ReparsePoint)
551*c2c66affSColin Finck     {
552*c2c66affSColin Finck         ReparseDataBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0,
553*c2c66affSColin Finck                                             MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
554*c2c66affSColin Finck         if (!ReparseDataBuffer)
555*c2c66affSColin Finck         {
556*c2c66affSColin Finck             NtClose(TemplateHandle);
557*c2c66affSColin Finck             NtClose(DirectoryHandle);
558*c2c66affSColin Finck             SetLastError(STATUS_NO_MEMORY);
559*c2c66affSColin Finck             return FALSE;
560*c2c66affSColin Finck         }
561*c2c66affSColin Finck 
562*c2c66affSColin Finck         /* First query data */
563*c2c66affSColin Finck         Status = NtFsControlFile(TemplateHandle,
564*c2c66affSColin Finck                                  NULL,
565*c2c66affSColin Finck                                  NULL,
566*c2c66affSColin Finck                                  NULL,
567*c2c66affSColin Finck                                  &IoStatusBlock,
568*c2c66affSColin Finck                                  FSCTL_GET_REPARSE_POINT,
569*c2c66affSColin Finck                                  NULL,
570*c2c66affSColin Finck                                  0,
571*c2c66affSColin Finck                                  ReparseDataBuffer,
572*c2c66affSColin Finck                                  MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
573*c2c66affSColin Finck         if (!NT_SUCCESS(Status))
574*c2c66affSColin Finck         {
575*c2c66affSColin Finck             RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer);
576*c2c66affSColin Finck             NtClose(TemplateHandle);
577*c2c66affSColin Finck             NtClose(DirectoryHandle);
578*c2c66affSColin Finck             SetLastError(Status);
579*c2c66affSColin Finck             return FALSE;
580*c2c66affSColin Finck         }
581*c2c66affSColin Finck 
582*c2c66affSColin Finck         /* Once again, ensure it is a mount point */
583*c2c66affSColin Finck         if (ReparseDataBuffer->ReparseTag != IO_REPARSE_TAG_MOUNT_POINT)
584*c2c66affSColin Finck         {
585*c2c66affSColin Finck             RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer);
586*c2c66affSColin Finck             NtClose(TemplateHandle);
587*c2c66affSColin Finck             NtClose(DirectoryHandle);
588*c2c66affSColin Finck             SetLastError(STATUS_OBJECT_NAME_INVALID);
589*c2c66affSColin Finck             return FALSE;
590*c2c66affSColin Finck         }
591*c2c66affSColin Finck 
592*c2c66affSColin Finck         /* Get volume name */
593*c2c66affSColin Finck         SubstituteName = (PWSTR)((ULONG_PTR)ReparseDataBuffer->MountPointReparseBuffer.PathBuffer +
594*c2c66affSColin Finck                                  ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameOffset);
595*c2c66affSColin Finck         if (IS_VOLUME_NAME(SubstituteName, ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameLength))
596*c2c66affSColin Finck         {
597*c2c66affSColin Finck             /* Prepare to define a new mount point for that volume */
598*c2c66affSColin Finck             RtlInitUnicodeString(&NewDirectory, lpNewDirectory);
599*c2c66affSColin Finck             NewDirectory.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, NewDirectory.Length + 2 * sizeof(WCHAR));
600*c2c66affSColin Finck             if (!NewDirectory.Buffer)
601*c2c66affSColin Finck             {
602*c2c66affSColin Finck                 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
603*c2c66affSColin Finck                 RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer);
604*c2c66affSColin Finck                 NtClose(TemplateHandle);
605*c2c66affSColin Finck                 NtClose(DirectoryHandle);
606*c2c66affSColin Finck                 return FALSE;
607*c2c66affSColin Finck             }
608*c2c66affSColin Finck 
609*c2c66affSColin Finck             RtlCopyMemory(&NewDirectory.Buffer, lpNewDirectory, NewDirectory.Length);
610*c2c66affSColin Finck             if (NewDirectory.Buffer[NewDirectory.Length / sizeof(WCHAR)] != L'\\')
611*c2c66affSColin Finck             {
612*c2c66affSColin Finck                 NewDirectory.Buffer[NewDirectory.Length / sizeof(WCHAR)] = L'\\';
613*c2c66affSColin Finck                 NewDirectory.Buffer[(NewDirectory.Length / sizeof(WCHAR)) + 1] = UNICODE_NULL;
614*c2c66affSColin Finck             }
615*c2c66affSColin Finck 
616*c2c66affSColin Finck             /* Define a new mount point for that volume */
617*c2c66affSColin Finck             SetVolumeMountPointW(NewDirectory.Buffer, SubstituteName);
618*c2c66affSColin Finck 
619*c2c66affSColin Finck             RtlFreeHeap(RtlGetProcessHeap(), 0, NewDirectory.Buffer);
620*c2c66affSColin Finck             RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer);
621*c2c66affSColin Finck             NtClose(TemplateHandle);
622*c2c66affSColin Finck             NtClose(DirectoryHandle);
623*c2c66affSColin Finck             return TRUE;
624*c2c66affSColin Finck         }
625*c2c66affSColin Finck 
626*c2c66affSColin Finck         /* Otherwise copy data raw */
627*c2c66affSColin Finck         Status = NtFsControlFile(DirectoryHandle,
628*c2c66affSColin Finck                                  NULL,
629*c2c66affSColin Finck                                  NULL,
630*c2c66affSColin Finck                                  NULL,
631*c2c66affSColin Finck                                  &IoStatusBlock,
632*c2c66affSColin Finck                                  FSCTL_SET_REPARSE_POINT,
633*c2c66affSColin Finck                                  ReparseDataBuffer,
634*c2c66affSColin Finck                                  ReparseDataBuffer->ReparseDataLength +
635*c2c66affSColin Finck                                  FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer),
636*c2c66affSColin Finck                                  NULL,
637*c2c66affSColin Finck                                  0);
638*c2c66affSColin Finck 
639*c2c66affSColin Finck         RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer);
640*c2c66affSColin Finck         NtClose(TemplateHandle);
641*c2c66affSColin Finck         NtClose(DirectoryHandle);
642*c2c66affSColin Finck 
643*c2c66affSColin Finck         if (NT_SUCCESS(Status))
644*c2c66affSColin Finck         {
645*c2c66affSColin Finck             return TRUE;
646*c2c66affSColin Finck         }
647*c2c66affSColin Finck 
648*c2c66affSColin Finck         BaseSetLastNTError(Status);
649*c2c66affSColin Finck         return FALSE;
650*c2c66affSColin Finck     }
651*c2c66affSColin Finck     /* In case it's not a reparse point, handle streams on the file */
652*c2c66affSColin Finck     else
653*c2c66affSColin Finck     {
654*c2c66affSColin Finck         for (StreamSize = 0x1000; ; StreamSize = StreamSize * 2)
655*c2c66affSColin Finck         {
656*c2c66affSColin Finck             FileStreamInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, StreamSize);
657*c2c66affSColin Finck             if (!FileStreamInfo)
658*c2c66affSColin Finck             {
659*c2c66affSColin Finck                 BaseMarkFileForDelete(DirectoryHandle, FileBasicInfo.FileAttributes);
660*c2c66affSColin Finck                 SetLastError(STATUS_NO_MEMORY);
661*c2c66affSColin Finck                 break;
662*c2c66affSColin Finck             }
663*c2c66affSColin Finck 
664*c2c66affSColin Finck             /* Query stream information */
665*c2c66affSColin Finck             Status = NtQueryInformationFile(TemplateHandle,
666*c2c66affSColin Finck                                             &IoStatusBlock,
667*c2c66affSColin Finck                                             FileStreamInfo,
668*c2c66affSColin Finck                                             StreamSize,
669*c2c66affSColin Finck                                             FileStreamInformation);
670*c2c66affSColin Finck             if (NT_SUCCESS(Status))
671*c2c66affSColin Finck             {
672*c2c66affSColin Finck                 break;
673*c2c66affSColin Finck             }
674*c2c66affSColin Finck 
675*c2c66affSColin Finck             RtlFreeHeap(RtlGetProcessHeap(), 0, FileStreamInfo);
676*c2c66affSColin Finck             FileStreamInfo = NULL;
677*c2c66affSColin Finck 
678*c2c66affSColin Finck             /* If it failed, ensure that's not because of too small buffer */
679*c2c66affSColin Finck             if (Status != STATUS_BUFFER_OVERFLOW &&
680*c2c66affSColin Finck                 Status != STATUS_BUFFER_TOO_SMALL)
681*c2c66affSColin Finck             {
682*c2c66affSColin Finck                 break;
683*c2c66affSColin Finck             }
684*c2c66affSColin Finck         }
685*c2c66affSColin Finck 
686*c2c66affSColin Finck         if (!NT_SUCCESS(Status) || IoStatusBlock.Information == 0)
687*c2c66affSColin Finck         {
688*c2c66affSColin Finck             if (FileStreamInfo)
689*c2c66affSColin Finck             {
690*c2c66affSColin Finck                 RtlFreeHeap(RtlGetProcessHeap(), 0, FileStreamInfo);
691*c2c66affSColin Finck             }
692*c2c66affSColin Finck 
693*c2c66affSColin Finck             NtClose(TemplateHandle);
694*c2c66affSColin Finck             NtClose(DirectoryHandle);
695*c2c66affSColin Finck             return TRUE;
696*c2c66affSColin Finck         }
697*c2c66affSColin Finck 
698*c2c66affSColin Finck #if 1
699*c2c66affSColin Finck         /* FIXME: TODO */
700*c2c66affSColin Finck         DPRINT1("Warning: streams copying is unimplemented!\n");
701*c2c66affSColin Finck         RtlFreeHeap(RtlGetProcessHeap(), 0, FileStreamInfo);
702*c2c66affSColin Finck         NtClose(TemplateHandle);
703*c2c66affSColin Finck         NtClose(DirectoryHandle);
704*c2c66affSColin Finck #endif
705*c2c66affSColin Finck         return TRUE;
706*c2c66affSColin Finck     }
707*c2c66affSColin Finck }
708*c2c66affSColin Finck 
709*c2c66affSColin Finck /*
710*c2c66affSColin Finck  * @implemented
711*c2c66affSColin Finck  */
712*c2c66affSColin Finck BOOL
713*c2c66affSColin Finck WINAPI
RemoveDirectoryA(IN LPCSTR lpPathName)714*c2c66affSColin Finck RemoveDirectoryA(IN LPCSTR lpPathName)
715*c2c66affSColin Finck {
716*c2c66affSColin Finck     PUNICODE_STRING PathNameW;
717*c2c66affSColin Finck 
718*c2c66affSColin Finck     PathNameW = Basep8BitStringToStaticUnicodeString(lpPathName);
719*c2c66affSColin Finck     if (!PathNameW)
720*c2c66affSColin Finck     {
721*c2c66affSColin Finck         return FALSE;
722*c2c66affSColin Finck     }
723*c2c66affSColin Finck 
724*c2c66affSColin Finck     return RemoveDirectoryW(PathNameW->Buffer);
725*c2c66affSColin Finck }
726*c2c66affSColin Finck 
727*c2c66affSColin Finck /*
728*c2c66affSColin Finck  * @implemented
729*c2c66affSColin Finck  */
730*c2c66affSColin Finck BOOL
731*c2c66affSColin Finck WINAPI
RemoveDirectoryW(IN LPCWSTR lpPathName)732*c2c66affSColin Finck RemoveDirectoryW(IN LPCWSTR lpPathName)
733*c2c66affSColin Finck {
734*c2c66affSColin Finck     NTSTATUS Status;
735*c2c66affSColin Finck     DWORD BytesReturned;
736*c2c66affSColin Finck     HANDLE DirectoryHandle;
737*c2c66affSColin Finck     IO_STATUS_BLOCK IoStatusBlock;
738*c2c66affSColin Finck     UNICODE_STRING NtPathU, PathName;
739*c2c66affSColin Finck     RTL_RELATIVE_NAME_U RelativeName;
740*c2c66affSColin Finck     PWSTR PathUBuffer, SubstituteName;
741*c2c66affSColin Finck     OBJECT_ATTRIBUTES ObjectAttributes;
742*c2c66affSColin Finck     PREPARSE_DATA_BUFFER ReparseDataBuffer;
743*c2c66affSColin Finck     FILE_DISPOSITION_INFORMATION FileDispInfo;
744*c2c66affSColin Finck     FILE_ATTRIBUTE_TAG_INFORMATION FileTagInfo;
745*c2c66affSColin Finck 
746*c2c66affSColin Finck     /* Get relative name */
747*c2c66affSColin Finck     if (!RtlDosPathNameToRelativeNtPathName_U(lpPathName, &NtPathU, NULL, &RelativeName))
748*c2c66affSColin Finck     {
749*c2c66affSColin Finck         SetLastError(ERROR_PATH_NOT_FOUND);
750*c2c66affSColin Finck         return FALSE;
751*c2c66affSColin Finck     }
752*c2c66affSColin Finck 
753*c2c66affSColin Finck     /* Save buffer to allow later freeing */
754*c2c66affSColin Finck     PathUBuffer = NtPathU.Buffer;
755*c2c66affSColin Finck 
756*c2c66affSColin Finck     /* If we have relative name (and root dir), use them instead */
757*c2c66affSColin Finck     if (RelativeName.RelativeName.Length != 0)
758*c2c66affSColin Finck     {
759*c2c66affSColin Finck         NtPathU.Length = RelativeName.RelativeName.Length;
760*c2c66affSColin Finck         NtPathU.MaximumLength = RelativeName.RelativeName.MaximumLength;
761*c2c66affSColin Finck         NtPathU.Buffer = RelativeName.RelativeName.Buffer;
762*c2c66affSColin Finck     }
763*c2c66affSColin Finck     else
764*c2c66affSColin Finck     {
765*c2c66affSColin Finck         RelativeName.ContainingDirectory = NULL;
766*c2c66affSColin Finck     }
767*c2c66affSColin Finck 
768*c2c66affSColin Finck     InitializeObjectAttributes(&ObjectAttributes,
769*c2c66affSColin Finck                                &NtPathU,
770*c2c66affSColin Finck                                OBJ_CASE_INSENSITIVE,
771*c2c66affSColin Finck                                RelativeName.ContainingDirectory,
772*c2c66affSColin Finck                                NULL);
773*c2c66affSColin Finck 
774*c2c66affSColin Finck     /* Try to open directory */
775*c2c66affSColin Finck     Status = NtOpenFile(&DirectoryHandle,
776*c2c66affSColin Finck                         DELETE | SYNCHRONIZE | FAILED_ACCESS_ACE_FLAG,
777*c2c66affSColin Finck                         &ObjectAttributes,
778*c2c66affSColin Finck                         &IoStatusBlock,
779*c2c66affSColin Finck                         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
780*c2c66affSColin Finck                         FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
781*c2c66affSColin Finck                         FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT);
782*c2c66affSColin Finck     if (!NT_SUCCESS(Status))
783*c2c66affSColin Finck     {
784*c2c66affSColin Finck         /* We only accept failure for reparse points not being supported */
785*c2c66affSColin Finck         if (Status != STATUS_INVALID_PARAMETER)
786*c2c66affSColin Finck         {
787*c2c66affSColin Finck             goto Cleanup;
788*c2c66affSColin Finck         }
789*c2c66affSColin Finck 
790*c2c66affSColin Finck         /* Try to open, with reparse points support */
791*c2c66affSColin Finck         Status = NtOpenFile(&DirectoryHandle,
792*c2c66affSColin Finck                             DELETE | SYNCHRONIZE,
793*c2c66affSColin Finck                             &ObjectAttributes,
794*c2c66affSColin Finck                             &IoStatusBlock,
795*c2c66affSColin Finck                             FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
796*c2c66affSColin Finck                             FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
797*c2c66affSColin Finck                             FILE_OPEN_FOR_BACKUP_INTENT);
798*c2c66affSColin Finck         if (!NT_SUCCESS(Status))
799*c2c66affSColin Finck         {
800*c2c66affSColin Finck             goto Cleanup;
801*c2c66affSColin Finck         }
802*c2c66affSColin Finck 
803*c2c66affSColin Finck         /* Success, mark directory */
804*c2c66affSColin Finck         goto MarkFileForDelete;
805*c2c66affSColin Finck     }
806*c2c66affSColin Finck 
807*c2c66affSColin Finck     /* Get information about file (and reparse point) */
808*c2c66affSColin Finck     Status = NtQueryInformationFile(DirectoryHandle,
809*c2c66affSColin Finck                                     &IoStatusBlock,
810*c2c66affSColin Finck                                     &FileTagInfo,
811*c2c66affSColin Finck                                     sizeof(FileTagInfo),
812*c2c66affSColin Finck                                     FileAttributeTagInformation);
813*c2c66affSColin Finck     if (!NT_SUCCESS(Status))
814*c2c66affSColin Finck     {
815*c2c66affSColin Finck         /* FSD might not support querying reparse points information */
816*c2c66affSColin Finck         if (Status != STATUS_NOT_IMPLEMENTED &&
817*c2c66affSColin Finck             Status != STATUS_INVALID_PARAMETER)
818*c2c66affSColin Finck         {
819*c2c66affSColin Finck             goto CleanupHandle;
820*c2c66affSColin Finck         }
821*c2c66affSColin Finck 
822*c2c66affSColin Finck         /* If that's the case, then just delete directory */
823*c2c66affSColin Finck         goto MarkFileForDelete;
824*c2c66affSColin Finck     }
825*c2c66affSColin Finck 
826*c2c66affSColin Finck     /* If that's not a reparse point, nothing more to do than just delete */
827*c2c66affSColin Finck     if (!(FileTagInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
828*c2c66affSColin Finck     {
829*c2c66affSColin Finck         goto MarkFileForDelete;
830*c2c66affSColin Finck     }
831*c2c66affSColin Finck 
832*c2c66affSColin Finck     /* Check if that's a mount point */
833*c2c66affSColin Finck     if (FileTagInfo.ReparseTag != IO_REPARSE_TAG_MOUNT_POINT)
834*c2c66affSColin Finck     {
835*c2c66affSColin Finck         /* It's not */
836*c2c66affSColin Finck         NtClose(DirectoryHandle);
837*c2c66affSColin Finck 
838*c2c66affSColin Finck         /* So, try to reopen directory, ignoring mount point */
839*c2c66affSColin Finck         Status = NtOpenFile(&DirectoryHandle,
840*c2c66affSColin Finck                             DELETE | SYNCHRONIZE,
841*c2c66affSColin Finck                             &ObjectAttributes,
842*c2c66affSColin Finck                             &IoStatusBlock,
843*c2c66affSColin Finck                             FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
844*c2c66affSColin Finck                             FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
845*c2c66affSColin Finck                             FILE_OPEN_FOR_BACKUP_INTENT);
846*c2c66affSColin Finck         if (NT_SUCCESS(Status))
847*c2c66affSColin Finck         {
848*c2c66affSColin Finck             /* It succeed, we can safely delete directory (and ignore reparse point) */
849*c2c66affSColin Finck             goto MarkFileForDelete;
850*c2c66affSColin Finck         }
851*c2c66affSColin Finck 
852*c2c66affSColin Finck         /* If it failed, only allow case where IO mount point was ignored */
853*c2c66affSColin Finck         if (Status != STATUS_IO_REPARSE_TAG_NOT_HANDLED)
854*c2c66affSColin Finck         {
855*c2c66affSColin Finck             goto Cleanup;
856*c2c66affSColin Finck         }
857*c2c66affSColin Finck 
858*c2c66affSColin Finck         /* Reopen with reparse point support */
859*c2c66affSColin Finck         Status = NtOpenFile(&DirectoryHandle,
860*c2c66affSColin Finck                             DELETE | SYNCHRONIZE,
861*c2c66affSColin Finck                             &ObjectAttributes,
862*c2c66affSColin Finck                             &IoStatusBlock,
863*c2c66affSColin Finck                             FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
864*c2c66affSColin Finck                             FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
865*c2c66affSColin Finck                             FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT);
866*c2c66affSColin Finck         if (NT_SUCCESS(Status))
867*c2c66affSColin Finck         {
868*c2c66affSColin Finck             /* And mark for delete */
869*c2c66affSColin Finck             goto MarkFileForDelete;
870*c2c66affSColin Finck         }
871*c2c66affSColin Finck 
872*c2c66affSColin Finck         goto Cleanup;
873*c2c66affSColin Finck     }
874*c2c66affSColin Finck 
875*c2c66affSColin Finck     /* Here, we have a mount point, prepare to query information about it */
876*c2c66affSColin Finck     ReparseDataBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0,
877*c2c66affSColin Finck                                         MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
878*c2c66affSColin Finck     if (!ReparseDataBuffer)
879*c2c66affSColin Finck     {
880*c2c66affSColin Finck         RtlReleaseRelativeName(&RelativeName);
881*c2c66affSColin Finck         RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
882*c2c66affSColin Finck         NtClose(DirectoryHandle);
883*c2c66affSColin Finck         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
884*c2c66affSColin Finck         return FALSE;
885*c2c66affSColin Finck     }
886*c2c66affSColin Finck 
887*c2c66affSColin Finck     /* Query */
888*c2c66affSColin Finck     if (!DeviceIoControl(DirectoryHandle,
889*c2c66affSColin Finck                          FSCTL_GET_REPARSE_POINT,
890*c2c66affSColin Finck                          NULL, 0,
891*c2c66affSColin Finck                          ReparseDataBuffer,
892*c2c66affSColin Finck                          MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
893*c2c66affSColin Finck                          &BytesReturned,
894*c2c66affSColin Finck                          NULL))
895*c2c66affSColin Finck     {
896*c2c66affSColin Finck         RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer);
897*c2c66affSColin Finck         goto MarkFileForDelete;
898*c2c66affSColin Finck     }
899*c2c66affSColin Finck 
900*c2c66affSColin Finck     /* Get volume name */
901*c2c66affSColin Finck     SubstituteName = (PWSTR)((ULONG_PTR)ReparseDataBuffer->MountPointReparseBuffer.PathBuffer +
902*c2c66affSColin Finck                              ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameOffset);
903*c2c66affSColin Finck     if (!IS_VOLUME_NAME(SubstituteName, ReparseDataBuffer->MountPointReparseBuffer.SubstituteNameLength))
904*c2c66affSColin Finck     {
905*c2c66affSColin Finck         /* This is not a volume, we can safely delete */
906*c2c66affSColin Finck         RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer);
907*c2c66affSColin Finck         goto MarkFileForDelete;
908*c2c66affSColin Finck     }
909*c2c66affSColin Finck 
910*c2c66affSColin Finck     /* Prepare to delete mount point */
911*c2c66affSColin Finck     RtlInitUnicodeString(&PathName, lpPathName);
912*c2c66affSColin Finck     PathName.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, PathName.Length + 2 * sizeof(WCHAR));
913*c2c66affSColin Finck     if (!PathName.Buffer)
914*c2c66affSColin Finck     {
915*c2c66affSColin Finck         RtlReleaseRelativeName(&RelativeName);
916*c2c66affSColin Finck         RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer);
917*c2c66affSColin Finck         NtClose(DirectoryHandle);
918*c2c66affSColin Finck         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
919*c2c66affSColin Finck         return FALSE;
920*c2c66affSColin Finck     }
921*c2c66affSColin Finck 
922*c2c66affSColin Finck     RtlCopyMemory(&PathName.Buffer, lpPathName, PathName.Length);
923*c2c66affSColin Finck     if (PathName.Buffer[PathName.Length / sizeof(WCHAR)] != L'\\')
924*c2c66affSColin Finck     {
925*c2c66affSColin Finck         PathName.Buffer[PathName.Length / sizeof(WCHAR)] = L'\\';
926*c2c66affSColin Finck         PathName.Buffer[(PathName.Length / sizeof(WCHAR)) + 1] = UNICODE_NULL;
927*c2c66affSColin Finck     }
928*c2c66affSColin Finck 
929*c2c66affSColin Finck     /* Delete mount point for that volume */
930*c2c66affSColin Finck     DeleteVolumeMountPointW(PathName.Buffer);
931*c2c66affSColin Finck     RtlFreeHeap(RtlGetProcessHeap(), 0, PathName.Buffer);
932*c2c66affSColin Finck     RtlFreeHeap(RtlGetProcessHeap(), 0, ReparseDataBuffer);
933*c2c66affSColin Finck 
934*c2c66affSColin Finck     /* And mark directory for delete */
935*c2c66affSColin Finck MarkFileForDelete:
936*c2c66affSColin Finck     RtlReleaseRelativeName(&RelativeName);
937*c2c66affSColin Finck     RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
938*c2c66affSColin Finck 
939*c2c66affSColin Finck     /* Mark & set */
940*c2c66affSColin Finck     FileDispInfo.DeleteFile = TRUE;
941*c2c66affSColin Finck     Status = NtSetInformationFile(DirectoryHandle,
942*c2c66affSColin Finck                                   &IoStatusBlock,
943*c2c66affSColin Finck                                   &FileDispInfo,
944*c2c66affSColin Finck                                   sizeof(FILE_DISPOSITION_INFORMATION),
945*c2c66affSColin Finck                                   FileDispositionInformation);
946*c2c66affSColin Finck     NtClose(DirectoryHandle);
947*c2c66affSColin Finck 
948*c2c66affSColin Finck     if (!NT_SUCCESS(Status))
949*c2c66affSColin Finck     {
950*c2c66affSColin Finck         BaseSetLastNTError(Status);
951*c2c66affSColin Finck         return FALSE;
952*c2c66affSColin Finck     }
953*c2c66affSColin Finck 
954*c2c66affSColin Finck     return TRUE;
955*c2c66affSColin Finck 
956*c2c66affSColin Finck CleanupHandle:
957*c2c66affSColin Finck     NtClose(DirectoryHandle);
958*c2c66affSColin Finck 
959*c2c66affSColin Finck Cleanup:
960*c2c66affSColin Finck     RtlReleaseRelativeName(&RelativeName);
961*c2c66affSColin Finck     RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
962*c2c66affSColin Finck     BaseSetLastNTError(Status);
963*c2c66affSColin Finck     return FALSE;
964*c2c66affSColin Finck }
965*c2c66affSColin Finck 
966*c2c66affSColin Finck /* EOF */
967