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