Source code of Windows XP (NT5)
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.

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