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.

2480 lines
75 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. filemisc.c
  5. Abstract:
  6. Misc file operations for Win32
  7. Author:
  8. Mark Lucovsky (markl) 26-Sep-1990
  9. Revision History:
  10. --*/
  11. #include <basedll.h>
  12. DWORD
  13. BasepGetComputerNameFromNtPath (
  14. PUNICODE_STRING NtPathName,
  15. HANDLE hFile,
  16. LPWSTR lpBuffer,
  17. LPDWORD nSize
  18. );
  19. NTSTATUS
  20. BasepMoveFileDelayed(
  21. IN PUNICODE_STRING OldFileName,
  22. IN PUNICODE_STRING NewFileName,
  23. IN ULONG Index,
  24. IN BOOL OkayToCreateNewValue
  25. );
  26. BOOL
  27. APIENTRY
  28. SetFileAttributesA(
  29. LPCSTR lpFileName,
  30. DWORD dwFileAttributes
  31. )
  32. /*++
  33. Routine Description:
  34. ANSI thunk to SetFileAttributesW
  35. --*/
  36. {
  37. PUNICODE_STRING Unicode;
  38. Unicode = Basep8BitStringToStaticUnicodeString( lpFileName );
  39. if (Unicode == NULL) {
  40. return FALSE;
  41. }
  42. return ( SetFileAttributesW(
  43. (LPCWSTR)Unicode->Buffer,
  44. dwFileAttributes
  45. )
  46. );
  47. }
  48. BOOL
  49. APIENTRY
  50. SetFileAttributesW(
  51. LPCWSTR lpFileName,
  52. DWORD dwFileAttributes
  53. )
  54. /*++
  55. Routine Description:
  56. The attributes of a file can be set using SetFileAttributes.
  57. This API provides the same functionality as DOS (int 21h, function
  58. 43H with AL=1), and provides a subset of OS/2's DosSetFileInfo.
  59. Arguments:
  60. lpFileName - Supplies the file name of the file whose attributes are to
  61. be set.
  62. dwFileAttributes - Specifies the file attributes to be set for the
  63. file. Any combination of flags is acceptable except that all
  64. other flags override the normal file attribute,
  65. FILE_ATTRIBUTE_NORMAL.
  66. FileAttributes Flags:
  67. FILE_ATTRIBUTE_NORMAL - A normal file should be created.
  68. FILE_ATTRIBUTE_READONLY - A read-only file should be created.
  69. FILE_ATTRIBUTE_HIDDEN - A hidden file should be created.
  70. FILE_ATTRIBUTE_SYSTEM - A system file should be created.
  71. FILE_ATTRIBUTE_ARCHIVE - The file should be marked so that it
  72. will be archived.
  73. Return Value:
  74. TRUE - The operation was successful.
  75. FALSE/NULL - The operation failed. Extended error status is available
  76. using GetLastError.
  77. --*/
  78. {
  79. NTSTATUS Status;
  80. OBJECT_ATTRIBUTES Obja;
  81. HANDLE Handle;
  82. UNICODE_STRING FileName;
  83. IO_STATUS_BLOCK IoStatusBlock;
  84. FILE_BASIC_INFORMATION BasicInfo;
  85. BOOLEAN TranslationStatus;
  86. RTL_RELATIVE_NAME_U RelativeName;
  87. PVOID FreeBuffer;
  88. TranslationStatus = RtlDosPathNameToRelativeNtPathName_U(
  89. lpFileName,
  90. &FileName,
  91. NULL,
  92. &RelativeName
  93. );
  94. if ( !TranslationStatus ) {
  95. SetLastError(ERROR_PATH_NOT_FOUND);
  96. return FALSE;
  97. }
  98. FreeBuffer = FileName.Buffer;
  99. if ( RelativeName.RelativeName.Length ) {
  100. FileName = RelativeName.RelativeName;
  101. }
  102. else {
  103. RelativeName.ContainingDirectory = NULL;
  104. }
  105. InitializeObjectAttributes(
  106. &Obja,
  107. &FileName,
  108. OBJ_CASE_INSENSITIVE,
  109. RelativeName.ContainingDirectory,
  110. NULL
  111. );
  112. //
  113. // Open the file inhibiting the reparse behavior.
  114. //
  115. Status = NtOpenFile(
  116. &Handle,
  117. (ACCESS_MASK)FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
  118. &Obja,
  119. &IoStatusBlock,
  120. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  121. FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT
  122. );
  123. if ( !NT_SUCCESS(Status) ) {
  124. //
  125. // Back level file systems may not support reparse points.
  126. // We infer this is the case when the Status is STATUS_INVALID_PARAMETER.
  127. //
  128. if ( Status == STATUS_INVALID_PARAMETER ) {
  129. //
  130. // Open the file without inhibiting the reparse behavior.
  131. //
  132. Status = NtOpenFile(
  133. &Handle,
  134. (ACCESS_MASK)FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
  135. &Obja,
  136. &IoStatusBlock,
  137. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  138. FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT
  139. );
  140. if ( !NT_SUCCESS(Status) ) {
  141. RtlReleaseRelativeName(&RelativeName);
  142. RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
  143. BaseSetLastNTError(Status);
  144. return FALSE;
  145. }
  146. }
  147. else {
  148. RtlReleaseRelativeName(&RelativeName);
  149. RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
  150. BaseSetLastNTError(Status);
  151. return FALSE;
  152. }
  153. }
  154. RtlReleaseRelativeName(&RelativeName);
  155. RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
  156. //
  157. // Set the attributes
  158. //
  159. RtlZeroMemory(&BasicInfo,sizeof(BasicInfo));
  160. BasicInfo.FileAttributes = (dwFileAttributes & FILE_ATTRIBUTE_VALID_SET_FLAGS) | FILE_ATTRIBUTE_NORMAL;
  161. Status = NtSetInformationFile(
  162. Handle,
  163. &IoStatusBlock,
  164. &BasicInfo,
  165. sizeof(BasicInfo),
  166. FileBasicInformation
  167. );
  168. NtClose(Handle);
  169. if ( NT_SUCCESS(Status) ) {
  170. return TRUE;
  171. }
  172. else {
  173. BaseSetLastNTError(Status);
  174. return FALSE;
  175. }
  176. }
  177. DWORD
  178. APIENTRY
  179. GetFileAttributesA(
  180. LPCSTR lpFileName
  181. )
  182. /*++
  183. Routine Description:
  184. ANSI thunk to GetFileAttributesW
  185. --*/
  186. {
  187. PUNICODE_STRING Unicode;
  188. Unicode = Basep8BitStringToStaticUnicodeString( lpFileName );
  189. if (Unicode == NULL) {
  190. return (DWORD)-1;
  191. }
  192. return ( GetFileAttributesW((LPCWSTR)Unicode->Buffer) );
  193. }
  194. DWORD
  195. APIENTRY
  196. GetFileAttributesW(
  197. LPCWSTR lpFileName
  198. )
  199. /*++
  200. Routine Description:
  201. The attributes of a file can be obtained using GetFileAttributes.
  202. This API provides the same functionality as DOS (int 21h, function
  203. 43H with AL=0), and provides a subset of OS/2's DosQueryFileInfo.
  204. Arguments:
  205. lpFileName - Supplies the file name of the file whose attributes are to
  206. be set.
  207. Return Value:
  208. Not -1 - Returns the attributes of the specified file. Valid
  209. returned attributes are:
  210. FILE_ATTRIBUTE_NORMAL - The file is a normal file.
  211. FILE_ATTRIBUTE_READONLY - The file is marked read-only.
  212. FILE_ATTRIBUTE_HIDDEN - The file is marked as hidden.
  213. FILE_ATTRIBUTE_SYSTEM - The file is marked as a system file.
  214. FILE_ATTRIBUTE_ARCHIVE - The file is marked for archive.
  215. FILE_ATTRIBUTE_DIRECTORY - The file is marked as a directory.
  216. FILE_ATTRIBUTE_REPARSE_POINT - The file is marked as a reparse point.
  217. FILE_ATTRIBUTE_VOLUME_LABEL - The file is marked as a volume lable.
  218. 0xffffffff - The operation failed. Extended error status is available
  219. using GetLastError.
  220. --*/
  221. {
  222. NTSTATUS Status;
  223. OBJECT_ATTRIBUTES Obja;
  224. UNICODE_STRING FileName;
  225. FILE_BASIC_INFORMATION BasicInfo;
  226. BOOLEAN TranslationStatus;
  227. PVOID FreeBuffer;
  228. TranslationStatus = RtlDosPathNameToNtPathName_U(
  229. lpFileName,
  230. &FileName,
  231. NULL,
  232. NULL
  233. );
  234. if ( !TranslationStatus ) {
  235. SetLastError(ERROR_PATH_NOT_FOUND);
  236. return (DWORD)-1;
  237. }
  238. FreeBuffer = FileName.Buffer;
  239. InitializeObjectAttributes(
  240. &Obja,
  241. &FileName,
  242. OBJ_CASE_INSENSITIVE,
  243. NULL,
  244. NULL
  245. );
  246. //
  247. // Open the file
  248. //
  249. Status = NtQueryAttributesFile(
  250. &Obja,
  251. &BasicInfo
  252. );
  253. RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
  254. if ( NT_SUCCESS(Status) ) {
  255. return BasicInfo.FileAttributes;
  256. }
  257. else {
  258. //
  259. // Check for a device name.
  260. //
  261. if ( RtlIsDosDeviceName_U((PWSTR)lpFileName) ) {
  262. return FILE_ATTRIBUTE_ARCHIVE;
  263. }
  264. BaseSetLastNTError(Status);
  265. return (DWORD)-1;
  266. }
  267. }
  268. BOOL
  269. APIENTRY
  270. GetFileAttributesExA(
  271. LPCSTR lpFileName,
  272. GET_FILEEX_INFO_LEVELS fInfoLevelId,
  273. LPVOID lpFileInformation
  274. )
  275. /*++
  276. Routine Description:
  277. ANSI thunk to GetFileAttributesExW
  278. --*/
  279. {
  280. PUNICODE_STRING Unicode;
  281. Unicode = Basep8BitStringToStaticUnicodeString( lpFileName );
  282. if (Unicode == NULL) {
  283. return FALSE;
  284. }
  285. return ( GetFileAttributesExW((LPCWSTR)Unicode->Buffer,fInfoLevelId,lpFileInformation) );
  286. }
  287. BOOL
  288. APIENTRY
  289. GetFileAttributesExW(
  290. LPCWSTR lpFileName,
  291. GET_FILEEX_INFO_LEVELS fInfoLevelId,
  292. LPVOID lpFileInformation
  293. )
  294. /*++
  295. Routine Description:
  296. The main attributes of a file can be obtained using GetFileAttributesEx.
  297. Arguments:
  298. lpFileName - Supplies the file name of the file whose attributes are to
  299. be set.
  300. fInfoLevelId - Supplies the info level indicating the information to be
  301. returned about the file.
  302. lpFileInformation - Supplies a buffer to receive the specified information
  303. about the file.
  304. Return Value:
  305. TRUE - The operation was successful.
  306. FALSE/NULL - The operation failed. Extended error status is available
  307. using GetLastError.
  308. --*/
  309. {
  310. NTSTATUS Status;
  311. OBJECT_ATTRIBUTES Obja;
  312. UNICODE_STRING FileName;
  313. FILE_NETWORK_OPEN_INFORMATION NetworkInfo;
  314. LPWIN32_FILE_ATTRIBUTE_DATA AttributeData;
  315. BOOLEAN TranslationStatus;
  316. RTL_RELATIVE_NAME_U RelativeName;
  317. PVOID FreeBuffer;
  318. //
  319. // Check the parameters. Note that for now there is only one info level,
  320. // so there's no special code here to determine what to do.
  321. //
  322. if ( fInfoLevelId >= GetFileExMaxInfoLevel || fInfoLevelId < GetFileExInfoStandard ) {
  323. SetLastError(ERROR_INVALID_PARAMETER);
  324. return FALSE;
  325. }
  326. TranslationStatus = RtlDosPathNameToRelativeNtPathName_U(
  327. lpFileName,
  328. &FileName,
  329. NULL,
  330. &RelativeName
  331. );
  332. if ( !TranslationStatus ) {
  333. SetLastError(ERROR_PATH_NOT_FOUND);
  334. return FALSE;
  335. }
  336. FreeBuffer = FileName.Buffer;
  337. if ( RelativeName.RelativeName.Length ) {
  338. FileName = RelativeName.RelativeName;
  339. }
  340. else {
  341. RelativeName.ContainingDirectory = NULL;
  342. }
  343. InitializeObjectAttributes(
  344. &Obja,
  345. &FileName,
  346. OBJ_CASE_INSENSITIVE,
  347. RelativeName.ContainingDirectory,
  348. NULL
  349. );
  350. //
  351. // Query the information about the file using the path-based NT service.
  352. //
  353. Status = NtQueryFullAttributesFile( &Obja, &NetworkInfo );
  354. RtlReleaseRelativeName(&RelativeName);
  355. RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
  356. if ( NT_SUCCESS(Status) ) {
  357. AttributeData = (LPWIN32_FILE_ATTRIBUTE_DATA)lpFileInformation;
  358. AttributeData->dwFileAttributes = NetworkInfo.FileAttributes;
  359. AttributeData->ftCreationTime = *(PFILETIME)&NetworkInfo.CreationTime;
  360. AttributeData->ftLastAccessTime = *(PFILETIME)&NetworkInfo.LastAccessTime;
  361. AttributeData->ftLastWriteTime = *(PFILETIME)&NetworkInfo.LastWriteTime;
  362. AttributeData->nFileSizeHigh = NetworkInfo.EndOfFile.HighPart;
  363. AttributeData->nFileSizeLow = (DWORD)NetworkInfo.EndOfFile.LowPart;
  364. return TRUE;
  365. }
  366. else {
  367. BaseSetLastNTError(Status);
  368. return FALSE;
  369. }
  370. }
  371. BOOL
  372. APIENTRY
  373. DeleteFileA(
  374. LPCSTR lpFileName
  375. )
  376. /*++
  377. Routine Description:
  378. ANSI thunk to DeleteFileW
  379. --*/
  380. {
  381. PUNICODE_STRING Unicode;
  382. Unicode = Basep8BitStringToStaticUnicodeString( lpFileName );
  383. if (Unicode == NULL) {
  384. return FALSE;
  385. }
  386. return ( DeleteFileW((LPCWSTR)Unicode->Buffer) );
  387. }
  388. BOOL
  389. APIENTRY
  390. DeleteFileW(
  391. LPCWSTR lpFileName
  392. )
  393. /*++
  394. Routine Description:
  395. An existing file can be deleted using DeleteFile.
  396. This API provides the same functionality as DOS (int 21h, function 41H)
  397. and OS/2's DosDelete.
  398. Arguments:
  399. lpFileName - Supplies the file name of the file to be deleted.
  400. Return Value:
  401. TRUE - The operation was successful.
  402. FALSE/NULL - The operation failed. Extended error status is available
  403. using GetLastError.
  404. --*/
  405. {
  406. NTSTATUS Status;
  407. OBJECT_ATTRIBUTES Obja;
  408. HANDLE Handle;
  409. UNICODE_STRING FileName;
  410. IO_STATUS_BLOCK IoStatusBlock;
  411. FILE_DISPOSITION_INFORMATION Disposition;
  412. FILE_ATTRIBUTE_TAG_INFORMATION FileTagInformation;
  413. BOOLEAN TranslationStatus;
  414. RTL_RELATIVE_NAME_U RelativeName;
  415. PVOID FreeBuffer;
  416. BOOLEAN fIsSymbolicLink = FALSE;
  417. TranslationStatus = RtlDosPathNameToRelativeNtPathName_U(
  418. lpFileName,
  419. &FileName,
  420. NULL,
  421. &RelativeName
  422. );
  423. if ( !TranslationStatus ) {
  424. SetLastError(ERROR_PATH_NOT_FOUND);
  425. return FALSE;
  426. }
  427. FreeBuffer = FileName.Buffer;
  428. if ( RelativeName.RelativeName.Length ) {
  429. FileName = RelativeName.RelativeName;
  430. }
  431. else {
  432. RelativeName.ContainingDirectory = NULL;
  433. }
  434. InitializeObjectAttributes(
  435. &Obja,
  436. &FileName,
  437. OBJ_CASE_INSENSITIVE,
  438. RelativeName.ContainingDirectory,
  439. NULL
  440. );
  441. //
  442. // Open the file for delete access.
  443. // Inhibit the reparse behavior using FILE_OPEN_REPARSE_POINT.
  444. //
  445. Status = NtOpenFile(
  446. &Handle,
  447. (ACCESS_MASK)DELETE | FILE_READ_ATTRIBUTES,
  448. &Obja,
  449. &IoStatusBlock,
  450. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
  451. FILE_NON_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT
  452. );
  453. if ( !NT_SUCCESS(Status) ) {
  454. //
  455. // Back level file systems may not support reparse points and thus not
  456. // support symbolic links.
  457. // We infer this is the case when the Status is STATUS_INVALID_PARAMETER.
  458. //
  459. if ( Status == STATUS_INVALID_PARAMETER ) {
  460. //
  461. // Open without inhibiting the reparse behavior and not needing to
  462. // read the attributes.
  463. //
  464. Status = NtOpenFile(
  465. &Handle,
  466. (ACCESS_MASK)DELETE,
  467. &Obja,
  468. &IoStatusBlock,
  469. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
  470. FILE_NON_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT
  471. );
  472. if ( !NT_SUCCESS(Status) ) {
  473. RtlReleaseRelativeName(&RelativeName);
  474. RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
  475. BaseSetLastNTError(Status);
  476. return FALSE;
  477. }
  478. }
  479. else {
  480. //
  481. // A second case of interest is when the caller does not have rights
  482. // to read attributes yet it does have rights to delete the file.
  483. // In this case Status is to be STATUS_ACCESS_DENIED.
  484. //
  485. if ( Status != STATUS_ACCESS_DENIED ) {
  486. RtlReleaseRelativeName(&RelativeName);
  487. RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
  488. BaseSetLastNTError(Status);
  489. return FALSE;
  490. }
  491. //
  492. // Re-open inhibiting reparse point and not requiring read attributes.
  493. //
  494. Status = NtOpenFile(
  495. &Handle,
  496. (ACCESS_MASK)DELETE,
  497. &Obja,
  498. &IoStatusBlock,
  499. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
  500. FILE_NON_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT
  501. );
  502. if ( !NT_SUCCESS(Status) ) {
  503. RtlReleaseRelativeName(&RelativeName);
  504. RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
  505. BaseSetLastNTError(Status);
  506. return FALSE;
  507. }
  508. //
  509. // If we are here, Handle is valid.
  510. //
  511. // Moreover, Handle is to a file for which the caller has DELETE right yet
  512. // does not have FILE_READ_ATTRIBUTES rights.
  513. //
  514. // The underlying file may or not be a reparse point.
  515. // As the caller does not have rights to read the attributes this code
  516. // will delete this file without giving the opportunity to the
  517. // appropriate manager of these reparse points to clean-up its internal
  518. // state at this time.
  519. //
  520. }
  521. }
  522. else {
  523. //
  524. // If we found a reparse point that is not a symbolic link, we re-open
  525. // without inhibiting the reparse behavior.
  526. //
  527. Status = NtQueryInformationFile(
  528. Handle,
  529. &IoStatusBlock,
  530. (PVOID) &FileTagInformation,
  531. sizeof(FileTagInformation),
  532. FileAttributeTagInformation
  533. );
  534. if ( !NT_SUCCESS(Status) ) {
  535. //
  536. // Not all File Systems implement all information classes.
  537. // The value STATUS_INVALID_PARAMETER is returned when a non-supported
  538. // information class is requested to a back-level File System. As all the
  539. // parameters to NtQueryInformationFile are correct, we can infer that
  540. // we found a back-level system.
  541. //
  542. // If FileAttributeTagInformation is not implemented, we assume that
  543. // the file at hand is not a reparse point.
  544. //
  545. if ( (Status != STATUS_NOT_IMPLEMENTED) &&
  546. (Status != STATUS_INVALID_PARAMETER) ) {
  547. RtlReleaseRelativeName(&RelativeName);
  548. RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
  549. NtClose(Handle);
  550. BaseSetLastNTError(Status);
  551. return FALSE;
  552. }
  553. }
  554. if ( NT_SUCCESS(Status) &&
  555. (FileTagInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ) {
  556. if ( FileTagInformation.ReparseTag == IO_REPARSE_TAG_MOUNT_POINT ) {
  557. fIsSymbolicLink = TRUE;
  558. }
  559. }
  560. if ( NT_SUCCESS(Status) &&
  561. (FileTagInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
  562. !fIsSymbolicLink) {
  563. //
  564. // Re-open without inhibiting the reparse behavior and not needing to
  565. // read the attributes.
  566. //
  567. NtClose(Handle);
  568. Status = NtOpenFile(
  569. &Handle,
  570. (ACCESS_MASK)DELETE,
  571. &Obja,
  572. &IoStatusBlock,
  573. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
  574. FILE_NON_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT
  575. );
  576. if ( !NT_SUCCESS(Status) ) {
  577. //
  578. // When the FS Filter is absent, delete it any way.
  579. //
  580. if ( Status == STATUS_IO_REPARSE_TAG_NOT_HANDLED ) {
  581. //
  582. // We re-open (possible 3rd open) for delete access inhibiting the reparse behavior.
  583. //
  584. Status = NtOpenFile(
  585. &Handle,
  586. (ACCESS_MASK)DELETE,
  587. &Obja,
  588. &IoStatusBlock,
  589. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  590. FILE_NON_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT
  591. );
  592. }
  593. if ( !NT_SUCCESS(Status) ) {
  594. RtlReleaseRelativeName(&RelativeName);
  595. RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
  596. BaseSetLastNTError(Status);
  597. return FALSE;
  598. }
  599. }
  600. }
  601. }
  602. RtlReleaseRelativeName(&RelativeName);
  603. RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
  604. //
  605. // Delete the file
  606. //
  607. #undef DeleteFile
  608. Disposition.DeleteFile = TRUE;
  609. Status = NtSetInformationFile(
  610. Handle,
  611. &IoStatusBlock,
  612. &Disposition,
  613. sizeof(Disposition),
  614. FileDispositionInformation
  615. );
  616. NtClose(Handle);
  617. if ( NT_SUCCESS(Status) ) {
  618. return TRUE;
  619. }
  620. else {
  621. BaseSetLastNTError(Status);
  622. return FALSE;
  623. }
  624. }
  625. //
  626. // Ascii versions that thunk to the common code
  627. //
  628. BOOL
  629. APIENTRY
  630. MoveFileA(
  631. LPCSTR lpExistingFileName,
  632. LPCSTR lpNewFileName
  633. )
  634. {
  635. return MoveFileWithProgressA( lpExistingFileName,
  636. lpNewFileName,
  637. (LPPROGRESS_ROUTINE)NULL,
  638. NULL,
  639. MOVEFILE_COPY_ALLOWED );
  640. }
  641. BOOL
  642. APIENTRY
  643. MoveFileExA(
  644. LPCSTR lpExistingFileName,
  645. LPCSTR lpNewFileName,
  646. DWORD dwFlags
  647. )
  648. {
  649. return MoveFileWithProgressA( lpExistingFileName,
  650. lpNewFileName,
  651. (LPPROGRESS_ROUTINE)NULL,
  652. NULL,
  653. dwFlags );
  654. }
  655. BOOL
  656. APIENTRY
  657. MoveFileWithProgressA(
  658. LPCSTR lpExistingFileName,
  659. LPCSTR lpNewFileName,
  660. LPPROGRESS_ROUTINE lpProgressRoutine,
  661. LPVOID lpData OPTIONAL,
  662. DWORD dwFlags
  663. )
  664. /*++
  665. Routine Description:
  666. ANSI thunk to MoveFileWithProgressW
  667. --*/
  668. {
  669. UNICODE_STRING UnicodeOldFileName;
  670. UNICODE_STRING UnicodeNewFileName;
  671. BOOL ReturnValue;
  672. if ( !Basep8BitStringToDynamicUnicodeString(&UnicodeOldFileName, lpExistingFileName) ) {
  673. return FALSE;
  674. }
  675. if ( ARGUMENT_PRESENT(lpNewFileName) ) {
  676. if ( !Basep8BitStringToDynamicUnicodeString(&UnicodeNewFileName, lpNewFileName) ) {
  677. RtlFreeUnicodeString(&UnicodeOldFileName);
  678. return FALSE;
  679. }
  680. }
  681. else {
  682. UnicodeNewFileName.Buffer = NULL;
  683. }
  684. ReturnValue =
  685. MoveFileWithProgressW( (LPCWSTR)UnicodeOldFileName.Buffer,
  686. (LPCWSTR)UnicodeNewFileName.Buffer,
  687. lpProgressRoutine,
  688. lpData,
  689. dwFlags
  690. );
  691. RtlFreeUnicodeString(&UnicodeOldFileName);
  692. RtlFreeUnicodeString(&UnicodeNewFileName);
  693. return ReturnValue;
  694. }
  695. typedef struct _HELPER_CONTEXT {
  696. DWORD dwFlags;
  697. LPPROGRESS_ROUTINE lpProgressRoutine;
  698. LPVOID lpData;
  699. } HELPER_CONTEXT, *PHELPER_CONTEXT;
  700. DWORD
  701. APIENTRY
  702. BasepMoveFileCopyProgress(
  703. LARGE_INTEGER TotalFileSize,
  704. LARGE_INTEGER TotalBytesTransferred,
  705. LARGE_INTEGER StreamSize,
  706. LARGE_INTEGER StreamBytesTransferred,
  707. DWORD dwStreamNumber,
  708. DWORD dwCallbackReason,
  709. HANDLE SourceFile,
  710. HANDLE DestinationFile,
  711. LPVOID lpData OPTIONAL
  712. )
  713. /*++
  714. Routine Description:
  715. Perform special actions when doing move-by-copy.
  716. Arguments:
  717. TotalFileSize - total number of bytes being transferred
  718. TotalBytesTransferred - current progress through the file
  719. StreamSize - total number of bytes being transferred in this stream
  720. StreamBytesTransferred - current progress through this stream
  721. dwStreamNumber - ordinal number of stream
  722. dwCallbackReason - CopyFile's reason for calling us
  723. SourceFile - source handle of transfer
  724. DestinationFile - destination handle of transfer
  725. lpData - pointer to HELPER_CONTEXT constructed by MoveFileWithProgressW.
  726. Return Value:
  727. PROGRESS_CONTINUE if no progress routine was specified, otherwise
  728. the return value from the progress routine specified to
  729. MoveFileWithProgress
  730. --*/
  731. {
  732. PHELPER_CONTEXT Context = (PHELPER_CONTEXT)lpData;
  733. //
  734. // If we are finished with a stream and the caller
  735. // specified WRITE_THROUGH then we make sure the file buffers
  736. // actually made it out to disk.
  737. //
  738. if ((Context->dwFlags & MOVEFILE_WRITE_THROUGH) != 0
  739. && dwCallbackReason == CALLBACK_CHUNK_FINISHED
  740. && StreamBytesTransferred.QuadPart == StreamSize.QuadPart ) {
  741. FlushFileBuffers(DestinationFile);
  742. }
  743. //
  744. // If a callback routine was specified, call through him
  745. //
  746. if (Context->lpProgressRoutine == NULL) {
  747. return PROGRESS_CONTINUE;
  748. }
  749. return (Context->lpProgressRoutine) (
  750. TotalFileSize,
  751. TotalBytesTransferred,
  752. StreamSize,
  753. StreamBytesTransferred,
  754. dwStreamNumber,
  755. dwCallbackReason,
  756. SourceFile,
  757. DestinationFile,
  758. Context->lpData );
  759. }
  760. NTSTATUS
  761. BasepNotifyTrackingService( PHANDLE SourceFile,
  762. POBJECT_ATTRIBUTES SourceFileObjAttributes,
  763. HANDLE DestFile,
  764. PUNICODE_STRING NewFileName
  765. )
  766. {
  767. NTSTATUS Status = STATUS_SUCCESS;
  768. FILE_BASIC_INFORMATION BasicInformation;
  769. IO_STATUS_BLOCK IoStatusBlock;
  770. ULONG FileAttributes;
  771. ULONG cchComputerName;
  772. WCHAR ComputerName[ MAX_COMPUTERNAME_LENGTH + 1 ];
  773. DWORD dwError;
  774. BYTE FTIBuffer[ sizeof(FILE_TRACKING_INFORMATION) + MAX_COMPUTERNAME_LENGTH + 1 ];
  775. PFILE_TRACKING_INFORMATION pfti = (PFILE_TRACKING_INFORMATION) &FTIBuffer[0];
  776. try
  777. {
  778. cchComputerName = MAX_COMPUTERNAME_LENGTH + 1;
  779. dwError = BasepGetComputerNameFromNtPath( NewFileName,
  780. DestFile,
  781. ComputerName,
  782. &cchComputerName );
  783. if (ERROR_SUCCESS != dwError) {
  784. pfti->ObjectInformationLength = 0;
  785. } else {
  786. CHAR ComputerNameOemBuffer[ MAX_PATH ];
  787. OEM_STRING ComputerNameOemString = { 0,
  788. sizeof(ComputerNameOemBuffer),
  789. ComputerNameOemBuffer };
  790. UNICODE_STRING ComputerNameUnicodeString;
  791. RtlInitUnicodeString( &ComputerNameUnicodeString,
  792. ComputerName );
  793. Status = RtlUnicodeStringToOemString( &ComputerNameOemString,
  794. &ComputerNameUnicodeString,
  795. FALSE ); // Don't allocate
  796. if( !NT_SUCCESS(Status) ) {
  797. leave;
  798. }
  799. memcpy( pfti->ObjectInformation,
  800. ComputerNameOemString.Buffer,
  801. ComputerNameOemString.Length );
  802. pfti->ObjectInformation[ ComputerNameOemString.Length ] = '\0';
  803. // Fill in the rest of the fti buffer, and set the file information
  804. pfti->ObjectInformationLength = ComputerNameOemString.Length + 1;
  805. }
  806. pfti->DestinationFile = DestFile;
  807. Status = NtSetInformationFile(
  808. *SourceFile,
  809. &IoStatusBlock,
  810. pfti,
  811. sizeof( FTIBuffer ),
  812. FileTrackingInformation );
  813. //
  814. // Check to see if tracking failed because
  815. // the source has a read-only attribute set.
  816. //
  817. if (Status != STATUS_ACCESS_DENIED) {
  818. leave;
  819. }
  820. //
  821. // reopen the source file and reset the read-only attribute
  822. // so that we'll be able to open for write access.
  823. //
  824. CloseHandle(*SourceFile);
  825. Status = NtOpenFile(
  826. SourceFile,
  827. SYNCHRONIZE | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
  828. SourceFileObjAttributes,
  829. &IoStatusBlock,
  830. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  831. FILE_SYNCHRONOUS_IO_NONALERT
  832. );
  833. if (!NT_SUCCESS(Status)) {
  834. *SourceFile = INVALID_HANDLE_VALUE;
  835. leave;
  836. }
  837. Status = NtQueryInformationFile(
  838. *SourceFile,
  839. &IoStatusBlock,
  840. &BasicInformation,
  841. sizeof(BasicInformation),
  842. FileBasicInformation );
  843. if (!NT_SUCCESS(Status)) {
  844. leave;
  845. }
  846. //
  847. // Reset the r/o bit and write the attributes back.
  848. //
  849. FileAttributes = BasicInformation.FileAttributes;
  850. RtlZeroMemory(&BasicInformation, sizeof(BasicInformation));
  851. BasicInformation.FileAttributes = FileAttributes & ~FILE_ATTRIBUTE_READONLY;
  852. Status = NtSetInformationFile(
  853. *SourceFile,
  854. &IoStatusBlock,
  855. &BasicInformation,
  856. sizeof(BasicInformation),
  857. FileBasicInformation);
  858. if (!NT_SUCCESS(Status)) {
  859. //
  860. // If this fails, we can't track the file.
  861. //
  862. leave;
  863. }
  864. //
  865. // Now that the r/o bit is reset, reopen for write access and
  866. // retry the tracking notification.
  867. //
  868. else {
  869. HANDLE hSourceRw;
  870. Status = NtOpenFile(
  871. &hSourceRw,
  872. SYNCHRONIZE | GENERIC_WRITE,
  873. SourceFileObjAttributes,
  874. &IoStatusBlock,
  875. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  876. FILE_SYNCHRONOUS_IO_NONALERT
  877. );
  878. if (NT_SUCCESS(Status)) {
  879. NtClose(*SourceFile);
  880. *SourceFile = hSourceRw;
  881. //
  882. // Send the source machine a tracking notification.
  883. //
  884. Status = NtSetInformationFile( *SourceFile,
  885. &IoStatusBlock,
  886. pfti,
  887. sizeof( FTIBuffer ),
  888. FileTrackingInformation );
  889. }
  890. }
  891. if (!NT_SUCCESS(Status)) {
  892. //
  893. // Try to put back the r/o bit -- don't assign Status here
  894. // because we want to fail. If we crash here, we may leave
  895. // the r/o attribute clear when it should be set, but there's
  896. // not much we can do about it without a transaction.
  897. //
  898. BasicInformation.FileAttributes |= FILE_ATTRIBUTE_READONLY;
  899. NtSetInformationFile(
  900. *SourceFile,
  901. &IoStatusBlock,
  902. &BasicInformation,
  903. sizeof(BasicInformation),
  904. FileBasicInformation);
  905. }
  906. }
  907. finally
  908. {
  909. }
  910. return( Status );
  911. }
  912. BOOL
  913. APIENTRY
  914. MoveFileW(
  915. LPCWSTR lpExistingFileName,
  916. LPCWSTR lpNewFileName
  917. )
  918. {
  919. return MoveFileWithProgressW( lpExistingFileName,
  920. lpNewFileName,
  921. (LPPROGRESS_ROUTINE)NULL,
  922. NULL,
  923. MOVEFILE_COPY_ALLOWED );
  924. }
  925. BOOL
  926. APIENTRY
  927. MoveFileExW(
  928. LPCWSTR lpExistingFileName,
  929. LPCWSTR lpNewFileName,
  930. DWORD dwFlags
  931. )
  932. {
  933. return MoveFileWithProgressW( lpExistingFileName,
  934. lpNewFileName,
  935. (LPPROGRESS_ROUTINE)NULL,
  936. NULL,
  937. dwFlags );
  938. }
  939. BOOL
  940. APIENTRY
  941. MoveFileWithProgressW(
  942. LPCWSTR lpExistingFileName,
  943. LPCWSTR lpNewFileName,
  944. LPPROGRESS_ROUTINE lpProgressRoutine OPTIONAL,
  945. LPVOID lpData OPTIONAL,
  946. DWORD dwFlags
  947. )
  948. /*++
  949. Routine Description:
  950. An existing file can be renamed using MoveFileWithProgressW.
  951. Arguments:
  952. lpExistingFileName - Supplies the name of an existing file that is to be
  953. renamed.
  954. lpNewFileName - Supplies the new name for the existing file. The new
  955. name must reside in the same file system/drive as the existing
  956. file and must not already exist.
  957. lpProgressRoutine - Supplies a callback routine that is notified.
  958. lpData - Supplies context data passed to the progress routine.
  959. dwFlags - Supplies optional flag bits to control the behavior of the
  960. rename. The following bits are currently defined:
  961. MOVEFILE_REPLACE_EXISTING - if the new file name exists, replace
  962. it by renaming the old file name on top of the new file name.
  963. MOVEFILE_COPY_ALLOWED - if the new file name is on a different
  964. volume than the old file name, and causes the rename operation
  965. to fail, then setting this flag allows the MoveFileEx API
  966. call to simulate the rename with a call to CopyFile followed
  967. by a call to DeleteFile to the delete the old file if the
  968. CopyFile was successful.
  969. MOVEFILE_DELAY_UNTIL_REBOOT - dont actually do the rename now, but
  970. instead queue the rename so that it will happen the next time
  971. the system boots. If this flag is set, then the lpNewFileName
  972. parameter may be NULL, in which case a delay DeleteFile of
  973. the old file name will occur the next time the system is
  974. booted.
  975. The delay rename/delete operations occur immediately after
  976. AUTOCHK is run, but prior to creating any paging files, so
  977. it can be used to delete paging files from previous boots
  978. before they are reused.
  979. MOVEFILE_WRITE_THROUGH - perform the rename operation in such a
  980. way that the file has actually been moved on the disk before
  981. the API returns to the caller. Note that this flag causes a
  982. flush at the end of a copy operation (if one were allowed and
  983. necessary), and has no effect if the rename operation is
  984. delayed until the next reboot.
  985. MOVEFILE_CREATE_HARDLINK - create a hard link from the new file name to
  986. the existing file name. May not be specified with
  987. MOVEFILE_DELAY_UNTIL_REBOOT
  988. MOVEFILE_FAIL_IF_NOT_TRACKABLE - fail the move request if the file cannot
  989. be tracked.
  990. Return Value:
  991. TRUE - The operation was successful.
  992. FALSE/NULL - The operation failed. Extended error status is available
  993. using GetLastError.
  994. --*/
  995. {
  996. NTSTATUS Status;
  997. BOOLEAN ReplaceIfExists;
  998. OBJECT_ATTRIBUTES Obja;
  999. HANDLE Handle = INVALID_HANDLE_VALUE;
  1000. UNICODE_STRING OldFileName;
  1001. UNICODE_STRING NewFileName;
  1002. IO_STATUS_BLOCK IoStatusBlock;
  1003. PFILE_RENAME_INFORMATION NewName;
  1004. FILE_ATTRIBUTE_TAG_INFORMATION FileTagInformation;
  1005. BOOLEAN TranslationStatus;
  1006. ULONG OpenFlags;
  1007. BOOLEAN b = FALSE;
  1008. HELPER_CONTEXT Context;
  1009. NewFileName.Buffer = NULL;
  1010. OldFileName.Buffer = NULL;
  1011. try {
  1012. //
  1013. // if the target is a device, do not allow the rename !
  1014. //
  1015. if ( lpNewFileName ) {
  1016. if ( RtlIsDosDeviceName_U((PWSTR)lpNewFileName) ) {
  1017. BaseSetLastNTError( STATUS_OBJECT_NAME_COLLISION );
  1018. leave;
  1019. }
  1020. }
  1021. ReplaceIfExists = (dwFlags & MOVEFILE_REPLACE_EXISTING) != 0;
  1022. TranslationStatus = RtlDosPathNameToNtPathName_U(
  1023. lpExistingFileName,
  1024. &OldFileName,
  1025. NULL,
  1026. NULL
  1027. );
  1028. if ( !TranslationStatus ) {
  1029. BaseSetLastNTError( STATUS_OBJECT_PATH_NOT_FOUND );
  1030. leave;
  1031. }
  1032. //
  1033. // Cannot perform delayed-move-by-creating-hardlink
  1034. //
  1035. if ((dwFlags & MOVEFILE_DELAY_UNTIL_REBOOT) != 0 &&
  1036. (dwFlags & MOVEFILE_CREATE_HARDLINK) != 0) {
  1037. BaseSetLastNTError( STATUS_INVALID_PARAMETER );
  1038. leave;
  1039. }
  1040. //
  1041. // Get a handle to the source of the move. We do this even for
  1042. // the delayed move in order to validate that we have delete
  1043. // access to the file.
  1044. //
  1045. InitializeObjectAttributes(
  1046. &Obja,
  1047. &OldFileName,
  1048. OBJ_CASE_INSENSITIVE,
  1049. NULL,
  1050. NULL
  1051. );
  1052. //
  1053. // Establish whether we are renaming a symbolic link or not by:
  1054. // (1) obtaining a handle to the local entity, and
  1055. // (2) finding whether a symbolic link was found.
  1056. //
  1057. // Open the file for delete access inhibiting the reparse
  1058. // point behavior.
  1059. //
  1060. OpenFlags = FILE_SYNCHRONOUS_IO_NONALERT |
  1061. FILE_OPEN_FOR_BACKUP_INTENT |
  1062. ((dwFlags & MOVEFILE_WRITE_THROUGH) ? FILE_WRITE_THROUGH : 0);
  1063. Status = NtOpenFile( &Handle,
  1064. FILE_READ_ATTRIBUTES | DELETE | SYNCHRONIZE,
  1065. &Obja,
  1066. &IoStatusBlock,
  1067. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  1068. FILE_OPEN_REPARSE_POINT | OpenFlags
  1069. );
  1070. if (!NT_SUCCESS( Status )) {
  1071. //
  1072. // The Open may fail for a number of reasons. If we're
  1073. // delaying the operation until reboot, it doesn't matter
  1074. // if we get a sharing violation or a non-existent file
  1075. // or a non-existent path.
  1076. //
  1077. if (((dwFlags & MOVEFILE_DELAY_UNTIL_REBOOT) != 0)
  1078. && (Status == STATUS_SHARING_VIOLATION
  1079. || Status == STATUS_OBJECT_NAME_NOT_FOUND
  1080. || Status == STATUS_OBJECT_PATH_NOT_FOUND)) {
  1081. Handle = INVALID_HANDLE_VALUE;
  1082. } else {
  1083. //
  1084. // Back level file systems may not support reparse points and thus not
  1085. // support symbolic links.
  1086. //
  1087. // We infer this is the case when the Status is STATUS_INVALID_PARAMETER.
  1088. //
  1089. if ( Status == STATUS_INVALID_PARAMETER ) {
  1090. //
  1091. // Retry the open without reparse behaviour. This should be compatible
  1092. // with older file systems.
  1093. //
  1094. Status = NtOpenFile(
  1095. &Handle,
  1096. DELETE | SYNCHRONIZE,
  1097. &Obja,
  1098. &IoStatusBlock,
  1099. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1100. OpenFlags
  1101. );
  1102. }
  1103. if ( !NT_SUCCESS( Status ) ) {
  1104. BaseSetLastNTError( Status );
  1105. leave;
  1106. }
  1107. }
  1108. } else {
  1109. //
  1110. // The open succeeded. If we do not find a symbolic link or a mount point,
  1111. // re-open without inhibiting the reparse behavior.
  1112. //
  1113. Status = NtQueryInformationFile(
  1114. Handle,
  1115. &IoStatusBlock,
  1116. (PVOID) &FileTagInformation,
  1117. sizeof(FileTagInformation),
  1118. FileAttributeTagInformation
  1119. );
  1120. if ( !NT_SUCCESS( Status ) ) {
  1121. //
  1122. // Not all File Systems implement all information classes.
  1123. // The value STATUS_INVALID_PARAMETER is returned when a non-supported
  1124. // information class is requested to a back-level File System. As all the
  1125. // parameters to NtQueryInformationFile are correct, we can infer that
  1126. // we found a back-level system.
  1127. //
  1128. // If FileAttributeTagInformation is not implemented, we assume that
  1129. // the file at hand is not a reparse point.
  1130. //
  1131. if ( (Status != STATUS_NOT_IMPLEMENTED) &&
  1132. (Status != STATUS_INVALID_PARAMETER) ) {
  1133. BaseSetLastNTError( Status );
  1134. leave;
  1135. }
  1136. }
  1137. if ( NT_SUCCESS(Status) &&
  1138. (FileTagInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
  1139. FileTagInformation.ReparseTag != IO_REPARSE_TAG_MOUNT_POINT ) {
  1140. //
  1141. // Open without inhibiting the reparse behavior and not needing to
  1142. // read the attributes.
  1143. //
  1144. NtClose( Handle );
  1145. Handle = INVALID_HANDLE_VALUE;
  1146. Status = NtOpenFile(
  1147. &Handle,
  1148. DELETE | SYNCHRONIZE,
  1149. &Obja,
  1150. &IoStatusBlock,
  1151. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1152. OpenFlags
  1153. );
  1154. if ( !NT_SUCCESS( Status ) ) {
  1155. BaseSetLastNTError( Status );
  1156. leave;
  1157. }
  1158. }
  1159. }
  1160. if (!(dwFlags & MOVEFILE_DELAY_UNTIL_REBOOT) ||
  1161. (lpNewFileName != NULL)) {
  1162. TranslationStatus = RtlDosPathNameToNtPathName_U(
  1163. lpNewFileName,
  1164. &NewFileName,
  1165. NULL,
  1166. NULL
  1167. );
  1168. if ( !TranslationStatus ) {
  1169. BaseSetLastNTError( STATUS_OBJECT_PATH_NOT_FOUND );
  1170. leave;
  1171. }
  1172. } else {
  1173. RtlInitUnicodeString( &NewFileName, NULL );
  1174. }
  1175. if (dwFlags & MOVEFILE_DELAY_UNTIL_REBOOT) {
  1176. //
  1177. // (typical stevewo hack, preserved for sentimental value)
  1178. //
  1179. // If ReplaceIfExists is TRUE, prepend an exclamation point
  1180. // to the new filename in order to pass this bit of data
  1181. // along to the session manager.
  1182. //
  1183. if (ReplaceIfExists && NewFileName.Length != 0) {
  1184. PWSTR NewBuffer;
  1185. NewBuffer = RtlAllocateHeap( RtlProcessHeap(),
  1186. MAKE_TAG( TMP_TAG ),
  1187. NewFileName.Length + sizeof(WCHAR) );
  1188. if (NewBuffer == NULL) {
  1189. BaseSetLastNTError( STATUS_NO_MEMORY );
  1190. leave;
  1191. }
  1192. NewBuffer[0] = L'!';
  1193. CopyMemory(&NewBuffer[1], NewFileName.Buffer, NewFileName.Length);
  1194. NewFileName.Length += sizeof(WCHAR);
  1195. NewFileName.MaximumLength += sizeof(WCHAR);
  1196. RtlFreeHeap(RtlProcessHeap(), 0, NewFileName.Buffer);
  1197. NewFileName.Buffer = NewBuffer;
  1198. }
  1199. //
  1200. // Check to see if the existing file is on a remote share. If it
  1201. // is, flag the error rather than let the operation silently fail
  1202. // because the delayed operations are done before the net is
  1203. // available. Rather than open the file and do a hard core file type,
  1204. // we just check for UNC in the file name. This isn't perfect, but it is
  1205. // pretty good. Chances are we can not open and manipulate the file. That is
  1206. // why the caller is using the delay until reboot option !
  1207. //
  1208. if ( RtlDetermineDosPathNameType_U(lpExistingFileName) == RtlPathTypeUncAbsolute ) {
  1209. Status = STATUS_INVALID_PARAMETER;
  1210. }
  1211. //
  1212. // copy allowed is not permitted on delayed renames
  1213. //
  1214. else if ( dwFlags & MOVEFILE_COPY_ALLOWED ) {
  1215. Status = STATUS_INVALID_PARAMETER;
  1216. } else {
  1217. Status = BasepMoveFileDelayed( &OldFileName,
  1218. &NewFileName,
  1219. 2,
  1220. FALSE );
  1221. if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
  1222. Status = BasepMoveFileDelayed( &OldFileName,
  1223. &NewFileName,
  1224. 1,
  1225. TRUE );
  1226. if (Status == STATUS_INSUFFICIENT_RESOURCES) {
  1227. Status = BasepMoveFileDelayed( &OldFileName,
  1228. &NewFileName,
  1229. 2,
  1230. TRUE );
  1231. }
  1232. }
  1233. }
  1234. if (!NT_SUCCESS( Status )) {
  1235. BaseSetLastNTError( Status );
  1236. leave;
  1237. }
  1238. b = TRUE;
  1239. leave;
  1240. }
  1241. //
  1242. // We must to the real move now.
  1243. //
  1244. NewName = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), NewFileName.Length+sizeof(*NewName));
  1245. if (NewName == NULL) {
  1246. BaseSetLastNTError( STATUS_NO_MEMORY );
  1247. leave;
  1248. }
  1249. RtlCopyMemory( NewName->FileName, NewFileName.Buffer, NewFileName.Length );
  1250. NewName->ReplaceIfExists = ReplaceIfExists;
  1251. NewName->RootDirectory = NULL;
  1252. NewName->FileNameLength = NewFileName.Length;
  1253. Status = NtSetInformationFile(
  1254. Handle,
  1255. &IoStatusBlock,
  1256. NewName,
  1257. NewFileName.Length+sizeof(*NewName),
  1258. (dwFlags & MOVEFILE_CREATE_HARDLINK) ?
  1259. FileLinkInformation :
  1260. FileRenameInformation
  1261. );
  1262. RtlFreeHeap(RtlProcessHeap(), 0, NewName);
  1263. if (NT_SUCCESS( Status )) {
  1264. b = TRUE;
  1265. leave;
  1266. }
  1267. if (Status != STATUS_NOT_SAME_DEVICE || (dwFlags & MOVEFILE_COPY_ALLOWED) == 0) {
  1268. BaseSetLastNTError( Status );
  1269. leave;
  1270. }
  1271. NtClose( Handle );
  1272. Handle = INVALID_HANDLE_VALUE;
  1273. //
  1274. // Perform a copy/delete. Handle link tracking.
  1275. //
  1276. {
  1277. HANDLE hSource = INVALID_HANDLE_VALUE;
  1278. HANDLE hDest = INVALID_HANDLE_VALUE;
  1279. Context.dwFlags = dwFlags;
  1280. Context.lpProgressRoutine = lpProgressRoutine;
  1281. Context.lpData = lpData;
  1282. b = (BOOLEAN)BasepCopyFileExW(
  1283. lpExistingFileName,
  1284. lpNewFileName,
  1285. BasepMoveFileCopyProgress,
  1286. &Context,
  1287. NULL,
  1288. (ReplaceIfExists ? 0 : COPY_FILE_FAIL_IF_EXISTS) | COPY_FILE_OPEN_SOURCE_FOR_WRITE,
  1289. 0, // PrivCopyFile flags
  1290. &hSource,
  1291. &hDest
  1292. );
  1293. if ( b && hSource != INVALID_HANDLE_VALUE && hDest != INVALID_HANDLE_VALUE) {
  1294. //
  1295. // attempt to do tracking
  1296. //
  1297. Status = BasepNotifyTrackingService( &hSource,
  1298. &Obja,
  1299. hDest,
  1300. &NewFileName );
  1301. if ( !NT_SUCCESS(Status) &&
  1302. (dwFlags & MOVEFILE_FAIL_IF_NOT_TRACKABLE)) {
  1303. if (hDest != INVALID_HANDLE_VALUE)
  1304. CloseHandle( hDest );
  1305. hDest = INVALID_HANDLE_VALUE;
  1306. DeleteFileW( lpNewFileName );
  1307. b = FALSE;
  1308. BaseSetLastNTError( Status );
  1309. }
  1310. }
  1311. if (hSource != INVALID_HANDLE_VALUE) {
  1312. CloseHandle(hSource);
  1313. hSource = INVALID_HANDLE_VALUE;
  1314. }
  1315. if (hDest != INVALID_HANDLE_VALUE) {
  1316. CloseHandle(hDest);
  1317. hDest = INVALID_HANDLE_VALUE;
  1318. }
  1319. //
  1320. // the copy worked... Delete the source of the rename
  1321. // if it fails, try a set attributes and then a delete
  1322. //
  1323. if (b && !DeleteFileW( lpExistingFileName ) ) {
  1324. //
  1325. // If the delete fails, we will return true, but possibly
  1326. // leave the source dangling
  1327. //
  1328. SetFileAttributesW(lpExistingFileName,FILE_ATTRIBUTE_NORMAL);
  1329. DeleteFileW( lpExistingFileName );
  1330. }
  1331. }
  1332. } finally {
  1333. if (Handle != INVALID_HANDLE_VALUE) {
  1334. NtClose( Handle );
  1335. }
  1336. RtlFreeHeap( RtlProcessHeap(), 0, OldFileName.Buffer );
  1337. RtlFreeHeap( RtlProcessHeap(), 0, NewFileName.Buffer );
  1338. }
  1339. return b;
  1340. }
  1341. NTSTATUS
  1342. BasepMoveFileDelayed(
  1343. IN PUNICODE_STRING OldFileName,
  1344. IN PUNICODE_STRING NewFileName,
  1345. IN ULONG Index,
  1346. IN BOOL OkayToCreateNewValue
  1347. )
  1348. /*++
  1349. Routine Description:
  1350. Appends the given delayed move file operation to the registry
  1351. value that contains the list of move file operations to be
  1352. performed on the next boot.
  1353. Arguments:
  1354. OldFileName - Supplies the old file name
  1355. NewFileName - Supplies the new file name
  1356. Return Value:
  1357. NTSTATUS
  1358. --*/
  1359. {
  1360. OBJECT_ATTRIBUTES Obja;
  1361. UNICODE_STRING KeyName;
  1362. UNICODE_STRING ValueName;
  1363. HANDLE KeyHandle;
  1364. PWSTR ValueData, s;
  1365. PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
  1366. ULONG ValueLength = 1024;
  1367. ULONG ReturnedLength;
  1368. WCHAR ValueNameBuf[64];
  1369. NTSTATUS Status;
  1370. RtlInitUnicodeString( &KeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager" );
  1371. if (Index == 1) {
  1372. RtlInitUnicodeString( &ValueName, L"PendingFileRenameOperations" );
  1373. } else {
  1374. swprintf(ValueNameBuf,L"PendingFileRenameOperations%d",Index);
  1375. RtlInitUnicodeString( &ValueName, ValueNameBuf );
  1376. }
  1377. InitializeObjectAttributes(
  1378. &Obja,
  1379. &KeyName,
  1380. OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
  1381. NULL,
  1382. NULL
  1383. );
  1384. Status = NtCreateKey( &KeyHandle,
  1385. GENERIC_READ | GENERIC_WRITE,
  1386. &Obja,
  1387. 0,
  1388. NULL,
  1389. 0,
  1390. NULL
  1391. );
  1392. if ( Status == STATUS_ACCESS_DENIED ) {
  1393. Status = NtCreateKey( &KeyHandle,
  1394. GENERIC_READ | GENERIC_WRITE,
  1395. &Obja,
  1396. 0,
  1397. NULL,
  1398. REG_OPTION_BACKUP_RESTORE,
  1399. NULL
  1400. );
  1401. }
  1402. if (!NT_SUCCESS( Status )) {
  1403. return Status;
  1404. }
  1405. while (TRUE) {
  1406. ValueInfo = RtlAllocateHeap(RtlProcessHeap(),
  1407. MAKE_TAG(TMP_TAG),
  1408. ValueLength + OldFileName->Length + sizeof(WCHAR) +
  1409. NewFileName->Length + 2*sizeof(WCHAR));
  1410. if (ValueInfo == NULL) {
  1411. NtClose(KeyHandle);
  1412. return(STATUS_NO_MEMORY);
  1413. }
  1414. //
  1415. // File rename operations are stored in the registry in a
  1416. // single MULTI_SZ value. This allows the renames to be
  1417. // performed in the same order that they were originally
  1418. // requested. Each rename operation consists of a pair of
  1419. // NULL-terminated strings.
  1420. //
  1421. Status = NtQueryValueKey(KeyHandle,
  1422. &ValueName,
  1423. KeyValuePartialInformation,
  1424. ValueInfo,
  1425. ValueLength,
  1426. &ReturnedLength);
  1427. if (Status != STATUS_BUFFER_OVERFLOW) {
  1428. break;
  1429. }
  1430. //
  1431. // The existing value is too large for our buffer.
  1432. // Retry with a larger buffer.
  1433. //
  1434. ValueLength = ReturnedLength;
  1435. RtlFreeHeap(RtlProcessHeap(), 0, ValueInfo);
  1436. }
  1437. if ((Status == STATUS_OBJECT_NAME_NOT_FOUND)
  1438. && OkayToCreateNewValue) {
  1439. //
  1440. // The value does not currently exist. Create the
  1441. // value with our data.
  1442. //
  1443. s = ValueData = (PWSTR)ValueInfo;
  1444. } else if (NT_SUCCESS(Status)) {
  1445. //
  1446. // A value already exists, append our two strings to the
  1447. // MULTI_SZ.
  1448. //
  1449. ValueData = (PWSTR)(&ValueInfo->Data);
  1450. s = (PWSTR)((PCHAR)ValueData + ValueInfo->DataLength) - 1;
  1451. } else {
  1452. NtClose(KeyHandle);
  1453. RtlFreeHeap(RtlProcessHeap(), 0, ValueInfo);
  1454. return(Status);
  1455. }
  1456. CopyMemory(s, OldFileName->Buffer, OldFileName->Length);
  1457. s += (OldFileName->Length/sizeof(WCHAR));
  1458. *s++ = L'\0';
  1459. CopyMemory(s, NewFileName->Buffer, NewFileName->Length);
  1460. s += (NewFileName->Length/sizeof(WCHAR));
  1461. *s++ = L'\0';
  1462. *s++ = L'\0';
  1463. Status = NtSetValueKey(KeyHandle,
  1464. &ValueName,
  1465. 0,
  1466. REG_MULTI_SZ,
  1467. ValueData,
  1468. (ULONG)((s-ValueData)*sizeof(WCHAR)));
  1469. NtClose(KeyHandle);
  1470. RtlFreeHeap(RtlProcessHeap(), 0, ValueInfo);
  1471. return(Status);
  1472. }
  1473. NTSTATUS
  1474. BasepOpenFileForMove( IN LPCWSTR lpFileName,
  1475. OUT PUNICODE_STRING FileName,
  1476. OUT PVOID *FileNameFreeBuffer,
  1477. OUT PHANDLE Handle,
  1478. OUT POBJECT_ATTRIBUTES Obja,
  1479. IN ULONG DesiredAccess,
  1480. IN ULONG ShareAccess,
  1481. IN ULONG OpenOptions )
  1482. /*++
  1483. Routine Description:
  1484. Opens a file such that it may be used in MoveFile or MoveFileIdentity.
  1485. Arguments:
  1486. lpFileName - the file to open
  1487. FileName - lpFileName translated to an NT path
  1488. FileNameFreeBuffer - a buffer which needs to be freed when FileName
  1489. is no longer in use
  1490. Handle - Location in which to put the handle for the opened file.
  1491. Obja - Object attributes used to open the file
  1492. DesiredAccess - Access flags which must be set, in addition to
  1493. FILE_READ_ATTRIBUTES and SYNCHRONIZE which may also be set.
  1494. ShareAccess - Sharing flags which must be set, though additional
  1495. flags may also be set.
  1496. OpenOptions - FILE_OPEN_ flags which must be set, though
  1497. FILE_OPEN_REPARSE_POINT, FILE_SYNCHRONOUS_IO_NONALERT, and
  1498. FILE_OPEN_FOR_BACKUP_INTENT may also be set.
  1499. Return Value:
  1500. NTSTATUS
  1501. --*/
  1502. {
  1503. NTSTATUS Status = STATUS_SUCCESS;
  1504. BOOL TranslationStatus;
  1505. RTL_RELATIVE_NAME_U RelativeName;
  1506. IO_STATUS_BLOCK IoStatusBlock;
  1507. BOOL ReleaseRelativeName = FALSE;
  1508. try
  1509. {
  1510. FileName->Length = FileName->MaximumLength = 0;
  1511. FileName->Buffer = NULL;
  1512. *FileNameFreeBuffer = NULL;
  1513. //
  1514. // Initialize the object attributes
  1515. //
  1516. TranslationStatus = RtlDosPathNameToRelativeNtPathName_U(
  1517. lpFileName,
  1518. FileName,
  1519. NULL,
  1520. &RelativeName
  1521. );
  1522. if ( !TranslationStatus ) {
  1523. Status = STATUS_OBJECT_PATH_NOT_FOUND;
  1524. leave;
  1525. }
  1526. ReleaseRelativeName = TRUE;
  1527. *FileNameFreeBuffer = FileName->Buffer;
  1528. if ( RelativeName.RelativeName.Length ) {
  1529. *FileName = RelativeName.RelativeName;
  1530. } else {
  1531. RelativeName.ContainingDirectory = NULL;
  1532. }
  1533. InitializeObjectAttributes(
  1534. Obja,
  1535. FileName,
  1536. OBJ_CASE_INSENSITIVE,
  1537. RelativeName.ContainingDirectory,
  1538. NULL
  1539. );
  1540. //
  1541. // Establish whether we are handling a symbolic link or not by:
  1542. // (1) obtaining a handle to the local entity, and
  1543. // (2) finding whether a symbolic link was found.
  1544. //
  1545. // Open the file for delete access inhibiting the reparse
  1546. // point behavior.
  1547. //
  1548. OpenOptions |= (FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT);
  1549. Status = NtOpenFile( Handle,
  1550. FILE_READ_ATTRIBUTES | SYNCHRONIZE | DesiredAccess,
  1551. Obja,
  1552. &IoStatusBlock,
  1553. FILE_SHARE_READ | FILE_SHARE_WRITE | ShareAccess,
  1554. FILE_OPEN_REPARSE_POINT | OpenOptions
  1555. );
  1556. if (!NT_SUCCESS( Status )) {
  1557. //
  1558. // Back level file systems may not support reparse points and thus not
  1559. // support symbolic links.
  1560. //
  1561. // We infer this is the case when the Status is STATUS_INVALID_PARAMETER.
  1562. //
  1563. if ( Status == STATUS_INVALID_PARAMETER ) {
  1564. //
  1565. // Retry the open without reparse behaviour. This should be compatible
  1566. // with older file systems.
  1567. //
  1568. Status = NtOpenFile(
  1569. Handle,
  1570. SYNCHRONIZE | DesiredAccess,
  1571. Obja,
  1572. &IoStatusBlock,
  1573. FILE_SHARE_READ | FILE_SHARE_WRITE | ShareAccess,
  1574. OpenOptions
  1575. );
  1576. }
  1577. if ( !NT_SUCCESS( Status ) ) {
  1578. leave;
  1579. }
  1580. } else {
  1581. FILE_ATTRIBUTE_TAG_INFORMATION FileTagInformation;
  1582. //
  1583. // The open succeeded. If we do not find a symbolic link or a mount point,
  1584. // re-open without inhibiting the reparse behavior.
  1585. //
  1586. Status = NtQueryInformationFile(
  1587. *Handle,
  1588. &IoStatusBlock,
  1589. (PVOID) &FileTagInformation,
  1590. sizeof(FileTagInformation),
  1591. FileAttributeTagInformation
  1592. );
  1593. if ( !NT_SUCCESS( Status ) ) {
  1594. //
  1595. // Not all File Systems implement all information classes.
  1596. // The value STATUS_INVALID_PARAMETER is returned when a non-supported
  1597. // information class is requested to a back-level File System. As all the
  1598. // parameters to NtQueryInformationFile are correct, we can infer that
  1599. // we found a back-level system.
  1600. //
  1601. // If FileAttributeTagInformation is not implemented, we assume that
  1602. // the file at hand is not a reparse point.
  1603. //
  1604. if ( (Status != STATUS_NOT_IMPLEMENTED) &&
  1605. (Status != STATUS_INVALID_PARAMETER) ) {
  1606. leave;
  1607. }
  1608. }
  1609. if ( NT_SUCCESS(Status) &&
  1610. (FileTagInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
  1611. FileTagInformation.ReparseTag != IO_REPARSE_TAG_MOUNT_POINT ) {
  1612. //
  1613. // Open without inhibiting the reparse behavior and not needing to
  1614. // read the attributes.
  1615. //
  1616. NtClose( *Handle );
  1617. *Handle = INVALID_HANDLE_VALUE;
  1618. Status = NtOpenFile(
  1619. Handle,
  1620. SYNCHRONIZE | DesiredAccess,
  1621. Obja,
  1622. &IoStatusBlock,
  1623. FILE_SHARE_DELETE | FILE_SHARE_READ | ShareAccess,
  1624. OpenOptions
  1625. );
  1626. if ( !NT_SUCCESS( Status ) ) {
  1627. leave;
  1628. }
  1629. }
  1630. }
  1631. }
  1632. finally
  1633. {
  1634. if (ReleaseRelativeName) {
  1635. RtlReleaseRelativeName(&RelativeName);
  1636. }
  1637. }
  1638. return( Status );
  1639. }
  1640. BOOL
  1641. APIENTRY
  1642. PrivMoveFileIdentityW(
  1643. LPCWSTR lpOldFileName,
  1644. LPCWSTR lpNewFileName,
  1645. DWORD dwFlags
  1646. )
  1647. /*++
  1648. Routine Description:
  1649. Moves an identity from one file to another. The identity is composed
  1650. of the file's create date, and its object ID. The Object ID isn't
  1651. necessarily copied straight across; it's handled as if the actual
  1652. file were being moved by MoveFileWithProgressW.
  1653. Arguments:
  1654. lpOldFileName - Supplies the old file name
  1655. lpNewFileName - Supplies the new file name
  1656. Return Value:
  1657. TRUE if successful. Otherwise the error can be found by calling GetLastError().
  1658. --*/
  1659. { // MOVE_FILEIDentityW
  1660. NTSTATUS Status = STATUS_SUCCESS;
  1661. NTSTATUS StatusIgnored = STATUS_SUCCESS;
  1662. HANDLE SourceFile = INVALID_HANDLE_VALUE;
  1663. HANDLE DestFile = INVALID_HANDLE_VALUE;
  1664. UNICODE_STRING SourceFileName = { 0, 0, NULL };
  1665. PVOID SourceFileNameFreeBuffer = NULL;
  1666. UNICODE_STRING DestFileName = { 0, 0, NULL };
  1667. PVOID DestFileNameFreeBuffer = NULL;
  1668. BOOL TranslationStatus;
  1669. OBJECT_ATTRIBUTES SourceObja;
  1670. OBJECT_ATTRIBUTES DestObja;
  1671. ULONG OpenFlags;
  1672. FILE_DISPOSITION_INFORMATION DispositionInformation = { TRUE };
  1673. IO_STATUS_BLOCK IoStatus;
  1674. FILE_BASIC_INFORMATION SourceBasicInfo;
  1675. FILE_BASIC_INFORMATION DestBasicInfo;
  1676. DWORD SourceFileAccess;
  1677. DWORD DestFileAccess;
  1678. try {
  1679. // Open the source file. It must be opened for write or the
  1680. // FileTrackingInformation call will fail.
  1681. SourceFileAccess = FILE_WRITE_DATA | FILE_READ_ATTRIBUTES;
  1682. if( dwFlags & PRIVMOVE_FILEID_DELETE_OLD_FILE ) {
  1683. SourceFileAccess |= DELETE;
  1684. }
  1685. while( TRUE ) {
  1686. Status = BasepOpenFileForMove( lpOldFileName,
  1687. &SourceFileName,
  1688. &SourceFileNameFreeBuffer,
  1689. &SourceFile,
  1690. &SourceObja,
  1691. SourceFileAccess,
  1692. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
  1693. FILE_OPEN_NO_RECALL );
  1694. if( NT_SUCCESS(Status) ) {
  1695. break;
  1696. } else {
  1697. // We might be able to try again without requesting write access
  1698. if( (SourceFileAccess & FILE_WRITE_DATA) &&
  1699. (dwFlags & PRIVMOVE_FILEID_IGNORE_ID_ERRORS) ) {
  1700. //
  1701. // BasepOpenFileForMove may return a buffer or handle even
  1702. // in a failure case
  1703. //
  1704. if( SourceFileNameFreeBuffer != NULL ) {
  1705. RtlFreeHeap( RtlProcessHeap(), 0, SourceFileNameFreeBuffer );
  1706. SourceFileNameFreeBuffer = NULL;
  1707. }
  1708. if( SourceFile != INVALID_HANDLE_VALUE ) {
  1709. NtClose( SourceFile );
  1710. SourceFile = INVALID_HANDLE_VALUE;
  1711. }
  1712. // Try again without write access
  1713. SourceFileAccess &= ~FILE_WRITE_DATA;
  1714. if( NT_SUCCESS(StatusIgnored) ) {
  1715. StatusIgnored = Status;
  1716. }
  1717. Status = STATUS_SUCCESS;
  1718. } else {
  1719. // Nothing we can do.
  1720. break;
  1721. }
  1722. }
  1723. }
  1724. if( !NT_SUCCESS(Status) ) {
  1725. leave;
  1726. }
  1727. // Open the destination file
  1728. DestFileAccess = FILE_WRITE_ATTRIBUTES;
  1729. if( SourceFileAccess & FILE_WRITE_DATA )
  1730. DestFileAccess |= FILE_WRITE_DATA;
  1731. while( TRUE ) {
  1732. Status = BasepOpenFileForMove( lpNewFileName,
  1733. &DestFileName,
  1734. &DestFileNameFreeBuffer,
  1735. &DestFile,
  1736. &DestObja,
  1737. (SourceFileAccess & FILE_WRITE_DATA)
  1738. ? FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA
  1739. : FILE_WRITE_ATTRIBUTES,
  1740. FILE_SHARE_DELETE | FILE_SHARE_WRITE | FILE_SHARE_READ,
  1741. FILE_OPEN_NO_RECALL );
  1742. if( NT_SUCCESS(Status) ) {
  1743. break;
  1744. } else {
  1745. // We might be able to try again without requesting write access
  1746. if( (DestFileAccess & FILE_WRITE_DATA) &&
  1747. (dwFlags & PRIVMOVE_FILEID_IGNORE_ID_ERRORS) ) {
  1748. //
  1749. // BasepOpenFileForMove may return a buffer or handle even
  1750. // in a failure case
  1751. //
  1752. if( DestFileNameFreeBuffer != NULL ) {
  1753. RtlFreeHeap( RtlProcessHeap(), 0, DestFileNameFreeBuffer );
  1754. DestFileNameFreeBuffer = NULL;
  1755. }
  1756. if( DestFile != INVALID_HANDLE_VALUE ) {
  1757. NtClose( DestFile );
  1758. DestFile = INVALID_HANDLE_VALUE;
  1759. }
  1760. // Try again
  1761. DestFileAccess &= ~FILE_WRITE_DATA;
  1762. if( NT_SUCCESS(StatusIgnored) ) {
  1763. StatusIgnored = Status;
  1764. }
  1765. Status = STATUS_SUCCESS;
  1766. } else {
  1767. // Nothing we can do.
  1768. break;
  1769. }
  1770. }
  1771. }
  1772. if( !NT_SUCCESS(Status) ) {
  1773. leave;
  1774. }
  1775. // Copy the create date to the dest file
  1776. Status = NtQueryInformationFile( SourceFile,
  1777. &IoStatus,
  1778. &SourceBasicInfo,
  1779. sizeof(SourceBasicInfo),
  1780. FileBasicInformation );
  1781. if( NT_SUCCESS(Status) ) {
  1782. RtlZeroMemory( &DestBasicInfo, sizeof(DestBasicInfo) );
  1783. DestBasicInfo.CreationTime = SourceBasicInfo.CreationTime;
  1784. Status = NtSetInformationFile( DestFile,
  1785. &IoStatus,
  1786. &DestBasicInfo,
  1787. sizeof(DestBasicInfo),
  1788. FileBasicInformation );
  1789. }
  1790. // If we had an error and can't ignore it, abort.
  1791. if( !NT_SUCCESS(Status) ) {
  1792. if( dwFlags & PRIVMOVE_FILEID_IGNORE_ID_ERRORS ) {
  1793. if( NT_SUCCESS(StatusIgnored) ) {
  1794. StatusIgnored = Status;
  1795. }
  1796. Status = STATUS_SUCCESS;
  1797. }
  1798. else {
  1799. leave;
  1800. }
  1801. }
  1802. // Transfer the tracking information to the dest file, but only if we
  1803. // were able to get write access to both files.
  1804. if( (DestFileAccess & FILE_WRITE_DATA) &&
  1805. (SourceFileAccess & FILE_WRITE_DATA) ) {
  1806. Status = BasepNotifyTrackingService( &SourceFile,
  1807. &SourceObja,
  1808. DestFile,
  1809. &DestFileName );
  1810. if( !NT_SUCCESS(Status) ) {
  1811. if( dwFlags & PRIVMOVE_FILEID_IGNORE_ID_ERRORS ) {
  1812. if( NT_SUCCESS(StatusIgnored) ) {
  1813. StatusIgnored = Status;
  1814. }
  1815. Status = STATUS_SUCCESS;
  1816. }
  1817. else {
  1818. leave;
  1819. }
  1820. }
  1821. }
  1822. }
  1823. finally
  1824. {
  1825. if( SourceFileNameFreeBuffer != NULL )
  1826. RtlFreeHeap( RtlProcessHeap(), 0, SourceFileNameFreeBuffer );
  1827. if( DestFileNameFreeBuffer != NULL )
  1828. RtlFreeHeap( RtlProcessHeap(), 0, DestFileNameFreeBuffer );
  1829. }
  1830. // If requested, delete the source file. DispositionInformation.DeleteFile
  1831. // has already been initialized to TRUE.
  1832. if( NT_SUCCESS(Status) && (dwFlags & PRIVMOVE_FILEID_DELETE_OLD_FILE) ) {
  1833. Status = NtSetInformationFile(
  1834. SourceFile,
  1835. &IoStatus,
  1836. &DispositionInformation,
  1837. sizeof(DispositionInformation),
  1838. FileDispositionInformation
  1839. );
  1840. }
  1841. if( DestFile != INVALID_HANDLE_VALUE )
  1842. NtClose( DestFile );
  1843. if( SourceFile != INVALID_HANDLE_VALUE )
  1844. NtClose( SourceFile );
  1845. if( !NT_SUCCESS(Status) ) {
  1846. BaseSetLastNTError(Status);
  1847. }
  1848. else if( !NT_SUCCESS(StatusIgnored) ) {
  1849. BaseSetLastNTError(StatusIgnored);
  1850. }
  1851. return( NT_SUCCESS(Status) );
  1852. }
  1853. DWORD
  1854. WINAPI
  1855. GetCompressedFileSizeA(
  1856. LPCSTR lpFileName,
  1857. LPDWORD lpFileSizeHigh
  1858. )
  1859. {
  1860. PUNICODE_STRING Unicode;
  1861. Unicode = Basep8BitStringToStaticUnicodeString( lpFileName );
  1862. if (Unicode == NULL) {
  1863. return (DWORD)-1;
  1864. }
  1865. return ( GetCompressedFileSizeW((LPCWSTR)Unicode->Buffer,lpFileSizeHigh) );
  1866. }
  1867. DWORD
  1868. WINAPI
  1869. GetCompressedFileSizeW(
  1870. LPCWSTR lpFileName,
  1871. LPDWORD lpFileSizeHigh
  1872. )
  1873. {
  1874. NTSTATUS Status;
  1875. OBJECT_ATTRIBUTES Obja;
  1876. HANDLE Handle;
  1877. UNICODE_STRING FileName;
  1878. IO_STATUS_BLOCK IoStatusBlock;
  1879. FILE_COMPRESSION_INFORMATION CompressionInfo;
  1880. BOOLEAN TranslationStatus;
  1881. RTL_RELATIVE_NAME_U RelativeName;
  1882. PVOID FreeBuffer;
  1883. DWORD FileSizeLow;
  1884. TranslationStatus = RtlDosPathNameToRelativeNtPathName_U(
  1885. lpFileName,
  1886. &FileName,
  1887. NULL,
  1888. &RelativeName
  1889. );
  1890. if ( !TranslationStatus ) {
  1891. SetLastError(ERROR_PATH_NOT_FOUND);
  1892. return (DWORD)-1;
  1893. }
  1894. FreeBuffer = FileName.Buffer;
  1895. if ( RelativeName.RelativeName.Length ) {
  1896. FileName = RelativeName.RelativeName;
  1897. }
  1898. else {
  1899. RelativeName.ContainingDirectory = NULL;
  1900. }
  1901. InitializeObjectAttributes(
  1902. &Obja,
  1903. &FileName,
  1904. OBJ_CASE_INSENSITIVE,
  1905. RelativeName.ContainingDirectory,
  1906. NULL
  1907. );
  1908. //
  1909. // Open the file
  1910. //
  1911. Status = NtOpenFile(
  1912. &Handle,
  1913. FILE_READ_ATTRIBUTES,
  1914. &Obja,
  1915. &IoStatusBlock,
  1916. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  1917. FILE_OPEN_FOR_BACKUP_INTENT
  1918. );
  1919. RtlReleaseRelativeName(&RelativeName);
  1920. RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
  1921. if ( !NT_SUCCESS(Status) ) {
  1922. BaseSetLastNTError(Status);
  1923. return (DWORD)-1;
  1924. }
  1925. //
  1926. // Get the compressed file size.
  1927. //
  1928. Status = NtQueryInformationFile(
  1929. Handle,
  1930. &IoStatusBlock,
  1931. &CompressionInfo,
  1932. sizeof(CompressionInfo),
  1933. FileCompressionInformation
  1934. );
  1935. if ( !NT_SUCCESS(Status) ) {
  1936. FileSizeLow = GetFileSize(Handle,lpFileSizeHigh);
  1937. NtClose(Handle);
  1938. return FileSizeLow;
  1939. }
  1940. NtClose(Handle);
  1941. if ( ARGUMENT_PRESENT(lpFileSizeHigh) ) {
  1942. *lpFileSizeHigh = (DWORD)CompressionInfo.CompressedFileSize.HighPart;
  1943. }
  1944. if (CompressionInfo.CompressedFileSize.LowPart == -1 ) {
  1945. SetLastError(0);
  1946. }
  1947. return CompressionInfo.CompressedFileSize.LowPart;
  1948. }