Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1308 lines
42 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. dir.c
  5. Abstract:
  6. This module implements Win32 Directory functions.
  7. Author:
  8. Mark Lucovsky (markl) 26-Sep-1990
  9. Revision History:
  10. --*/
  11. #include "basedll.h"
  12. #include "mountmgr.h"
  13. BOOL
  14. APIENTRY
  15. CreateDirectoryA(
  16. LPCSTR lpPathName,
  17. LPSECURITY_ATTRIBUTES lpSecurityAttributes
  18. )
  19. /*++
  20. Routine Description:
  21. ANSI thunk to CreateDirectoryW
  22. --*/
  23. {
  24. PUNICODE_STRING Unicode;
  25. Unicode = Basep8BitStringToStaticUnicodeString( lpPathName );
  26. if (Unicode == NULL) {
  27. return FALSE;
  28. }
  29. return ( CreateDirectoryW((LPCWSTR)Unicode->Buffer,lpSecurityAttributes) );
  30. }
  31. BOOL
  32. APIENTRY
  33. CreateDirectoryW(
  34. LPCWSTR lpPathName,
  35. LPSECURITY_ATTRIBUTES lpSecurityAttributes
  36. )
  37. /*++
  38. Routine Description:
  39. A directory can be created using CreateDirectory.
  40. This API causes a directory with the specified pathname to be
  41. created. If the underlying file system supports security on files
  42. and directories, then the SecurityDescriptor argument is applied to
  43. the new directory.
  44. This call is similar to DOS (int 21h, function 39h) and OS/2's
  45. DosCreateDir.
  46. Arguments:
  47. lpPathName - Supplies the pathname of the directory to be created.
  48. lpSecurityAttributes - An optional parameter that, if present, and
  49. supported on the target file system supplies a security
  50. descriptor for the new directory.
  51. Return Value:
  52. TRUE - The operation was successful.
  53. FALSE/NULL - The operation failed. Extended error status is available
  54. using GetLastError.
  55. --*/
  56. {
  57. NTSTATUS Status;
  58. OBJECT_ATTRIBUTES Obja;
  59. HANDLE Handle;
  60. UNICODE_STRING FileName;
  61. IO_STATUS_BLOCK IoStatusBlock;
  62. BOOLEAN TranslationStatus;
  63. RTL_RELATIVE_NAME_U RelativeName;
  64. PVOID FreeBuffer;
  65. TranslationStatus = RtlDosPathNameToRelativeNtPathName_U(
  66. lpPathName,
  67. &FileName,
  68. NULL,
  69. &RelativeName
  70. );
  71. if ( !TranslationStatus ) {
  72. SetLastError(ERROR_PATH_NOT_FOUND);
  73. return FALSE;
  74. }
  75. //
  76. // dont create a directory unless there is room in the directory for
  77. // at least an 8.3 name. This way everyone will be able to delete all
  78. // files in the directory by using del *.* which expands to path+\*.*
  79. //
  80. if ( FileName.Length > ((MAX_PATH-12)<<1) ) {
  81. DWORD L;
  82. LPWSTR lp;
  83. if ( !(lpPathName[0] == '\\' && lpPathName[1] == '\\' &&
  84. lpPathName[2] == '?' && lpPathName[3] == '\\') ) {
  85. L = GetFullPathNameW(lpPathName,0,NULL,&lp);
  86. if ( !L || L+12 > MAX_PATH ) {
  87. RtlReleaseRelativeName(&RelativeName);
  88. RtlFreeHeap(RtlProcessHeap(), 0,FileName.Buffer);
  89. SetLastError(ERROR_FILENAME_EXCED_RANGE);
  90. return FALSE;
  91. }
  92. }
  93. }
  94. FreeBuffer = FileName.Buffer;
  95. if ( RelativeName.RelativeName.Length ) {
  96. FileName = RelativeName.RelativeName;
  97. }
  98. else {
  99. RelativeName.ContainingDirectory = NULL;
  100. }
  101. InitializeObjectAttributes(
  102. &Obja,
  103. &FileName,
  104. OBJ_CASE_INSENSITIVE,
  105. RelativeName.ContainingDirectory,
  106. NULL
  107. );
  108. if ( ARGUMENT_PRESENT(lpSecurityAttributes) ) {
  109. Obja.SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
  110. }
  111. Status = NtCreateFile(
  112. &Handle,
  113. FILE_LIST_DIRECTORY | SYNCHRONIZE,
  114. &Obja,
  115. &IoStatusBlock,
  116. NULL,
  117. FILE_ATTRIBUTE_NORMAL,
  118. FILE_SHARE_READ | FILE_SHARE_WRITE,
  119. FILE_CREATE,
  120. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT,
  121. NULL,
  122. 0L
  123. );
  124. RtlReleaseRelativeName(&RelativeName);
  125. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  126. if ( NT_SUCCESS(Status) ) {
  127. NtClose(Handle);
  128. return TRUE;
  129. }
  130. else {
  131. if ( RtlIsDosDeviceName_U((LPWSTR)lpPathName) ) {
  132. Status = STATUS_NOT_A_DIRECTORY;
  133. }
  134. BaseSetLastNTError(Status);
  135. return FALSE;
  136. }
  137. }
  138. BOOL
  139. APIENTRY
  140. CreateDirectoryExA(
  141. LPCSTR lpTemplateDirectory,
  142. LPCSTR lpNewDirectory,
  143. LPSECURITY_ATTRIBUTES lpSecurityAttributes
  144. )
  145. /*++
  146. Routine Description:
  147. ANSI thunk to CreateDirectoryFromTemplateW
  148. --*/
  149. {
  150. PUNICODE_STRING StaticUnicode;
  151. UNICODE_STRING DynamicUnicode;
  152. BOOL b;
  153. StaticUnicode = Basep8BitStringToStaticUnicodeString( lpTemplateDirectory );
  154. if (StaticUnicode == NULL) {
  155. return FALSE;
  156. }
  157. if (!Basep8BitStringToDynamicUnicodeString( &DynamicUnicode, lpNewDirectory )) {
  158. return FALSE;
  159. }
  160. b = CreateDirectoryExW(
  161. (LPCWSTR)StaticUnicode->Buffer,
  162. (LPCWSTR)DynamicUnicode.Buffer,
  163. lpSecurityAttributes
  164. );
  165. RtlFreeUnicodeString(&DynamicUnicode);
  166. return b;
  167. }
  168. BOOL
  169. APIENTRY
  170. CreateDirectoryExW(
  171. LPCWSTR lpTemplateDirectory,
  172. LPCWSTR lpNewDirectory,
  173. LPSECURITY_ATTRIBUTES lpSecurityAttributes
  174. )
  175. /*++
  176. Routine Description:
  177. A directory can be created using CreateDirectoryEx, retaining the
  178. attributes of the original directory file.
  179. This API causes a directory with the specified pathname to be
  180. created. If the underlying file system supports security on files
  181. and directories, then the SecurityDescriptor argument is applied to
  182. the new directory. The other attributes of the template directory are
  183. retained when creating the new directory.
  184. If the original directory is a volume mount point then the new directory
  185. is also a volume mount point to the same volume as the original one.
  186. Arguments:
  187. lpTemplateDirectory - Supplies the pathname of the directory to be used as
  188. a template when creating the new directory.
  189. lpPathName - Supplies the pathname of the directory to be created.
  190. lpSecurityAttributes - An optional parameter that, if present, and
  191. supported on the target file system supplies a security
  192. descriptor for the new directory.
  193. Return Value:
  194. TRUE - The operation was successful.
  195. FALSE/NULL - The operation failed. Extended error status is available
  196. using GetLastError.
  197. --*/
  198. {
  199. NTSTATUS Status;
  200. OBJECT_ATTRIBUTES Obja;
  201. HANDLE SourceFile;
  202. HANDLE DestFile;
  203. UNICODE_STRING PathName;
  204. UNICODE_STRING TargetName;
  205. IO_STATUS_BLOCK IoStatusBlock;
  206. BOOLEAN TranslationStatus;
  207. BOOLEAN IsNameGrafting = FALSE;
  208. UNICODE_STRING VolumeName;
  209. UNICODE_STRING MountPoint;
  210. PWCHAR VolumeMountPoint = NULL;
  211. RTL_RELATIVE_NAME_U PathRelativeName;
  212. RTL_RELATIVE_NAME_U TargetRelativeName;
  213. PVOID FreePathBuffer;
  214. PVOID FreeTargetBuffer;
  215. UNICODE_STRING StreamName;
  216. WCHAR FileName[MAXIMUM_FILENAME_LENGTH+1];
  217. HANDLE StreamHandle;
  218. HANDLE OutputStream;
  219. PFILE_STREAM_INFORMATION StreamInfo;
  220. FILE_ATTRIBUTE_TAG_INFORMATION FileTagInformation;
  221. PFILE_STREAM_INFORMATION StreamInfoBase;
  222. PFILE_FULL_EA_INFORMATION EaBuffer;
  223. FILE_EA_INFORMATION EaInfo;
  224. FILE_BASIC_INFORMATION BasicInfo;
  225. ULONG EaSize;
  226. ULONG StreamInfoSize;
  227. ULONG CopySize;
  228. ULONG i;
  229. ULONG DesiredAccess = 0;
  230. DWORD Options;
  231. DWORD b;
  232. LPCOPYFILE_CONTEXT CopyFileContext = NULL;
  233. //
  234. // Process the input template directory name and then open the directory
  235. // file, ensuring that it really is a directory.
  236. //
  237. TranslationStatus = RtlDosPathNameToRelativeNtPathName_U(
  238. lpTemplateDirectory,
  239. &PathName,
  240. NULL,
  241. &PathRelativeName
  242. );
  243. if ( !TranslationStatus ) {
  244. SetLastError(ERROR_PATH_NOT_FOUND);
  245. return FALSE;
  246. }
  247. FreePathBuffer = PathName.Buffer;
  248. if ( PathRelativeName.RelativeName.Length ) {
  249. PathName = PathRelativeName.RelativeName;
  250. }
  251. else {
  252. PathRelativeName.ContainingDirectory = NULL;
  253. }
  254. InitializeObjectAttributes(
  255. &Obja,
  256. &PathName,
  257. OBJ_CASE_INSENSITIVE,
  258. PathRelativeName.ContainingDirectory,
  259. NULL
  260. );
  261. //
  262. // Inhibit the reparse behavior using FILE_OPEN_REPARSE_POINT.
  263. //
  264. Status = NtOpenFile(
  265. &SourceFile,
  266. FILE_LIST_DIRECTORY | FILE_READ_EA | FILE_READ_ATTRIBUTES,
  267. &Obja,
  268. &IoStatusBlock,
  269. FILE_SHARE_READ | FILE_SHARE_WRITE,
  270. FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT
  271. );
  272. if ( !NT_SUCCESS(Status) ) {
  273. //
  274. // Back level file systems may not support reparse points and thus not
  275. // support symbolic links.
  276. // We infer this is the case when the Status is STATUS_INVALID_PARAMETER.
  277. //
  278. if ( Status == STATUS_INVALID_PARAMETER ) {
  279. //
  280. // Re-open not inhibiting the reparse behavior.
  281. //
  282. Status = NtOpenFile(
  283. &SourceFile,
  284. FILE_LIST_DIRECTORY | FILE_READ_EA | FILE_READ_ATTRIBUTES,
  285. &Obja,
  286. &IoStatusBlock,
  287. FILE_SHARE_READ | FILE_SHARE_WRITE,
  288. FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT
  289. );
  290. if ( !NT_SUCCESS(Status) ) {
  291. RtlReleaseRelativeName(&PathRelativeName);
  292. RtlFreeHeap(RtlProcessHeap(), 0, FreePathBuffer);
  293. BaseSetLastNTError(Status);
  294. return FALSE;
  295. }
  296. }
  297. else {
  298. RtlReleaseRelativeName(&PathRelativeName);
  299. RtlFreeHeap(RtlProcessHeap(), 0, FreePathBuffer);
  300. BaseSetLastNTError(Status);
  301. return FALSE;
  302. }
  303. }
  304. else {
  305. //
  306. // See whether we have a name grafting operation.
  307. //
  308. BasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
  309. Status = NtQueryInformationFile(
  310. SourceFile,
  311. &IoStatusBlock,
  312. (PVOID)&BasicInfo,
  313. sizeof(BasicInfo),
  314. FileBasicInformation
  315. );
  316. if ( !NT_SUCCESS(Status) ) {
  317. RtlReleaseRelativeName(&PathRelativeName);
  318. RtlFreeHeap(RtlProcessHeap(), 0, FreePathBuffer);
  319. CloseHandle(SourceFile);
  320. BaseSetLastNTError(Status);
  321. return FALSE;
  322. }
  323. if ( BasicInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ) {
  324. Status = NtQueryInformationFile(
  325. SourceFile,
  326. &IoStatusBlock,
  327. (PVOID)&FileTagInformation,
  328. sizeof(FileTagInformation),
  329. FileAttributeTagInformation
  330. );
  331. if ( !NT_SUCCESS(Status) ) {
  332. RtlReleaseRelativeName(&PathRelativeName);
  333. RtlFreeHeap(RtlProcessHeap(), 0, FreePathBuffer);
  334. CloseHandle(SourceFile);
  335. BaseSetLastNTError(Status);
  336. return FALSE;
  337. }
  338. if ( FileTagInformation.ReparseTag != IO_REPARSE_TAG_MOUNT_POINT ) {
  339. //
  340. // Close and re-open not inhibiting the reparse behavior.
  341. //
  342. CloseHandle(SourceFile);
  343. Status = NtOpenFile(
  344. &SourceFile,
  345. FILE_LIST_DIRECTORY | FILE_READ_EA | FILE_READ_ATTRIBUTES,
  346. &Obja,
  347. &IoStatusBlock,
  348. FILE_SHARE_READ | FILE_SHARE_WRITE,
  349. FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT
  350. );
  351. if ( !NT_SUCCESS(Status) ) {
  352. RtlReleaseRelativeName(&PathRelativeName);
  353. RtlFreeHeap(RtlProcessHeap(), 0, FreePathBuffer);
  354. BaseSetLastNTError(Status);
  355. return FALSE;
  356. }
  357. }
  358. else {
  359. IsNameGrafting = TRUE;
  360. }
  361. }
  362. }
  363. TranslationStatus = RtlDosPathNameToRelativeNtPathName_U(
  364. lpNewDirectory,
  365. &TargetName,
  366. NULL,
  367. &TargetRelativeName
  368. );
  369. if ( !TranslationStatus ) {
  370. RtlReleaseRelativeName(&PathRelativeName);
  371. RtlFreeHeap(RtlProcessHeap(), 0, FreePathBuffer);
  372. NtClose(SourceFile);
  373. SetLastError(ERROR_PATH_NOT_FOUND);
  374. return FALSE;
  375. }
  376. FreeTargetBuffer = TargetName.Buffer;
  377. //
  378. // Verify that the source and target are different.
  379. //
  380. if ( RtlEqualUnicodeString(&PathName, &TargetName, TRUE) ) {
  381. //
  382. // Do nothing. Source and target are the same.
  383. //
  384. RtlReleaseRelativeName(&PathRelativeName);
  385. RtlReleaseRelativeName(&TargetRelativeName);
  386. RtlFreeHeap(RtlProcessHeap(), 0, FreePathBuffer);
  387. RtlFreeHeap(RtlProcessHeap(), 0, FreeTargetBuffer);
  388. NtClose(SourceFile);
  389. SetLastError(ERROR_INVALID_NAME);
  390. return FALSE;
  391. }
  392. RtlReleaseRelativeName(&PathRelativeName);
  393. RtlFreeHeap(RtlProcessHeap(), 0, FreePathBuffer);
  394. //
  395. // Do not create a directory unless there is room in the directory for
  396. // at least an 8.3 name. This way everyone will be able to delete all
  397. // files in the directory by using del *.* which expands to path+\*.*
  398. //
  399. if ( TargetName.Length > ((MAX_PATH-12)<<1) ) {
  400. DWORD L;
  401. LPWSTR lp;
  402. if ( !(lpNewDirectory[0] == '\\' && lpNewDirectory[1] == '\\' &&
  403. lpNewDirectory[2] == '?' && lpNewDirectory[3] == '\\') ) {
  404. L = GetFullPathNameW(lpNewDirectory,0,NULL,&lp);
  405. if ( !L || L+12 > MAX_PATH ) {
  406. RtlReleaseRelativeName(&TargetRelativeName);
  407. RtlFreeHeap(RtlProcessHeap(), 0, FreeTargetBuffer);
  408. CloseHandle(SourceFile);
  409. SetLastError(ERROR_FILENAME_EXCED_RANGE);
  410. return FALSE;
  411. }
  412. }
  413. }
  414. if ( TargetRelativeName.RelativeName.Length ) {
  415. TargetName = TargetRelativeName.RelativeName;
  416. }
  417. else {
  418. TargetRelativeName.ContainingDirectory = NULL;
  419. }
  420. EaBuffer = NULL;
  421. EaSize = 0;
  422. Status = NtQueryInformationFile(
  423. SourceFile,
  424. &IoStatusBlock,
  425. &EaInfo,
  426. sizeof(EaInfo),
  427. FileEaInformation
  428. );
  429. if ( !NT_SUCCESS(Status) ) {
  430. RtlReleaseRelativeName(&TargetRelativeName);
  431. RtlFreeHeap(RtlProcessHeap(), 0, FreeTargetBuffer);
  432. CloseHandle(SourceFile);
  433. BaseSetLastNTError(Status);
  434. return FALSE;
  435. }
  436. if ( NT_SUCCESS(Status) && EaInfo.EaSize ) {
  437. EaSize = EaInfo.EaSize;
  438. do {
  439. EaSize *= 2;
  440. EaBuffer = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), EaSize);
  441. if ( !EaBuffer ) {
  442. RtlReleaseRelativeName(&TargetRelativeName);
  443. RtlFreeHeap(RtlProcessHeap(), 0, FreeTargetBuffer);
  444. CloseHandle(SourceFile);
  445. BaseSetLastNTError(STATUS_NO_MEMORY);
  446. return FALSE;
  447. }
  448. Status = NtQueryEaFile(
  449. SourceFile,
  450. &IoStatusBlock,
  451. EaBuffer,
  452. EaSize,
  453. FALSE,
  454. (PVOID)NULL,
  455. 0,
  456. (PULONG)NULL,
  457. TRUE
  458. );
  459. if ( !NT_SUCCESS(Status) ) {
  460. RtlFreeHeap(RtlProcessHeap(), 0, EaBuffer);
  461. EaBuffer = NULL;
  462. IoStatusBlock.Information = 0;
  463. }
  464. } while ( Status == STATUS_BUFFER_OVERFLOW ||
  465. Status == STATUS_BUFFER_TOO_SMALL );
  466. EaSize = (ULONG)IoStatusBlock.Information;
  467. }
  468. //
  469. // Open/create the destination directory.
  470. //
  471. InitializeObjectAttributes(
  472. &Obja,
  473. &TargetName,
  474. OBJ_CASE_INSENSITIVE,
  475. TargetRelativeName.ContainingDirectory,
  476. NULL
  477. );
  478. if ( ARGUMENT_PRESENT(lpSecurityAttributes) ) {
  479. Obja.SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
  480. }
  481. DesiredAccess = FILE_LIST_DIRECTORY | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES | SYNCHRONIZE;
  482. if ( BasicInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ) {
  483. //
  484. // To set the reparse point at the target one needs FILE_WRITE_DATA.
  485. //
  486. DesiredAccess |= FILE_WRITE_DATA;
  487. }
  488. //
  489. // Clear the reparse attribute before creating the target. Only the
  490. // name grafting use of reparse points is preserved at this level.
  491. // Open first inhibiting the reparse behavior.
  492. //
  493. BasicInfo.FileAttributes &= ~FILE_ATTRIBUTE_REPARSE_POINT;
  494. Status = NtCreateFile(
  495. &DestFile,
  496. DesiredAccess,
  497. &Obja,
  498. &IoStatusBlock,
  499. NULL,
  500. BasicInfo.FileAttributes,
  501. FILE_SHARE_READ | FILE_SHARE_WRITE,
  502. FILE_CREATE,
  503. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT,
  504. EaBuffer,
  505. EaSize
  506. );
  507. if ( !NT_SUCCESS(Status) ) {
  508. //
  509. // Back level file systems may not support reparse points.
  510. // We infer this is the case when the Status is STATUS_INVALID_PARAMETER.
  511. //
  512. if ( (Status == STATUS_INVALID_PARAMETER) ||
  513. (Status == STATUS_ACCESS_DENIED) ) {
  514. //
  515. // Either the FS does not support reparse points or we do not have enough
  516. // access to the target.
  517. //
  518. if ( IsNameGrafting ) {
  519. //
  520. // We need to return error, as the target cannot be opened correctly.
  521. //
  522. RtlReleaseRelativeName(&TargetRelativeName);
  523. RtlFreeHeap(RtlProcessHeap(), 0, FreeTargetBuffer);
  524. if ( EaBuffer ) {
  525. RtlFreeHeap(RtlProcessHeap(), 0, EaBuffer);
  526. }
  527. CloseHandle(SourceFile);
  528. BaseSetLastNTError(Status);
  529. return FALSE;
  530. }
  531. Status = NtCreateFile(
  532. &DestFile,
  533. FILE_LIST_DIRECTORY | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
  534. &Obja,
  535. &IoStatusBlock,
  536. NULL,
  537. BasicInfo.FileAttributes,
  538. FILE_SHARE_READ | FILE_SHARE_WRITE,
  539. FILE_CREATE,
  540. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT,
  541. EaBuffer,
  542. EaSize
  543. );
  544. }
  545. }
  546. RtlReleaseRelativeName(&TargetRelativeName);
  547. RtlFreeHeap(RtlProcessHeap(), 0, FreeTargetBuffer);
  548. if ( EaBuffer ) {
  549. RtlFreeHeap(RtlProcessHeap(), 0, EaBuffer);
  550. }
  551. if ( !NT_SUCCESS(Status) ) {
  552. NtClose(SourceFile);
  553. if ( RtlIsDosDeviceName_U((LPWSTR)lpNewDirectory) ) {
  554. Status = STATUS_NOT_A_DIRECTORY;
  555. }
  556. BaseSetLastNTError(Status);
  557. return FALSE;
  558. }
  559. else {
  560. if ( IsNameGrafting ) {
  561. PREPARSE_DATA_BUFFER ReparseBufferHeader = NULL;
  562. PUCHAR ReparseBuffer = NULL;
  563. //
  564. // Allocate the buffer to get/set the reparse point.
  565. //
  566. ReparseBuffer = RtlAllocateHeap(
  567. RtlProcessHeap(),
  568. MAKE_TAG( TMP_TAG ),
  569. MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
  570. if ( ReparseBuffer == NULL) {
  571. NtClose(SourceFile);
  572. NtClose(DestFile);
  573. BaseSetLastNTError(STATUS_NO_MEMORY);
  574. //
  575. // Notice that we leave behind the target directory.
  576. //
  577. return FALSE;
  578. }
  579. //
  580. // Get the data in the reparse point.
  581. //
  582. Status = NtFsControlFile(
  583. SourceFile,
  584. NULL,
  585. NULL,
  586. NULL,
  587. &IoStatusBlock,
  588. FSCTL_GET_REPARSE_POINT,
  589. NULL, // Input buffer
  590. 0, // Input buffer length
  591. ReparseBuffer, // Output buffer
  592. MAXIMUM_REPARSE_DATA_BUFFER_SIZE // Output buffer length
  593. );
  594. if ( !NT_SUCCESS( Status ) ) {
  595. RtlFreeHeap(RtlProcessHeap(), 0, ReparseBuffer);
  596. NtClose(SourceFile);
  597. NtClose(DestFile);
  598. BaseSetLastNTError(Status);
  599. return FALSE;
  600. }
  601. //
  602. // Defensive sanity check. The reparse buffer should be name grafting.
  603. //
  604. ReparseBufferHeader = (PREPARSE_DATA_BUFFER)ReparseBuffer;
  605. if ( ReparseBufferHeader->ReparseTag != IO_REPARSE_TAG_MOUNT_POINT ) {
  606. RtlFreeHeap(RtlProcessHeap(), 0, ReparseBuffer);
  607. NtClose(SourceFile);
  608. NtClose(DestFile);
  609. BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID);
  610. return FALSE;
  611. }
  612. //
  613. // Finish up the creation of the target directory.
  614. //
  615. VolumeName.Length = VolumeName.MaximumLength =
  616. ReparseBufferHeader->MountPointReparseBuffer.SubstituteNameLength;
  617. VolumeName.Buffer = (PWCHAR)
  618. ((PCHAR) ReparseBufferHeader->MountPointReparseBuffer.PathBuffer +
  619. ReparseBufferHeader->MountPointReparseBuffer.SubstituteNameOffset);
  620. if (MOUNTMGR_IS_NT_VOLUME_NAME_WB(&VolumeName)) {
  621. //
  622. // Set the volume mount point and be done.
  623. //
  624. // SetVolumeMountPoint requires the mount point name
  625. // to have a trailing backslash.
  626. //
  627. RtlInitUnicodeString(&MountPoint, lpNewDirectory);
  628. VolumeMountPoint = RtlAllocateHeap(RtlProcessHeap(),
  629. MAKE_TAG(TMP_TAG),
  630. MountPoint.Length +
  631. 2*sizeof(WCHAR));
  632. if (!VolumeMountPoint) {
  633. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  634. b = FALSE;
  635. }
  636. else {
  637. RtlCopyMemory(VolumeMountPoint, MountPoint.Buffer,
  638. MountPoint.Length);
  639. VolumeMountPoint[MountPoint.Length/sizeof(WCHAR)] = 0;
  640. if (MountPoint.Buffer[MountPoint.Length/sizeof(WCHAR) - 1] != '\\') {
  641. VolumeMountPoint[MountPoint.Length/sizeof(WCHAR)] = '\\';
  642. VolumeMountPoint[MountPoint.Length/sizeof(WCHAR) + 1] = 0;
  643. }
  644. //
  645. // The volume name should be like "\\?\Volume{guid}\"
  646. //
  647. VolumeName.Buffer[1] = '\\';
  648. b = SetVolumeMountPointW(
  649. VolumeMountPoint,
  650. VolumeName.Buffer
  651. );
  652. RtlFreeHeap(RtlProcessHeap(), 0, VolumeMountPoint);
  653. VolumeName.Buffer[1] = '?';
  654. }
  655. }
  656. else {
  657. //
  658. // Copy the directory junction and be done.
  659. //
  660. b = TRUE;
  661. Status = NtFsControlFile(
  662. DestFile,
  663. NULL,
  664. NULL,
  665. NULL,
  666. &IoStatusBlock,
  667. FSCTL_SET_REPARSE_POINT,
  668. ReparseBuffer,
  669. FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) + ReparseBufferHeader->ReparseDataLength,
  670. NULL, // Output buffer
  671. 0 // Output buffer length
  672. );
  673. }
  674. //
  675. // Free the buffer.
  676. //
  677. RtlFreeHeap(RtlProcessHeap(), 0, ReparseBuffer);
  678. //
  679. // Close all files and return appropriatelly.
  680. //
  681. NtClose(SourceFile);
  682. NtClose(DestFile);
  683. if ( !b ) {
  684. //
  685. // No need to set the last error as SetVolumeMountPointW has done it.
  686. //
  687. return FALSE;
  688. }
  689. if ( !NT_SUCCESS( Status ) ) {
  690. BaseSetLastNTError(Status);
  691. return FALSE;
  692. }
  693. return TRUE;
  694. //
  695. // The source directory was a name grafting directory.
  696. // No data streams are copied.
  697. //
  698. }
  699. //
  700. // Attempt to determine whether or not this file has any alternate
  701. // data streams associated with it. If it does, attempt to copy each
  702. // to the output file. If any copy fails, simply drop the error on
  703. // the floor, and continue.
  704. //
  705. StreamInfoSize = 4096;
  706. CopySize = 4096;
  707. do {
  708. StreamInfoBase = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), StreamInfoSize);
  709. if ( !StreamInfoBase ) {
  710. BaseMarkFileForDelete(DestFile, BasicInfo.FileAttributes);
  711. BaseSetLastNTError(STATUS_NO_MEMORY);
  712. b = FALSE;
  713. break;
  714. }
  715. Status = NtQueryInformationFile(
  716. SourceFile,
  717. &IoStatusBlock,
  718. (PVOID) StreamInfoBase,
  719. StreamInfoSize,
  720. FileStreamInformation
  721. );
  722. if ( !NT_SUCCESS(Status) ) {
  723. RtlFreeHeap(RtlProcessHeap(), 0, StreamInfoBase);
  724. StreamInfoBase = NULL;
  725. StreamInfoSize *= 2;
  726. }
  727. } while ( Status == STATUS_BUFFER_OVERFLOW ||
  728. Status == STATUS_BUFFER_TOO_SMALL );
  729. //
  730. // Directories do not always have a stream
  731. //
  732. if ( NT_SUCCESS(Status) && IoStatusBlock.Information ) {
  733. StreamInfo = StreamInfoBase;
  734. for (;;) {
  735. DWORD DestFileFsAttributes = 0;
  736. //
  737. // Build a string descriptor for the name of the stream.
  738. //
  739. StreamName.Buffer = &StreamInfo->StreamName[0];
  740. StreamName.Length = (USHORT) StreamInfo->StreamNameLength;
  741. StreamName.MaximumLength = StreamName.Length;
  742. //
  743. // Open the source stream.
  744. //
  745. InitializeObjectAttributes(
  746. &Obja,
  747. &StreamName,
  748. 0,
  749. SourceFile,
  750. NULL
  751. );
  752. Status = NtCreateFile(
  753. &StreamHandle,
  754. GENERIC_READ | SYNCHRONIZE,
  755. &Obja,
  756. &IoStatusBlock,
  757. NULL,
  758. 0,
  759. FILE_SHARE_READ,
  760. FILE_OPEN,
  761. FILE_SYNCHRONOUS_IO_NONALERT,
  762. NULL,
  763. 0
  764. );
  765. if ( NT_SUCCESS(Status) ) {
  766. for ( i = 0; i < (ULONG) StreamName.Length >> 1; i++ ) {
  767. FileName[i] = StreamName.Buffer[i];
  768. }
  769. FileName[i] = L'\0';
  770. OutputStream = (HANDLE)NULL;
  771. Options = 0;
  772. b = BaseCopyStream(
  773. NULL,
  774. StreamHandle,
  775. GENERIC_READ | SYNCHRONIZE,
  776. FileName,
  777. DestFile,
  778. &StreamInfo->StreamSize,
  779. &Options,
  780. &OutputStream,
  781. &CopySize,
  782. &CopyFileContext,
  783. (LPRESTART_STATE)NULL,
  784. (BOOL)FALSE,
  785. (DWORD)0,
  786. &DestFileFsAttributes
  787. );
  788. NtClose(StreamHandle);
  789. if ( OutputStream ) {
  790. NtClose(OutputStream);
  791. }
  792. }
  793. if ( StreamInfo->NextEntryOffset ) {
  794. StreamInfo = (PFILE_STREAM_INFORMATION)((PCHAR) StreamInfo + StreamInfo->NextEntryOffset);
  795. }
  796. else {
  797. break;
  798. }
  799. }
  800. }
  801. if ( StreamInfoBase ) {
  802. RtlFreeHeap(RtlProcessHeap(), 0, StreamInfoBase);
  803. }
  804. b = TRUE;
  805. }
  806. NtClose(SourceFile);
  807. if ( DestFile ) {
  808. NtClose(DestFile);
  809. }
  810. return b;
  811. }
  812. BOOL
  813. APIENTRY
  814. RemoveDirectoryA(
  815. LPCSTR lpPathName
  816. )
  817. /*++
  818. Routine Description:
  819. ANSI thunk to RemoveDirectoryW
  820. --*/
  821. {
  822. PUNICODE_STRING Unicode;
  823. Unicode = Basep8BitStringToStaticUnicodeString( lpPathName );
  824. if (Unicode == NULL) {
  825. return FALSE;
  826. }
  827. return ( RemoveDirectoryW((LPCWSTR)Unicode->Buffer) );
  828. }
  829. BOOL
  830. APIENTRY
  831. RemoveDirectoryW(
  832. LPCWSTR lpPathName
  833. )
  834. /*++
  835. Routine Description:
  836. An existing directory can be removed using RemoveDirectory.
  837. This API causes a directory with the specified pathname to be
  838. deleted. The directory must be empty before this call can succeed.
  839. This call is similar to DOS (int 21h, function 3Ah) and OS/2's
  840. DosDeleteDir.
  841. Arguments:
  842. lpPathName - Supplies the pathname of the directory to be removed.
  843. The path must specify an empty directory to which the caller has
  844. delete access.
  845. Return Value:
  846. TRUE - The operation was successful.
  847. FALSE/NULL - The operation failed. Extended error status is available
  848. using GetLastError.
  849. --*/
  850. {
  851. NTSTATUS Status;
  852. OBJECT_ATTRIBUTES Obja;
  853. HANDLE Handle;
  854. UNICODE_STRING FileName;
  855. IO_STATUS_BLOCK IoStatusBlock;
  856. FILE_DISPOSITION_INFORMATION Disposition;
  857. BOOLEAN TranslationStatus;
  858. RTL_RELATIVE_NAME_U RelativeName;
  859. PVOID FreeBuffer;
  860. BOOLEAN IsNameGrafting = FALSE;
  861. FILE_ATTRIBUTE_TAG_INFORMATION FileTagInformation;
  862. PREPARSE_DATA_BUFFER reparse;
  863. BOOL b;
  864. DWORD bytes;
  865. UNICODE_STRING mountName;
  866. PWCHAR volumeMountPoint;
  867. TranslationStatus = RtlDosPathNameToRelativeNtPathName_U(
  868. lpPathName,
  869. &FileName,
  870. NULL,
  871. &RelativeName
  872. );
  873. if ( !TranslationStatus ) {
  874. SetLastError(ERROR_PATH_NOT_FOUND);
  875. return FALSE;
  876. }
  877. FreeBuffer = FileName.Buffer;
  878. if ( RelativeName.RelativeName.Length ) {
  879. FileName = RelativeName.RelativeName;
  880. }
  881. else {
  882. RelativeName.ContainingDirectory = NULL;
  883. }
  884. InitializeObjectAttributes(
  885. &Obja,
  886. &FileName,
  887. OBJ_CASE_INSENSITIVE,
  888. RelativeName.ContainingDirectory,
  889. NULL
  890. );
  891. //
  892. // Open the directory for delete access.
  893. // Inhibit the reparse behavior using FILE_OPEN_REPARSE_POINT.
  894. //
  895. Status = NtOpenFile(
  896. &Handle,
  897. DELETE | SYNCHRONIZE | FILE_READ_ATTRIBUTES,
  898. &Obja,
  899. &IoStatusBlock,
  900. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  901. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT
  902. );
  903. if ( !NT_SUCCESS(Status) ) {
  904. //
  905. // Back level file systems may not support reparse points and thus not
  906. // support symbolic links.
  907. // We infer this is the case when the Status is STATUS_INVALID_PARAMETER.
  908. //
  909. if ( Status == STATUS_INVALID_PARAMETER ) {
  910. //
  911. // Re-open not inhibiting the reparse behavior and not needing to read the attributes.
  912. //
  913. Status = NtOpenFile(
  914. &Handle,
  915. DELETE | SYNCHRONIZE,
  916. &Obja,
  917. &IoStatusBlock,
  918. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  919. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT
  920. );
  921. if ( !NT_SUCCESS(Status) ) {
  922. RtlReleaseRelativeName(&RelativeName);
  923. RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
  924. BaseSetLastNTError(Status);
  925. return FALSE;
  926. }
  927. }
  928. else {
  929. RtlReleaseRelativeName(&RelativeName);
  930. RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
  931. BaseSetLastNTError(Status);
  932. return FALSE;
  933. }
  934. }
  935. else {
  936. //
  937. // If we found a reparse point that is not a name grafting operation,
  938. // either a symbolic link or a mount point, we re-open without
  939. // inhibiting the reparse behavior.
  940. //
  941. Status = NtQueryInformationFile(
  942. Handle,
  943. &IoStatusBlock,
  944. (PVOID) &FileTagInformation,
  945. sizeof(FileTagInformation),
  946. FileAttributeTagInformation
  947. );
  948. if ( !NT_SUCCESS(Status) ) {
  949. //
  950. // Not all File Systems implement all information classes.
  951. // The value STATUS_INVALID_PARAMETER is returned when a non-supported
  952. // information class is requested to a back-level File System. As all the
  953. // parameters to NtQueryInformationFile are correct, we can infer that
  954. // we found a back-level system.
  955. //
  956. // If FileAttributeTagInformation is not implemented, we assume that
  957. // the file at hand is not a reparse point.
  958. //
  959. if ( (Status != STATUS_NOT_IMPLEMENTED) &&
  960. (Status != STATUS_INVALID_PARAMETER) ) {
  961. RtlReleaseRelativeName(&RelativeName);
  962. RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
  963. NtClose(Handle);
  964. BaseSetLastNTError(Status);
  965. return FALSE;
  966. }
  967. }
  968. if ( NT_SUCCESS(Status) &&
  969. (FileTagInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ) {
  970. if ( FileTagInformation.ReparseTag == IO_REPARSE_TAG_MOUNT_POINT ) {
  971. //
  972. // If this is a volume mount point then fail with
  973. // "directory not empty".
  974. //
  975. reparse = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG),
  976. MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
  977. if (!reparse) {
  978. RtlReleaseRelativeName(&RelativeName);
  979. RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
  980. NtClose(Handle);
  981. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  982. return FALSE;
  983. }
  984. b = DeviceIoControl(Handle, FSCTL_GET_REPARSE_POINT, NULL, 0,
  985. reparse, MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
  986. &bytes, NULL);
  987. if (b) {
  988. mountName.Length = mountName.MaximumLength =
  989. reparse->MountPointReparseBuffer.SubstituteNameLength;
  990. mountName.Buffer = (PWCHAR)
  991. ((PCHAR) reparse->MountPointReparseBuffer.PathBuffer +
  992. reparse->MountPointReparseBuffer.SubstituteNameOffset);
  993. if (MOUNTMGR_IS_VOLUME_NAME(&mountName)) {
  994. RtlInitUnicodeString(&mountName, lpPathName);
  995. volumeMountPoint = RtlAllocateHeap(RtlProcessHeap(),
  996. MAKE_TAG(TMP_TAG),
  997. mountName.Length +
  998. 2*sizeof(WCHAR));
  999. if (!volumeMountPoint) {
  1000. RtlReleaseRelativeName(&RelativeName);
  1001. RtlFreeHeap(RtlProcessHeap(), 0, reparse);
  1002. RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
  1003. NtClose(Handle);
  1004. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1005. return FALSE;
  1006. }
  1007. RtlCopyMemory(volumeMountPoint, mountName.Buffer,
  1008. mountName.Length);
  1009. volumeMountPoint[mountName.Length/sizeof(WCHAR)] = 0;
  1010. if (mountName.Buffer[mountName.Length/sizeof(WCHAR) - 1] != '\\') {
  1011. volumeMountPoint[mountName.Length/sizeof(WCHAR)] = '\\';
  1012. volumeMountPoint[mountName.Length/sizeof(WCHAR) + 1] = 0;
  1013. }
  1014. DeleteVolumeMountPointW(volumeMountPoint);
  1015. RtlFreeHeap(RtlProcessHeap(), 0, volumeMountPoint);
  1016. }
  1017. }
  1018. RtlFreeHeap(RtlProcessHeap(), 0, reparse);
  1019. IsNameGrafting = TRUE;
  1020. }
  1021. }
  1022. if ( NT_SUCCESS(Status) &&
  1023. (FileTagInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
  1024. !IsNameGrafting) {
  1025. //
  1026. // Re-open without inhibiting the reparse behavior and not needing to
  1027. // read the attributes.
  1028. //
  1029. NtClose(Handle);
  1030. Status = NtOpenFile(
  1031. &Handle,
  1032. DELETE | SYNCHRONIZE,
  1033. &Obja,
  1034. &IoStatusBlock,
  1035. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  1036. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT
  1037. );
  1038. if ( !NT_SUCCESS(Status) ) {
  1039. //
  1040. // When the FS Filter is absent, delete it any way.
  1041. //
  1042. if ( Status == STATUS_IO_REPARSE_TAG_NOT_HANDLED ) {
  1043. //
  1044. // We re-open (possible 3rd open) for delete access inhibiting the reparse behavior.
  1045. //
  1046. Status = NtOpenFile(
  1047. &Handle,
  1048. DELETE | SYNCHRONIZE,
  1049. &Obja,
  1050. &IoStatusBlock,
  1051. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  1052. FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT
  1053. );
  1054. }
  1055. if ( !NT_SUCCESS(Status) ) {
  1056. RtlReleaseRelativeName(&RelativeName);
  1057. RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
  1058. BaseSetLastNTError(Status);
  1059. return FALSE;
  1060. }
  1061. }
  1062. }
  1063. }
  1064. RtlReleaseRelativeName(&RelativeName);
  1065. RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
  1066. //
  1067. // Delete the file
  1068. //
  1069. #undef DeleteFile
  1070. Disposition.DeleteFile = TRUE;
  1071. Status = NtSetInformationFile(
  1072. Handle,
  1073. &IoStatusBlock,
  1074. &Disposition,
  1075. sizeof(Disposition),
  1076. FileDispositionInformation
  1077. );
  1078. NtClose(Handle);
  1079. if ( NT_SUCCESS(Status) ) {
  1080. return TRUE;
  1081. }
  1082. else {
  1083. BaseSetLastNTError(Status);
  1084. return FALSE;
  1085. }
  1086. }