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