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.

8272 lines
310 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. fileopcr.c
  5. Abstract:
  6. This module implements File open and Create APIs for Win32
  7. Author:
  8. Mark Lucovsky (markl) 25-Sep-1990
  9. Revision History:
  10. --*/
  11. #include "basedll.h"
  12. #include "mountmgr.h"
  13. #include "aclapi.h"
  14. #include "winefs.h"
  15. WCHAR BasepDataAttributeType[] = DATA_ATTRIBUTE_NAME;
  16. typedef BOOL (WINAPI *ENCRYPTFILEWPTR)(LPCWSTR);
  17. typedef BOOL (WINAPI *DECRYPTFILEWPTR)(LPCWSTR, DWORD);
  18. extern const WCHAR AdvapiDllString[] = L"advapi32.dll";
  19. #define BASE_OF_SHARE_MASK 0x00000070
  20. #define TWO56K ( 256 * 1024 )
  21. ULONG
  22. BasepOfShareToWin32Share(
  23. IN ULONG OfShare
  24. )
  25. {
  26. DWORD ShareMode;
  27. if ( (OfShare & BASE_OF_SHARE_MASK) == OF_SHARE_DENY_READ ) {
  28. ShareMode = FILE_SHARE_WRITE;
  29. }
  30. else if ( (OfShare & BASE_OF_SHARE_MASK) == OF_SHARE_DENY_WRITE ) {
  31. ShareMode = FILE_SHARE_READ;
  32. }
  33. else if ( (OfShare & BASE_OF_SHARE_MASK) == OF_SHARE_DENY_NONE ) {
  34. ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
  35. }
  36. else if ( (OfShare & BASE_OF_SHARE_MASK) == OF_SHARE_EXCLUSIVE ) {
  37. ShareMode = 0;
  38. }
  39. else {
  40. ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;;
  41. }
  42. return ShareMode;
  43. }
  44. typedef DWORD (WINAPI DUPLICATEENCRYPTIONINFOFILE)(
  45. IN LPCWSTR SrcFileName,
  46. IN LPCWSTR DstFileName,
  47. IN DWORD dwCreationDistribution,
  48. IN DWORD dwAttributes,
  49. IN LPSECURITY_ATTRIBUTES lpSecurityAttributes
  50. );
  51. DUPLICATEENCRYPTIONINFOFILE LoadDuplicateEncryptionInfoFile;
  52. DUPLICATEENCRYPTIONINFOFILE *pfnDuplicateEncryptionInfoFile = LoadDuplicateEncryptionInfoFile;
  53. DWORD
  54. WINAPI
  55. LoadDuplicateEncryptionInfoFile(
  56. IN LPCWSTR SrcFileName,
  57. IN LPCWSTR DstFileName,
  58. IN DWORD dwCreationDistribution,
  59. IN DWORD dwAttributes,
  60. IN LPSECURITY_ATTRIBUTES lpSecurityAttributes
  61. )
  62. {
  63. DUPLICATEENCRYPTIONINFOFILE *pfnTemp;
  64. HANDLE Advapi32 = NULL;
  65. BOOL ReturnSuccess = FALSE;
  66. DWORD ErrorReturn = 0;
  67. Advapi32 = LoadLibraryW( AdvapiDllString );
  68. if( Advapi32 == NULL ) {
  69. return GetLastError();
  70. }
  71. pfnTemp = (DUPLICATEENCRYPTIONINFOFILE*)
  72. GetProcAddress( Advapi32, "DuplicateEncryptionInfoFile" );
  73. if( pfnTemp == NULL ) {
  74. return GetLastError();
  75. }
  76. pfnDuplicateEncryptionInfoFile = pfnTemp;
  77. return pfnDuplicateEncryptionInfoFile( SrcFileName,
  78. DstFileName,
  79. dwCreationDistribution,
  80. dwAttributes,
  81. lpSecurityAttributes );
  82. }
  83. PCUNICODE_STRING
  84. BaseIsThisAConsoleName(
  85. PCUNICODE_STRING FileNameString,
  86. DWORD dwDesiredAccess
  87. )
  88. {
  89. PCUNICODE_STRING FoundConsoleName;
  90. ULONG DeviceNameLength;
  91. ULONG DeviceNameOffset;
  92. UNICODE_STRING ConString;
  93. WCHAR sch,ech;
  94. FoundConsoleName = NULL;
  95. if ( FileNameString->Length ) {
  96. sch = FileNameString->Buffer[0];
  97. ech = FileNameString->Buffer[(FileNameString->Length-1)>>1];
  98. //
  99. // if CON, CONOUT$, CONIN$, \\.\CON...
  100. //
  101. //
  102. if ( sch == (WCHAR)'c' || sch == (WCHAR)'C' || sch == (WCHAR)'\\' ||
  103. ech == (WCHAR)'n' || ech == (WCHAR)'N' || ech == (WCHAR)':' || ech == (WCHAR)'$' ) {
  104. ConString = *FileNameString;
  105. DeviceNameLength = RtlIsDosDeviceName_U(ConString.Buffer);
  106. if ( DeviceNameLength ) {
  107. DeviceNameOffset = DeviceNameLength >> 16;
  108. DeviceNameLength &= 0x0000ffff;
  109. ConString.Buffer = (PWSTR)((PSZ)ConString.Buffer + DeviceNameOffset);
  110. ConString.Length = (USHORT)DeviceNameLength;
  111. ConString.MaximumLength = (USHORT)(DeviceNameLength + sizeof(UNICODE_NULL));
  112. }
  113. FoundConsoleName = NULL;
  114. try {
  115. if (RtlEqualUnicodeString(&ConString,&BaseConsoleInput,TRUE) ) {
  116. FoundConsoleName = &BaseConsoleInput;
  117. }
  118. else if (RtlEqualUnicodeString(&ConString,&BaseConsoleOutput,TRUE) ) {
  119. FoundConsoleName = &BaseConsoleOutput;
  120. }
  121. else if (RtlEqualUnicodeString(&ConString,&BaseConsoleGeneric,TRUE) ) {
  122. if ((dwDesiredAccess & (GENERIC_READ|GENERIC_WRITE)) == GENERIC_READ) {
  123. FoundConsoleName = &BaseConsoleInput;
  124. }
  125. else if ((dwDesiredAccess & (GENERIC_READ|GENERIC_WRITE)) == GENERIC_WRITE){
  126. FoundConsoleName = &BaseConsoleOutput;
  127. }
  128. }
  129. }
  130. except (EXCEPTION_EXECUTE_HANDLER) {
  131. return NULL;
  132. }
  133. }
  134. }
  135. return FoundConsoleName;
  136. }
  137. DWORD
  138. WINAPI
  139. CopyReparsePoint(
  140. HANDLE hSourceFile,
  141. HANDLE hDestinationFile
  142. )
  143. /*++
  144. Routine Description:
  145. This is an internal routine that copies a reparse point.
  146. Arguments:
  147. hSourceFile - Provides a handle to the source file.
  148. hDestinationFile - Provides a handle to the destination file.
  149. Return Value:
  150. TRUE - The operation was successful.
  151. FALSE - The operation failed. Extended error status is available
  152. using GetLastError.
  153. --*/
  154. {
  155. NTSTATUS Status;
  156. IO_STATUS_BLOCK IoStatusBlock;
  157. PUCHAR ReparseBuffer;
  158. PREPARSE_DATA_BUFFER ReparseBufferHeader;
  159. //
  160. // Allocate the buffer to set the reparse point.
  161. //
  162. ReparseBuffer = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( TMP_TAG ), MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
  163. if ( ReparseBuffer == NULL ) {
  164. BaseSetLastNTError(STATUS_NO_MEMORY);
  165. return FALSE;
  166. }
  167. //
  168. // Get the reparse point.
  169. //
  170. Status = NtFsControlFile(
  171. hSourceFile,
  172. NULL,
  173. NULL,
  174. NULL,
  175. &IoStatusBlock,
  176. FSCTL_GET_REPARSE_POINT,
  177. NULL, // Input buffer
  178. 0, // Input buffer length
  179. ReparseBuffer, // Output buffer
  180. MAXIMUM_REPARSE_DATA_BUFFER_SIZE // Output buffer length
  181. );
  182. if ( !NT_SUCCESS( Status ) ) {
  183. RtlFreeHeap(RtlProcessHeap(), 0, ReparseBuffer);
  184. BaseSetLastNTError(Status);
  185. return FALSE;
  186. }
  187. //
  188. // Decode the reparse point buffer.
  189. //
  190. ReparseBufferHeader = (PREPARSE_DATA_BUFFER)ReparseBuffer;
  191. //
  192. // Set the reparse point.
  193. //
  194. Status = NtFsControlFile(
  195. hDestinationFile,
  196. NULL,
  197. NULL,
  198. NULL,
  199. &IoStatusBlock,
  200. FSCTL_SET_REPARSE_POINT,
  201. ReparseBuffer,
  202. FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) + ReparseBufferHeader->ReparseDataLength,
  203. NULL,
  204. 0
  205. );
  206. RtlFreeHeap(RtlProcessHeap(), 0, ReparseBuffer);
  207. if ( !NT_SUCCESS( Status ) ) {
  208. BaseSetLastNTError(Status);
  209. return FALSE;
  210. }
  211. return TRUE;
  212. }
  213. DWORD
  214. WINAPI
  215. CopyNameGraftNow(
  216. HANDLE hSourceFile,
  217. LPCWSTR lpExistingFileName,
  218. LPCWSTR lpNewFileName,
  219. ULONG CreateOptions,
  220. LPPROGRESS_ROUTINE lpProgressRoutine OPTIONAL,
  221. LPVOID lpData OPTIONAL,
  222. LPBOOL pbCancel OPTIONAL,
  223. LPDWORD lpCopyFlags
  224. )
  225. /*++
  226. Routine Description:
  227. This is an internal routine that copies a name grafting file/directory preserving
  228. its characteristics.
  229. Arguments:
  230. hSourceFile - Provides a handle to the source file.
  231. lpExistingFileName - Provides the name of the existing, source file.
  232. lpNewFileName - Provides a name for the target file/stream. This must not
  233. be a UNC path name.
  234. lpProgressRoutine - Optionally supplies the address of a callback routine
  235. to be called as the copy operation progresses.
  236. lpData - Optionally supplies a context to be passed to the progress callback
  237. routine.
  238. pbCancel - Optionally supplies the address of a boolean to be set to TRUE
  239. if the caller would like the copy to abort.
  240. lpCopyFlags - Provides flags that modify how the copy is to proceed. See
  241. CopyFileEx for details.
  242. Return Value:
  243. TRUE - The operation was successful.
  244. FALSE - The operation failed. Extended error status is available
  245. using GetLastError.
  246. --*/
  247. { // CopyNameGraftNow
  248. NTSTATUS Status;
  249. DWORD ReturnValue = FALSE;
  250. HANDLE DestFile = INVALID_HANDLE_VALUE;
  251. IO_STATUS_BLOCK IoStatusBlock;
  252. PREPARSE_DATA_BUFFER ReparseBufferHeader;
  253. PUCHAR ReparseBuffer = NULL;
  254. FILE_BASIC_INFORMATION BasicInformation;
  255. FILE_STANDARD_INFORMATION StandardInformation;
  256. COPYFILE_CONTEXT CfContext;
  257. UNICODE_STRING SourceFileName;
  258. UNICODE_STRING DestFileName;
  259. PVOID SourceFileNameBuffer = NULL;
  260. PVOID DestFileNameBuffer = NULL;
  261. BOOL TranslationStatus;
  262. BOOL b;
  263. OBJECT_ATTRIBUTES Obja;
  264. IO_STATUS_BLOCK IoStatus;
  265. //
  266. // Set up the context if appropriate.
  267. //
  268. RtlZeroMemory(&StandardInformation, sizeof(StandardInformation));
  269. if ( ARGUMENT_PRESENT(lpProgressRoutine) || ARGUMENT_PRESENT(pbCancel) ) {
  270. CfContext.TotalFileSize = StandardInformation.EndOfFile;
  271. CfContext.TotalBytesTransferred.QuadPart = 0;
  272. CfContext.dwStreamNumber = 0;
  273. CfContext.lpCancel = pbCancel;
  274. CfContext.lpData = lpData;
  275. CfContext.lpProgressRoutine = lpProgressRoutine;
  276. }
  277. //
  278. // Allocate the buffer to set the reparse point.
  279. //
  280. ReparseBuffer = RtlAllocateHeap(
  281. RtlProcessHeap(),
  282. MAKE_TAG( TMP_TAG ),
  283. MAXIMUM_REPARSE_DATA_BUFFER_SIZE
  284. );
  285. if ( ReparseBuffer == NULL) {
  286. BaseSetLastNTError(STATUS_NO_MEMORY);
  287. return FALSE;
  288. }
  289. try {
  290. //
  291. // Translate both names.
  292. //
  293. TranslationStatus = RtlDosPathNameToNtPathName_U(
  294. lpExistingFileName,
  295. &SourceFileName,
  296. NULL,
  297. NULL
  298. );
  299. if ( !TranslationStatus ) {
  300. SetLastError(ERROR_PATH_NOT_FOUND);
  301. DestFile = INVALID_HANDLE_VALUE;
  302. leave;
  303. }
  304. SourceFileNameBuffer = SourceFileName.Buffer;
  305. TranslationStatus = RtlDosPathNameToNtPathName_U(
  306. lpNewFileName,
  307. &DestFileName,
  308. NULL,
  309. NULL
  310. );
  311. if ( !TranslationStatus ) {
  312. SetLastError(ERROR_PATH_NOT_FOUND);
  313. DestFile = INVALID_HANDLE_VALUE;
  314. leave;
  315. }
  316. DestFileNameBuffer = DestFileName.Buffer;
  317. //
  318. // Verify that the source and target are different.
  319. //
  320. if ( RtlEqualUnicodeString(&SourceFileName, &DestFileName, TRUE) ) {
  321. //
  322. // Do nothing. Source and target are the same.
  323. //
  324. DestFile = INVALID_HANDLE_VALUE;
  325. leave;
  326. }
  327. //
  328. // Open the destination.
  329. //
  330. InitializeObjectAttributes(
  331. &Obja,
  332. &DestFileName,
  333. OBJ_CASE_INSENSITIVE,
  334. NULL,
  335. NULL
  336. );
  337. Status = NtCreateFile( &DestFile,
  338. GENERIC_READ | GENERIC_WRITE,
  339. &Obja,
  340. &IoStatus,
  341. NULL,
  342. 0,
  343. FILE_SHARE_READ | FILE_SHARE_WRITE,
  344. (*lpCopyFlags & COPY_FILE_FAIL_IF_EXISTS) ? FILE_CREATE : FILE_OPEN_IF,
  345. FILE_OPEN_REPARSE_POINT | CreateOptions,
  346. NULL,
  347. 0 );
  348. if( !NT_SUCCESS(Status) ) {
  349. DestFile = INVALID_HANDLE_VALUE;
  350. BaseSetLastNTError(Status);
  351. leave;
  352. }
  353. //
  354. // We now have the handle to the destination.
  355. // We get and set the corresponding reparse point.
  356. //
  357. Status = NtFsControlFile(
  358. hSourceFile,
  359. NULL,
  360. NULL,
  361. NULL,
  362. &IoStatusBlock,
  363. FSCTL_GET_REPARSE_POINT,
  364. NULL, // Input buffer
  365. 0, // Input buffer length
  366. ReparseBuffer, // Output buffer
  367. MAXIMUM_REPARSE_DATA_BUFFER_SIZE // Output buffer length
  368. );
  369. if ( !NT_SUCCESS( Status ) ) {
  370. BaseSetLastNTError(Status);
  371. leave;
  372. }
  373. //
  374. // Defensive sanity check. The reparse buffer should be name grafting.
  375. //
  376. ReparseBufferHeader = (PREPARSE_DATA_BUFFER)ReparseBuffer;
  377. if ( ReparseBufferHeader->ReparseTag != IO_REPARSE_TAG_MOUNT_POINT ) {
  378. BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID);
  379. leave;
  380. }
  381. //
  382. // Determine whether the sourse is a volume mount point.
  383. //
  384. if ( MOUNTMGR_IS_VOLUME_NAME(&SourceFileName) ) {
  385. //
  386. // Set the volume mount point and be done.
  387. //
  388. b = SetVolumeMountPointW(
  389. lpNewFileName,
  390. ReparseBufferHeader->MountPointReparseBuffer.PathBuffer
  391. );
  392. if ( !b ) {
  393. leave;
  394. }
  395. }
  396. else {
  397. //
  398. // Set the reparse point of type name junction.
  399. //
  400. Status = NtFsControlFile(
  401. DestFile,
  402. NULL,
  403. NULL,
  404. NULL,
  405. &IoStatusBlock,
  406. FSCTL_SET_REPARSE_POINT,
  407. ReparseBuffer,
  408. FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) + ReparseBufferHeader->ReparseDataLength,
  409. NULL,
  410. 0
  411. );
  412. }
  413. if ( !(*lpCopyFlags & COPY_FILE_FAIL_IF_EXISTS) &&
  414. ((Status == STATUS_EAS_NOT_SUPPORTED) ||
  415. (Status == STATUS_IO_REPARSE_TAG_MISMATCH)) ) {
  416. //
  417. // In either of these error conditions, the correct behavior is to
  418. // first delete the destination file and then copy the name graft.
  419. //
  420. // Re-open the destination for the deletion without inhibiting the
  421. // reparse behavior.
  422. //
  423. BOOL DeleteStatus = FALSE;
  424. CloseHandle(DestFile);
  425. DestFile = INVALID_HANDLE_VALUE;
  426. DeleteStatus = DeleteFileW(
  427. lpNewFileName
  428. );
  429. if ( !DeleteStatus ) {
  430. leave;
  431. }
  432. //
  433. // Create the destination name graft.
  434. // Notice that either a file or a directory may be created.
  435. //
  436. Status = NtCreateFile( &DestFile,
  437. GENERIC_READ | GENERIC_WRITE,
  438. &Obja,
  439. &IoStatus,
  440. NULL,
  441. 0,
  442. FILE_SHARE_READ | FILE_SHARE_WRITE,
  443. FILE_CREATE,
  444. FILE_OPEN_REPARSE_POINT | CreateOptions,
  445. NULL,
  446. 0 );
  447. if( !NT_SUCCESS( Status )) {
  448. BaseSetLastNTError( Status );
  449. leave;
  450. }
  451. //
  452. // Set the reparse point.
  453. //
  454. Status = NtFsControlFile(
  455. DestFile,
  456. NULL,
  457. NULL,
  458. NULL,
  459. &IoStatusBlock,
  460. FSCTL_SET_REPARSE_POINT,
  461. ReparseBuffer,
  462. FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) + ReparseBufferHeader->ReparseDataLength,
  463. NULL,
  464. 0
  465. );
  466. } // if ( !(*lpCopyFlags & COPY_FILE_FAIL_IF_EXISTS) ...
  467. //
  468. // Close the destination file and return appropriatelly.
  469. //
  470. if ( !NT_SUCCESS( Status ) ) {
  471. BaseSetLastNTError(Status);
  472. leave;
  473. }
  474. //
  475. // The name graft was copied. Set the last write time for the file
  476. // so that it matches the input file.
  477. //
  478. Status = NtQueryInformationFile(
  479. hSourceFile,
  480. &IoStatusBlock,
  481. (PVOID) &BasicInformation,
  482. sizeof(BasicInformation),
  483. FileBasicInformation
  484. );
  485. if ( !NT_SUCCESS(Status) ) {
  486. BaseSetLastNTError(Status);
  487. leave;
  488. }
  489. BasicInformation.CreationTime.QuadPart = 0;
  490. BasicInformation.LastAccessTime.QuadPart = 0;
  491. BasicInformation.FileAttributes = 0;
  492. //
  493. // If the time cannot be set for whatever reason, we still return
  494. // TRUE.
  495. //
  496. Status = NtSetInformationFile(
  497. DestFile,
  498. &IoStatusBlock,
  499. &BasicInformation,
  500. sizeof(BasicInformation),
  501. FileBasicInformation
  502. );
  503. if ( Status == STATUS_SHARING_VIOLATION ) {
  504. //
  505. // IBM PC Lan Program (and other MS-NET servers) return
  506. // STATUS_SHARING_VIOLATION if an application attempts to perform
  507. // an NtSetInformationFile on a file handle opened for GENERIC_READ
  508. // or GENERIC_WRITE.
  509. //
  510. // If we get a STATUS_SHARING_VIOLATION on this API we want to:
  511. //
  512. // 1) Close the handle to the destination
  513. // 2) Re-open the file for FILE_WRITE_ATTRIBUTES
  514. // 3) Re-try the operation.
  515. //
  516. CloseHandle(DestFile);
  517. //
  518. // Re-Open the destination file inhibiting the reparse behavior as
  519. // we know that it is a symbolic link. Please note that we do this
  520. // using the CreateFileW API. The CreateFileW API allows you to
  521. // pass NT native desired access flags, even though it is not
  522. // documented to work in this manner.
  523. //
  524. Status = NtCreateFile( &DestFile,
  525. FILE_WRITE_ATTRIBUTES,
  526. &Obja,
  527. &IoStatus,
  528. NULL,
  529. 0,
  530. 0,
  531. FILE_OPEN,
  532. FILE_OPEN_REPARSE_POINT | CreateOptions,
  533. NULL,
  534. 0 );
  535. if ( NT_SUCCESS( Status )) {
  536. //
  537. // If the open succeeded, we update the file information on
  538. // the new file.
  539. //
  540. // Note that we ignore any errors from this point on.
  541. //
  542. Status = NtSetInformationFile(
  543. DestFile,
  544. &IoStatusBlock,
  545. &BasicInformation,
  546. sizeof(BasicInformation),
  547. FileBasicInformation
  548. );
  549. }
  550. }
  551. ReturnValue = TRUE;
  552. } finally {
  553. if( INVALID_HANDLE_VALUE != DestFile )
  554. CloseHandle( DestFile );
  555. RtlFreeHeap( RtlProcessHeap(), 0, SourceFileNameBuffer );
  556. RtlFreeHeap( RtlProcessHeap(), 0, DestFileNameBuffer );
  557. RtlFreeHeap(RtlProcessHeap(), 0, ReparseBuffer);
  558. }
  559. return ReturnValue;
  560. }
  561. BOOL
  562. WINAPI
  563. CopyFileA(
  564. LPCSTR lpExistingFileName,
  565. LPCSTR lpNewFileName,
  566. BOOL bFailIfExists
  567. )
  568. /*++
  569. Routine Description:
  570. ANSI thunk to CopyFileW
  571. --*/
  572. {
  573. PUNICODE_STRING StaticUnicode;
  574. UNICODE_STRING DynamicUnicode;
  575. BOOL b;
  576. StaticUnicode = Basep8BitStringToStaticUnicodeString( lpExistingFileName );
  577. if (StaticUnicode == NULL) {
  578. return FALSE;
  579. }
  580. if (!Basep8BitStringToDynamicUnicodeString( &DynamicUnicode, lpNewFileName )) {
  581. return FALSE;
  582. }
  583. b = CopyFileExW(
  584. (LPCWSTR)StaticUnicode->Buffer,
  585. (LPCWSTR)DynamicUnicode.Buffer,
  586. (LPPROGRESS_ROUTINE)NULL,
  587. (LPVOID)NULL,
  588. (LPBOOL)NULL,
  589. bFailIfExists ? COPY_FILE_FAIL_IF_EXISTS : 0
  590. );
  591. RtlFreeUnicodeString(&DynamicUnicode);
  592. return b;
  593. }
  594. BOOL
  595. WINAPI
  596. CopyFileW(
  597. LPCWSTR lpExistingFileName,
  598. LPCWSTR lpNewFileName,
  599. BOOL bFailIfExists
  600. )
  601. /*++
  602. Routine Description:
  603. A file, its extended attributes, alternate data streams, and any other
  604. attributes can be copied using CopyFile.
  605. Arguments:
  606. lpExistingFileName - Supplies the name of an existing file that is to be
  607. copied.
  608. lpNewFileName - Supplies the name where a copy of the existing
  609. files data and attributes are to be stored.
  610. bFailIfExists - Supplies a flag that indicates how this operation is
  611. to proceed if the specified new file already exists. A value of
  612. TRUE specifies that this call is to fail. A value of FALSE
  613. causes the call to the function to succeed whether or not the
  614. specified new file exists.
  615. Return Value:
  616. TRUE - The operation was successful.
  617. FALSE/NULL - The operation failed. Extended error status is available
  618. using GetLastError.
  619. --*/
  620. {
  621. BOOL b;
  622. b = CopyFileExW(
  623. lpExistingFileName,
  624. lpNewFileName,
  625. (LPPROGRESS_ROUTINE)NULL,
  626. (LPVOID)NULL,
  627. (LPBOOL)NULL,
  628. bFailIfExists ? COPY_FILE_FAIL_IF_EXISTS : 0
  629. );
  630. return b;
  631. }
  632. BOOL
  633. WINAPI
  634. CopyFileExA(
  635. LPCSTR lpExistingFileName,
  636. LPCSTR lpNewFileName,
  637. LPPROGRESS_ROUTINE lpProgressRoutine OPTIONAL,
  638. LPVOID lpData OPTIONAL,
  639. LPBOOL pbCancel OPTIONAL,
  640. DWORD dwCopyFlags
  641. )
  642. /*++
  643. Routine Description:
  644. ANSI thunk to CopyFileExW
  645. --*/
  646. {
  647. PUNICODE_STRING StaticUnicode;
  648. UNICODE_STRING DynamicUnicode;
  649. BOOL b;
  650. StaticUnicode = Basep8BitStringToStaticUnicodeString( lpExistingFileName );
  651. if (StaticUnicode == NULL) {
  652. return FALSE;
  653. }
  654. if (!Basep8BitStringToDynamicUnicodeString( &DynamicUnicode, lpNewFileName )) {
  655. return FALSE;
  656. }
  657. b = CopyFileExW(
  658. (LPCWSTR)StaticUnicode->Buffer,
  659. (LPCWSTR)DynamicUnicode.Buffer,
  660. lpProgressRoutine,
  661. lpData,
  662. pbCancel,
  663. dwCopyFlags
  664. );
  665. RtlFreeUnicodeString(&DynamicUnicode);
  666. return b;
  667. }
  668. #define COPY_FILE_VALID_FLAGS (COPY_FILE_FAIL_IF_EXISTS | \
  669. COPY_FILE_RESTARTABLE | \
  670. COPY_FILE_OPEN_SOURCE_FOR_WRITE | \
  671. COPY_FILE_ALLOW_DECRYPTED_DESTINATION)
  672. NTSTATUS
  673. BasepProcessNameGrafting( HANDLE SourceFile,
  674. PBOOL IsNameGrafting,
  675. PBOOL bCopyRawSourceFile,
  676. PBOOL bOpenFilesAsReparsePoint,
  677. PFILE_ATTRIBUTE_TAG_INFORMATION FileTagInformation )
  678. /*++
  679. Routine Description:
  680. During CopyFile, check to see if the source is a symlink which
  681. requires special processing during copy.
  682. Arguments:
  683. SourceFile - Handle for the source of the copy.
  684. IsNameGrafting - If true on return, the source file is grafted.
  685. bCopyRawSourceFile - If true on return, the source file needn't be
  686. reopened. If false, the file should be reopened without the
  687. FILE_OPEN_REPARSE_POINT flag.
  688. bOpenFilesAsReparsePoint - If true on return, source/dest named
  689. streams should be opened/created with FILE_OPEN_REPARSE_POINT
  690. specified.
  691. FileTagInformation - Pointer to location to hold the results of
  692. NtQueryInformationFile(FileAttributeTagInformation).
  693. Return Value:
  694. NTSTATUS
  695. --*/
  696. {
  697. IO_STATUS_BLOCK IoStatus;
  698. NTSTATUS Status = STATUS_SUCCESS;
  699. Status = NtQueryInformationFile(
  700. SourceFile,
  701. &IoStatus,
  702. (PVOID) FileTagInformation,
  703. sizeof(*FileTagInformation),
  704. FileAttributeTagInformation
  705. );
  706. if ( !NT_SUCCESS(Status) ) {
  707. //
  708. // Not all File Systems implement all information classes.
  709. // The value STATUS_INVALID_PARAMETER is returned when a non-supported
  710. // information class is requested to a back-level File System. As all
  711. // the parameters to NtQueryInformationFile are correct, we can infer
  712. // in this case that we found a back-level system.
  713. //
  714. if ( (Status != STATUS_INVALID_PARAMETER) &&
  715. (Status != STATUS_NOT_IMPLEMENTED) ) {
  716. return( Status );
  717. }
  718. Status = STATUS_SUCCESS;
  719. //
  720. // If FileAttributeTagInformation is not supported, we assume that
  721. // the file at hand is not a reparse point nor a symbolic link.
  722. // The copy of these files is the same as the raw copy of a file.
  723. // The target file is opened without inhibiting the reparse point
  724. // behavior.
  725. //
  726. *bCopyRawSourceFile = TRUE;
  727. } else {
  728. //
  729. // The source file is opened and the file system supports the
  730. // FileAttributeTagInformation information class.
  731. //
  732. if ( FileTagInformation->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT ) {
  733. //
  734. // We have a reparse point at hand.
  735. //
  736. if ( FileTagInformation->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT ) {
  737. //
  738. // We found a name grafting operation.
  739. //
  740. *IsNameGrafting = TRUE;
  741. }
  742. } else {
  743. //
  744. // We have a valid handle.
  745. // The underlying file system supports reparse points.
  746. // The source file is not a reparse point.
  747. // This is the case of a normal file in NT 5.0.
  748. // The SourceFile handle can be used for the copy. The copy of
  749. // these files is the same as the raw copy of a reparse point.
  750. // The target file is opened without inhibiting the reparse
  751. // point behavior.
  752. //
  753. *bCopyRawSourceFile = TRUE;
  754. }
  755. }
  756. return( Status );
  757. }
  758. BOOL
  759. BasepCopySecurityInformation( LPCWSTR lpExistingFileName,
  760. HANDLE SourceFile,
  761. ACCESS_MASK SourceFileAccess,
  762. LPCWSTR lpNewFileName,
  763. HANDLE DestFile,
  764. ACCESS_MASK DestFileAccess,
  765. SECURITY_INFORMATION SecurityInformation,
  766. LPCOPYFILE_CONTEXT Context,
  767. DWORD DestFileFsAttributes,
  768. PBOOL Canceled,
  769. BOOL CopyCreatorOwnerAce );
  770. BOOL
  771. BasepCopyFileCallback( BOOL ContinueByDefault,
  772. DWORD Win32ErrorOnStopOrCancel,
  773. LPCOPYFILE_CONTEXT Context,
  774. PLARGE_INTEGER StreamBytesCopied OPTIONAL,
  775. DWORD CallbackReason,
  776. HANDLE SourceFile,
  777. HANDLE DestFile,
  778. OPTIONAL PBOOL Canceled );
  779. BOOL
  780. BasepCopyFileExW(
  781. LPCWSTR lpExistingFileName,
  782. LPCWSTR lpNewFileName,
  783. LPPROGRESS_ROUTINE lpProgressRoutine OPTIONAL,
  784. LPVOID lpData OPTIONAL,
  785. LPBOOL pbCancel OPTIONAL,
  786. DWORD dwCopyFlags,
  787. DWORD dwPrivCopyFlags, // From PrivCopyFileExW
  788. LPHANDLE phSource,
  789. LPHANDLE phDest
  790. )
  791. {
  792. HANDLE SourceFile = INVALID_HANDLE_VALUE;
  793. HANDLE DestFile = INVALID_HANDLE_VALUE;
  794. DWORD b = FALSE;
  795. BOOL IsNameGrafting = FALSE;
  796. BOOL bCopyRawSourceFile = FALSE;
  797. BOOL bOpenFilesAsReparsePoint = FALSE;
  798. ULONG CopySize;
  799. NTSTATUS Status;
  800. OBJECT_ATTRIBUTES ObjectAttributes;
  801. IO_STATUS_BLOCK IoStatus;
  802. FILE_STANDARD_INFORMATION FileInformation;
  803. FILE_BASIC_INFORMATION BasicInformation;
  804. PFILE_STREAM_INFORMATION StreamInfo;
  805. PFILE_STREAM_INFORMATION StreamInfoBase = NULL;
  806. UNICODE_STRING StreamName;
  807. HANDLE OutputStream;
  808. HANDLE StreamHandle;
  809. ULONG StreamInfoSize;
  810. COPYFILE_CONTEXT CfContext;
  811. LPCOPYFILE_CONTEXT CopyFileContext = NULL;
  812. RESTART_STATE RestartState;
  813. DWORD SourceFileAttributes = 0;
  814. DWORD FlagsAndAttributes = 0;
  815. DWORD FileFlagBackupSemantics = 0;
  816. DWORD DestFileFsAttributes = 0;
  817. DWORD SourceFileAccessDefault;
  818. DWORD SourceFileAccess = 0;
  819. DWORD SourceFileFlagsAndAttributes = 0;
  820. DWORD SourceFileSharing = 0;
  821. DWORD SourceFileSharingDefault = 0;
  822. BOOL CheckedForNameGrafting = FALSE;
  823. FILE_ATTRIBUTE_TAG_INFORMATION FileTagInformation;
  824. //
  825. // Ensure that only valid flags were passed.
  826. //
  827. if ( dwCopyFlags & ~COPY_FILE_VALID_FLAGS ) {
  828. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  829. return FALSE;
  830. }
  831. if ( dwPrivCopyFlags & ~PRIVCOPY_FILE_VALID_FLAGS ) {
  832. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  833. return FALSE;
  834. }
  835. // Make sure the copy_file and privcopy_file flags don't overlap
  836. // in winbase.w.
  837. ASSERT( (PRIVCOPY_FILE_VALID_FLAGS & COPY_FILE_VALID_FLAGS) == 0 );
  838. dwCopyFlags |= dwPrivCopyFlags;
  839. try {
  840. //
  841. // We first establish whether we are copying a reparse point:
  842. // (1) obtain a handle inhibiting the reparse point behavior
  843. // (2) establish whether a symbolic link was found
  844. // (3) establish whether a reparse point that is not a symbolic link
  845. // is to be copied in raw format or re-enabling the reparse point
  846. // behavior
  847. //
  848. // Determine if backup-intent should be set.
  849. if( (PRIVCOPY_FILE_DIRECTORY|PRIVCOPY_FILE_BACKUP_SEMANTICS) & dwCopyFlags ) {
  850. FileFlagBackupSemantics = FILE_FLAG_BACKUP_SEMANTICS;
  851. }
  852. SourceFileAccessDefault = GENERIC_READ;
  853. SourceFileAccessDefault |= (dwCopyFlags & COPY_FILE_OPEN_SOURCE_FOR_WRITE) ? GENERIC_WRITE : 0;
  854. SourceFileAccessDefault |= (dwCopyFlags & PRIVCOPY_FILE_SACL) ? ACCESS_SYSTEM_SECURITY : 0;
  855. SourceFileFlagsAndAttributes = FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_SEQUENTIAL_SCAN | FileFlagBackupSemantics;
  856. CheckedForNameGrafting = FALSE;
  857. SourceFileSharingDefault = FILE_SHARE_READ;
  858. retry_open_SourceFile:
  859. SourceFileAccess = SourceFileAccessDefault;
  860. SourceFileSharing = SourceFileSharingDefault;
  861. while( TRUE ) {
  862. SourceFile = CreateFileW(
  863. lpExistingFileName,
  864. SourceFileAccess,
  865. SourceFileSharing,
  866. NULL,
  867. OPEN_EXISTING,
  868. SourceFileFlagsAndAttributes,
  869. NULL
  870. );
  871. if ( SourceFile == INVALID_HANDLE_VALUE ) {
  872. // If we tried to get ACCESS_SYSTEM_SECURITY access, that
  873. // might cause an access or privilege error.
  874. if( ( GetLastError() == ERROR_PRIVILEGE_NOT_HELD
  875. ||
  876. GetLastError() == ERROR_ACCESS_DENIED
  877. )
  878. &&
  879. (SourceFileAccess & ACCESS_SYSTEM_SECURITY) ) {
  880. // Turn it off
  881. SourceFileAccess &= ~ACCESS_SYSTEM_SECURITY;
  882. }
  883. // Maybe we should stop requesting write access (done for
  884. // COPYFILE_OPEN_SOURCE_FOR_WRITE
  885. else if( ( GetLastError() == ERROR_ACCESS_DENIED ||
  886. GetLastError() == ERROR_SHARING_VIOLATION ) &&
  887. (GENERIC_WRITE & SourceFileAccess) ) {
  888. // Turn it off, but if originally requested,
  889. // turn access_system_security back on.
  890. SourceFileAccess &= ~GENERIC_WRITE;
  891. if( SourceFileAccessDefault & ACCESS_SYSTEM_SECURITY ) {
  892. SourceFileAccess |= ACCESS_SYSTEM_SECURITY;
  893. }
  894. }
  895. // Try sharing for writing.
  896. else if( !(FILE_SHARE_WRITE & SourceFileSharing) ) {
  897. // Add write-sharing
  898. SourceFileSharing |= FILE_SHARE_WRITE;
  899. // Start back over wrt the access flags
  900. SourceFileAccess = SourceFileAccessDefault;
  901. }
  902. //
  903. // There is the case when we still do not get the file opened and we
  904. // do want to proceed with the copy. Pre NT 5.0 systems do not support
  905. // FILE_FLAG_OPEN_REPARSE_POINT. If this happens, by initialization we
  906. // have that:
  907. // IsNameGrafting is FALSE and
  908. // bCopyRawSourceFile is FALSE and
  909. // bOpenFilesAsReparsePoint is FALSE
  910. //
  911. else if( FILE_FLAG_OPEN_REPARSE_POINT & SourceFileFlagsAndAttributes ) {
  912. // Turn off open-reparse
  913. SourceFileFlagsAndAttributes &= ~FILE_FLAG_OPEN_REPARSE_POINT;
  914. // Reset the access & sharing back to default
  915. SourceFileAccess = SourceFileAccessDefault;
  916. SourceFileSharing = SourceFileSharingDefault;
  917. }
  918. // Otherwise there's nothing more we can try.
  919. else {
  920. leave;
  921. }
  922. } // if ( SourceFile == INVALID_HANDLE_VALUE )
  923. // We've opened the source file. If we haven't yet checked for
  924. // name grafting (symbolic links), do so now.
  925. else if( !CheckedForNameGrafting ) {
  926. CheckedForNameGrafting = TRUE;
  927. //
  928. // Find out whether the file is a symbolic link and whether a reparse
  929. // point can be copied with the reparse behavior inhibited.
  930. //
  931. Status = BasepProcessNameGrafting( SourceFile,
  932. &IsNameGrafting,
  933. &bCopyRawSourceFile,
  934. &bOpenFilesAsReparsePoint,
  935. &FileTagInformation );
  936. if( !NT_SUCCESS(Status) ) {
  937. CloseHandle( SourceFile );
  938. SourceFile = INVALID_HANDLE_VALUE;
  939. BaseSetLastNTError(Status);
  940. leave;
  941. }
  942. if ( IsNameGrafting ) {
  943. //
  944. // Do now the copy of a name grafting file/directory.
  945. //
  946. Status = CopyNameGraftNow(
  947. SourceFile,
  948. lpExistingFileName,
  949. lpNewFileName,
  950. (PRIVCOPY_FILE_DIRECTORY & dwPrivCopyFlags)
  951. ? (FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT)
  952. : 0,
  953. lpProgressRoutine,
  954. lpData,
  955. pbCancel,
  956. &dwCopyFlags
  957. );
  958. CloseHandle(SourceFile);
  959. SourceFile = INVALID_HANDLE_VALUE;
  960. if( !Status ) {
  961. b = FALSE;
  962. leave;
  963. }
  964. b = TRUE;
  965. leave;
  966. }
  967. // If we're doing a raw copy, we can start doing the copy with this
  968. // SourceFile handle.
  969. if ( bCopyRawSourceFile ) {
  970. break; // while( TRUE )
  971. }
  972. // Otherwise, we need to reopen without FILE_FLAG_OPEN_REPARSE_POINT;
  973. else {
  974. // Turn off open-as-reparse
  975. SourceFileFlagsAndAttributes &= ~FILE_FLAG_OPEN_REPARSE_POINT;
  976. CloseHandle( SourceFile );
  977. SourceFile = INVALID_HANDLE_VALUE;
  978. // Since SourceFileAccess & SourceFileSharing are already set,
  979. // the next CreateFile attempt should succeed.
  980. }
  981. } // else if( !CheckedForNameGrafting )
  982. // Otherwise, we have the file open, and we're done checking for grafting
  983. else {
  984. break;
  985. }
  986. } // while( TRUE )
  987. //
  988. // Size the source file to determine how much data is to be copied
  989. //
  990. Status = NtQueryInformationFile(
  991. SourceFile,
  992. &IoStatus,
  993. (PVOID) &FileInformation,
  994. sizeof(FileInformation),
  995. FileStandardInformation
  996. );
  997. if ( !NT_SUCCESS(Status) ) {
  998. BaseSetLastNTError(Status);
  999. leave;
  1000. }
  1001. //
  1002. // Get the timestamp info as well.
  1003. //
  1004. Status = NtQueryInformationFile(
  1005. SourceFile,
  1006. &IoStatus,
  1007. (PVOID) &BasicInformation,
  1008. sizeof(BasicInformation),
  1009. FileBasicInformation
  1010. );
  1011. if ( !NT_SUCCESS(Status) ) {
  1012. BaseSetLastNTError(Status);
  1013. leave;
  1014. }
  1015. SourceFileAttributes = BasicInformation.FileAttributes; // Cache for later use
  1016. //
  1017. // Set up the context if appropriate.
  1018. //
  1019. if ( ARGUMENT_PRESENT(lpProgressRoutine) || ARGUMENT_PRESENT(pbCancel) ) {
  1020. CfContext.TotalFileSize = FileInformation.EndOfFile;
  1021. CfContext.TotalBytesTransferred.QuadPart = 0;
  1022. CfContext.dwStreamNumber = 0;
  1023. CfContext.lpCancel = pbCancel;
  1024. CfContext.lpData = lpData;
  1025. CfContext.lpProgressRoutine = lpProgressRoutine;
  1026. CopyFileContext = &CfContext;
  1027. }
  1028. //
  1029. // Obtain the full set of streams we have to copy. Since the Io subsystem does
  1030. // not provide us a way to find out how much space this information will take,
  1031. // we must iterate the call, doubling the buffer size upon each failure.
  1032. //
  1033. // If the underlying file system does not support stream enumeration, we end up
  1034. // with a NULL buffer. This is acceptable since we have at least a default
  1035. // data stream.
  1036. //
  1037. // We also allocate one more character than necessary since we use the returned
  1038. // stream names in place when calling BaseCopyStream and we must NUL-terminate
  1039. // the names
  1040. //
  1041. StreamInfoSize = 4096;
  1042. do {
  1043. StreamInfoBase = RtlAllocateHeap( RtlProcessHeap(),
  1044. MAKE_TAG( TMP_TAG ),
  1045. StreamInfoSize );
  1046. if ( !StreamInfoBase ) {
  1047. BaseSetLastNTError( STATUS_NO_MEMORY );
  1048. leave;
  1049. }
  1050. Status = NtQueryInformationFile(
  1051. SourceFile,
  1052. &IoStatus,
  1053. (PVOID) StreamInfoBase,
  1054. StreamInfoSize - sizeof( WCHAR ),
  1055. FileStreamInformation
  1056. );
  1057. if ( !NT_SUCCESS(Status) ) {
  1058. //
  1059. // We failed the call. Free up the previous buffer and set up
  1060. // for another pass with a buffer twice as large
  1061. //
  1062. RtlFreeHeap(RtlProcessHeap(), 0, StreamInfoBase);
  1063. StreamInfoBase = NULL;
  1064. StreamInfoSize *= 2;
  1065. }
  1066. else if( IoStatus.Information == 0 ) {
  1067. //
  1068. // There are no streams (SourceFile must be a directory).
  1069. //
  1070. RtlFreeHeap(RtlProcessHeap(), 0, StreamInfoBase);
  1071. StreamInfoBase = NULL;
  1072. }
  1073. } while ( Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL );
  1074. //
  1075. // If a progress routine or a restartable copy was requested, obtain the
  1076. // full size of the entire file, including its alternate data streams, etc.
  1077. //
  1078. if ( ARGUMENT_PRESENT(lpProgressRoutine) ||
  1079. (dwCopyFlags & COPY_FILE_RESTARTABLE) ) {
  1080. if ( dwCopyFlags & COPY_FILE_RESTARTABLE ) {
  1081. RestartState.Type = 0x7a9b;
  1082. RestartState.Size = sizeof( RESTART_STATE );
  1083. RestartState.CreationTime = BasicInformation.CreationTime;
  1084. RestartState.WriteTime = BasicInformation.LastWriteTime;
  1085. RestartState.EndOfFile = FileInformation.EndOfFile;
  1086. RestartState.FileSize = FileInformation.EndOfFile;
  1087. RestartState.NumberOfStreams = 0;
  1088. RestartState.CurrentStream = 0;
  1089. RestartState.LastKnownGoodOffset.QuadPart = 0;
  1090. }
  1091. if ( StreamInfoBase != NULL ) {
  1092. ULONGLONG TotalSize = 0;
  1093. StreamInfo = StreamInfoBase;
  1094. while (TRUE) {
  1095. //
  1096. // Account for the size of this stream in the overall size of
  1097. // the file.
  1098. //
  1099. TotalSize += StreamInfo->StreamSize.QuadPart;
  1100. RestartState.NumberOfStreams++;
  1101. if (StreamInfo->NextEntryOffset == 0) {
  1102. break;
  1103. }
  1104. StreamInfo = (PFILE_STREAM_INFORMATION)((PCHAR) StreamInfo + StreamInfo->NextEntryOffset);
  1105. }
  1106. RestartState.FileSize.QuadPart =
  1107. CfContext.TotalFileSize.QuadPart = TotalSize;
  1108. RestartState.NumberOfStreams--;
  1109. }
  1110. }
  1111. //
  1112. // Set the Basic Info to change only the WriteTime
  1113. //
  1114. BasicInformation.CreationTime.QuadPart = 0;
  1115. BasicInformation.LastAccessTime.QuadPart = 0;
  1116. BasicInformation.FileAttributes = 0;
  1117. //
  1118. // Determine whether or not the copy operation should really be restartable
  1119. // based on the actual, total file size.
  1120. //
  1121. if ( (dwCopyFlags & COPY_FILE_RESTARTABLE) &&
  1122. ( RestartState.FileSize.QuadPart < (512 * 1024) ||
  1123. (SourceFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )) {
  1124. dwCopyFlags &= ~COPY_FILE_RESTARTABLE;
  1125. }
  1126. //
  1127. // Copy the default data stream, EAs, etc. to the output file
  1128. //
  1129. b = BaseCopyStream(
  1130. lpExistingFileName,
  1131. SourceFile,
  1132. SourceFileAccess,
  1133. lpNewFileName,
  1134. NULL,
  1135. &FileInformation.EndOfFile,
  1136. &dwCopyFlags,
  1137. &DestFile,
  1138. &CopySize,
  1139. &CopyFileContext,
  1140. &RestartState,
  1141. bOpenFilesAsReparsePoint,
  1142. FileTagInformation.ReparseTag,
  1143. &DestFileFsAttributes // In: 0, Out: Correct value
  1144. );
  1145. if ( bOpenFilesAsReparsePoint &&
  1146. !b &&
  1147. !((GetLastError() == ERROR_FILE_EXISTS) && (dwCopyFlags & COPY_FILE_FAIL_IF_EXISTS)) ) {
  1148. //
  1149. // Clean up.
  1150. //
  1151. if (!(SourceFileAttributes & FILE_ATTRIBUTE_READONLY)) {
  1152. BaseMarkFileForDelete(DestFile, FILE_ATTRIBUTE_NORMAL);
  1153. }
  1154. if (DestFile != INVALID_HANDLE_VALUE) {
  1155. CloseHandle( DestFile );
  1156. DestFile = INVALID_HANDLE_VALUE;
  1157. }
  1158. if (SourceFileAttributes & FILE_ATTRIBUTE_READONLY) {
  1159. // Delete the destination file before retry
  1160. // Some servers (like Win9x) won't let us set file attributes
  1161. // on the handle we already have opened. SetFileAttributesW
  1162. // can do the job nicely, so we'll call that to make sure that
  1163. // the read-only bit isn't set.
  1164. // We had to close DestFile before doing this because it was
  1165. // possibly opened share-exclusive.
  1166. SetFileAttributesW(lpNewFileName, FILE_ATTRIBUTE_NORMAL);
  1167. (void) DeleteFileW(lpNewFileName);
  1168. }
  1169. if (SourceFile != INVALID_HANDLE_VALUE) {
  1170. CloseHandle( SourceFile );
  1171. SourceFile = INVALID_HANDLE_VALUE;
  1172. }
  1173. RtlFreeHeap( RtlProcessHeap(), 0, StreamInfoBase );
  1174. StreamInfoBase = NULL ;
  1175. //
  1176. // Try again the copy operation without inhibiting the reparse
  1177. // behavior for the source.
  1178. //
  1179. SourceFileFlagsAndAttributes &= ~FILE_FLAG_OPEN_REPARSE_POINT;
  1180. bOpenFilesAsReparsePoint = FALSE;
  1181. //
  1182. // Go to re-open the source file without inhibiting the reparse
  1183. // point behavior and try the copy again.
  1184. //
  1185. goto retry_open_SourceFile;
  1186. }
  1187. if ( b ) {
  1188. //
  1189. // Attempt to determine whether or not this file has any alternate
  1190. // data streams associated with it. If it does, attempt to copy each
  1191. // to the output file. Note that the stream information may have
  1192. // already been obtained if a progress routine was requested.
  1193. //
  1194. if ( StreamInfoBase != NULL ) {
  1195. DWORD StreamCount = 0;
  1196. BOOLEAN CheckedForStreamCapable = FALSE;
  1197. BOOLEAN IsStreamCapable = FALSE;
  1198. StreamInfo = StreamInfoBase;
  1199. while (TRUE) {
  1200. FILE_STREAM_INFORMATION DestStreamInformation;
  1201. Status = STATUS_SUCCESS;
  1202. //
  1203. // Skip the default data stream since we've already copied
  1204. // it. Alas, this code is NTFS specific and documented
  1205. // nowhere in the Io spec.
  1206. //
  1207. if (StreamInfo->StreamNameLength <= sizeof(WCHAR) ||
  1208. StreamInfo->StreamName[1] == ':') {
  1209. if (StreamInfo->NextEntryOffset == 0)
  1210. break; // Done with streams
  1211. StreamInfo = (PFILE_STREAM_INFORMATION)((PCHAR) StreamInfo +
  1212. StreamInfo->NextEntryOffset);
  1213. continue; // Move on to the next stream
  1214. }
  1215. StreamCount++;
  1216. if ( b == SUCCESS_RETURNED_STATE && CopyFileContext ) {
  1217. if ( StreamCount < RestartState.CurrentStream ) {
  1218. CopyFileContext->TotalBytesTransferred.QuadPart += StreamInfo->StreamSize.QuadPart;
  1219. }
  1220. else {
  1221. CopyFileContext->TotalBytesTransferred.QuadPart += RestartState.LastKnownGoodOffset.QuadPart;
  1222. }
  1223. }
  1224. //
  1225. // If we haven't already, verify that both the source and destination
  1226. // are really stream capable.
  1227. //
  1228. if( !CheckedForStreamCapable ) {
  1229. struct {
  1230. FILE_FS_ATTRIBUTE_INFORMATION Info;
  1231. WCHAR Buffer[ MAX_PATH ];
  1232. } FileFsAttrInfoBuffer;
  1233. CheckedForStreamCapable = TRUE;
  1234. // Check for the supports-streams bit in the dest filesystem.
  1235. Status = NtQueryVolumeInformationFile( DestFile,
  1236. &IoStatus,
  1237. &FileFsAttrInfoBuffer.Info,
  1238. sizeof(FileFsAttrInfoBuffer),
  1239. FileFsAttributeInformation );
  1240. if( NT_SUCCESS(Status) &&
  1241. (FileFsAttrInfoBuffer.Info.FileSystemAttributes & FILE_NAMED_STREAMS) ) {
  1242. // It seems redundant to check to see if the source is stream capable,
  1243. // since we already got back a successful stream enumeration, but some
  1244. // SMB servers (SCO VisionFS) return success but don't really support
  1245. // streams.
  1246. Status = NtQueryVolumeInformationFile( SourceFile,
  1247. &IoStatus,
  1248. &FileFsAttrInfoBuffer.Info,
  1249. sizeof(FileFsAttrInfoBuffer),
  1250. FileFsAttributeInformation );
  1251. }
  1252. if( !NT_SUCCESS(Status) ||
  1253. !(FileFsAttrInfoBuffer.Info.FileSystemAttributes & FILE_NAMED_STREAMS) ) {
  1254. if( NT_SUCCESS(Status) ) {
  1255. Status = STATUS_NOT_SUPPORTED;
  1256. }
  1257. if( dwCopyFlags & PRIVCOPY_FILE_VALID_FLAGS ) {
  1258. if( !BasepCopyFileCallback( TRUE, // Continue by default
  1259. RtlNtStatusToDosError(Status),
  1260. CopyFileContext,
  1261. NULL,
  1262. PRIVCALLBACK_STREAMS_NOT_SUPPORTED,
  1263. SourceFile,
  1264. DestFile,
  1265. NULL )) {
  1266. // LastError has been set, but we need it in Status
  1267. // for compatibility with the rest of this routine.
  1268. PTEB Teb = NtCurrentTeb();
  1269. if ( Teb ) {
  1270. Status = Teb->LastStatusValue;
  1271. } else {
  1272. Status = STATUS_INVALID_PARAMETER;
  1273. }
  1274. b = FALSE;
  1275. } else {
  1276. // Ignore the named stream loss
  1277. Status = STATUS_SUCCESS;
  1278. }
  1279. } else {
  1280. // Ignore the named stream loss. We'll still try to copy the
  1281. // streams, though, since the target might be NT4 which didn't support
  1282. // the FILE_NAMED_STREAMS bit. But since IsStreamCapable is FALSE,
  1283. // if there's an error, we'll ignore it.
  1284. Status = STATUS_SUCCESS;
  1285. }
  1286. }
  1287. else {
  1288. Status = STATUS_SUCCESS;
  1289. IsStreamCapable = TRUE;
  1290. }
  1291. } // if( !CheckedForStreamCapable )
  1292. if ( b == TRUE ||
  1293. (b == SUCCESS_RETURNED_STATE &&
  1294. RestartState.CurrentStream == StreamCount) ) {
  1295. if ( b != SUCCESS_RETURNED_STATE ) {
  1296. RestartState.CurrentStream = StreamCount;
  1297. RestartState.LastKnownGoodOffset.QuadPart = 0;
  1298. }
  1299. //
  1300. // Build a string descriptor for the name of the stream.
  1301. //
  1302. StreamName.Buffer = &StreamInfo->StreamName[0];
  1303. StreamName.Length = (USHORT) StreamInfo->StreamNameLength;
  1304. StreamName.MaximumLength = StreamName.Length;
  1305. //
  1306. // Open the source stream.
  1307. //
  1308. InitializeObjectAttributes(
  1309. &ObjectAttributes,
  1310. &StreamName,
  1311. 0,
  1312. SourceFile,
  1313. NULL
  1314. );
  1315. //
  1316. // Inhibit reparse behavior when appropriate.
  1317. //
  1318. FlagsAndAttributes = FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY;
  1319. if ( bOpenFilesAsReparsePoint ) {
  1320. FlagsAndAttributes |= FILE_OPEN_REPARSE_POINT;
  1321. }
  1322. Status = NtCreateFile(
  1323. &StreamHandle,
  1324. GENERIC_READ | SYNCHRONIZE,
  1325. &ObjectAttributes,
  1326. &IoStatus,
  1327. NULL,
  1328. 0,
  1329. FILE_SHARE_READ,
  1330. FILE_OPEN,
  1331. FlagsAndAttributes,
  1332. NULL,
  1333. 0
  1334. );
  1335. //If we got a share violation, try again with
  1336. // FILE_SHARE_WRITE.
  1337. if ( Status == STATUS_SHARING_VIOLATION ) {
  1338. DWORD dwShare = FILE_SHARE_READ | FILE_SHARE_WRITE;
  1339. Status = NtCreateFile(
  1340. &StreamHandle,
  1341. GENERIC_READ | SYNCHRONIZE,
  1342. &ObjectAttributes,
  1343. &IoStatus,
  1344. NULL,
  1345. 0,
  1346. dwShare,
  1347. FILE_OPEN,
  1348. FlagsAndAttributes,
  1349. NULL,
  1350. 0
  1351. );
  1352. }
  1353. if ( NT_SUCCESS(Status) ) {
  1354. DWORD dwCopyFlagsNamedStreams;
  1355. WCHAR LastChar = StreamName.Buffer[StreamName.Length / sizeof( WCHAR )];
  1356. StreamName.Buffer[StreamName.Length / sizeof( WCHAR )] = L'\0';
  1357. OutputStream = (HANDLE)NULL;
  1358. //
  1359. // For named streams, ignore the fail-if-exists flag. If the dest
  1360. // file already existed at the time the copy started, then
  1361. // we would have failed on the copy of the unnamed stream. So if
  1362. // a named stream exists, that means that it was created by some
  1363. // other process while we were copying the unnamed stream. The
  1364. // assumption is that such a stream should be overwritten (this
  1365. // scenario can occur with SFM).
  1366. //
  1367. dwCopyFlagsNamedStreams = dwCopyFlags & ~COPY_FILE_FAIL_IF_EXISTS;
  1368. b = BaseCopyStream(
  1369. lpExistingFileName,
  1370. StreamHandle,
  1371. SourceFileAccess,
  1372. StreamName.Buffer,
  1373. DestFile,
  1374. &StreamInfo->StreamSize,
  1375. &dwCopyFlagsNamedStreams,
  1376. &OutputStream,
  1377. &CopySize,
  1378. &CopyFileContext,
  1379. &RestartState,
  1380. bOpenFilesAsReparsePoint,
  1381. FileTagInformation.ReparseTag,
  1382. &DestFileFsAttributes // Set by first call to BaseCopyStream
  1383. );
  1384. StreamName.Buffer[StreamName.Length / sizeof( WCHAR )] = LastChar;
  1385. NtClose(StreamHandle);
  1386. if ( OutputStream ) {
  1387. //
  1388. // We set the last write time on all streams
  1389. // since there is a problem with RDR caching
  1390. // open handles and closing them out of order.
  1391. //
  1392. if ( b ) {
  1393. Status = NtSetInformationFile(
  1394. OutputStream,
  1395. &IoStatus,
  1396. &BasicInformation,
  1397. sizeof(BasicInformation),
  1398. FileBasicInformation
  1399. );
  1400. }
  1401. NtClose(OutputStream);
  1402. }
  1403. } // Status = NtCreateFile; if( NT_SUCCESS(Status) )
  1404. } // if ( b == TRUE || ...
  1405. if ( !NT_SUCCESS(Status) ) {
  1406. b = FALSE;
  1407. BaseSetLastNTError(Status);
  1408. }
  1409. if ( !b ) {
  1410. // If the target is known to be capable of multi-stream files,
  1411. // then this is a fatal error. Otherwise we'll ignore it.
  1412. if( IsStreamCapable ) {
  1413. BaseMarkFileForDelete(DestFile,0);
  1414. break; // while( TRUE )
  1415. } else {
  1416. Status = STATUS_SUCCESS;
  1417. b = TRUE;
  1418. }
  1419. }
  1420. if (StreamInfo->NextEntryOffset == 0) {
  1421. break;
  1422. }
  1423. StreamInfo =
  1424. (PFILE_STREAM_INFORMATION)((PCHAR) StreamInfo +
  1425. StreamInfo->NextEntryOffset);
  1426. } // while (TRUE)
  1427. } // if ( StreamInfoBase != NULL )
  1428. } // b = BaseCopyStream; if ( b ) ...
  1429. //
  1430. // If the copy operation was successful, and it was restartable, and the
  1431. // output file was large enough that it was actually copied in a
  1432. // restartable manner, then copy the initial part of the file to its
  1433. // output.
  1434. //
  1435. // Restartability is accomplished by placing a restart header at the
  1436. // head of the default data stream. When the copy is complete, we
  1437. // overwite this header with the real user data.
  1438. //
  1439. if ( b && (dwCopyFlags & COPY_FILE_RESTARTABLE) ) {
  1440. DWORD BytesToRead, BytesRead;
  1441. DWORD BytesWritten;
  1442. FILE_END_OF_FILE_INFORMATION EofInformation;
  1443. SetFilePointer( SourceFile, 0, NULL, FILE_BEGIN );
  1444. SetFilePointer( DestFile, 0, NULL, FILE_BEGIN );
  1445. BytesToRead = sizeof(RESTART_STATE);
  1446. if ( FileInformation.EndOfFile.QuadPart < sizeof(RESTART_STATE) ) {
  1447. BytesToRead = FileInformation.EndOfFile.LowPart;
  1448. }
  1449. //
  1450. // Grab true data from the source stream
  1451. //
  1452. b = ReadFile(
  1453. SourceFile,
  1454. &RestartState,
  1455. BytesToRead,
  1456. &BytesRead,
  1457. NULL
  1458. );
  1459. if ( b && (BytesRead == BytesToRead) ) {
  1460. //
  1461. // Overwrite the restart header in the destination.
  1462. // After this point, the copy is no longer restartable
  1463. //
  1464. b = WriteFile(
  1465. DestFile,
  1466. &RestartState,
  1467. BytesRead,
  1468. &BytesWritten,
  1469. NULL
  1470. );
  1471. if ( b && (BytesRead == BytesWritten) ) {
  1472. if ( BytesRead < sizeof(RESTART_STATE) ) {
  1473. EofInformation.EndOfFile.QuadPart = BytesWritten;
  1474. Status = NtSetInformationFile(
  1475. DestFile,
  1476. &IoStatus,
  1477. &EofInformation,
  1478. sizeof(EofInformation),
  1479. FileEndOfFileInformation
  1480. );
  1481. if ( !NT_SUCCESS(Status) ) {
  1482. BaseMarkFileForDelete(DestFile,0);
  1483. b = FALSE;
  1484. }
  1485. }
  1486. } else {
  1487. BaseMarkFileForDelete(DestFile,0);
  1488. b = FALSE;
  1489. }
  1490. } else {
  1491. BaseMarkFileForDelete(DestFile,0);
  1492. b = FALSE;
  1493. }
  1494. }
  1495. //
  1496. // If the copy operation was successful, set the last write time for the
  1497. // default steam so that it matches the input file.
  1498. //
  1499. if ( b ) {
  1500. Status = NtSetInformationFile(
  1501. DestFile,
  1502. &IoStatus,
  1503. &BasicInformation,
  1504. sizeof(BasicInformation),
  1505. FileBasicInformation
  1506. );
  1507. if ( Status == STATUS_SHARING_VIOLATION ) {
  1508. //
  1509. // IBM PC Lan Program (and other MS-NET servers) return
  1510. // STATUS_SHARING_VIOLATION if an application attempts to perform
  1511. // an NtSetInformationFile on a file handle opened for GENERIC_READ
  1512. // or GENERIC_WRITE.
  1513. //
  1514. // If we get a STATUS_SHARING_VIOLATION on this API we want to:
  1515. //
  1516. // 1) Close the handle to the destination
  1517. // 2) Re-open the file for FILE_WRITE_ATTRIBUTES
  1518. // 3) Re-try the operation.
  1519. //
  1520. CloseHandle(DestFile);
  1521. DestFile = INVALID_HANDLE_VALUE;
  1522. //
  1523. // Re-Open the destination file. Please note that we do this
  1524. // using the CreateFileW API. The CreateFileW API allows you to
  1525. // pass NT native desired access flags, even though it is not
  1526. // documented to work in this manner.
  1527. //
  1528. // Inhibit reparse behavior when appropriate.
  1529. //
  1530. FlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
  1531. if ( bOpenFilesAsReparsePoint ) {
  1532. FlagsAndAttributes |= FILE_FLAG_OPEN_REPARSE_POINT;
  1533. }
  1534. DestFile = CreateFileW(
  1535. lpNewFileName,
  1536. FILE_WRITE_ATTRIBUTES,
  1537. 0,
  1538. NULL,
  1539. OPEN_EXISTING,
  1540. FlagsAndAttributes | FileFlagBackupSemantics,
  1541. NULL
  1542. );
  1543. if ( DestFile != INVALID_HANDLE_VALUE ) {
  1544. //
  1545. // If the open succeeded, we update the file information on
  1546. // the new file.
  1547. //
  1548. // Note that we ignore any errors from this point on.
  1549. //
  1550. NtSetInformationFile(
  1551. DestFile,
  1552. &IoStatus,
  1553. &BasicInformation,
  1554. sizeof(BasicInformation),
  1555. FileBasicInformation
  1556. );
  1557. }
  1558. }
  1559. }
  1560. } finally {
  1561. *phSource = SourceFile;
  1562. *phDest = DestFile;
  1563. RtlFreeHeap( RtlProcessHeap(), 0, StreamInfoBase );
  1564. }
  1565. return b;
  1566. }
  1567. BOOL
  1568. CopyFileExW(
  1569. LPCWSTR lpExistingFileName,
  1570. LPCWSTR lpNewFileName,
  1571. LPPROGRESS_ROUTINE lpProgressRoutine OPTIONAL,
  1572. LPVOID lpData OPTIONAL,
  1573. LPBOOL pbCancel OPTIONAL,
  1574. DWORD dwCopyFlags
  1575. )
  1576. /*
  1577. Routine Description:
  1578. A file, its extended attributes, alternate data streams, and any other
  1579. attributes can be copied using CopyFileEx. CopyFileEx also provides
  1580. callbacks and cancellability.
  1581. Arguments:
  1582. lpExistingFileName - Supplies the name of an existing file that is to be
  1583. copied.
  1584. lpNewFileName - Supplies the name where a copy of the existing
  1585. files data and attributes are to be stored.
  1586. lpProgressRoutine - Optionally supplies the address of a callback routine
  1587. to be called as the copy operation progresses.
  1588. lpData - Optionally supplies a context to be passed to the progress callback
  1589. routine.
  1590. lpCancel - Optionally supplies the address of a boolean to be set to TRUE
  1591. if the caller would like the copy to abort.
  1592. dwCopyFlags - Specifies flags that modify how the file is to be copied:
  1593. COPY_FILE_FAIL_IF_EXISTS - Indicates that the copy operation should
  1594. fail immediately if the target file already exists.
  1595. COPY_FILE_RESTARTABLE - Indicates that the file should be copied in
  1596. restartable mode; i.e., progress of the copy should be tracked in
  1597. the target file in case the copy fails for some reason. It can
  1598. then be restarted at a later date.
  1599. Return Value:
  1600. TRUE - The operation was successful.
  1601. FALSE/NULL - The operation failed. Extended error status is available
  1602. using GetLastError.
  1603. */
  1604. {
  1605. HANDLE DestFile = INVALID_HANDLE_VALUE;
  1606. HANDLE SourceFile = INVALID_HANDLE_VALUE;
  1607. BOOL b;
  1608. try
  1609. {
  1610. b = BasepCopyFileExW(
  1611. lpExistingFileName,
  1612. lpNewFileName,
  1613. lpProgressRoutine OPTIONAL,
  1614. lpData OPTIONAL,
  1615. pbCancel OPTIONAL,
  1616. dwCopyFlags,
  1617. 0, // PrivCopyFile flags
  1618. &DestFile,
  1619. &SourceFile
  1620. );
  1621. }
  1622. finally
  1623. {
  1624. if (DestFile != INVALID_HANDLE_VALUE) {
  1625. CloseHandle( DestFile );
  1626. }
  1627. if (SourceFile != INVALID_HANDLE_VALUE) {
  1628. CloseHandle( SourceFile );
  1629. }
  1630. }
  1631. return(b);
  1632. }
  1633. BOOL
  1634. PrivCopyFileExW(
  1635. LPCWSTR lpExistingFileName,
  1636. LPCWSTR lpNewFileName,
  1637. LPPROGRESS_ROUTINE lpProgressRoutine OPTIONAL,
  1638. LPVOID lpData OPTIONAL,
  1639. LPBOOL pbCancel OPTIONAL,
  1640. DWORD dwCopyFlags
  1641. )
  1642. /*
  1643. Routine Description:
  1644. A file, its extended attributes, alternate data streams, and any other
  1645. attributes can be copied using CopyFileEx. CopyFileEx also provides
  1646. callbacks and cancellability.
  1647. Arguments:
  1648. lpExistingFileName - Supplies the name of an existing file that is to be
  1649. copied.
  1650. lpNewFileName - Supplies the name where a copy of the existing
  1651. files data and attributes are to be stored.
  1652. lpProgressRoutine - Optionally supplies the address of a callback routine
  1653. to be called as the copy operation progresses.
  1654. lpData - Optionally supplies a context to be passed to the progress callback
  1655. routine.
  1656. lpCancel - Optionally supplies the address of a boolean to be set to TRUE
  1657. if the caller would like the copy to abort.
  1658. dwCopyFlags - Specifies flags that modify how the file is to be copied:
  1659. COPY_FILE_FAIL_IF_EXISTS - Indicates that the copy operation should
  1660. fail immediately if the target file already exists.
  1661. COPY_FILE_RESTARTABLE - Indicates that the file should be copied in
  1662. restartable mode; i.e., progress of the copy should be tracked in
  1663. the target file in case the copy fails for some reason. It can
  1664. then be restarted at a later date.
  1665. Return Value:
  1666. TRUE - The operation was successful.
  1667. FALSE/NULL - The operation failed. Extended error status is available
  1668. using GetLastError.
  1669. */
  1670. {
  1671. HANDLE DestFile = INVALID_HANDLE_VALUE;
  1672. HANDLE SourceFile = INVALID_HANDLE_VALUE;
  1673. BOOL b;
  1674. if( (dwCopyFlags & COPY_FILE_FAIL_IF_EXISTS) &&
  1675. (dwCopyFlags & PRIVCOPY_FILE_SUPERSEDE) ) {
  1676. SetLastError( ERROR_INVALID_PARAMETER );
  1677. return( FALSE );
  1678. }
  1679. try
  1680. {
  1681. b = BasepCopyFileExW(
  1682. lpExistingFileName,
  1683. lpNewFileName,
  1684. lpProgressRoutine OPTIONAL,
  1685. lpData OPTIONAL,
  1686. pbCancel OPTIONAL,
  1687. dwCopyFlags & COPY_FILE_VALID_FLAGS, // Copy flags
  1688. dwCopyFlags & ~COPY_FILE_VALID_FLAGS, // Priv copy flags
  1689. &DestFile,
  1690. &SourceFile
  1691. );
  1692. }
  1693. finally
  1694. {
  1695. if (DestFile != INVALID_HANDLE_VALUE) {
  1696. CloseHandle( DestFile );
  1697. }
  1698. if (SourceFile != INVALID_HANDLE_VALUE) {
  1699. CloseHandle( SourceFile );
  1700. }
  1701. }
  1702. return(b);
  1703. }
  1704. DWORD
  1705. BasepChecksum(
  1706. PUSHORT Source,
  1707. ULONG Length
  1708. )
  1709. /*++
  1710. Routine Description:
  1711. Compute a partial checksum on a structure.
  1712. Arguments:
  1713. Source - Supplies a pointer to the array of words for which the
  1714. checksum is computed.
  1715. Length - Supplies the length of the array in words.
  1716. Return Value:
  1717. The computed checksum value is returned as the function value.
  1718. --*/
  1719. {
  1720. ULONG PartialSum = 0;
  1721. //
  1722. // Compute the word wise checksum allowing carries to occur into the
  1723. // high order half of the checksum longword.
  1724. //
  1725. while (Length--) {
  1726. PartialSum += *Source++;
  1727. PartialSum = (PartialSum >> 16) + (PartialSum & 0xffff);
  1728. }
  1729. //
  1730. // Fold final carry into a single word result and return the resultant
  1731. // value.
  1732. //
  1733. return (((PartialSum >> 16) + PartialSum) & 0xffff);
  1734. }
  1735. BOOL
  1736. BasepRemoteFile(
  1737. HANDLE SourceFile,
  1738. HANDLE DestinationFile
  1739. )
  1740. {
  1741. NTSTATUS Status;
  1742. IO_STATUS_BLOCK IoStatus;
  1743. FILE_FS_DEVICE_INFORMATION DeviceInformation;
  1744. DeviceInformation.Characteristics = 0;
  1745. Status = NtQueryVolumeInformationFile(
  1746. SourceFile,
  1747. &IoStatus,
  1748. &DeviceInformation,
  1749. sizeof(DeviceInformation),
  1750. FileFsDeviceInformation
  1751. );
  1752. if ( NT_SUCCESS(Status) &&
  1753. (DeviceInformation.Characteristics & FILE_REMOTE_DEVICE) ) {
  1754. return TRUE;
  1755. }
  1756. Status = NtQueryVolumeInformationFile(
  1757. DestinationFile,
  1758. &IoStatus,
  1759. &DeviceInformation,
  1760. sizeof(DeviceInformation),
  1761. FileFsDeviceInformation
  1762. );
  1763. if ( NT_SUCCESS(Status) &&
  1764. DeviceInformation.Characteristics & FILE_REMOTE_DEVICE ) {
  1765. return TRUE;
  1766. }
  1767. return FALSE;
  1768. }
  1769. DWORD
  1770. WINAPI
  1771. BasepOpenRestartableFile(
  1772. HANDLE hSourceFile,
  1773. LPCWSTR lpNewFileName,
  1774. PHANDLE DestFile,
  1775. DWORD CopyFlags,
  1776. LPRESTART_STATE lpRestartState,
  1777. LARGE_INTEGER *lpFileSize,
  1778. LPCOPYFILE_CONTEXT *lpCopyFileContext,
  1779. DWORD FlagsAndAttributes,
  1780. BOOL OpenAsReparsePoint )
  1781. { // BasepRestartCopyFile
  1782. LPCOPYFILE_CONTEXT Context = *lpCopyFileContext;
  1783. OBJECT_ATTRIBUTES ObjectAttributes;
  1784. UNICODE_STRING UnicodeString;
  1785. HANDLE OverwriteHandle;
  1786. IO_STATUS_BLOCK IoStatus;
  1787. RESTART_STATE RestartState;
  1788. DWORD b = TRUE;
  1789. ULONG BytesRead = 0;
  1790. try {
  1791. //
  1792. // Note that setting the sequential scan flag is an optimization
  1793. // here that works because of the way that the Cache Manager on
  1794. // the target works vis-a-vis unmapping segments of the file
  1795. // behind write operations. This eventually allows the restart
  1796. // section and the end of the file to both be mapped, which is
  1797. // the desired result.
  1798. //
  1799. // Inhibit reparse behavior when appropriate.
  1800. //
  1801. FlagsAndAttributes |= FILE_FLAG_SEQUENTIAL_SCAN;
  1802. if ( OpenAsReparsePoint ) {
  1803. //
  1804. // The target has to be opened as reparse point. If
  1805. // this fails the source is to be closed and re-opened
  1806. // without inhibiting the reparse point behavior.
  1807. //
  1808. FlagsAndAttributes |= FILE_FLAG_OPEN_REPARSE_POINT;
  1809. }
  1810. *DestFile = CreateFileW(
  1811. lpNewFileName,
  1812. GENERIC_READ | GENERIC_WRITE | DELETE,
  1813. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1814. NULL,
  1815. OPEN_EXISTING,
  1816. FlagsAndAttributes,
  1817. hSourceFile
  1818. );
  1819. if( *DestFile == INVALID_HANDLE_VALUE ) {
  1820. // Caller should attempt to create/overwrite the dest file
  1821. b = TRUE;
  1822. leave;
  1823. }
  1824. //
  1825. // The target file already exists, so determine whether
  1826. // a restartable copy was already proceeding. If so,
  1827. // then continue; else, check to see whether or not
  1828. // the target file can be replaced. If not, bail with
  1829. // an error, otherwise simply overwrite the output file.
  1830. //
  1831. b = ReadFile(
  1832. *DestFile,
  1833. &RestartState,
  1834. sizeof(RESTART_STATE),
  1835. &BytesRead,
  1836. NULL
  1837. );
  1838. if ( !b || BytesRead != sizeof(RESTART_STATE) ) {
  1839. //
  1840. // The file could not be read, or there were not
  1841. // enough bytes to contain a restart record. In
  1842. // either case, if the output file cannot be
  1843. // replaced, simply return an error now.
  1844. //
  1845. if ( CopyFlags & COPY_FILE_FAIL_IF_EXISTS ) {
  1846. SetLastError( ERROR_ALREADY_EXISTS );
  1847. b = FALSE; // Fatal error
  1848. leave;
  1849. }
  1850. // The caller should create/overwrite the dest file.
  1851. b = TRUE;
  1852. CloseHandle( *DestFile );
  1853. *DestFile = INVALID_HANDLE_VALUE;
  1854. leave;
  1855. }
  1856. //
  1857. // Check the contents of the restart state just
  1858. // read against the known contents of what would
  1859. // be there if this were the same copy operation.
  1860. //
  1861. if ( RestartState.Type != 0x7a9b ||
  1862. RestartState.Size != sizeof(RESTART_STATE) ||
  1863. RestartState.FileSize.QuadPart != lpRestartState->FileSize.QuadPart ||
  1864. RestartState.EndOfFile.QuadPart != lpRestartState->EndOfFile.QuadPart ||
  1865. RestartState.NumberOfStreams != lpRestartState->NumberOfStreams ||
  1866. RestartState.CreationTime.QuadPart != lpRestartState->CreationTime.QuadPart ||
  1867. RestartState.WriteTime.QuadPart != lpRestartState->WriteTime.QuadPart ||
  1868. RestartState.Checksum != BasepChecksum((PUSHORT)&RestartState,FIELD_OFFSET(RESTART_STATE,Checksum) >> 1) ) {
  1869. if ( CopyFlags & COPY_FILE_FAIL_IF_EXISTS ) {
  1870. b = FALSE; // Fatal error
  1871. SetLastError( ERROR_ALREADY_EXISTS );
  1872. leave;
  1873. }
  1874. // The caller should create/overwrite the dest file.
  1875. b = TRUE;
  1876. CloseHandle( *DestFile );
  1877. *DestFile = INVALID_HANDLE_VALUE;
  1878. leave;
  1879. }
  1880. //
  1881. // A valid restart state has been found. Copy
  1882. // the appropriate values into the internal
  1883. // restart state so the operation can continue
  1884. // from there.
  1885. //
  1886. lpRestartState->CurrentStream = RestartState.CurrentStream;
  1887. lpRestartState->LastKnownGoodOffset.QuadPart = RestartState.LastKnownGoodOffset.QuadPart;
  1888. if ( !RestartState.CurrentStream ) {
  1889. // We were in the middle of copying the unnamed data stream.
  1890. if ( Context ) {
  1891. Context->TotalBytesTransferred.QuadPart = RestartState.LastKnownGoodOffset.QuadPart;
  1892. }
  1893. // We'll leave the handle in *DestFile, and the caller and pick up the
  1894. // copy of this stream.
  1895. b = TRUE;
  1896. } else {
  1897. // We were in the middle of copying a named data stream.
  1898. if ( Context ) {
  1899. ULONG ReturnCode;
  1900. Context->TotalBytesTransferred.QuadPart = lpFileSize->QuadPart;
  1901. Context->dwStreamNumber = RestartState.CurrentStream;
  1902. if ( Context->lpProgressRoutine ) {
  1903. ReturnCode = Context->lpProgressRoutine(
  1904. Context->TotalFileSize,
  1905. Context->TotalBytesTransferred,
  1906. *lpFileSize,
  1907. Context->TotalBytesTransferred,
  1908. 1,
  1909. CALLBACK_STREAM_SWITCH,
  1910. hSourceFile,
  1911. *DestFile,
  1912. Context->lpData
  1913. );
  1914. } else {
  1915. ReturnCode = PROGRESS_CONTINUE;
  1916. }
  1917. if ( ReturnCode == PROGRESS_CANCEL ||
  1918. (Context->lpCancel && *Context->lpCancel) ) {
  1919. BaseMarkFileForDelete(
  1920. *DestFile,
  1921. 0
  1922. );
  1923. BaseSetLastNTError(STATUS_REQUEST_ABORTED);
  1924. b = FALSE;
  1925. leave;
  1926. }
  1927. if ( ReturnCode == PROGRESS_STOP ) {
  1928. BaseSetLastNTError(STATUS_REQUEST_ABORTED);
  1929. b = FALSE;
  1930. leave;
  1931. }
  1932. if ( ReturnCode == PROGRESS_QUIET ) {
  1933. Context = NULL;
  1934. *lpCopyFileContext = NULL;
  1935. }
  1936. }
  1937. b = SUCCESS_RETURNED_STATE;
  1938. } // if ( !RestartState.CurrentStream ) ... else
  1939. }
  1940. finally {
  1941. if( b == FALSE &&
  1942. *DestFile != INVALID_HANDLE_VALUE ) {
  1943. CloseHandle( *DestFile );
  1944. *DestFile = INVALID_HANDLE_VALUE;
  1945. }
  1946. }
  1947. return( b );
  1948. }
  1949. BOOL
  1950. WINAPI
  1951. BasepCopyCompression( HANDLE hSourceFile,
  1952. HANDLE DestFile,
  1953. DWORD SourceFileAttributes,
  1954. DWORD DestFileAttributes,
  1955. DWORD DestFileFsAttributes,
  1956. DWORD CopyFlags,
  1957. LPCOPYFILE_CONTEXT *lpCopyFileContext )
  1958. /*++
  1959. Routine Description:
  1960. This is an internal routine that copies the compression state during
  1961. a copyfile. If the source is compressed, that same compression
  1962. algorithm is copied to the dest. If that fails, an attempt is made
  1963. to set the default compression. Depending on the copy flags, it
  1964. may alternatively be necessary to decompress the destination.
  1965. Arguments:
  1966. hSourceFile - Provides a handle to the source file.
  1967. DestFile - Provides a handle to the destination file.
  1968. SourceFileAttributes - FileBasicInformation attributes queried from the
  1969. source file.
  1970. DestFileAttributes - FileBasicInformation attributes for the current
  1971. state of the destination file.
  1972. DestFileFsAttributes - FileFsAttributeInformation.FileSystemAttributes
  1973. for the file system of the dest file.
  1974. CopyFlags - Provides flags that modify how the copy is to proceed. See
  1975. CopyFileEx for details.
  1976. lpCopyFileContext - Provides a pointer to a pointer to the context
  1977. information to track callbacks, file sizes, etc. across streams during
  1978. the copy operation.
  1979. Return Value:
  1980. TRUE - The operation was successful.
  1981. FALSE/NULL - The operation failed. Extended error status is available
  1982. using GetLastError. The DestFile has already been marked
  1983. for delete.
  1984. --*/
  1985. { // BasepCopyCompression
  1986. IO_STATUS_BLOCK IoStatus;
  1987. NTSTATUS Status = STATUS_SUCCESS;
  1988. LPCOPYFILE_CONTEXT Context = *lpCopyFileContext;
  1989. BOOL SuccessReturn = FALSE;
  1990. BOOL Canceled = FALSE;
  1991. try
  1992. {
  1993. if( !(SourceFileAttributes & FILE_ATTRIBUTE_COMPRESSED) ) {
  1994. // The source file is not compressed. If necessary, decompress
  1995. // the target.
  1996. if( (DestFileAttributes & FILE_ATTRIBUTE_COMPRESSED) &&
  1997. (CopyFlags & PRIVCOPY_FILE_SUPERSEDE) ) {
  1998. // The source isn't compressed, but the dest is, and we don't
  1999. // want to acquire attributes from the dest. So we need to manually
  2000. // decompress it.
  2001. ULONG CompressionType = COMPRESSION_FORMAT_NONE;
  2002. Status = NtFsControlFile(
  2003. DestFile,
  2004. NULL,
  2005. NULL,
  2006. NULL,
  2007. &IoStatus,
  2008. FSCTL_SET_COMPRESSION,
  2009. &CompressionType, // Input buffer
  2010. sizeof(CompressionType), // Input buffer length
  2011. NULL, // Output buffer
  2012. 0 // Output buffer length
  2013. );
  2014. if( !NT_SUCCESS(Status) ) {
  2015. // See if it's OK to ignore the error
  2016. if( !BasepCopyFileCallback( TRUE, // Continue by default
  2017. RtlNtStatusToDosError(Status),
  2018. Context,
  2019. NULL,
  2020. PRIVCALLBACK_COMPRESSION_NOT_SUPPORTED,
  2021. hSourceFile,
  2022. DestFile,
  2023. &Canceled )) {
  2024. BaseMarkFileForDelete( DestFile, 0 );
  2025. BaseSetLastNTError( Status );
  2026. leave;
  2027. } else {
  2028. Status = STATUS_SUCCESS;
  2029. }
  2030. }
  2031. }
  2032. } // if( !(SourceFileAttributes & FILE_ATTRIBUTE_COMPRESSED) )
  2033. else {
  2034. // The source file is compressed. Does the target filesystem
  2035. // even support compression?
  2036. if( !(FILE_FILE_COMPRESSION & DestFileFsAttributes) ) {
  2037. // No, it won't be compressable. See if it's OK to continue.
  2038. if( !BasepCopyFileCallback( TRUE, // Continue by default
  2039. ERROR_NOT_SUPPORTED,
  2040. Context,
  2041. NULL,
  2042. PRIVCALLBACK_COMPRESSION_NOT_SUPPORTED,
  2043. hSourceFile,
  2044. DestFile,
  2045. &Canceled )) {
  2046. if( Canceled ) {
  2047. BaseMarkFileForDelete(
  2048. DestFile,
  2049. 0 );
  2050. }
  2051. leave;
  2052. }
  2053. } // if( !(FILE_FILE_COMPRESSION & *DestFileFsAttributes) )
  2054. else {
  2055. // Target volume supports compression. Compress the target file if
  2056. // it's not already.
  2057. if( !(DestFileAttributes & FILE_ATTRIBUTE_COMPRESSED) ) {
  2058. USHORT CompressionType;
  2059. // Get the source file's compression type
  2060. Status = NtFsControlFile(
  2061. hSourceFile,
  2062. NULL,
  2063. NULL,
  2064. NULL,
  2065. &IoStatus,
  2066. FSCTL_GET_COMPRESSION,
  2067. NULL, // Input buffer
  2068. 0, // Input buffer length
  2069. &CompressionType, // Output buffer
  2070. sizeof(CompressionType) // Output buffer length
  2071. );
  2072. if( NT_SUCCESS(Status) ) {
  2073. // Set the compression type on the target
  2074. Status = NtFsControlFile(
  2075. DestFile,
  2076. NULL,
  2077. NULL,
  2078. NULL,
  2079. &IoStatus,
  2080. FSCTL_SET_COMPRESSION,
  2081. &CompressionType, // Input buffer
  2082. sizeof(CompressionType), // Input buffer length
  2083. NULL, // Output buffer
  2084. 0 // Output buffer length
  2085. );
  2086. // If that didn't work, try the default compression
  2087. // format (maybe we're copying from uplevel to downlevel).
  2088. if( !NT_SUCCESS(Status) &&
  2089. COMPRESSION_FORMAT_DEFAULT != CompressionType ) {
  2090. CompressionType = COMPRESSION_FORMAT_DEFAULT;
  2091. Status = NtFsControlFile(
  2092. DestFile,
  2093. NULL,
  2094. NULL,
  2095. NULL,
  2096. &IoStatus,
  2097. FSCTL_SET_COMPRESSION,
  2098. &CompressionType, // Input buffer
  2099. sizeof(CompressionType), // Input buffer length
  2100. NULL, // Output buffer
  2101. 0 // Output buffer length
  2102. );
  2103. }
  2104. } // FSCTL_GET_COMPRESSION ... if( NT_SUCCESS(Status) )
  2105. // If something went wrong and we couldn't compress it, there's a good
  2106. // chance that the caller doesn't want this to be fatal. Ask and find
  2107. // out.
  2108. if( !NT_SUCCESS(Status) ) {
  2109. BOOL Canceled = FALSE;
  2110. if( !BasepCopyFileCallback( TRUE, // Continue by default
  2111. RtlNtStatusToDosError(Status),
  2112. Context,
  2113. NULL,
  2114. PRIVCALLBACK_COMPRESSION_FAILED,
  2115. hSourceFile,
  2116. DestFile,
  2117. &Canceled )) {
  2118. if( Canceled ) {
  2119. BaseMarkFileForDelete(
  2120. DestFile,
  2121. 0 );
  2122. }
  2123. leave;
  2124. }
  2125. }
  2126. } // if( !(DestFileAttributes & FILE_FILE_COMPRESSION) )
  2127. } // if( !(FILE_FILE_COMPRESSION & *DestFileFsAttributes) )
  2128. } // if( !(SourceFileAttributes & FILE_ATTRIBUTE_COMPRESSED) ) ... else
  2129. SuccessReturn = TRUE;
  2130. }
  2131. finally
  2132. {
  2133. }
  2134. return( SuccessReturn );
  2135. }
  2136. NTSTATUS
  2137. BasepCreateDispositionToWin32( DWORD CreateDisposition, DWORD *Win32CreateDisposition )
  2138. /*++
  2139. Routine Description:
  2140. This is an internal routine used by BaseCopyStream. It is used to translate
  2141. from NT API CreateDisposition flags to Win32 CreateDisposition flags (this was
  2142. added in order to use the NT CreateDisposition in a call to DuplicateEncryptionInformation).
  2143. This routine does the inverse of the Win32->NT mapping in CreateFile, except that there is
  2144. no way to obtain TRUNCATE_EXISTING from an NT flag. The FILE_SUPERSEDE and FILE_OVERWRITE
  2145. flags are not supported by this routine.
  2146. Arguments:
  2147. CreateDisposition - The NT CreateDisposition flags.
  2148. Returns:
  2149. STATUS_INVALID_PARAMETER if an unsupported NT flag is passed in.
  2150. STATUS_SUCCESS otherwise.
  2151. ++*/
  2152. {
  2153. switch ( CreateDisposition ) {
  2154. case FILE_CREATE :
  2155. *Win32CreateDisposition = CREATE_NEW;
  2156. break;
  2157. case FILE_OVERWRITE_IF:
  2158. *Win32CreateDisposition = CREATE_ALWAYS;
  2159. break;
  2160. case FILE_OPEN:
  2161. *Win32CreateDisposition = OPEN_EXISTING;
  2162. break;
  2163. case FILE_OPEN_IF:
  2164. *Win32CreateDisposition = OPEN_ALWAYS;
  2165. break;
  2166. default :
  2167. return STATUS_INVALID_PARAMETER;
  2168. }
  2169. return STATUS_SUCCESS;
  2170. }
  2171. BOOL
  2172. CheckAllowDecryptedRemoteDestinationPolicy()
  2173. /*++
  2174. Routine Description:
  2175. This routine is used by BasepCopyEncryption (part of CopyFile), when
  2176. an attempt has been made to copy an encrypted file to a destination that
  2177. for some reason can't support encryption (e.g. it's FAT, not trusted for
  2178. delegation, NT4, etc). By default, copyfile fails for this scenario. The
  2179. way to override that default is to pass the COPY_FILE_ALLOW_DECRYPTED_DESTINATION
  2180. flag to CopyFile. The other way to override that default (if you can't update
  2181. your copy utilities to use the new flag), is to set the
  2182. CopyFileAllowDecryptedRemoteDestination system policy. This routine checks that policy.
  2183. This routine caches the result of the registry check per process. So an update
  2184. to the policy may require a reboot to take effect in existing processes.
  2185. Arguments:
  2186. None
  2187. Return Value:
  2188. TRUE - The decrypted destination is allowed
  2189. FALSE - The destination may not be left decrypted
  2190. --*/
  2191. {
  2192. // Static flags indicating if we've already been called once, and if
  2193. // so what the answer was. These are static so that we need to do the registry
  2194. // call only once per process.
  2195. static BOOL Allowed = FALSE;
  2196. static BOOL AlreadyChecked = FALSE;
  2197. NTSTATUS Status;
  2198. HANDLE Key;
  2199. BYTE QueryBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD)];
  2200. PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo =
  2201. (PKEY_VALUE_PARTIAL_INFORMATION) QueryBuffer;
  2202. ULONG ActualSize;
  2203. const static UNICODE_STRING KeyName =
  2204. RTL_CONSTANT_STRING( L"\\Registry\\Machine\\Software\\Policies\\Microsoft\\Windows\\System" );
  2205. const static OBJECT_ATTRIBUTES ObjectAttributes =
  2206. RTL_CONSTANT_OBJECT_ATTRIBUTES(&KeyName, OBJ_CASE_INSENSITIVE);
  2207. const static UNICODE_STRING ValueName =
  2208. RTL_CONSTANT_STRING( L"CopyFileAllowDecryptedRemoteDestination" );
  2209. // Check to see if we've already been called once in this process. If so,
  2210. // return the value that was calculated then (thus this process needs a reboot
  2211. // to reflect a change to this policy). Technically there's a race condition here,
  2212. // but assuming the registry isn't being updated during the call, each call to this
  2213. // routine will get the same answer anyway.
  2214. if( AlreadyChecked )
  2215. return Allowed;
  2216. // We need to do the check.
  2217. // Try to open the system policy key.
  2218. // If it doesn't exist, then we'll just fall through and return false.
  2219. Status = NtOpenKey( &Key,
  2220. KEY_QUERY_VALUE,
  2221. (POBJECT_ATTRIBUTES) &ObjectAttributes);
  2222. if (NT_SUCCESS(Status)) {
  2223. // We have the system policy key. Now try to open the value. If it
  2224. // doesn't exist, we'll just fall through, and return false.
  2225. Status = NtQueryValueKey(
  2226. Key,
  2227. (PUNICODE_STRING) &ValueName,
  2228. KeyValuePartialInformation,
  2229. KeyValueInfo,
  2230. sizeof(QueryBuffer),
  2231. &ActualSize);
  2232. if (NT_SUCCESS(Status)) {
  2233. // The value exists. If it's the right shape and value, then
  2234. // we'll allow the decrypted destination.
  2235. if( KeyValueInfo->Type == REG_DWORD &&
  2236. KeyValueInfo->DataLength == sizeof(DWORD) &&
  2237. *((PDWORD) KeyValueInfo->Data) == 1) {
  2238. Allowed = TRUE;
  2239. }
  2240. }
  2241. NtClose( Key );
  2242. }
  2243. // Update the static so that we don't execute this code again.
  2244. AlreadyChecked = TRUE;
  2245. return Allowed;
  2246. }
  2247. typedef BOOL (WINAPI *ENCRYPTFILEWPTR)(LPCWSTR);
  2248. typedef BOOL (WINAPI *DECRYPTFILEWPTR)(LPCWSTR, DWORD);
  2249. BOOL
  2250. WINAPI
  2251. BasepCopyEncryption( HANDLE hSourceFile,
  2252. LPCWSTR lpNewFileName,
  2253. PHANDLE DestFile,
  2254. POBJECT_ATTRIBUTES Obja,
  2255. DWORD DestFileAccess,
  2256. DWORD DestFileSharing,
  2257. DWORD CreateDisposition,
  2258. DWORD CreateOptions,
  2259. DWORD SourceFileAttributes,
  2260. DWORD SourceFileAttributesMask,
  2261. PDWORD DestFileAttributes,
  2262. DWORD DestFileFsAttributes,
  2263. DWORD CopyFlags,
  2264. LPCOPYFILE_CONTEXT *lpCopyFileContext )
  2265. /*++
  2266. Routine Description:
  2267. This is an internal routine that copies the encryption state during
  2268. a copyfile. Depending on the copy flags, it may be necessary to
  2269. decompress the destination. To encrypt/decrypt a file it is necessary
  2270. to close the current handle, encrypt/decrypt, and reopen.
  2271. Arguments:
  2272. hSourceFile - Provides a handle to the source file.
  2273. lpNewFileName - Provides a name for the target file/stream.
  2274. Obja - ObjectAttributes structure for the destination file.
  2275. DestFileAccess - ACCESS_MASK to use when opening the dest.
  2276. DestFileSharing - Sharing options to use when openting the dest.
  2277. CreateDisposition - Creation/disposition options for opening the dest.
  2278. SourceFileAttributes - FileBasicInformation attributes queried from the
  2279. source file.
  2280. SourceFileAttributesMask - the attributes from the source that are intended
  2281. to be set on the dest.
  2282. DestFileAttributes - FileBasicInformation attributes for the current
  2283. state of the destination file. This value is updated to reflect
  2284. changes to the encryption state of the dest file.
  2285. DestFileFsAttributes - FileFsAttributeInformation.FileSystemAttributes
  2286. for the file system of the dest file.
  2287. CopyFlags - Provides flags that modify how the copy is to proceed. See
  2288. CopyFileEx for details.
  2289. lpCopyFileContext - Provides a pointer to a pointer to the context
  2290. information to track callbacks, file sizes, etc. across streams during
  2291. the copy operation.
  2292. Return Value:
  2293. TRUE - The operation was successful.
  2294. FALSE/NULL - The operation failed. Extended error status is available
  2295. using GetLastError. The DestFile has already been marked
  2296. for delete.
  2297. --*/
  2298. { // BasepCopyEncryption
  2299. NTSTATUS Status = 0;
  2300. BOOL SuccessReturn = FALSE;
  2301. BOOL EncryptFile = FALSE;
  2302. BOOL DecryptFile = FALSE;
  2303. HANDLE Advapi32 = NULL;
  2304. BOOL RestoreReadOnly = FALSE;
  2305. ENCRYPTFILEWPTR EncryptFileWPtr = NULL;
  2306. DECRYPTFILEWPTR DecryptFileWPtr = NULL;
  2307. IO_STATUS_BLOCK IoStatusBlock;
  2308. LPCOPYFILE_CONTEXT Context = *lpCopyFileContext;
  2309. FILE_BASIC_INFORMATION FileBasicInformationData;
  2310. try
  2311. {
  2312. // Check to see if we need to do some encryption or decryption,
  2313. // and set EncryptFile/DescryptFile bools if set.
  2314. if( (SourceFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) &&
  2315. (SourceFileAttributesMask & FILE_ATTRIBUTE_ENCRYPTED) &&
  2316. !(*DestFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) ) {
  2317. // We tried to copy over encryption, but it didn't stick:
  2318. // * This may be a system file, encryption is not supported on
  2319. // system files.
  2320. // * If this is a non-directory file, then encryption is not
  2321. // supported on the target file system.
  2322. // * If this is a directory file, then we must try to encrypt
  2323. // it manually (since we opened it, rather than creating it).
  2324. // It still may not be possible but we'll have to try to
  2325. // find out.
  2326. if( (SourceFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  2327. &&
  2328. !(*DestFileAttributes & FILE_ATTRIBUTE_SYSTEM) ) {
  2329. EncryptFile = TRUE;
  2330. }
  2331. } else if( !(SourceFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) &&
  2332. (*DestFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) &&
  2333. (CopyFlags & PRIVCOPY_FILE_SUPERSEDE) ) {
  2334. // The source is decrypted, the destination was encrypted, and the
  2335. // caller specified that the source should be copied as-is. So
  2336. // we must manually decrypt the destination. This can happen if
  2337. // the dest file already existed and was encrypted.
  2338. DecryptFile = TRUE;
  2339. }
  2340. // If we decided above to either encrypt or decrypt, then we have
  2341. // more work to do.
  2342. if( DecryptFile || EncryptFile ) {
  2343. // If the destination file is read-only, we have to take it off
  2344. // until we do the encrypt/decrypt (and restore it later).
  2345. if( *DestFileAttributes & FILE_ATTRIBUTE_READONLY ) {
  2346. RestoreReadOnly = TRUE;
  2347. RtlZeroMemory(&FileBasicInformationData, sizeof(FileBasicInformationData));
  2348. FileBasicInformationData.FileAttributes = (*DestFileAttributes) & ~FILE_ATTRIBUTE_READONLY;
  2349. Status = NtSetInformationFile(
  2350. *DestFile,
  2351. &IoStatusBlock,
  2352. &FileBasicInformationData,
  2353. sizeof(FileBasicInformationData),
  2354. FileBasicInformation
  2355. );
  2356. if( !NT_SUCCESS(Status) ) {
  2357. BaseMarkFileForDelete( *DestFile, 0 );
  2358. BaseSetLastNTError(Status);
  2359. leave;
  2360. }
  2361. }
  2362. // Close the file so that we can call EncryptFile/DecryptFile
  2363. NtClose( *DestFile );
  2364. *DestFile = INVALID_HANDLE_VALUE;
  2365. // Load the EncryptFile/DecryptFile API, and make the call
  2366. Advapi32 = LoadLibraryW(AdvapiDllString);
  2367. if( Advapi32 == NULL ) {
  2368. leave;
  2369. }
  2370. if( EncryptFile ) {
  2371. EncryptFileWPtr = (ENCRYPTFILEWPTR)GetProcAddress(Advapi32, "EncryptFileW");
  2372. if( EncryptFileWPtr == NULL ) {
  2373. leave;
  2374. }
  2375. if( EncryptFileWPtr(lpNewFileName) )
  2376. *DestFileAttributes |= FILE_ATTRIBUTE_ENCRYPTED;
  2377. } else {
  2378. DecryptFileWPtr = (DECRYPTFILEWPTR)GetProcAddress(Advapi32, "DecryptFileW");
  2379. if( DecryptFileWPtr == NULL ) {
  2380. leave;
  2381. }
  2382. if( DecryptFileWPtr(lpNewFileName, 0) )
  2383. *DestFileAttributes &= ~FILE_ATTRIBUTE_ENCRYPTED;
  2384. }
  2385. // The encrypt/decrypt call was successful, so we can reopen the file.
  2386. Status = NtCreateFile(
  2387. DestFile,
  2388. DestFileAccess,
  2389. Obja,
  2390. &IoStatusBlock,
  2391. NULL,
  2392. SourceFileAttributes & FILE_ATTRIBUTE_VALID_FLAGS & SourceFileAttributesMask,
  2393. DestFileSharing,
  2394. CreateDisposition,
  2395. CreateOptions,
  2396. NULL,
  2397. 0
  2398. );
  2399. if( !NT_SUCCESS(Status) ) {
  2400. *DestFile = INVALID_HANDLE_VALUE;
  2401. BaseSetLastNTError(Status);
  2402. leave;
  2403. }
  2404. // If we took off the read-only bit above, put it back on now.
  2405. if( RestoreReadOnly ) {
  2406. FileBasicInformationData.FileAttributes |= FILE_ATTRIBUTE_READONLY;
  2407. Status = NtSetInformationFile(
  2408. *DestFile,
  2409. &IoStatusBlock,
  2410. &FileBasicInformationData,
  2411. sizeof(FileBasicInformationData),
  2412. FileBasicInformation
  2413. );
  2414. if( !NT_SUCCESS(Status) ) {
  2415. BaseMarkFileForDelete( *DestFile, 0 );
  2416. BaseSetLastNTError(Status);
  2417. leave;
  2418. }
  2419. }
  2420. } // if( DecryptFile || EncryptFile )
  2421. // If it's still not encrypted, see if it's OK to leave it that way.
  2422. if( (SourceFileAttributes & FILE_ATTRIBUTE_ENCRYPTED)
  2423. && !(*DestFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) ) {
  2424. // Either there was an encryption problem (e.g. no keys available)
  2425. // or the target just doesn't support encryption. See if it's OK
  2426. // to continue with the copy by checking the CopyFlags, by making
  2427. // a callback, or by checking policy.
  2428. BOOL Canceled = FALSE;
  2429. DWORD dwCallbackReason = 0;
  2430. LONG lError = ERROR_ENCRYPTION_FAILED;
  2431. // If the COPY_FILE_ALLOW_DECRYPTED_DESTINATION flag is set, then
  2432. // we can fall through and return success. Otherwise, we need to do some
  2433. // more checking.
  2434. if( !(CopyFlags & COPY_FILE_ALLOW_DECRYPTED_DESTINATION) ) {
  2435. // There's a policy in the registry which may be set indicating
  2436. // that we can ignore loss of encryption on network targets.
  2437. // If that's set, and this is a remote destination, then the
  2438. // copy can continue. We check the policy first, because it
  2439. // caches its result. Consequently, in the typical case, we only
  2440. // check the registry once, and we never make the NtQueryVolInfoFile
  2441. // call.
  2442. if( CheckAllowDecryptedRemoteDestinationPolicy() ) {
  2443. IO_STATUS_BLOCK IoStatus;
  2444. FILE_FS_DEVICE_INFORMATION DeviceInformation;
  2445. // See if the destination is remote
  2446. DeviceInformation.Characteristics = 0;
  2447. Status = NtQueryVolumeInformationFile(
  2448. *DestFile,
  2449. &IoStatus,
  2450. &DeviceInformation,
  2451. sizeof(DeviceInformation),
  2452. FileFsDeviceInformation
  2453. );
  2454. if( NT_SUCCESS(Status) &&
  2455. (DeviceInformation.Characteristics & FILE_REMOTE_DEVICE) )
  2456. {
  2457. // Yes, it's remote, and the policy is set, so
  2458. // it's OK to continue.
  2459. SuccessReturn = TRUE;
  2460. }
  2461. } // if( CheckAllowDecryptedRemoteDestinationPolicy() )
  2462. // If that didn't work, do we have a callback on which we can
  2463. // check for permission to drop? We checked the policy first,
  2464. // because if it allows the copy, we needn't even call the
  2465. // callback.
  2466. if( !SuccessReturn
  2467. && Context != NULL
  2468. && Context->lpProgressRoutine != NULL
  2469. && (CopyFlags & PRIVCOPY_FILE_METADATA) ) {
  2470. // Yes, we have an applicable callback.
  2471. // Figure out what the explanation (dwCallbackReason)
  2472. // is for the problem.
  2473. if( DestFileFsAttributes & FILE_SUPPORTS_ENCRYPTION ) {
  2474. if( !(SourceFileAttributesMask & FILE_ATTRIBUTE_ENCRYPTED) ) {
  2475. // We opened the file with encryption turned off, so we must
  2476. // have gotten an access-denied on the first try.
  2477. dwCallbackReason = PRIVCALLBACK_ENCRYPTION_FAILED;
  2478. }
  2479. else if( *DestFileAttributes & FILE_ATTRIBUTE_SYSTEM )
  2480. dwCallbackReason = PRIVCALLBACK_CANT_ENCRYPT_SYSTEM_FILE;
  2481. else
  2482. dwCallbackReason = PRIVCALLBACK_ENCRYPTION_FAILED;
  2483. }
  2484. else
  2485. dwCallbackReason = PRIVCALLBACK_ENCRYPTION_NOT_SUPPORTED;
  2486. // Make the callback.
  2487. if( BasepCopyFileCallback( FALSE, // Fail by default
  2488. lError,
  2489. Context,
  2490. NULL,
  2491. dwCallbackReason,
  2492. hSourceFile,
  2493. *DestFile,
  2494. &Canceled )) {
  2495. // We've been given permission to drop the encryption
  2496. SuccessReturn = TRUE;
  2497. }
  2498. } // if( Context != NULL
  2499. // We checked everything, and nothing allows us to contine,
  2500. // so fail the call.
  2501. if( !SuccessReturn ) {
  2502. BaseMarkFileForDelete(
  2503. *DestFile,
  2504. 0 );
  2505. SetLastError( lError );
  2506. leave;
  2507. }
  2508. } // if( !(CopyFlags & COPY_FILE_ALLOW_DECRYPTED_DESTINATION) )
  2509. } // if( (SourceFileAttributes & FILE_ATTRIBUTE_ENCRYPTED)
  2510. SuccessReturn = TRUE;
  2511. }
  2512. finally
  2513. {
  2514. if (Advapi32 != NULL) {
  2515. FreeLibrary( Advapi32 );
  2516. }
  2517. }
  2518. return( SuccessReturn );
  2519. }
  2520. DWORD
  2521. WINAPI
  2522. BaseCopyStream(
  2523. OPTIONAL LPCWSTR lpExistingFileName,
  2524. HANDLE hSourceFile,
  2525. ACCESS_MASK SourceFileAccess OPTIONAL,
  2526. LPCWSTR lpNewFileName,
  2527. HANDLE hTargetFile OPTIONAL,
  2528. LARGE_INTEGER *lpFileSize,
  2529. LPDWORD lpCopyFlags,
  2530. LPHANDLE lpDestFile,
  2531. LPDWORD lpCopySize,
  2532. LPCOPYFILE_CONTEXT *lpCopyFileContext,
  2533. LPRESTART_STATE lpRestartState OPTIONAL,
  2534. BOOL OpenFileAsReparsePoint,
  2535. DWORD dwReparseTag,
  2536. PDWORD DestFileFsAttributes
  2537. )
  2538. /*++
  2539. Routine Description:
  2540. This is an internal routine that copies an entire file (default data stream
  2541. only), or a single stream of a file. If the hTargetFile parameter is
  2542. present, then only a single stream of the output file is copied. Otherwise,
  2543. the entire file is copied.
  2544. Arguments:
  2545. hSourceFile - Provides a handle to the source file.
  2546. SourceFileAccess - The ACCESS_MASK bits used to open the source file handle.
  2547. This variable is only used with the PRIVCOPY_FILE_* flags.
  2548. lpNewFileName - Provides a name for the target file/stream.
  2549. hTargetFile - Optionally provides a handle to the target file. If the
  2550. stream being copied is an alternate data stream, then this handle must
  2551. be provided.
  2552. lpFileSize - Provides the size of the input stream.
  2553. lpCopyFlags - Provides flags that modify how the copy is to proceed. See
  2554. CopyFileEx for details.
  2555. lpDestFile - Provides a variable to store the handle to the target file.
  2556. lpCopySize - Provides variable to store size of copy chunks to be used in
  2557. copying the streams. This is set for the file, and then reused on
  2558. alternate streams.
  2559. lpCopyFileContext - Provides a pointer to a pointer to the context
  2560. information to track callbacks, file sizes, etc. across streams during
  2561. the copy operation.
  2562. lpRestartState - Optionally provides storage to maintain restart state
  2563. during the copy operation. This pointer is only valid if the caller
  2564. has specified the COPY_FILE_RESTARTABLE flag in the lpCopyFlags word.
  2565. OpenFileAsReparsePoint - Flag to indicate whether the target file is to
  2566. be opened as a reparse point or not.
  2567. DestFileFsAttributes - If hTargetFile is present, provides a location to
  2568. store the destination file's filesystem attributes. If hTargetFile
  2569. is not present, provides those attributes to this routine.
  2570. Return Value:
  2571. TRUE - The operation was successful.
  2572. SUCCESS_RETURNED_STATE - The operation was successful, but extended
  2573. information was returned in the restart state structure.
  2574. FALSE/NULL - The operation failed. Extended error status is available
  2575. using GetLastError.
  2576. --*/
  2577. { // BaseCopyStream
  2578. HANDLE DestFile = INVALID_HANDLE_VALUE;
  2579. HANDLE Section;
  2580. NTSTATUS Status;
  2581. PVOID SourceBase, IoDestBase;
  2582. PCHAR SourceBuffer;
  2583. LARGE_INTEGER SectionOffset;
  2584. LARGE_INTEGER BytesWritten;
  2585. SIZE_T BigViewSize;
  2586. ULONG ViewSize;
  2587. ULONG BytesToWrite;
  2588. ULONG BytesRead;
  2589. FILE_BASIC_INFORMATION FileBasicInformationData;
  2590. FILE_END_OF_FILE_INFORMATION EndOfFileInformation;
  2591. IO_STATUS_BLOCK IoStatus;
  2592. LPCOPYFILE_CONTEXT Context = *lpCopyFileContext;
  2593. DWORD ReturnCode;
  2594. DWORD b;
  2595. BOOL Restartable;
  2596. DWORD ReturnValue = FALSE;
  2597. DWORD WriteCount = 0;
  2598. DWORD FlagsAndAttributes;
  2599. DWORD DesiredAccess;
  2600. DWORD DestFileAccess;
  2601. DWORD DestFileSharing;
  2602. DWORD DesiredCreateDisposition;
  2603. DWORD CreateDisposition;
  2604. BOOL Canceled = FALSE;
  2605. DWORD SourceFileAttributes;
  2606. DWORD SourceFileAttributesMask;
  2607. DWORD BlockSize;
  2608. BOOL fSkipBlock;
  2609. UNICODE_STRING DestFileName;
  2610. PVOID DestFileNameBuffer = NULL;
  2611. OBJECT_ATTRIBUTES Obja;
  2612. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  2613. FILE_EA_INFORMATION EaInfo;
  2614. PFILE_FULL_EA_INFORMATION EaBuffer = NULL;
  2615. ULONG EaSize = 0;
  2616. BOOL EasDropped = FALSE;
  2617. IO_STATUS_BLOCK IoStatusBlock;
  2618. WCHAR SaveStaticUnicodeBuffer[STATIC_UNICODE_BUFFER_LENGTH];
  2619. // Default the size of copy chunks
  2620. *lpCopySize = BASE_COPY_FILE_CHUNK;
  2621. // The lpExistingFileName sits in the TEB buffer, which has a tendency
  2622. // to get trashed (e.g. LoadLibaryW). So use a local buffer.
  2623. if( lpExistingFileName == NtCurrentTeb()->StaticUnicodeBuffer ) {
  2624. memcpy( SaveStaticUnicodeBuffer,
  2625. NtCurrentTeb()->StaticUnicodeBuffer,
  2626. STATIC_UNICODE_BUFFER_LENGTH );
  2627. lpExistingFileName = SaveStaticUnicodeBuffer;
  2628. }
  2629. //
  2630. // Get times and attributes for the file if the entire file is being
  2631. // copied
  2632. //
  2633. Status = NtQueryInformationFile(
  2634. hSourceFile,
  2635. &IoStatus,
  2636. (PVOID) &FileBasicInformationData,
  2637. sizeof(FileBasicInformationData),
  2638. FileBasicInformation
  2639. );
  2640. SourceFileAttributes = NT_SUCCESS(Status) ?
  2641. FileBasicInformationData.FileAttributes :
  2642. 0;
  2643. if ( !ARGUMENT_PRESENT(hTargetFile) ) {
  2644. if ( !NT_SUCCESS(Status) ) {
  2645. BaseSetLastNTError(Status);
  2646. return FALSE;
  2647. }
  2648. } else {
  2649. //
  2650. // A zero in the file's attributes informs latter DeleteFile that
  2651. // this code does not know what the actual file attributes are so
  2652. // that this code does not actually have to retrieve them for each
  2653. // stream, nor does it have to remember them across streams. The
  2654. // error path will simply get them if needed.
  2655. //
  2656. FileBasicInformationData.FileAttributes = 0;
  2657. }
  2658. //
  2659. // We don't allow restartable copies of directory files, because the
  2660. // unnamed data stream is used to store restart context, and directory files
  2661. // don't have an unnamed data stream.
  2662. //
  2663. Restartable = (*lpCopyFlags & COPY_FILE_RESTARTABLE) != 0;
  2664. if( Restartable && SourceFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
  2665. Restartable = FALSE;
  2666. *lpCopyFlags &= ~COPY_FILE_RESTARTABLE;
  2667. }
  2668. try {
  2669. //
  2670. // Create the destination file or alternate data stream
  2671. //
  2672. SourceBase = NULL;
  2673. IoDestBase = NULL;
  2674. Section = NULL;
  2675. if ( !ARGUMENT_PRESENT(hTargetFile) ) {
  2676. ULONG CreateOptions = 0, DesiredCreateOptions = 0;
  2677. BOOL TranslationStatus = FALSE;
  2678. PFILE_FULL_EA_INFORMATION EaBufferToUse = NULL;
  2679. DWORD SourceFileFsAttributes = 0;
  2680. ULONG EaSizeToUse = 0;
  2681. // We're being called to copy the unnamed stream of the file, and
  2682. // we need to create the file itself.
  2683. DWORD DestFileAttributes = 0;
  2684. struct {
  2685. FILE_FS_ATTRIBUTE_INFORMATION Info;
  2686. WCHAR Buffer[ MAX_PATH ];
  2687. } FileFsAttrInfoBuffer;
  2688. //
  2689. // Begin by determining how the target file is to be opened based
  2690. // on whether or not the copy operation is to be restartable.
  2691. //
  2692. if ( Restartable ) {
  2693. b = BasepOpenRestartableFile( hSourceFile,
  2694. lpNewFileName,
  2695. &DestFile,
  2696. *lpCopyFlags,
  2697. lpRestartState,
  2698. lpFileSize,
  2699. lpCopyFileContext,
  2700. FileBasicInformationData.FileAttributes,
  2701. OpenFileAsReparsePoint );
  2702. if( b == SUCCESS_RETURNED_STATE ) {
  2703. // We've picked up in the middle of a restartable copy.
  2704. // The destination file handle is in DestFile, which will
  2705. // be given back to our caller below in the finally.
  2706. if ( BasepRemoteFile(hSourceFile,DestFile) ) {
  2707. *lpCopySize = BASE_COPY_FILE_CHUNK - 4096;
  2708. }
  2709. ReturnValue = b;
  2710. leave;
  2711. } else if( b == FALSE ) {
  2712. // There was a fatal error.
  2713. leave;
  2714. }
  2715. // Otherwise we should copy the first stream. If we are to restart copying
  2716. // in that stream, DestFile will be valid.
  2717. }
  2718. //
  2719. // If the dest file is not already opened (the restart case), open it now.
  2720. //
  2721. if( DestFile == INVALID_HANDLE_VALUE ) {
  2722. BOOL EndsInSlash = FALSE;
  2723. UNICODE_STRING Win32NewFileName;
  2724. PCUNICODE_STRING lpConsoleName = NULL;
  2725. FILE_BASIC_INFORMATION DestBasicInformation;
  2726. //
  2727. // Determine the create options
  2728. //
  2729. CreateOptions = FILE_SYNCHRONOUS_IO_NONALERT;
  2730. if( SourceFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
  2731. CreateOptions |= FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT;
  2732. else
  2733. CreateOptions |= FILE_NON_DIRECTORY_FILE | FILE_SEQUENTIAL_ONLY;
  2734. if( *lpCopyFlags & (PRIVCOPY_FILE_BACKUP_SEMANTICS|PRIVCOPY_FILE_OWNER_GROUP) )
  2735. CreateOptions |= FILE_OPEN_FOR_BACKUP_INTENT;
  2736. //
  2737. // Determine the create disposition
  2738. //
  2739. // Directory files are copied with merge semantics. The rationale
  2740. // is that copying of a directory tree has merge semantics wrt the
  2741. // contained files, so copying of a directory file should also have
  2742. // merge semantics.
  2743. //
  2744. if( SourceFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
  2745. CreateDisposition = (*lpCopyFlags & COPY_FILE_FAIL_IF_EXISTS) ? FILE_CREATE : FILE_OPEN_IF;
  2746. else
  2747. CreateDisposition = (*lpCopyFlags & COPY_FILE_FAIL_IF_EXISTS) ? FILE_CREATE : FILE_OVERWRITE_IF;
  2748. //
  2749. // Determine what access is necessary based on what is being copied
  2750. //
  2751. DesiredAccess = SYNCHRONIZE | FILE_READ_ATTRIBUTES | GENERIC_WRITE | DELETE;
  2752. if( SourceFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
  2753. // We may or may not be able to get FILE_WRITE_DATA access, necessary for
  2754. // setting compression.
  2755. DesiredAccess &= ~GENERIC_WRITE;
  2756. DesiredAccess |= FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_LIST_DIRECTORY;
  2757. }
  2758. if( *lpCopyFlags & PRIVCOPY_FILE_METADATA ) {
  2759. // We need read access for compression, write_dac for the DACL
  2760. DesiredAccess |= GENERIC_READ | WRITE_DAC;
  2761. }
  2762. if( *lpCopyFlags & PRIVCOPY_FILE_OWNER_GROUP ) {
  2763. DesiredAccess |= WRITE_OWNER;
  2764. }
  2765. if( (*lpCopyFlags & PRIVCOPY_FILE_SACL)
  2766. &&
  2767. (SourceFileAccess & ACCESS_SYSTEM_SECURITY) ) {
  2768. // Don't bother trying to get access_system_security unless it was
  2769. // successfully obtained on the source (requires SeSecurityPrivilege)
  2770. DesiredAccess |= ACCESS_SYSTEM_SECURITY;
  2771. }
  2772. SourceFileAttributesMask = ~0;
  2773. if ( OpenFileAsReparsePoint ) {
  2774. //
  2775. // The target has to be opened as reparse point. If the open
  2776. // below fails, the source is to be closed and re-opened
  2777. // without inhibiting the reparse point behavior.
  2778. //
  2779. CreateOptions |= FILE_OPEN_REPARSE_POINT;
  2780. DesiredAccess = (DesiredAccess & ~DELETE) | GENERIC_READ;
  2781. CreateDisposition = (*lpCopyFlags & COPY_FILE_FAIL_IF_EXISTS) ? FILE_CREATE : FILE_OPEN_IF;
  2782. }
  2783. DesiredCreateOptions = CreateOptions;
  2784. DesiredCreateDisposition = CreateDisposition;
  2785. //
  2786. // Get the Win32 path in a unicode_string, and get the NT path
  2787. //
  2788. RtlInitUnicodeString( &Win32NewFileName, lpNewFileName );
  2789. if ( lpNewFileName[(Win32NewFileName.Length >> 1)-1] == (WCHAR)'\\' ) {
  2790. EndsInSlash = TRUE;
  2791. }
  2792. else {
  2793. EndsInSlash = FALSE;
  2794. }
  2795. TranslationStatus = RtlDosPathNameToNtPathName_U(
  2796. lpNewFileName,
  2797. &DestFileName,
  2798. NULL,
  2799. NULL
  2800. );
  2801. if ( !TranslationStatus ) {
  2802. SetLastError(ERROR_PATH_NOT_FOUND);
  2803. DestFile = INVALID_HANDLE_VALUE;
  2804. leave;
  2805. }
  2806. DestFileNameBuffer = DestFileName.Buffer;
  2807. InitializeObjectAttributes(
  2808. &Obja,
  2809. &DestFileName,
  2810. OBJ_CASE_INSENSITIVE,
  2811. NULL,
  2812. NULL
  2813. );
  2814. SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  2815. SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
  2816. SecurityQualityOfService.EffectiveOnly = TRUE;
  2817. SecurityQualityOfService.Length = sizeof( SECURITY_QUALITY_OF_SERVICE );
  2818. Obja.SecurityQualityOfService = &SecurityQualityOfService;
  2819. //
  2820. // Get the EAs
  2821. //
  2822. EaBuffer = NULL;
  2823. EaSize = 0;
  2824. Status = NtQueryInformationFile(
  2825. hSourceFile,
  2826. &IoStatusBlock,
  2827. &EaInfo,
  2828. sizeof(EaInfo),
  2829. FileEaInformation
  2830. );
  2831. if ( NT_SUCCESS(Status) && EaInfo.EaSize ) {
  2832. EaSize = EaInfo.EaSize;
  2833. do {
  2834. EaSize *= 2;
  2835. EaBuffer = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( TMP_TAG ), EaSize);
  2836. if ( !EaBuffer ) {
  2837. BaseSetLastNTError(STATUS_NO_MEMORY);
  2838. leave;
  2839. }
  2840. Status = NtQueryEaFile(
  2841. hSourceFile,
  2842. &IoStatusBlock,
  2843. EaBuffer,
  2844. EaSize,
  2845. FALSE,
  2846. (PVOID)NULL,
  2847. 0,
  2848. (PULONG)NULL,
  2849. TRUE
  2850. );
  2851. if ( !NT_SUCCESS(Status) ) {
  2852. RtlFreeHeap(RtlProcessHeap(), 0,EaBuffer);
  2853. EaBuffer = NULL;
  2854. IoStatusBlock.Information = 0;
  2855. }
  2856. } while ( Status == STATUS_BUFFER_OVERFLOW ||
  2857. Status == STATUS_BUFFER_TOO_SMALL );
  2858. EaSize = (ULONG)IoStatusBlock.Information;
  2859. } // if ( NT_SUCCESS(Status) && EaInfo.EaSize )
  2860. //
  2861. // Open the destination file. If the destination is a console name,
  2862. // open as such, otherwise loop until we find a way to open it with
  2863. // NtCreateFile.
  2864. //
  2865. DestFileAccess = DesiredAccess;
  2866. DestFileSharing = 0;
  2867. EaBufferToUse = EaBuffer;
  2868. EaSizeToUse = EaSize;
  2869. if( (lpConsoleName = BaseIsThisAConsoleName( &Win32NewFileName, GENERIC_WRITE )) ) {
  2870. DestFileAccess = DesiredAccess = GENERIC_WRITE;
  2871. DestFileSharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
  2872. if( EaBuffer != NULL )
  2873. EasDropped = TRUE; // We're not copying the EAs
  2874. DestFile= OpenConsoleW( lpConsoleName->Buffer,
  2875. DestFileAccess,
  2876. FALSE, // Not inheritable
  2877. DestFileSharing
  2878. );
  2879. if ( DestFile == INVALID_HANDLE_VALUE ) {
  2880. BaseSetLastNTError(STATUS_ACCESS_DENIED);
  2881. NtClose( DestFile );
  2882. DestFile = INVALID_HANDLE_VALUE;
  2883. leave;
  2884. }
  2885. }
  2886. //
  2887. // Even if the source is offline, the destination should
  2888. // not be (at least not as part of the copy).
  2889. //
  2890. SourceFileAttributes &= ~FILE_ATTRIBUTE_OFFLINE;
  2891. //
  2892. // If the source file was encrypted and if we are intending
  2893. // to create/overwrite/supersede the destination, attempt
  2894. // to establish the encryption state first by calling
  2895. // DuplicateEncryptionInfoFile. This API not only makes
  2896. // the target file encrypted, it also copies over the source's
  2897. // $efs stream (i.e. everyone who had access to the source file
  2898. // will have access to the dest file).
  2899. //
  2900. //
  2901. if (!(SourceFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  2902. && (SourceFileAttributes & FILE_ATTRIBUTE_ENCRYPTED)
  2903. && (SourceFileAttributesMask & FILE_ATTRIBUTE_ENCRYPTED)
  2904. && (CreateDisposition == FILE_CREATE
  2905. || CreateDisposition == FILE_OVERWRITE_IF)) {
  2906. // We'll attempt the DuplicateEncryptionInfoCall.
  2907. DWORD Win32CreateDisposition;
  2908. DWORD LastError;
  2909. // Convert the NT create-disposition flags into a Win32 version.
  2910. Status = BasepCreateDispositionToWin32( CreateDisposition,
  2911. &Win32CreateDisposition );
  2912. if( !NT_SUCCESS(Status) ) {
  2913. BaseSetLastNTError( Status );
  2914. } else {
  2915. // Mask out the read-only bit for now, so that we can
  2916. // do an NtCreateFile after this DuplicateEncryptionInfoFile
  2917. SourceFileAttributesMask &= ~FILE_ATTRIBUTE_READONLY;
  2918. // DuplicateEncryptionInfoFile returns the error code.
  2919. // The "pfn" version of this API is a lazy-loader, so we
  2920. // don't have to implicitely link against advapi32.
  2921. LastError = pfnDuplicateEncryptionInfoFile(
  2922. lpExistingFileName,
  2923. lpNewFileName,
  2924. Win32CreateDisposition,
  2925. SourceFileAttributes
  2926. & FILE_ATTRIBUTE_VALID_FLAGS
  2927. & SourceFileAttributesMask,
  2928. NULL );
  2929. if( LastError != 0 ) {
  2930. //
  2931. // We'll fall through and try using NtCreateFile. That,
  2932. // at least, will try to encrypt the target via the
  2933. // FILE_ATTRIBUTE_ENCRYPTED bit. Not as good as
  2934. // DupEncInfo, but better than leaving plain text.
  2935. //
  2936. SetLastError( LastError );
  2937. } else {
  2938. //
  2939. // Destination was created. Now make it open
  2940. //
  2941. CreateDisposition = FILE_OPEN;
  2942. }
  2943. }
  2944. } // if (!(SourceFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  2945. //
  2946. // Open the destination file. This can take some effort & retries,
  2947. // because there are so many scenarios for the target file
  2948. // (e.g. different destination servers have different capabilities).
  2949. //
  2950. while( DestFile == NULL || DestFile == INVALID_HANDLE_VALUE ) {
  2951. // Attempt to create the destination
  2952. Status = NtCreateFile(
  2953. &DestFile,
  2954. DestFileAccess,
  2955. &Obja,
  2956. &IoStatusBlock,
  2957. NULL,
  2958. SourceFileAttributes
  2959. & FILE_ATTRIBUTE_VALID_FLAGS
  2960. & SourceFileAttributesMask,
  2961. DestFileSharing,
  2962. CreateDisposition,
  2963. CreateOptions,
  2964. EaBufferToUse,
  2965. EaSizeToUse
  2966. );
  2967. if( !NT_SUCCESS(Status) ) {
  2968. // Set the last error and fall through. We will attempt below to
  2969. // resolve the problem and try again.
  2970. BaseSetLastNTError( Status );
  2971. } else {
  2972. //
  2973. // We successfully created the file. For some special cases,
  2974. // we must post-process this create before continuing with the copy.
  2975. //
  2976. if( (SourceFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
  2977. CreateDisposition == FILE_OPEN &&
  2978. (DestFileAccess & FILE_WRITE_DATA) == FILE_WRITE_DATA &&
  2979. (CreateOptions & FILE_DIRECTORY_FILE) == FILE_DIRECTORY_FILE ) {
  2980. //
  2981. // If we're copying to NT4, a previous iteration through this
  2982. // large while loop switched the CreateDisposition from
  2983. // FILE_OPENIF to FILE_OPEN; otherwise, NT4 fails the open
  2984. // (when passing FILE_OPENIF and FILE_WRITE_DATA to a directory
  2985. // file that already exists). The open worked, but the problem
  2986. // is that now if we need to set compression on the target, we'll
  2987. // get status_invalid_parameter because the FILE_DIRECTORY_FILE
  2988. // CreateOption was set. So, to allow compression to work, and
  2989. // since at this point we already know the target is a directory
  2990. // file, we can re-open it without that create option.
  2991. //
  2992. CreateOptions &= ~FILE_DIRECTORY_FILE;
  2993. NtClose( DestFile );
  2994. Status = NtCreateFile(
  2995. &DestFile,
  2996. DestFileAccess,
  2997. &Obja,
  2998. &IoStatusBlock,
  2999. NULL,
  3000. SourceFileAttributes & FILE_ATTRIBUTE_VALID_FLAGS & SourceFileAttributesMask,
  3001. DestFileSharing,
  3002. CreateDisposition,
  3003. CreateOptions,
  3004. EaBufferToUse,
  3005. EaSizeToUse
  3006. );
  3007. if( !NT_SUCCESS(Status) ) {
  3008. // But if that didn't work, go back to the combination that
  3009. // did (this happens on Samba servers).
  3010. CreateOptions |= FILE_DIRECTORY_FILE;
  3011. Status = NtCreateFile(
  3012. &DestFile,
  3013. DestFileAccess,
  3014. &Obja,
  3015. &IoStatusBlock,
  3016. NULL,
  3017. SourceFileAttributes & FILE_ATTRIBUTE_VALID_FLAGS & SourceFileAttributesMask,
  3018. DestFileSharing,
  3019. CreateDisposition,
  3020. CreateOptions,
  3021. EaBufferToUse,
  3022. EaSizeToUse
  3023. );
  3024. if( !NT_SUCCESS(Status) ) {
  3025. DestFile = INVALID_HANDLE_VALUE;
  3026. BaseSetLastNTError( Status );
  3027. leave;
  3028. }
  3029. }
  3030. }
  3031. else if( (SourceFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
  3032. CreateDisposition == FILE_OPEN_IF &&
  3033. lpConsoleName == NULL ) {
  3034. //
  3035. // Compatibility hack: We successfully created the target, but
  3036. // some servers (SCO VisionFS) get confused by the FILE_OPEN_IF
  3037. // flag and create a non-directory file instead. Check to see if
  3038. // this hapenned, and if so deleted it and re-create with FILE_CREATE
  3039. // instead. This is a perf hit that we have to query the file attributes,
  3040. // but at least it is not a net round-trip because the rdr caches the
  3041. // file attributes in Create&X.
  3042. //
  3043. FILE_BASIC_INFORMATION NewDestInfo;
  3044. Status = NtQueryInformationFile( DestFile,
  3045. &IoStatus,
  3046. &NewDestInfo,
  3047. sizeof(NewDestInfo),
  3048. FileBasicInformation );
  3049. if( !NT_SUCCESS(Status) ) {
  3050. BaseMarkFileForDelete( DestFile, 0 );
  3051. BaseSetLastNTError(Status);
  3052. leave;
  3053. }
  3054. if( !(NewDestInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) {
  3055. // Yes, a non-directory file got created. Delete it, then
  3056. // try again without FILE_OPEN_IF.
  3057. BaseMarkFileForDelete( DestFile,
  3058. NewDestInfo.FileAttributes );
  3059. NtClose( DestFile );
  3060. DestFile = INVALID_HANDLE_VALUE;
  3061. CreateDisposition = FILE_CREATE;
  3062. // Also, if we request FILE_WRITE_DATA access, the
  3063. // directory gets created but the NtCreateFile call
  3064. // returns status_object_name_collision. Since this
  3065. // is a very VisionFS-specific workaround, we'll just
  3066. // turn off that bit
  3067. DestFileAccess &= ~FILE_WRITE_DATA;
  3068. continue;
  3069. }
  3070. }
  3071. if( (FileBasicInformationData.FileAttributes & FILE_ATTRIBUTE_READONLY)
  3072. &&
  3073. !(SourceFileAttributesMask & FILE_ATTRIBUTE_READONLY) ) {
  3074. // The read-only bit was turned off, and must now be
  3075. // reset (it gets turned off when we call DuplicateEncryptionInfo,
  3076. // since that API does not return a handle).
  3077. Status = NtSetInformationFile(
  3078. DestFile,
  3079. &IoStatus,
  3080. &FileBasicInformationData,
  3081. sizeof(FileBasicInformationData),
  3082. FileBasicInformation
  3083. );
  3084. if( !NT_SUCCESS(Status) ) {
  3085. BaseMarkFileForDelete( DestFile, 0 );
  3086. BaseSetLastNTError(Status);
  3087. leave;
  3088. }
  3089. }
  3090. break; // while( TRUE )
  3091. } // NtCreateFile ... if( !NT_SUCCESS(Status) ) ... else
  3092. // If we reach this point, some error has occurred in the attempt to
  3093. // create the file.
  3094. //
  3095. // If a file/directory already exists and we can't overwrite it,
  3096. // abort now.
  3097. //
  3098. if ( (*lpCopyFlags & COPY_FILE_FAIL_IF_EXISTS) &&
  3099. (STATUS_OBJECT_NAME_COLLISION == Status) ) {
  3100. // Not allowed to overwrite an existing file.
  3101. SetLastError( ERROR_FILE_EXISTS );
  3102. DestFile = INVALID_HANDLE_VALUE;
  3103. leave;
  3104. } else if ( Status == STATUS_FILE_IS_A_DIRECTORY ) {
  3105. // Not allowed to overwrite a directory with a file.
  3106. if ( EndsInSlash ) {
  3107. SetLastError(ERROR_PATH_NOT_FOUND);
  3108. }
  3109. else {
  3110. SetLastError(ERROR_ACCESS_DENIED);
  3111. }
  3112. DestFile = INVALID_HANDLE_VALUE;
  3113. leave;
  3114. }
  3115. //
  3116. // If we're trying to create a directory, and a non-directory
  3117. // file already exists by that name, we need to manually delete
  3118. // it (FILE_OVERWRITE isn't valid for a directory file).
  3119. //
  3120. if( (*lpCopyFlags & PRIVCOPY_FILE_DIRECTORY) &&
  3121. Status == STATUS_NOT_A_DIRECTORY &&
  3122. !(*lpCopyFlags & COPY_FILE_FAIL_IF_EXISTS) ) {
  3123. Status = NtCreateFile(
  3124. &DestFile,
  3125. DELETE|SYNCHRONIZE,
  3126. &Obja,
  3127. &IoStatusBlock,
  3128. NULL,
  3129. FILE_ATTRIBUTE_NORMAL,
  3130. 0,
  3131. FILE_OPEN,
  3132. FILE_DELETE_ON_CLOSE | FILE_SYNCHRONOUS_IO_NONALERT,
  3133. NULL,
  3134. 0
  3135. );
  3136. if( !NT_SUCCESS(Status) ) {
  3137. BaseSetLastNTError(Status);
  3138. DestFile = INVALID_HANDLE_VALUE;
  3139. leave;
  3140. }
  3141. NtClose( DestFile );
  3142. DestFile = INVALID_HANDLE_VALUE;
  3143. continue;
  3144. }
  3145. //
  3146. // Some sharing and access errors can be handled
  3147. // by reducing the access we request on the target
  3148. // file.
  3149. //
  3150. if( GetLastError() == ERROR_SHARING_VIOLATION ||
  3151. GetLastError() == ERROR_ACCESS_DENIED ) {
  3152. //
  3153. // If the create failed because of a sharing violation or because access
  3154. // was denied, attempt to open the file and allow other readers and
  3155. // writers.
  3156. //
  3157. if( (DestFileSharing & (FILE_SHARE_READ|FILE_SHARE_WRITE))
  3158. != (FILE_SHARE_READ|FILE_SHARE_WRITE) ) {
  3159. DestFileSharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
  3160. continue;
  3161. }
  3162. //
  3163. // If this failed as well, then attempt to open w/o specifying
  3164. // delete access. It is probably not necessary to have delete
  3165. // access to the file anyway, since it will not be able to clean
  3166. // it up because it's probably open. However, this is not
  3167. // necessarily the case.
  3168. //
  3169. else if ( (DestFileAccess & DELETE) ) {
  3170. DestFileAccess &= ~DELETE;
  3171. continue;
  3172. }
  3173. }
  3174. //
  3175. // If the destination has not been successfully created/opened, see
  3176. // if it's because EAs aren't supported
  3177. //
  3178. if( EaBufferToUse != NULL
  3179. &&
  3180. GetLastError() == ERROR_EAS_NOT_SUPPORTED ) {
  3181. // Attempt the create again, but don't use the EAs
  3182. EasDropped = TRUE;
  3183. EaBufferToUse = NULL;
  3184. EaSizeToUse = 0;
  3185. DestFileAccess = DesiredAccess;
  3186. DestFileSharing = 0;
  3187. continue;
  3188. } // if( EaBufferToUse != NULL ...
  3189. // If we still have an access-denied problem, try dropping
  3190. // the WRITE_DAC or WRITE_OWNER access
  3191. if(( GetLastError() == ERROR_ACCESS_DENIED )
  3192. && (DestFileAccess & (WRITE_DAC | WRITE_OWNER)) ) {
  3193. // If WRITE_DAC is set, try turning it off.
  3194. if( DestFileAccess & WRITE_DAC ) {
  3195. DestFileAccess &= ~WRITE_DAC;
  3196. }
  3197. // Or, if WRITE_OWNER is set, try turning it off. We'll
  3198. // turn WRITE_DAC back on if it was previously turned off. Then,
  3199. // if this still doesn't work, then the next iteration will turn
  3200. // WRITE_DAC back off, thus covering both scenarios.
  3201. else if( DestFileAccess & WRITE_OWNER ) {
  3202. DestFileAccess &= ~WRITE_OWNER;
  3203. DestFileAccess |= (DesiredAccess & WRITE_DAC);
  3204. }
  3205. DestFileSharing = 0;
  3206. continue;
  3207. }
  3208. //
  3209. //
  3210. // We might be having a problem copying encryption. E.g.
  3211. // we might get an access-denied because the remote target machine
  3212. // isn't trusted for delegation.
  3213. // We'll try copying without encryption. If that works, then later, in
  3214. // BasepCopyEncryption, we'll see if it's OK that we lost
  3215. // encryption.
  3216. //
  3217. if ( (SourceFileAttributes & FILE_ATTRIBUTE_ENCRYPTED)
  3218. && (SourceFileAttributesMask & FILE_ATTRIBUTE_ENCRYPTED) )
  3219. {
  3220. // Try taking the encryption bit out of the
  3221. // attributes we pass to NtCreateFile.
  3222. SourceFileAttributesMask &= ~FILE_ATTRIBUTE_ENCRYPTED;
  3223. CreateOptions = DesiredCreateOptions;
  3224. DestFileAccess = DesiredAccess;
  3225. DestFileSharing = 0;
  3226. continue;
  3227. }
  3228. //
  3229. // NT4 returns invalid-parameter error on an attempt to open
  3230. // a directory file with both FILE_WRITE_DATA and FILE_OPEN_IF.
  3231. // Samba 2.x returns ERROR_ALREADY_EXISTS, even though
  3232. // the semantics of FILE_OPEN_IF says that it should open the
  3233. // existing directory.
  3234. // For both cases, we'll try it with FILE_OPEN.
  3235. //
  3236. if( ( GetLastError() == ERROR_INVALID_PARAMETER ||
  3237. GetLastError() == ERROR_ALREADY_EXISTS ) &&
  3238. (SourceFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
  3239. CreateDisposition == FILE_OPEN_IF ) {
  3240. CreateDisposition = FILE_OPEN;
  3241. SourceFileAttributesMask = ~0;
  3242. CreateOptions = DesiredCreateOptions;
  3243. DestFileAccess = DesiredAccess;
  3244. DestFileSharing = 0;
  3245. continue;
  3246. }
  3247. //
  3248. // Some downlevel servers don't allow a directory to be opened for write_data
  3249. // access. We need write_data in order to set compression, but the
  3250. // downlevel server likely won't support that anyway. (This happens on
  3251. // NTFS4 if the target directory file doesn't already exist. In this
  3252. // case the compression will get copied over anyway as part of the create.)
  3253. //
  3254. if( (SourceFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
  3255. (DestFileAccess & FILE_WRITE_DATA) ) {
  3256. DestFileAccess = DesiredAccess & ~FILE_WRITE_DATA;
  3257. CreateDisposition = DesiredCreateDisposition;
  3258. CreateOptions = DesiredCreateOptions;
  3259. DestFileSharing = 0;
  3260. continue;
  3261. }
  3262. // If we reach this point, we've run out of options and must give up.
  3263. DestFile = INVALID_HANDLE_VALUE;
  3264. leave;
  3265. } // while( DestFile == INVALID_HANDLE_VALUE )
  3266. // If we reach this point, we've successfully opened the dest file.
  3267. //
  3268. // If we lost the EAs, check to see if that's OK before carrying on.
  3269. //
  3270. if( EasDropped && (*lpCopyFlags & PRIVCOPY_FILE_METADATA) ) {
  3271. // Check to see if it's OK that we skip the EAs.
  3272. if( !BasepCopyFileCallback( TRUE, // Continue by default
  3273. ERROR_EAS_NOT_SUPPORTED,
  3274. Context,
  3275. NULL,
  3276. PRIVCALLBACK_EAS_NOT_SUPPORTED,
  3277. hSourceFile,
  3278. INVALID_HANDLE_VALUE,
  3279. &Canceled
  3280. ) ) {
  3281. // Not OK. The last error has already been set.
  3282. if( Canceled ) {
  3283. BaseMarkFileForDelete(
  3284. DestFile,
  3285. 0
  3286. );
  3287. }
  3288. NtClose( DestFile );
  3289. DestFile = INVALID_HANDLE_VALUE;
  3290. leave;
  3291. }
  3292. }
  3293. //
  3294. // When appropriate, copy the reparse point.
  3295. //
  3296. if ( OpenFileAsReparsePoint &&
  3297. (DestFile != INVALID_HANDLE_VALUE)) {
  3298. DWORD CopyResult = FALSE;
  3299. CopyResult = CopyReparsePoint(
  3300. hSourceFile,
  3301. DestFile
  3302. );
  3303. if ( !CopyResult ) {
  3304. //
  3305. // Note that when OpenFileAsReparsePoint is TRUE, by
  3306. // exiting at this point the effect is that the caller
  3307. // will re-start the copy without inhibiting the reparse
  3308. // behavior.
  3309. //
  3310. //If we fail here, we may be leaving a newly created
  3311. // file around at the destination. If
  3312. // COPY_FILE_FAIL_IF_EXISTS has been specified,
  3313. // further retries will fail. Therefore we need to
  3314. // try to delete the new file here.
  3315. if (*lpCopyFlags & COPY_FILE_FAIL_IF_EXISTS)
  3316. {
  3317. FILE_DISPOSITION_INFORMATION Disposition = {TRUE};
  3318. Status = NtSetInformationFile(
  3319. DestFile,
  3320. &IoStatus,
  3321. &Disposition,
  3322. sizeof(Disposition),
  3323. FileDispositionInformation
  3324. );
  3325. //Ignore an error if there is one.
  3326. }
  3327. *lpDestFile = DestFile;
  3328. leave;
  3329. }
  3330. } // if ( OpenFileAsReparsePoint &&(DestFile != INVALID_HANDLE_VALUE))
  3331. //
  3332. // Get the File & FileSys attributes for the target volume, plus
  3333. // the FileSys attributes for the source volume. Ignore errors in
  3334. // the target, e.g. it might be a printer and not support these calls
  3335. // (just assume the attrs in this case are zero).
  3336. //
  3337. *DestFileFsAttributes = 0;
  3338. SourceFileFsAttributes = 0;
  3339. DestFileAttributes = 0;
  3340. Status = NtQueryVolumeInformationFile( DestFile,
  3341. &IoStatus,
  3342. &FileFsAttrInfoBuffer.Info,
  3343. sizeof(FileFsAttrInfoBuffer),
  3344. FileFsAttributeInformation );
  3345. if( NT_SUCCESS(Status) ) {
  3346. *DestFileFsAttributes = FileFsAttrInfoBuffer.Info.FileSystemAttributes;
  3347. }
  3348. if( lpConsoleName == NULL ) {
  3349. Status = NtQueryInformationFile( DestFile,
  3350. &IoStatus,
  3351. &DestBasicInformation,
  3352. sizeof(DestBasicInformation),
  3353. FileBasicInformation );
  3354. if( NT_SUCCESS(Status) ) {
  3355. DestFileAttributes = DestBasicInformation.FileAttributes;
  3356. }
  3357. }
  3358. Status = NtQueryVolumeInformationFile( hSourceFile,
  3359. &IoStatus,
  3360. &FileFsAttrInfoBuffer.Info,
  3361. sizeof(FileFsAttrInfoBuffer),
  3362. FileFsAttributeInformation );
  3363. if( NT_SUCCESS(Status) ) {
  3364. SourceFileFsAttributes = FileFsAttrInfoBuffer.Info.FileSystemAttributes;
  3365. } else {
  3366. BaseMarkFileForDelete( DestFile, 0 );
  3367. BaseSetLastNTError(Status);
  3368. leave;
  3369. }
  3370. //
  3371. // If requested and applicable, copy one or more of the the DACL, SACL, owner, and group.
  3372. // If the source doesn't support persistent ACLs, assume that that means that
  3373. // it doesn't support any of DACL, SACL, and owner/group.
  3374. //
  3375. if( (SourceFileFsAttributes & FILE_PERSISTENT_ACLS)
  3376. &&
  3377. (*lpCopyFlags & (PRIVCOPY_FILE_METADATA | PRIVCOPY_FILE_SACL | PRIVCOPY_FILE_OWNER_GROUP)) ) {
  3378. SECURITY_INFORMATION SecurityInformation = 0;
  3379. if( *lpCopyFlags & PRIVCOPY_FILE_METADATA
  3380. && !(*lpCopyFlags & PRIVCOPY_FILE_SKIP_DACL) ) {
  3381. // Copy the DACL if metadata flag is set, but skip_dacl is not.
  3382. // The skip_dacl flag is a temporary workaround for a problem
  3383. // in CSC & roaming profiles.
  3384. SecurityInformation |= DACL_SECURITY_INFORMATION;
  3385. }
  3386. if( *lpCopyFlags & PRIVCOPY_FILE_SACL )
  3387. SecurityInformation |= SACL_SECURITY_INFORMATION;
  3388. if( *lpCopyFlags & PRIVCOPY_FILE_OWNER_GROUP )
  3389. SecurityInformation |= OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION;
  3390. if( SecurityInformation != 0 ) {
  3391. if( !BasepCopySecurityInformation( lpExistingFileName,
  3392. hSourceFile,
  3393. SourceFileAccess,
  3394. lpNewFileName,
  3395. DestFile,
  3396. DestFileAccess,
  3397. SecurityInformation,
  3398. Context,
  3399. *DestFileFsAttributes,
  3400. &Canceled,
  3401. FALSE )) {
  3402. if( Canceled ) {
  3403. BaseMarkFileForDelete(
  3404. DestFile,
  3405. 0
  3406. );
  3407. }
  3408. leave;
  3409. }
  3410. }
  3411. }
  3412. //
  3413. // Copy compression and encryption
  3414. //
  3415. if( (*lpCopyFlags & PRIVCOPY_FILE_METADATA) ) {
  3416. BOOL DoCompression = FALSE;
  3417. int i = 0;
  3418. // Compression and encryption must be handled in the proper
  3419. // order, since a file can't be both at once. For example,
  3420. // if copying (with supersede) a compressed/unencrypted file over an
  3421. // uncompressed/encrypted file, we must decrypt the dest
  3422. // before attempting to compress it.
  3423. if( DestFileAttributes & FILE_ATTRIBUTE_COMPRESSED ) {
  3424. // Handle compression first
  3425. DoCompression = TRUE;
  3426. }
  3427. for( i = 0; i < 2; i++ ) {
  3428. if( DoCompression ) {
  3429. DoCompression = FALSE;
  3430. b = BasepCopyCompression( hSourceFile,
  3431. DestFile,
  3432. SourceFileAttributes,
  3433. DestFileAttributes,
  3434. *DestFileFsAttributes,
  3435. *lpCopyFlags,
  3436. &Context );
  3437. } else {
  3438. DoCompression = TRUE;
  3439. b = BasepCopyEncryption( hSourceFile,
  3440. lpNewFileName,
  3441. &DestFile,
  3442. &Obja,
  3443. DestFileAccess,
  3444. DestFileSharing,
  3445. CreateDisposition,
  3446. CreateOptions,
  3447. SourceFileAttributes,
  3448. SourceFileAttributesMask,
  3449. &DestFileAttributes,
  3450. *DestFileFsAttributes,
  3451. *lpCopyFlags,
  3452. &Context );
  3453. }
  3454. if( !b ) {
  3455. // The dest file is already marked for delete and
  3456. // last error has been set.
  3457. leave;
  3458. }
  3459. } // for( i = 0; i < 2; i++ )
  3460. } // if( (*lpCopyFlags & PRIVCOPY_FILE_METADATA) )
  3461. else {
  3462. //
  3463. // For the public copyfile, we still need to handle encryption.
  3464. //
  3465. b = BasepCopyEncryption( hSourceFile,
  3466. lpNewFileName,
  3467. &DestFile,
  3468. &Obja,
  3469. DestFileAccess,
  3470. DestFileSharing,
  3471. CreateDisposition,
  3472. CreateOptions,
  3473. SourceFileAttributes,
  3474. SourceFileAttributesMask,
  3475. &DestFileAttributes,
  3476. *DestFileFsAttributes,
  3477. *lpCopyFlags,
  3478. &Context );
  3479. if( !b ) {
  3480. // The dest file is already marked for delete and
  3481. // last error has been set.
  3482. leave;
  3483. }
  3484. } // if( (*lpCopyFlags & PRIVCOPY_FILE_METADATA) ) ... else
  3485. //
  3486. // If copying a directory file, see if any attributes need to be
  3487. // added. For non-directory files, this is handled in the NtCreateFile since
  3488. // either FILE_CREATE or FILE_OVERWRITE_IF is specified.
  3489. //
  3490. if( SourceFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
  3491. //
  3492. // But before copying attributes, in the supersede case, the target's
  3493. // named streams should be removed. We need to do this first,
  3494. // in case copying the attributes sets the read-only bit.
  3495. //
  3496. if( *lpCopyFlags & PRIVCOPY_FILE_SUPERSEDE ) {
  3497. ULONG StreamInfoSize;
  3498. PFILE_STREAM_INFORMATION StreamInfo;
  3499. PFILE_STREAM_INFORMATION StreamInfoBase = NULL;
  3500. // Get the dest file's streams
  3501. StreamInfoSize = 4096;
  3502. do {
  3503. StreamInfoBase = RtlAllocateHeap( RtlProcessHeap(),
  3504. MAKE_TAG( TMP_TAG ),
  3505. StreamInfoSize );
  3506. if ( !StreamInfoBase ) {
  3507. BaseSetLastNTError( STATUS_NO_MEMORY );
  3508. leave;
  3509. }
  3510. Status = NtQueryInformationFile(
  3511. DestFile,
  3512. &IoStatus,
  3513. (PVOID) StreamInfoBase,
  3514. StreamInfoSize,
  3515. FileStreamInformation
  3516. );
  3517. if ( !NT_SUCCESS(Status) ) {
  3518. //
  3519. // We failed the call. Free up the previous buffer and set up
  3520. // for another pass with a buffer twice as large
  3521. //
  3522. RtlFreeHeap(RtlProcessHeap(), 0, StreamInfoBase);
  3523. StreamInfoBase = NULL;
  3524. StreamInfoSize *= 2;
  3525. }
  3526. else if( IoStatus.Information == 0 ) {
  3527. // There are no streams
  3528. RtlFreeHeap(RtlProcessHeap(), 0, StreamInfoBase);
  3529. StreamInfoBase = NULL;
  3530. }
  3531. } while ( Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL );
  3532. // If there were any streams, delete them.
  3533. if( StreamInfoBase != NULL ) {
  3534. StreamInfo = StreamInfoBase;
  3535. while (TRUE) {
  3536. OBJECT_ATTRIBUTES Obja;
  3537. UNICODE_STRING StreamName;
  3538. HANDLE DestStream;
  3539. StreamName.Length = (USHORT) StreamInfo->StreamNameLength;
  3540. StreamName.MaximumLength = (USHORT) StreamName.Length;
  3541. StreamName.Buffer = StreamInfo->StreamName;
  3542. InitializeObjectAttributes(
  3543. &Obja,
  3544. &StreamName,
  3545. OBJ_CASE_INSENSITIVE,
  3546. DestFile,
  3547. NULL
  3548. );
  3549. // Relative-open the stream to be deleted.
  3550. Status = NtCreateFile(
  3551. &DestStream,
  3552. DELETE|SYNCHRONIZE,
  3553. &Obja,
  3554. &IoStatusBlock,
  3555. NULL,
  3556. 0,
  3557. FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
  3558. FILE_OPEN,
  3559. FILE_DELETE_ON_CLOSE | FILE_SYNCHRONOUS_IO_NONALERT,
  3560. NULL,
  3561. 0
  3562. );
  3563. if( !NT_SUCCESS(Status) ) {
  3564. RtlFreeHeap(RtlProcessHeap(), 0, StreamInfoBase);
  3565. BaseMarkFileForDelete( DestFile, 0 );
  3566. BaseSetLastNTError( Status );
  3567. leave;
  3568. }
  3569. // Delete the stream
  3570. NtClose( DestStream );
  3571. if (StreamInfo->NextEntryOffset == 0) {
  3572. break;
  3573. }
  3574. StreamInfo = (PFILE_STREAM_INFORMATION)((PCHAR) StreamInfo + StreamInfo->NextEntryOffset);
  3575. } // while (TRUE)
  3576. RtlFreeHeap(RtlProcessHeap(), 0, StreamInfoBase);
  3577. } // if( StreamInfoBase != NULL )
  3578. } // if( *lpCopyFlags & PRIVCOPY_FILE_SUPERSEDE )
  3579. // Now, if necessary, copy over attributes.
  3580. if( SourceFileAttributes != DestFileAttributes ) {
  3581. DestFileAttributes |= SourceFileAttributes;
  3582. RtlZeroMemory( &DestBasicInformation, sizeof(DestBasicInformation) );
  3583. DestBasicInformation.FileAttributes = DestFileAttributes;
  3584. Status = NtSetInformationFile( DestFile,
  3585. &IoStatus,
  3586. &DestBasicInformation,
  3587. sizeof(DestBasicInformation),
  3588. FileBasicInformation );
  3589. if( !NT_SUCCESS(Status) ) {
  3590. BaseMarkFileForDelete( DestFile, 0 );
  3591. BaseSetLastNTError(Status);
  3592. leave;
  3593. }
  3594. DestFileAttributes = 0;
  3595. Status = NtQueryInformationFile( DestFile,
  3596. &IoStatus,
  3597. &DestBasicInformation,
  3598. sizeof(DestBasicInformation),
  3599. FileBasicInformation );
  3600. if( NT_SUCCESS(Status) ) {
  3601. DestFileAttributes = DestBasicInformation.FileAttributes;
  3602. } else {
  3603. BaseMarkFileForDelete( DestFile, 0 );
  3604. BaseSetLastNTError(Status);
  3605. leave;
  3606. }
  3607. }
  3608. } // if( SourceFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
  3609. } // if( DestFile != INVALID_HANDLE_VALUE )
  3610. //
  3611. // If this is a directory file, there is nothing left to copy
  3612. //
  3613. if( SourceFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
  3614. BOOL Canceled = FALSE;
  3615. if( !BasepCopyFileCallback( TRUE, // ContinueByDefault
  3616. RtlNtStatusToDosError(STATUS_REQUEST_ABORTED),
  3617. Context,
  3618. NULL,
  3619. CALLBACK_STREAM_SWITCH,
  3620. hSourceFile,
  3621. DestFile,
  3622. &Canceled ) ) {
  3623. ReturnValue = FALSE;
  3624. if( Canceled ) {
  3625. BaseMarkFileForDelete(
  3626. DestFile,
  3627. 0
  3628. );
  3629. }
  3630. } else {
  3631. ReturnValue = TRUE;
  3632. }
  3633. leave;
  3634. }
  3635. } else { // if ( !ARGUMENT_PRESENT(hTargetFile) )
  3636. // We're copying a named stream.
  3637. OBJECT_ATTRIBUTES ObjectAttributes;
  3638. UNICODE_STRING StreamName;
  3639. IO_STATUS_BLOCK IoStatus;
  3640. ULONG Disposition;
  3641. //
  3642. // Create the output stream relative to the file specified by the
  3643. // hTargetFile file handle.
  3644. //
  3645. RtlInitUnicodeString(&StreamName, lpNewFileName);
  3646. InitializeObjectAttributes(
  3647. &ObjectAttributes,
  3648. &StreamName,
  3649. 0,
  3650. hTargetFile,
  3651. (PSECURITY_DESCRIPTOR)NULL
  3652. );
  3653. //
  3654. // Determine the disposition type.
  3655. //
  3656. if ( *lpCopyFlags & COPY_FILE_FAIL_IF_EXISTS ) {
  3657. Disposition = FILE_CREATE;
  3658. } else {
  3659. Disposition = FILE_OVERWRITE_IF;
  3660. }
  3661. if ( Restartable ) {
  3662. if ( lpRestartState->LastKnownGoodOffset.QuadPart ) {
  3663. Disposition = FILE_OPEN;
  3664. } else {
  3665. Disposition = FILE_OVERWRITE_IF;
  3666. }
  3667. }
  3668. //
  3669. // Inhibit reparse behavior when appropriate.
  3670. //
  3671. FlagsAndAttributes = FILE_SYNCHRONOUS_IO_NONALERT | FILE_SEQUENTIAL_ONLY;
  3672. DesiredAccess = GENERIC_WRITE | SYNCHRONIZE;
  3673. if ( OpenFileAsReparsePoint ) {
  3674. //
  3675. // The target has to be opened as reparse point. If
  3676. // this fails the source is to be closed and re-opened
  3677. // without inhibiting the reparse point behavior.
  3678. //
  3679. FlagsAndAttributes |= FILE_OPEN_REPARSE_POINT;
  3680. DesiredAccess |= GENERIC_READ;
  3681. if ( !(*lpCopyFlags & COPY_FILE_FAIL_IF_EXISTS) ||
  3682. !(Restartable && (lpRestartState->LastKnownGoodOffset.QuadPart)) ) {
  3683. Disposition = FILE_OPEN_IF;
  3684. }
  3685. }
  3686. Status = NtCreateFile(
  3687. &DestFile,
  3688. DesiredAccess,
  3689. &ObjectAttributes,
  3690. &IoStatus,
  3691. lpFileSize,
  3692. 0,
  3693. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  3694. Disposition,
  3695. FlagsAndAttributes,
  3696. (PVOID)NULL,
  3697. 0);
  3698. if ( !NT_SUCCESS(Status) ) {
  3699. BaseSetLastNTError(Status);
  3700. // If we failed the create with an invalid name error, it might be becuase
  3701. // we tried to copy an NTFS5 property set to pre-NTFS5 (and pre-NTFS4/SP4)
  3702. // To detect this, we first check the error, and that the prefix character
  3703. // of the stream name is a reserved ole character.
  3704. if( Status == STATUS_OBJECT_NAME_INVALID
  3705. &&
  3706. StreamName.Buffer[1] <= 0x1f
  3707. &&
  3708. StreamName.Buffer[1] >= 1 ) {
  3709. // Now we check to see if we're copying to pre-NTFS5.
  3710. // If so, we'll assume that the leading ole character is
  3711. // the cause of the problem, and will silently fail the
  3712. // copy of this stream just as NT4 did.
  3713. NTSTATUS StatusT = STATUS_SUCCESS;
  3714. IO_STATUS_BLOCK Iosb;
  3715. FILE_FS_ATTRIBUTE_INFORMATION FsAttrInfo;
  3716. StatusT = NtQueryVolumeInformationFile( hTargetFile, &Iosb,
  3717. &FsAttrInfo,
  3718. sizeof(FsAttrInfo),
  3719. FileFsAttributeInformation );
  3720. // We should always get a buffer-overflow error here, because we don't
  3721. // provide enough buffer for the file system name, but that's OK because
  3722. // we don't need it (status_buffer_overflow is just a warning, so the rest
  3723. // of the data is good).
  3724. if( !NT_SUCCESS(StatusT) && STATUS_BUFFER_OVERFLOW != StatusT) {
  3725. Status = StatusT;
  3726. BaseSetLastNTError(Status);
  3727. leave;
  3728. }
  3729. // If this is pre-NTFS5, then silently ignore the error.
  3730. if( !(FILE_SUPPORTS_OBJECT_IDS & FsAttrInfo.FileSystemAttributes) ) {
  3731. Status = STATUS_SUCCESS;
  3732. ReturnValue = TRUE;
  3733. leave;
  3734. }
  3735. }
  3736. if ( Status != STATUS_ACCESS_DENIED ) {
  3737. BaseSetLastNTError(Status);
  3738. leave;
  3739. }
  3740. //
  3741. // Determine whether or not this failed because the file
  3742. // is a readonly file. If so, change it to read/write,
  3743. // re-attempt the open, and set it back to readonly again.
  3744. //
  3745. Status = NtQueryInformationFile(
  3746. hTargetFile,
  3747. &IoStatus,
  3748. (PVOID) &FileBasicInformationData,
  3749. sizeof(FileBasicInformationData),
  3750. FileBasicInformation
  3751. );
  3752. if ( !NT_SUCCESS(Status) ) {
  3753. BaseSetLastNTError(Status);
  3754. leave;
  3755. }
  3756. if ( FileBasicInformationData.FileAttributes & FILE_ATTRIBUTE_READONLY ) {
  3757. ULONG attributes = FileBasicInformationData.FileAttributes;
  3758. RtlZeroMemory( &FileBasicInformationData,
  3759. sizeof(FileBasicInformationData)
  3760. );
  3761. FileBasicInformationData.FileAttributes = FILE_ATTRIBUTE_NORMAL;
  3762. (VOID) NtSetInformationFile(
  3763. hTargetFile,
  3764. &IoStatus,
  3765. &FileBasicInformationData,
  3766. sizeof(FileBasicInformationData),
  3767. FileBasicInformation
  3768. );
  3769. Status = NtCreateFile(
  3770. &DestFile,
  3771. DesiredAccess,
  3772. &ObjectAttributes,
  3773. &IoStatus,
  3774. lpFileSize,
  3775. 0,
  3776. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  3777. Disposition,
  3778. FlagsAndAttributes,
  3779. (PVOID)NULL,
  3780. 0);
  3781. FileBasicInformationData.FileAttributes = attributes;
  3782. (VOID) NtSetInformationFile(
  3783. hTargetFile,
  3784. &IoStatus,
  3785. &FileBasicInformationData,
  3786. sizeof(FileBasicInformationData),
  3787. FileBasicInformation
  3788. );
  3789. if ( !NT_SUCCESS(Status) ) {
  3790. BaseSetLastNTError(Status);
  3791. leave;
  3792. }
  3793. } else {
  3794. leave;
  3795. }
  3796. }
  3797. //
  3798. // Adjust the file length in the case of a destination open with the
  3799. // reparse behavior inhibited. This is needed because of the incompatibility
  3800. // between FILE_OPEN_REPARSE_POINT and FILE_OVERWRITE_IF.
  3801. //
  3802. if ( OpenFileAsReparsePoint ) {
  3803. if ( !(*lpCopyFlags & COPY_FILE_FAIL_IF_EXISTS) ||
  3804. !(Restartable && (lpRestartState->LastKnownGoodOffset.QuadPart)) ) {
  3805. SetFilePointer(DestFile,0,NULL,FILE_BEGIN);
  3806. }
  3807. }
  3808. } // if ( !ARGUMENT_PRESENT(hTargetFile) ) ... else
  3809. //
  3810. // Adjust the notion of restartability and chunk size based on whether
  3811. // or not one of the files is remote.
  3812. //
  3813. if ( Restartable || lpFileSize->QuadPart >= BASE_COPY_FILE_CHUNK ) {
  3814. if ( BasepRemoteFile(hSourceFile,DestFile) ) {
  3815. *lpCopySize = BASE_COPY_FILE_CHUNK - 4096;
  3816. } else if ( Restartable ) {
  3817. *lpCopyFlags &= ~COPY_FILE_RESTARTABLE;
  3818. Restartable = FALSE;
  3819. }
  3820. }
  3821. //
  3822. // Preallocate the size of this file/stream so that extends do not
  3823. // occur.
  3824. //
  3825. if ( !(Restartable && lpRestartState->LastKnownGoodOffset.QuadPart) &&
  3826. lpFileSize->QuadPart) {
  3827. EndOfFileInformation.EndOfFile = *lpFileSize;
  3828. Status = NtSetInformationFile(
  3829. DestFile,
  3830. &IoStatus,
  3831. &EndOfFileInformation,
  3832. sizeof(EndOfFileInformation),
  3833. FileEndOfFileInformation
  3834. );
  3835. if ( Status == STATUS_DISK_FULL ) {
  3836. BaseSetLastNTError(Status);
  3837. BaseMarkFileForDelete(
  3838. DestFile,
  3839. FileBasicInformationData.FileAttributes
  3840. );
  3841. CloseHandle(DestFile);
  3842. DestFile = INVALID_HANDLE_VALUE;
  3843. leave;
  3844. }
  3845. }
  3846. //
  3847. // If the caller has a progress routine, invoke it and indicate that the
  3848. // output file or alternate data stream has been created. Note that a
  3849. // stream number of 1 means that the file itself has been created.
  3850. //
  3851. BytesWritten.QuadPart = 0;
  3852. if ( Context ) {
  3853. if ( Context->lpProgressRoutine ) {
  3854. Context->dwStreamNumber += 1;
  3855. ReturnCode = Context->lpProgressRoutine(
  3856. Context->TotalFileSize,
  3857. Context->TotalBytesTransferred,
  3858. *lpFileSize,
  3859. BytesWritten,
  3860. Context->dwStreamNumber,
  3861. CALLBACK_STREAM_SWITCH,
  3862. hSourceFile,
  3863. DestFile,
  3864. Context->lpData
  3865. );
  3866. } else {
  3867. ReturnCode = PROGRESS_CONTINUE;
  3868. }
  3869. if ( ReturnCode == PROGRESS_CANCEL ||
  3870. (Context->lpCancel && *Context->lpCancel) ) {
  3871. BaseMarkFileForDelete(
  3872. hTargetFile ? hTargetFile : DestFile,
  3873. FileBasicInformationData.FileAttributes
  3874. );
  3875. BaseSetLastNTError(STATUS_REQUEST_ABORTED);
  3876. leave;
  3877. }
  3878. if ( ReturnCode == PROGRESS_STOP ) {
  3879. BaseSetLastNTError(STATUS_REQUEST_ABORTED);
  3880. leave;
  3881. }
  3882. if ( ReturnCode == PROGRESS_QUIET ) {
  3883. Context = NULL;
  3884. *lpCopyFileContext = NULL;
  3885. }
  3886. }
  3887. if (!Restartable) {
  3888. while (!lpFileSize->HighPart && (lpFileSize->LowPart < TWO56K)) {
  3889. // If there's nothing to copy, then we're done (this happens when
  3890. // copying directory files, as there's no unnamed data stream).
  3891. if( lpFileSize->LowPart == 0 ) {
  3892. ReturnValue = TRUE;
  3893. leave;
  3894. }
  3895. //
  3896. // Create a section and map the source file. If anything fails,
  3897. // then drop into an I/O system copy mode.
  3898. //
  3899. Status = NtCreateSection(
  3900. &Section,
  3901. SECTION_ALL_ACCESS,
  3902. NULL,
  3903. NULL,
  3904. PAGE_READONLY,
  3905. SEC_COMMIT,
  3906. hSourceFile
  3907. );
  3908. if ( !NT_SUCCESS(Status) ) {
  3909. break;
  3910. }
  3911. SectionOffset.LowPart = 0;
  3912. SectionOffset.HighPart = 0;
  3913. ViewSize = 0;
  3914. BigViewSize = 0;
  3915. Status = NtMapViewOfSection(
  3916. Section,
  3917. NtCurrentProcess(),
  3918. &SourceBase,
  3919. 0L,
  3920. 0L,
  3921. &SectionOffset,
  3922. &BigViewSize,
  3923. ViewShare,
  3924. 0L,
  3925. PAGE_READONLY
  3926. );
  3927. NtClose(Section);
  3928. Section = NULL;
  3929. if ( !NT_SUCCESS(Status) ) {
  3930. break;
  3931. }
  3932. //
  3933. // note that this is OK since ViewSize will never be > 256k in this path
  3934. //
  3935. ViewSize = (ULONG)BigViewSize;
  3936. //
  3937. // Everything is mapped, so copy the stream
  3938. //
  3939. SourceBuffer = SourceBase;
  3940. BytesToWrite = lpFileSize->LowPart;
  3941. //
  3942. // Since we are playing with user memory here, the user
  3943. // may decommit or unmap it on us. We wrap the access
  3944. // in try/except to clean up if anything goes wrong
  3945. //
  3946. // We set ReturnCode inside the try/except so that we
  3947. // can detect failure and leave from the enclosing try/finally.
  3948. //
  3949. ReturnCode = TRUE;
  3950. try {
  3951. while (BytesToWrite) {
  3952. if (BytesToWrite > *lpCopySize) {
  3953. ViewSize = *lpCopySize;
  3954. } else {
  3955. ViewSize = BytesToWrite;
  3956. }
  3957. if ( !WriteFile(DestFile,SourceBuffer,ViewSize, &ViewSize, NULL) ) {
  3958. if ( !ARGUMENT_PRESENT(hTargetFile) &&
  3959. GetLastError() != ERROR_NO_MEDIA_IN_DRIVE ) {
  3960. BaseMarkFileForDelete(
  3961. DestFile,
  3962. FileBasicInformationData.FileAttributes
  3963. );
  3964. }
  3965. ReturnCode = PROGRESS_STOP;
  3966. leave;
  3967. }
  3968. BytesToWrite -= ViewSize;
  3969. SourceBuffer += ViewSize;
  3970. //
  3971. // If the caller has a progress routine, invoke it for this
  3972. // chunk's completion.
  3973. //
  3974. if ( Context ) {
  3975. if ( Context->lpProgressRoutine ) {
  3976. BytesWritten.QuadPart += ViewSize;
  3977. Context->TotalBytesTransferred.QuadPart += ViewSize;
  3978. ReturnCode = Context->lpProgressRoutine(
  3979. Context->TotalFileSize,
  3980. Context->TotalBytesTransferred,
  3981. *lpFileSize,
  3982. BytesWritten,
  3983. Context->dwStreamNumber,
  3984. CALLBACK_CHUNK_FINISHED,
  3985. hSourceFile,
  3986. DestFile,
  3987. Context->lpData
  3988. );
  3989. } else {
  3990. ReturnCode = PROGRESS_CONTINUE;
  3991. }
  3992. if ( ReturnCode == PROGRESS_CANCEL ||
  3993. (Context->lpCancel && *Context->lpCancel) ) {
  3994. if ( !ARGUMENT_PRESENT(hTargetFile) ) {
  3995. BaseMarkFileForDelete(
  3996. hTargetFile ? hTargetFile : DestFile,
  3997. FileBasicInformationData.FileAttributes
  3998. );
  3999. BaseSetLastNTError(STATUS_REQUEST_ABORTED);
  4000. }
  4001. ReturnCode = PROGRESS_STOP;
  4002. leave;
  4003. }
  4004. if ( ReturnCode == PROGRESS_STOP ) {
  4005. BaseSetLastNTError(STATUS_REQUEST_ABORTED);
  4006. ReturnCode = PROGRESS_STOP;
  4007. leave;
  4008. }
  4009. if ( ReturnCode == PROGRESS_QUIET ) {
  4010. Context = NULL;
  4011. *lpCopyFileContext = NULL;
  4012. }
  4013. }
  4014. } // while (BytesToWrite)
  4015. } except(EXCEPTION_EXECUTE_HANDLER) {
  4016. if ( !ARGUMENT_PRESENT(hTargetFile) ) {
  4017. BaseMarkFileForDelete(
  4018. DestFile,
  4019. FileBasicInformationData.FileAttributes
  4020. );
  4021. }
  4022. BaseSetLastNTError(GetExceptionCode());
  4023. ReturnCode = PROGRESS_STOP;
  4024. }
  4025. if (ReturnCode != PROGRESS_STOP) {
  4026. ReturnValue = TRUE;
  4027. }
  4028. leave;
  4029. } // while (!lpFileSize->HighPart && (lpFileSize->LowPart < TWO56K)
  4030. } // if (!Restartable)
  4031. if ( Restartable ) {
  4032. //
  4033. // A restartable operation is being performed. Reset the state
  4034. // of the copy to the last known good offset that was written
  4035. // to the output file to continue the operation.
  4036. //
  4037. SetFilePointer(
  4038. hSourceFile,
  4039. lpRestartState->LastKnownGoodOffset.LowPart,
  4040. &lpRestartState->LastKnownGoodOffset.HighPart,
  4041. FILE_BEGIN
  4042. );
  4043. SetFilePointer(
  4044. DestFile,
  4045. lpRestartState->LastKnownGoodOffset.LowPart,
  4046. &lpRestartState->LastKnownGoodOffset.HighPart,
  4047. FILE_BEGIN
  4048. );
  4049. BytesWritten.QuadPart = lpRestartState->LastKnownGoodOffset.QuadPart;
  4050. }
  4051. IoDestBase = RtlAllocateHeap(
  4052. RtlProcessHeap(),
  4053. MAKE_TAG( TMP_TAG ),
  4054. *lpCopySize
  4055. );
  4056. if ( !IoDestBase ) {
  4057. if ( !ARGUMENT_PRESENT(hTargetFile) && !Restartable ) {
  4058. BaseMarkFileForDelete(
  4059. DestFile,
  4060. FileBasicInformationData.FileAttributes
  4061. );
  4062. }
  4063. BaseSetLastNTError(STATUS_NO_MEMORY);
  4064. leave;
  4065. }
  4066. do {
  4067. BlockSize = *lpCopySize;
  4068. fSkipBlock = FALSE;
  4069. if (!fSkipBlock) {
  4070. b = ReadFile(hSourceFile,IoDestBase,BlockSize, &ViewSize, NULL);
  4071. } else {
  4072. LARGE_INTEGER BytesRead;
  4073. BytesRead = BytesWritten;
  4074. if (BytesRead.QuadPart > lpFileSize->QuadPart) {
  4075. BlockSize = 0;
  4076. } else if (BytesRead.QuadPart + BlockSize >= lpFileSize->QuadPart) {
  4077. BlockSize = (ULONG)(lpFileSize->QuadPart - BytesRead.QuadPart);
  4078. }
  4079. BytesRead.QuadPart += BlockSize;
  4080. if ( SetFilePointer(hSourceFile,
  4081. BytesRead.LowPart,
  4082. &BytesRead.HighPart,
  4083. FILE_BEGIN) != 0xffffffff ) {
  4084. } else {
  4085. if (GetLastError() != NO_ERROR)
  4086. b = FALSE;
  4087. }
  4088. ViewSize = BlockSize;
  4089. }
  4090. if (!b || !ViewSize)
  4091. break;
  4092. if (!fSkipBlock) {
  4093. if ( !WriteFile(DestFile,IoDestBase,ViewSize, &ViewSize, NULL) ) {
  4094. if ( !ARGUMENT_PRESENT(hTargetFile) &&
  4095. GetLastError() != ERROR_NO_MEDIA_IN_DRIVE &&
  4096. !Restartable ) {
  4097. BaseMarkFileForDelete(
  4098. DestFile,
  4099. FileBasicInformationData.FileAttributes
  4100. );
  4101. }
  4102. leave;
  4103. }
  4104. BytesWritten.QuadPart += ViewSize;
  4105. } else {
  4106. BytesWritten.QuadPart += ViewSize;
  4107. if (( SetFilePointer(DestFile,
  4108. BytesWritten.LowPart,
  4109. &BytesWritten.HighPart,
  4110. FILE_BEGIN) == 0xffffffff ) &&
  4111. ( GetLastError() != NO_ERROR )) {
  4112. b = FALSE;
  4113. break;
  4114. }
  4115. }
  4116. WriteCount++;
  4117. if ( Restartable &&
  4118. (((WriteCount & 3) == 0 &&
  4119. BytesWritten.QuadPart ) ||
  4120. BytesWritten.QuadPart == lpFileSize->QuadPart) ) {
  4121. LARGE_INTEGER SavedOffset;
  4122. DWORD Bytes;
  4123. HANDLE DestinationFile = hTargetFile ? hTargetFile : DestFile;
  4124. //
  4125. // Another 256kb has been written to the target file, or
  4126. // this stream of the file has been completely copied, so
  4127. // update the restart state in the output file accordingly.
  4128. //
  4129. NtFlushBuffersFile(DestinationFile,&IoStatus);
  4130. SavedOffset.QuadPart = BytesWritten.QuadPart;
  4131. SetFilePointer(DestinationFile,0,NULL,FILE_BEGIN);
  4132. lpRestartState->LastKnownGoodOffset.QuadPart = BytesWritten.QuadPart;
  4133. lpRestartState->Checksum = BasepChecksum((PUSHORT)lpRestartState,FIELD_OFFSET(RESTART_STATE,Checksum) >> 1);
  4134. b = WriteFile(
  4135. DestinationFile,
  4136. lpRestartState,
  4137. sizeof(RESTART_STATE),
  4138. &Bytes,
  4139. NULL
  4140. );
  4141. if ( !b || Bytes != sizeof(RESTART_STATE) ) {
  4142. leave;
  4143. }
  4144. NtFlushBuffersFile(DestinationFile,&IoStatus);
  4145. SetFilePointer(
  4146. DestinationFile,
  4147. SavedOffset.LowPart,
  4148. &SavedOffset.HighPart,
  4149. FILE_BEGIN
  4150. );
  4151. }
  4152. //
  4153. // If the caller has a progress routine, invoke it for this
  4154. // chunk's completion.
  4155. //
  4156. if ( Context ) {
  4157. if ( Context->lpProgressRoutine ) {
  4158. Context->TotalBytesTransferred.QuadPart += ViewSize;
  4159. ReturnCode = Context->lpProgressRoutine(
  4160. Context->TotalFileSize,
  4161. Context->TotalBytesTransferred,
  4162. *lpFileSize,
  4163. BytesWritten,
  4164. Context->dwStreamNumber,
  4165. CALLBACK_CHUNK_FINISHED,
  4166. hSourceFile,
  4167. DestFile,
  4168. Context->lpData
  4169. );
  4170. } else {
  4171. ReturnCode = PROGRESS_CONTINUE;
  4172. }
  4173. if ( ReturnCode == PROGRESS_CANCEL ||
  4174. (Context->lpCancel && *Context->lpCancel) ) {
  4175. if ( !ARGUMENT_PRESENT(hTargetFile) ) {
  4176. BaseMarkFileForDelete(
  4177. hTargetFile ? hTargetFile : DestFile,
  4178. FileBasicInformationData.FileAttributes
  4179. );
  4180. BaseSetLastNTError(STATUS_REQUEST_ABORTED);
  4181. leave;
  4182. }
  4183. }
  4184. if ( ReturnCode == PROGRESS_STOP ) {
  4185. BaseSetLastNTError(STATUS_REQUEST_ABORTED);
  4186. leave;
  4187. }
  4188. if ( ReturnCode == PROGRESS_QUIET ) {
  4189. Context = NULL;
  4190. *lpCopyFileContext = NULL;
  4191. }
  4192. }
  4193. } while (TRUE);
  4194. if ( !b && !ARGUMENT_PRESENT(hTargetFile) ) {
  4195. if ( !Restartable ) {
  4196. BaseMarkFileForDelete(
  4197. DestFile,
  4198. FileBasicInformationData.FileAttributes
  4199. );
  4200. }
  4201. leave;
  4202. }
  4203. ReturnValue = TRUE;
  4204. } finally {
  4205. if ( DestFile != INVALID_HANDLE_VALUE ) {
  4206. *lpDestFile = DestFile;
  4207. }
  4208. if ( Section ) {
  4209. NtClose(Section);
  4210. }
  4211. if ( SourceBase ) {
  4212. NtUnmapViewOfSection(NtCurrentProcess(),SourceBase);
  4213. }
  4214. RtlFreeHeap(RtlProcessHeap(), 0,IoDestBase);
  4215. RtlFreeHeap(RtlProcessHeap(), 0, DestFileNameBuffer );
  4216. RtlFreeHeap(RtlProcessHeap(), 0, EaBuffer );
  4217. // If the TEB buffer was saved, restore it now.
  4218. if( lpExistingFileName == SaveStaticUnicodeBuffer ) {
  4219. memcpy( NtCurrentTeb()->StaticUnicodeBuffer,
  4220. SaveStaticUnicodeBuffer,
  4221. STATIC_UNICODE_BUFFER_LENGTH );
  4222. }
  4223. }
  4224. return ReturnValue;
  4225. }
  4226. HANDLE
  4227. WINAPI
  4228. ReOpenFile(
  4229. HANDLE hOriginalFile,
  4230. DWORD dwDesiredAccess,
  4231. DWORD dwShareMode,
  4232. DWORD dwFlags
  4233. )
  4234. /*++
  4235. Routine Description:
  4236. This API allows an application to reopen a file with different access, share modes
  4237. and flags given an already open handle. This API should be used if the application wants
  4238. to ensure that the original file does not go away but wants to reopen it with
  4239. Arguments:
  4240. hOriginalFile - Supplies the handle to the original file relative to which
  4241. we open a new handle.
  4242. dwDesiredAccess - Supplies the caller's desired access to the file. Any combination of
  4243. flags can be passed in (like FILE_READ_ATTRIBUTES)
  4244. Possible DesiredAccess Flags:
  4245. GENERIC_READ - Read access to the file is requested. This
  4246. allows data to be read from the file and the file pointer to
  4247. be modified.
  4248. GENERIC_WRITE - Write access to the file is requested. This
  4249. allows data to be written to the file and the file pointer to
  4250. be modified.
  4251. dwShareMode - Supplies a set of flags that indicates how this file is
  4252. to be shared with other openers of the file. A value of zero
  4253. for this parameter indicates no sharing of the file, or
  4254. exclusive access to the file is to occur.
  4255. ShareMode Flags:
  4256. FILE_SHARE_READ - Other open operations may be performed on the
  4257. file for read access.
  4258. FILE_SHARE_WRITE - Other open operations may be performed on the
  4259. file for write access.
  4260. FILE_SHARE_DELETE - Other open operations may be performed on the
  4261. file for delete access.
  4262. dwFlags - Specifies flags and attributes for the file.
  4263. The attributes are not accepted by this API as they are used only for Creating a file
  4264. This API reopens an existing file. All FILE_ATTRIBUTE_* flags are not allowed.
  4265. dwFlagsAndAttributes Flags:
  4266. FILE_FLAG_WRITE_THROUGH - Indicates that the system should
  4267. always write through any intermediate cache and go directly
  4268. to the file. The system may still cache writes, but may not
  4269. lazily flush the writes.
  4270. FILE_FLAG_OVERLAPPED - Indicates that the system should initialize
  4271. the file so that ReadFile and WriteFile operations that may
  4272. take a significant time to complete will return ERROR_IO_PENDING.
  4273. An event will be set to the signalled state when the operation
  4274. completes. When FILE_FLAG_OVERLAPPED is specified the system will
  4275. not maintain the file pointer. The position to read/write from
  4276. is passed to the system as part of the OVERLAPPED structure
  4277. which is an optional parameter to ReadFile and WriteFile.
  4278. FILE_FLAG_NO_BUFFERING - Indicates that the file is to be opened
  4279. with no intermediate buffering or caching done by the
  4280. system. Reads and writes to the file must be done on sector
  4281. boundries. Buffer addresses for reads and writes must be
  4282. aligned on at least disk sector boundries in memory.
  4283. FILE_FLAG_RANDOM_ACCESS - Indicates that access to the file may
  4284. be random. The system cache manager may use this to influence
  4285. its caching strategy for this file.
  4286. FILE_FLAG_SEQUENTIAL_SCAN - Indicates that access to the file
  4287. may be sequential. The system cache manager may use this to
  4288. influence its caching strategy for this file. The file may
  4289. in fact be accessed randomly, but the cache manager may
  4290. optimize its cacheing policy for sequential access.
  4291. FILE_FLAG_DELETE_ON_CLOSE - Indicates that the file is to be
  4292. automatically deleted when the last handle to it is closed.
  4293. FILE_FLAG_BACKUP_SEMANTICS - Indicates that the file is being opened
  4294. or created for the purposes of either a backup or a restore
  4295. operation. Thus, the system should make whatever checks are
  4296. appropriate to ensure that the caller is able to override
  4297. whatever security checks have been placed on the file to allow
  4298. this to happen.
  4299. FILE_FLAG_POSIX_SEMANTICS - Indicates that the file being opened
  4300. should be accessed in a manner compatible with the rules used
  4301. by POSIX. This includes allowing multiple files with the same
  4302. name, differing only in case. WARNING: Use of this flag may
  4303. render it impossible for a DOS, WIN-16, or WIN-32 application
  4304. to access the file.
  4305. FILE_FLAG_OPEN_REPARSE_POINT - Indicates that the file being opened
  4306. should be accessed as if it were a reparse point. WARNING: Use
  4307. of this flag may inhibit the operation of file system filter drivers
  4308. present in the I/O subsystem.
  4309. FILE_FLAG_OPEN_NO_RECALL - Indicates that all the state of the file
  4310. should be acessed without changing its storage location. Thus,
  4311. in the case of files that have parts of its state stored at a
  4312. remote servicer, no permanent recall of data is to happen.
  4313. Security Quality of Service information may also be specified in
  4314. the dwFlagsAndAttributes parameter. These bits are meaningful
  4315. only if the file being opened is the client side of a Named
  4316. Pipe. Otherwise they are ignored.
  4317. SECURITY_SQOS_PRESENT - Indicates that the Security Quality of
  4318. Service bits contain valid values.
  4319. Impersonation Levels:
  4320. SECURITY_ANONYMOUS - Specifies that the client should be impersonated
  4321. at Anonymous impersonation level.
  4322. SECURITY_IDENTIFICAION - Specifies that the client should be impersonated
  4323. at Identification impersonation level.
  4324. SECURITY_IMPERSONATION - Specifies that the client should be impersonated
  4325. at Impersonation impersonation level.
  4326. SECURITY_DELEGATION - Specifies that the client should be impersonated
  4327. at Delegation impersonation level.
  4328. Context Tracking:
  4329. SECURITY_CONTEXT_TRACKING - A boolean flag that when set,
  4330. specifies that the Security Tracking Mode should be
  4331. Dynamic, otherwise Static.
  4332. SECURITY_EFFECTIVE_ONLY - A boolean flag indicating whether
  4333. the entire security context of the client is to be made
  4334. available to the server or only the effective aspects of
  4335. the context.
  4336. Return Value:
  4337. Not -1 - Returns an open handle to the specified file. Subsequent
  4338. access to the file is controlled by the DesiredAccess parameter.
  4339. 0xffffffff - The operation failed. Extended error status is available
  4340. using GetLastError.
  4341. --*/
  4342. {
  4343. ULONG CreateFlags = 0;
  4344. ULONG CreateDisposition;
  4345. NTSTATUS Status;
  4346. OBJECT_ATTRIBUTES Obja;
  4347. HANDLE Handle;
  4348. IO_STATUS_BLOCK IoStatusBlock;
  4349. DWORD SQOSFlags;
  4350. SECURITY_IMPERSONATION_LEVEL ImpersonationLevel = 0;
  4351. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  4352. UNICODE_STRING FileName;
  4353. //
  4354. // Don't support console handles.
  4355. //
  4356. if (CONSOLE_HANDLE(hOriginalFile)) {
  4357. BaseSetLastNTError(STATUS_INVALID_HANDLE);
  4358. return INVALID_HANDLE_VALUE;
  4359. }
  4360. //
  4361. // The attributes are useless as this reopen of an existing file.
  4362. //
  4363. if (dwFlags & FILE_ATTRIBUTE_VALID_FLAGS) {
  4364. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  4365. return INVALID_HANDLE_VALUE;
  4366. }
  4367. //
  4368. // Initialize all the create flags from the Attribute flags.
  4369. //
  4370. CreateFlags |= (dwFlags & FILE_FLAG_NO_BUFFERING ? FILE_NO_INTERMEDIATE_BUFFERING : 0 );
  4371. CreateFlags |= (dwFlags & FILE_FLAG_WRITE_THROUGH ? FILE_WRITE_THROUGH : 0 );
  4372. CreateFlags |= (dwFlags & FILE_FLAG_OVERLAPPED ? 0 : FILE_SYNCHRONOUS_IO_NONALERT );
  4373. CreateFlags |= (dwFlags & FILE_FLAG_SEQUENTIAL_SCAN ? FILE_SEQUENTIAL_ONLY : 0 );
  4374. CreateFlags |= (dwFlags & FILE_FLAG_RANDOM_ACCESS ? FILE_RANDOM_ACCESS : 0 );
  4375. CreateFlags |= (dwFlags & FILE_FLAG_BACKUP_SEMANTICS ? FILE_OPEN_FOR_BACKUP_INTENT : 0 );
  4376. CreateFlags |= (dwFlags & FILE_FLAG_OPEN_REPARSE_POINT ? FILE_OPEN_REPARSE_POINT : 0 );
  4377. CreateFlags |= (dwFlags & FILE_FLAG_OPEN_NO_RECALL ? FILE_OPEN_NO_RECALL : 0 );
  4378. if ( dwFlags & FILE_FLAG_DELETE_ON_CLOSE ) {
  4379. CreateFlags |= FILE_DELETE_ON_CLOSE;
  4380. dwDesiredAccess |= DELETE;
  4381. }
  4382. CreateFlags |= FILE_NON_DIRECTORY_FILE;
  4383. CreateDisposition = FILE_OPEN;
  4384. RtlInitUnicodeString( &FileName, L"");
  4385. //
  4386. // Pass a NULL name relative to the original handle.
  4387. //
  4388. InitializeObjectAttributes(
  4389. &Obja,
  4390. &FileName,
  4391. dwFlags & FILE_FLAG_POSIX_SEMANTICS ? 0 : OBJ_CASE_INSENSITIVE,
  4392. hOriginalFile, // Related handle
  4393. NULL
  4394. );
  4395. SQOSFlags = dwFlags & SECURITY_VALID_SQOS_FLAGS;
  4396. if ( SQOSFlags & SECURITY_SQOS_PRESENT ) {
  4397. SQOSFlags &= ~SECURITY_SQOS_PRESENT;
  4398. if (SQOSFlags & SECURITY_CONTEXT_TRACKING) {
  4399. SecurityQualityOfService.ContextTrackingMode = (SECURITY_CONTEXT_TRACKING_MODE) TRUE;
  4400. SQOSFlags &= ~SECURITY_CONTEXT_TRACKING;
  4401. } else {
  4402. SecurityQualityOfService.ContextTrackingMode = (SECURITY_CONTEXT_TRACKING_MODE) FALSE;
  4403. }
  4404. if (SQOSFlags & SECURITY_EFFECTIVE_ONLY) {
  4405. SecurityQualityOfService.EffectiveOnly = TRUE;
  4406. SQOSFlags &= ~SECURITY_EFFECTIVE_ONLY;
  4407. } else {
  4408. SecurityQualityOfService.EffectiveOnly = FALSE;
  4409. }
  4410. SecurityQualityOfService.ImpersonationLevel = SQOSFlags >> 16;
  4411. } else {
  4412. SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  4413. SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
  4414. SecurityQualityOfService.EffectiveOnly = TRUE;
  4415. }
  4416. SecurityQualityOfService.Length = sizeof( SECURITY_QUALITY_OF_SERVICE );
  4417. Obja.SecurityQualityOfService = &SecurityQualityOfService;
  4418. Status = NtCreateFile(
  4419. &Handle,
  4420. (ACCESS_MASK)dwDesiredAccess | SYNCHRONIZE | FILE_READ_ATTRIBUTES,
  4421. &Obja,
  4422. &IoStatusBlock,
  4423. NULL,
  4424. 0,
  4425. dwShareMode,
  4426. CreateDisposition,
  4427. CreateFlags,
  4428. NULL,
  4429. 0
  4430. );
  4431. if ( !NT_SUCCESS(Status) ) {
  4432. BaseSetLastNTError(Status);
  4433. return INVALID_HANDLE_VALUE;
  4434. }
  4435. SetLastError(0);
  4436. return Handle;
  4437. }
  4438. HANDLE
  4439. WINAPI
  4440. CreateFileA(
  4441. LPCSTR lpFileName,
  4442. DWORD dwDesiredAccess,
  4443. DWORD dwShareMode,
  4444. LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  4445. DWORD dwCreationDisposition,
  4446. DWORD dwFlagsAndAttributes,
  4447. HANDLE hTemplateFile
  4448. )
  4449. /*++
  4450. Routine Description:
  4451. ANSI thunk to CreateFileW
  4452. --*/
  4453. {
  4454. PUNICODE_STRING Unicode;
  4455. Unicode = Basep8BitStringToStaticUnicodeString( lpFileName );
  4456. if (Unicode == NULL) {
  4457. return INVALID_HANDLE_VALUE;
  4458. }
  4459. return ( CreateFileW( Unicode->Buffer,
  4460. dwDesiredAccess,
  4461. dwShareMode,
  4462. lpSecurityAttributes,
  4463. dwCreationDisposition,
  4464. dwFlagsAndAttributes,
  4465. hTemplateFile
  4466. )
  4467. );
  4468. }
  4469. HANDLE
  4470. WINAPI
  4471. CreateFileW(
  4472. LPCWSTR lpFileName,
  4473. DWORD dwDesiredAccess,
  4474. DWORD dwShareMode,
  4475. LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  4476. DWORD dwCreationDisposition,
  4477. DWORD dwFlagsAndAttributes,
  4478. HANDLE hTemplateFile
  4479. )
  4480. /*++
  4481. Routine Description:
  4482. A file can be created, opened, or truncated, and a handle opened to
  4483. access the new file using CreateFile.
  4484. This API is used to create or open a file and obtain a handle to it
  4485. that allows reading data, writing data, and moving the file pointer.
  4486. This API allows the caller to specify the following creation
  4487. dispositions:
  4488. - Create a new file and fail if the file exists ( CREATE_NEW )
  4489. - Create a new file and succeed if it exists ( CREATE_ALWAYS )
  4490. - Open an existing file ( OPEN_EXISTING )
  4491. - Open and existing file or create it if it does not exist (
  4492. OPEN_ALWAYS )
  4493. - Truncate and existing file ( TRUNCATE_EXISTING )
  4494. If this call is successful, a handle is returned that has
  4495. appropriate access to the specified file.
  4496. If as a result of this call, a file is created,
  4497. - The attributes of the file are determined by the value of the
  4498. FileAttributes parameter or'd with the FILE_ATTRIBUTE_ARCHIVE bit.
  4499. - The length of the file will be set to zero.
  4500. - If the hTemplateFile parameter is specified, any extended
  4501. attributes associated with the file are assigned to the new file.
  4502. If a new file is not created, then the hTemplateFile is ignored as
  4503. are any extended attributes.
  4504. For DOS based systems running share.exe the file sharing semantics
  4505. work as described above. Without share.exe no share level
  4506. protection exists.
  4507. This call is logically equivalent to DOS (int 21h, function 5Bh), or
  4508. DOS (int 21h, function 3Ch) depending on the value of the
  4509. FailIfExists parameter.
  4510. Arguments:
  4511. lpFileName - Supplies the file name of the file to open. Depending on
  4512. the value of the FailIfExists parameter, this name may or may
  4513. not already exist.
  4514. dwDesiredAccess - Supplies the caller's desired access to the file.
  4515. DesiredAccess Flags:
  4516. GENERIC_READ - Read access to the file is requested. This
  4517. allows data to be read from the file and the file pointer to
  4518. be modified.
  4519. GENERIC_WRITE - Write access to the file is requested. This
  4520. allows data to be written to the file and the file pointer to
  4521. be modified.
  4522. dwShareMode - Supplies a set of flags that indicates how this file is
  4523. to be shared with other openers of the file. A value of zero
  4524. for this parameter indicates no sharing of the file, or
  4525. exclusive access to the file is to occur.
  4526. ShareMode Flags:
  4527. FILE_SHARE_READ - Other open operations may be performed on the
  4528. file for read access.
  4529. FILE_SHARE_WRITE - Other open operations may be performed on the
  4530. file for write access.
  4531. lpSecurityAttributes - An optional parameter that, if present, and
  4532. supported on the target file system supplies a security
  4533. descriptor for the new file.
  4534. dwCreationDisposition - Supplies a creation disposition that
  4535. specifies how this call is to operate. This parameter must be
  4536. one of the following values.
  4537. dwCreationDisposition Value:
  4538. CREATE_NEW - Create a new file. If the specified file already
  4539. exists, then fail. The attributes for the new file are what
  4540. is specified in the dwFlagsAndAttributes parameter or'd with
  4541. FILE_ATTRIBUTE_ARCHIVE. If the hTemplateFile is specified,
  4542. then any extended attributes associated with that file are
  4543. propogated to the new file.
  4544. CREATE_ALWAYS - Always create the file. If the file already
  4545. exists, then it is overwritten. The attributes for the new
  4546. file are what is specified in the dwFlagsAndAttributes
  4547. parameter or'd with FILE_ATTRIBUTE_ARCHIVE. If the
  4548. hTemplateFile is specified, then any extended attributes
  4549. associated with that file are propogated to the new file.
  4550. OPEN_EXISTING - Open the file, but if it does not exist, then
  4551. fail the call.
  4552. OPEN_ALWAYS - Open the file if it exists. If it does not exist,
  4553. then create the file using the same rules as if the
  4554. disposition were CREATE_NEW.
  4555. TRUNCATE_EXISTING - Open the file, but if it does not exist,
  4556. then fail the call. Once opened, the file is truncated such
  4557. that its size is zero bytes. This disposition requires that
  4558. the caller open the file with at least GENERIC_WRITE access.
  4559. dwFlagsAndAttributes - Specifies flags and attributes for the file.
  4560. The attributes are only used when the file is created (as
  4561. opposed to opened or truncated). Any combination of attribute
  4562. flags is acceptable except that all other attribute flags
  4563. override the normal file attribute, FILE_ATTRIBUTE_NORMAL. The
  4564. FILE_ATTRIBUTE_ARCHIVE flag is always implied.
  4565. dwFlagsAndAttributes Flags:
  4566. FILE_ATTRIBUTE_NORMAL - A normal file should be created.
  4567. FILE_ATTRIBUTE_READONLY - A read-only file should be created.
  4568. FILE_ATTRIBUTE_HIDDEN - A hidden file should be created.
  4569. FILE_ATTRIBUTE_SYSTEM - A system file should be created.
  4570. FILE_FLAG_WRITE_THROUGH - Indicates that the system should
  4571. always write through any intermediate cache and go directly
  4572. to the file. The system may still cache writes, but may not
  4573. lazily flush the writes.
  4574. FILE_FLAG_OVERLAPPED - Indicates that the system should initialize
  4575. the file so that ReadFile and WriteFile operations that may
  4576. take a significant time to complete will return ERROR_IO_PENDING.
  4577. An event will be set to the signalled state when the operation
  4578. completes. When FILE_FLAG_OVERLAPPED is specified the system will
  4579. not maintain the file pointer. The position to read/write from
  4580. is passed to the system as part of the OVERLAPPED structure
  4581. which is an optional parameter to ReadFile and WriteFile.
  4582. FILE_FLAG_NO_BUFFERING - Indicates that the file is to be opened
  4583. with no intermediate buffering or caching done by the
  4584. system. Reads and writes to the file must be done on sector
  4585. boundries. Buffer addresses for reads and writes must be
  4586. aligned on at least disk sector boundries in memory.
  4587. FILE_FLAG_RANDOM_ACCESS - Indicates that access to the file may
  4588. be random. The system cache manager may use this to influence
  4589. its caching strategy for this file.
  4590. FILE_FLAG_SEQUENTIAL_SCAN - Indicates that access to the file
  4591. may be sequential. The system cache manager may use this to
  4592. influence its caching strategy for this file. The file may
  4593. in fact be accessed randomly, but the cache manager may
  4594. optimize its cacheing policy for sequential access.
  4595. FILE_FLAG_DELETE_ON_CLOSE - Indicates that the file is to be
  4596. automatically deleted when the last handle to it is closed.
  4597. FILE_FLAG_BACKUP_SEMANTICS - Indicates that the file is being opened
  4598. or created for the purposes of either a backup or a restore
  4599. operation. Thus, the system should make whatever checks are
  4600. appropriate to ensure that the caller is able to override
  4601. whatever security checks have been placed on the file to allow
  4602. this to happen.
  4603. FILE_FLAG_POSIX_SEMANTICS - Indicates that the file being opened
  4604. should be accessed in a manner compatible with the rules used
  4605. by POSIX. This includes allowing multiple files with the same
  4606. name, differing only in case. WARNING: Use of this flag may
  4607. render it impossible for a DOS, WIN-16, or WIN-32 application
  4608. to access the file.
  4609. FILE_FLAG_OPEN_REPARSE_POINT - Indicates that the file being opened
  4610. should be accessed as if it were a reparse point. WARNING: Use
  4611. of this flag may inhibit the operation of file system filter drivers
  4612. present in the I/O subsystem.
  4613. FILE_FLAG_OPEN_NO_RECALL - Indicates that all the state of the file
  4614. should be acessed without changing its storage location. Thus,
  4615. in the case of files that have parts of its state stored at a
  4616. remote servicer, no permanent recall of data is to happen.
  4617. Security Quality of Service information may also be specified in
  4618. the dwFlagsAndAttributes parameter. These bits are meaningful
  4619. only if the file being opened is the client side of a Named
  4620. Pipe. Otherwise they are ignored.
  4621. SECURITY_SQOS_PRESENT - Indicates that the Security Quality of
  4622. Service bits contain valid values.
  4623. Impersonation Levels:
  4624. SECURITY_ANONYMOUS - Specifies that the client should be impersonated
  4625. at Anonymous impersonation level.
  4626. SECURITY_IDENTIFICAION - Specifies that the client should be impersonated
  4627. at Identification impersonation level.
  4628. SECURITY_IMPERSONATION - Specifies that the client should be impersonated
  4629. at Impersonation impersonation level.
  4630. SECURITY_DELEGATION - Specifies that the client should be impersonated
  4631. at Delegation impersonation level.
  4632. Context Tracking:
  4633. SECURITY_CONTEXT_TRACKING - A boolean flag that when set,
  4634. specifies that the Security Tracking Mode should be
  4635. Dynamic, otherwise Static.
  4636. SECURITY_EFFECTIVE_ONLY - A boolean flag indicating whether
  4637. the entire security context of the client is to be made
  4638. available to the server or only the effective aspects of
  4639. the context.
  4640. hTemplateFile - An optional parameter, then if specified, supplies a
  4641. handle with GENERIC_READ access to a template file. The
  4642. template file is used to supply extended attributes for the file
  4643. being created. When the new file is created, the relevant attributes
  4644. from the template file are used in creating the new file.
  4645. Return Value:
  4646. Not -1 - Returns an open handle to the specified file. Subsequent
  4647. access to the file is controlled by the DesiredAccess parameter.
  4648. 0xffffffff - The operation failed. Extended error status is available
  4649. using GetLastError.
  4650. --*/
  4651. {
  4652. NTSTATUS Status;
  4653. OBJECT_ATTRIBUTES Obja;
  4654. HANDLE Handle;
  4655. UNICODE_STRING FileName;
  4656. IO_STATUS_BLOCK IoStatusBlock;
  4657. BOOLEAN TranslationStatus;
  4658. RTL_RELATIVE_NAME_U RelativeName;
  4659. PVOID FreeBuffer;
  4660. ULONG CreateDisposition;
  4661. ULONG CreateFlags;
  4662. FILE_ALLOCATION_INFORMATION AllocationInfo;
  4663. FILE_EA_INFORMATION EaInfo;
  4664. PFILE_FULL_EA_INFORMATION EaBuffer;
  4665. ULONG EaSize;
  4666. PCUNICODE_STRING lpConsoleName;
  4667. BOOL bInheritHandle;
  4668. BOOL EndsInSlash;
  4669. DWORD SQOSFlags;
  4670. BOOLEAN ContextTrackingMode = FALSE;
  4671. BOOLEAN EffectiveOnly = FALSE;
  4672. SECURITY_IMPERSONATION_LEVEL ImpersonationLevel = 0;
  4673. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  4674. switch ( dwCreationDisposition ) {
  4675. case CREATE_NEW :
  4676. CreateDisposition = FILE_CREATE;
  4677. break;
  4678. case CREATE_ALWAYS :
  4679. CreateDisposition = FILE_OVERWRITE_IF;
  4680. break;
  4681. case OPEN_EXISTING :
  4682. CreateDisposition = FILE_OPEN;
  4683. break;
  4684. case OPEN_ALWAYS :
  4685. CreateDisposition = FILE_OPEN_IF;
  4686. break;
  4687. case TRUNCATE_EXISTING :
  4688. CreateDisposition = FILE_OPEN;
  4689. if ( !(dwDesiredAccess & GENERIC_WRITE) ) {
  4690. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  4691. return INVALID_HANDLE_VALUE;
  4692. }
  4693. break;
  4694. default :
  4695. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  4696. return INVALID_HANDLE_VALUE;
  4697. }
  4698. // temporary routing code
  4699. RtlInitUnicodeString(&FileName,lpFileName);
  4700. if ( FileName.Length > 1 && lpFileName[(FileName.Length >> 1)-1] == (WCHAR)'\\' ) {
  4701. EndsInSlash = TRUE;
  4702. }
  4703. else {
  4704. EndsInSlash = FALSE;
  4705. }
  4706. if ((lpConsoleName = BaseIsThisAConsoleName(&FileName,dwDesiredAccess)) ) {
  4707. Handle = INVALID_HANDLE_VALUE;
  4708. bInheritHandle = FALSE;
  4709. if ( ARGUMENT_PRESENT(lpSecurityAttributes) ) {
  4710. bInheritHandle = lpSecurityAttributes->bInheritHandle;
  4711. }
  4712. Handle = OpenConsoleW(lpConsoleName->Buffer,
  4713. dwDesiredAccess,
  4714. bInheritHandle,
  4715. FILE_SHARE_READ | FILE_SHARE_WRITE //dwShareMode
  4716. );
  4717. if ( Handle == INVALID_HANDLE_VALUE ) {
  4718. BaseSetLastNTError(STATUS_ACCESS_DENIED);
  4719. return INVALID_HANDLE_VALUE;
  4720. }
  4721. else {
  4722. SetLastError(0);
  4723. return Handle;
  4724. }
  4725. }
  4726. // end temporary code
  4727. CreateFlags = 0;
  4728. TranslationStatus = RtlDosPathNameToRelativeNtPathName_U(
  4729. lpFileName,
  4730. &FileName,
  4731. NULL,
  4732. &RelativeName
  4733. );
  4734. if ( !TranslationStatus ) {
  4735. SetLastError(ERROR_PATH_NOT_FOUND);
  4736. return INVALID_HANDLE_VALUE;
  4737. }
  4738. FreeBuffer = FileName.Buffer;
  4739. if ( RelativeName.RelativeName.Length ) {
  4740. FileName = RelativeName.RelativeName;
  4741. }
  4742. else {
  4743. RelativeName.ContainingDirectory = NULL;
  4744. }
  4745. InitializeObjectAttributes(
  4746. &Obja,
  4747. &FileName,
  4748. dwFlagsAndAttributes & FILE_FLAG_POSIX_SEMANTICS ? 0 : OBJ_CASE_INSENSITIVE,
  4749. RelativeName.ContainingDirectory,
  4750. NULL
  4751. );
  4752. SQOSFlags = dwFlagsAndAttributes & SECURITY_VALID_SQOS_FLAGS;
  4753. if ( SQOSFlags & SECURITY_SQOS_PRESENT ) {
  4754. SQOSFlags &= ~SECURITY_SQOS_PRESENT;
  4755. if (SQOSFlags & SECURITY_CONTEXT_TRACKING) {
  4756. SecurityQualityOfService.ContextTrackingMode = (SECURITY_CONTEXT_TRACKING_MODE) TRUE;
  4757. SQOSFlags &= ~SECURITY_CONTEXT_TRACKING;
  4758. } else {
  4759. SecurityQualityOfService.ContextTrackingMode = (SECURITY_CONTEXT_TRACKING_MODE) FALSE;
  4760. }
  4761. if (SQOSFlags & SECURITY_EFFECTIVE_ONLY) {
  4762. SecurityQualityOfService.EffectiveOnly = TRUE;
  4763. SQOSFlags &= ~SECURITY_EFFECTIVE_ONLY;
  4764. } else {
  4765. SecurityQualityOfService.EffectiveOnly = FALSE;
  4766. }
  4767. SecurityQualityOfService.ImpersonationLevel = SQOSFlags >> 16;
  4768. } else {
  4769. SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  4770. SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
  4771. SecurityQualityOfService.EffectiveOnly = TRUE;
  4772. }
  4773. SecurityQualityOfService.Length = sizeof( SECURITY_QUALITY_OF_SERVICE );
  4774. Obja.SecurityQualityOfService = &SecurityQualityOfService;
  4775. if ( ARGUMENT_PRESENT(lpSecurityAttributes) ) {
  4776. Obja.SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
  4777. if ( lpSecurityAttributes->bInheritHandle ) {
  4778. Obja.Attributes |= OBJ_INHERIT;
  4779. }
  4780. }
  4781. EaBuffer = NULL;
  4782. EaSize = 0;
  4783. if ( ARGUMENT_PRESENT(hTemplateFile) ) {
  4784. Status = NtQueryInformationFile(
  4785. hTemplateFile,
  4786. &IoStatusBlock,
  4787. &EaInfo,
  4788. sizeof(EaInfo),
  4789. FileEaInformation
  4790. );
  4791. if ( NT_SUCCESS(Status) && EaInfo.EaSize ) {
  4792. EaSize = EaInfo.EaSize;
  4793. do {
  4794. EaSize *= 2;
  4795. EaBuffer = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( TMP_TAG ), EaSize);
  4796. if ( !EaBuffer ) {
  4797. RtlReleaseRelativeName(&RelativeName);
  4798. RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
  4799. BaseSetLastNTError(STATUS_NO_MEMORY);
  4800. return INVALID_HANDLE_VALUE;
  4801. }
  4802. Status = NtQueryEaFile(
  4803. hTemplateFile,
  4804. &IoStatusBlock,
  4805. EaBuffer,
  4806. EaSize,
  4807. FALSE,
  4808. (PVOID)NULL,
  4809. 0,
  4810. (PULONG)NULL,
  4811. TRUE
  4812. );
  4813. if ( !NT_SUCCESS(Status) ) {
  4814. RtlFreeHeap(RtlProcessHeap(), 0,EaBuffer);
  4815. EaBuffer = NULL;
  4816. IoStatusBlock.Information = 0;
  4817. }
  4818. } while ( Status == STATUS_BUFFER_OVERFLOW ||
  4819. Status == STATUS_BUFFER_TOO_SMALL );
  4820. EaSize = (ULONG)IoStatusBlock.Information;
  4821. }
  4822. }
  4823. CreateFlags |= (dwFlagsAndAttributes & FILE_FLAG_NO_BUFFERING ? FILE_NO_INTERMEDIATE_BUFFERING : 0 );
  4824. CreateFlags |= (dwFlagsAndAttributes & FILE_FLAG_WRITE_THROUGH ? FILE_WRITE_THROUGH : 0 );
  4825. CreateFlags |= (dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED ? 0 : FILE_SYNCHRONOUS_IO_NONALERT );
  4826. CreateFlags |= (dwFlagsAndAttributes & FILE_FLAG_SEQUENTIAL_SCAN ? FILE_SEQUENTIAL_ONLY : 0 );
  4827. CreateFlags |= (dwFlagsAndAttributes & FILE_FLAG_RANDOM_ACCESS ? FILE_RANDOM_ACCESS : 0 );
  4828. CreateFlags |= (dwFlagsAndAttributes & FILE_FLAG_BACKUP_SEMANTICS ? FILE_OPEN_FOR_BACKUP_INTENT : 0 );
  4829. if ( dwFlagsAndAttributes & FILE_FLAG_DELETE_ON_CLOSE ) {
  4830. CreateFlags |= FILE_DELETE_ON_CLOSE;
  4831. dwDesiredAccess |= DELETE;
  4832. }
  4833. if ( dwFlagsAndAttributes & FILE_FLAG_OPEN_REPARSE_POINT ) {
  4834. CreateFlags |= FILE_OPEN_REPARSE_POINT;
  4835. }
  4836. if ( dwFlagsAndAttributes & FILE_FLAG_OPEN_NO_RECALL ) {
  4837. CreateFlags |= FILE_OPEN_NO_RECALL;
  4838. }
  4839. //
  4840. // Backup semantics allow directories to be opened
  4841. //
  4842. if ( !(dwFlagsAndAttributes & FILE_FLAG_BACKUP_SEMANTICS) ) {
  4843. CreateFlags |= FILE_NON_DIRECTORY_FILE;
  4844. }
  4845. else {
  4846. //
  4847. // Backup intent was specified... Now look to see if we are to allow
  4848. // directory creation
  4849. //
  4850. if ( (dwFlagsAndAttributes & FILE_ATTRIBUTE_DIRECTORY ) &&
  4851. (dwFlagsAndAttributes & FILE_FLAG_POSIX_SEMANTICS ) &&
  4852. (CreateDisposition == FILE_CREATE) ) {
  4853. CreateFlags |= FILE_DIRECTORY_FILE;
  4854. }
  4855. }
  4856. Status = NtCreateFile(
  4857. &Handle,
  4858. (ACCESS_MASK)dwDesiredAccess | SYNCHRONIZE | FILE_READ_ATTRIBUTES,
  4859. &Obja,
  4860. &IoStatusBlock,
  4861. NULL,
  4862. dwFlagsAndAttributes & (FILE_ATTRIBUTE_VALID_FLAGS & ~FILE_ATTRIBUTE_DIRECTORY),
  4863. dwShareMode,
  4864. CreateDisposition,
  4865. CreateFlags,
  4866. EaBuffer,
  4867. EaSize
  4868. );
  4869. RtlReleaseRelativeName(&RelativeName);
  4870. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  4871. RtlFreeHeap(RtlProcessHeap(), 0, EaBuffer);
  4872. if ( !NT_SUCCESS(Status) ) {
  4873. BaseSetLastNTError(Status);
  4874. if ( Status == STATUS_OBJECT_NAME_COLLISION ) {
  4875. SetLastError(ERROR_FILE_EXISTS);
  4876. }
  4877. else if ( Status == STATUS_FILE_IS_A_DIRECTORY ) {
  4878. if ( EndsInSlash ) {
  4879. SetLastError(ERROR_PATH_NOT_FOUND);
  4880. }
  4881. else {
  4882. SetLastError(ERROR_ACCESS_DENIED);
  4883. }
  4884. }
  4885. return INVALID_HANDLE_VALUE;
  4886. }
  4887. //
  4888. // if NT returns supersede/overwritten, it means that a create_always, openalways
  4889. // found an existing copy of the file. In this case ERROR_ALREADY_EXISTS is returned
  4890. //
  4891. if ( (dwCreationDisposition == CREATE_ALWAYS && IoStatusBlock.Information == FILE_OVERWRITTEN) ||
  4892. (dwCreationDisposition == OPEN_ALWAYS && IoStatusBlock.Information == FILE_OPENED) ){
  4893. SetLastError(ERROR_ALREADY_EXISTS);
  4894. }
  4895. else {
  4896. SetLastError(0);
  4897. }
  4898. //
  4899. // Truncate the file if required
  4900. //
  4901. if ( dwCreationDisposition == TRUNCATE_EXISTING) {
  4902. AllocationInfo.AllocationSize.QuadPart = 0;
  4903. Status = NtSetInformationFile(
  4904. Handle,
  4905. &IoStatusBlock,
  4906. &AllocationInfo,
  4907. sizeof(AllocationInfo),
  4908. FileAllocationInformation
  4909. );
  4910. if ( !NT_SUCCESS(Status) ) {
  4911. BaseSetLastNTError(Status);
  4912. NtClose(Handle);
  4913. Handle = INVALID_HANDLE_VALUE;
  4914. }
  4915. }
  4916. //
  4917. // Deal with hTemplateFile
  4918. //
  4919. return Handle;
  4920. }
  4921. HFILE
  4922. WINAPI
  4923. OpenFile(
  4924. LPCSTR lpFileName,
  4925. LPOFSTRUCT lpReOpenBuff,
  4926. UINT uStyle
  4927. )
  4928. {
  4929. BOOL b;
  4930. FILETIME LastWriteTime;
  4931. HANDLE hFile;
  4932. DWORD DesiredAccess;
  4933. DWORD ShareMode;
  4934. DWORD CreateDisposition;
  4935. DWORD PathLength;
  4936. LPSTR FilePart;
  4937. IO_STATUS_BLOCK IoStatusBlock;
  4938. FILE_FS_DEVICE_INFORMATION DeviceInfo;
  4939. NTSTATUS Status;
  4940. OFSTRUCT OriginalReOpenBuff;
  4941. BOOL SearchFailed;
  4942. SearchFailed = FALSE;
  4943. OriginalReOpenBuff = *lpReOpenBuff;
  4944. hFile = (HANDLE)-1;
  4945. try {
  4946. SetLastError(0);
  4947. if ( uStyle & OF_PARSE ) {
  4948. PathLength = GetFullPathName(lpFileName,(OFS_MAXPATHNAME - 1),lpReOpenBuff->szPathName,&FilePart);
  4949. if ( PathLength > (OFS_MAXPATHNAME - 1) ) {
  4950. SetLastError(ERROR_INVALID_DATA);
  4951. hFile = (HANDLE)-1;
  4952. goto finally_exit;
  4953. }
  4954. lpReOpenBuff->cBytes = sizeof(*lpReOpenBuff);
  4955. lpReOpenBuff->fFixedDisk = 1;
  4956. lpReOpenBuff->nErrCode = 0;
  4957. lpReOpenBuff->Reserved1 = 0;
  4958. lpReOpenBuff->Reserved2 = 0;
  4959. hFile = (HANDLE)0;
  4960. goto finally_exit;
  4961. }
  4962. //
  4963. // Compute Desired Access
  4964. //
  4965. if ( uStyle & OF_WRITE ) {
  4966. DesiredAccess = GENERIC_WRITE;
  4967. }
  4968. else {
  4969. DesiredAccess = GENERIC_READ;
  4970. }
  4971. if ( uStyle & OF_READWRITE ) {
  4972. DesiredAccess |= (GENERIC_READ | GENERIC_WRITE);
  4973. }
  4974. //
  4975. // Compute ShareMode
  4976. //
  4977. ShareMode = BasepOfShareToWin32Share(uStyle);
  4978. //
  4979. // Compute Create Disposition
  4980. //
  4981. CreateDisposition = OPEN_EXISTING;
  4982. if ( uStyle & OF_CREATE ) {
  4983. CreateDisposition = CREATE_ALWAYS;
  4984. DesiredAccess = (GENERIC_READ | GENERIC_WRITE);
  4985. }
  4986. //
  4987. // if this is anything other than a re-open, fill the re-open buffer
  4988. // with the full pathname for the file
  4989. //
  4990. if ( !(uStyle & OF_REOPEN) ) {
  4991. PathLength = SearchPath(NULL,lpFileName,NULL,OFS_MAXPATHNAME-1,lpReOpenBuff->szPathName,&FilePart);
  4992. if ( PathLength > (OFS_MAXPATHNAME - 1) ) {
  4993. SetLastError(ERROR_INVALID_DATA);
  4994. hFile = (HANDLE)-1;
  4995. goto finally_exit;
  4996. }
  4997. if ( PathLength == 0 ) {
  4998. SearchFailed = TRUE;
  4999. PathLength = GetFullPathName(lpFileName,(OFS_MAXPATHNAME - 1),lpReOpenBuff->szPathName,&FilePart);
  5000. if ( !PathLength || PathLength > (OFS_MAXPATHNAME - 1) ) {
  5001. SetLastError(ERROR_INVALID_DATA);
  5002. hFile = (HANDLE)-1;
  5003. goto finally_exit;
  5004. }
  5005. }
  5006. }
  5007. //
  5008. // Special case, Delete, Exist, and Parse
  5009. //
  5010. if ( uStyle & OF_EXIST ) {
  5011. if ( !(uStyle & OF_CREATE) ) {
  5012. DWORD FileAttributes;
  5013. if (SearchFailed) {
  5014. SetLastError(ERROR_FILE_NOT_FOUND);
  5015. hFile = (HANDLE)-1;
  5016. goto finally_exit;
  5017. }
  5018. FileAttributes = GetFileAttributesA(lpReOpenBuff->szPathName);
  5019. if ( FileAttributes == 0xffffffff ) {
  5020. SetLastError(ERROR_FILE_NOT_FOUND);
  5021. hFile = (HANDLE)-1;
  5022. goto finally_exit;
  5023. }
  5024. if ( FileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
  5025. SetLastError(ERROR_ACCESS_DENIED);
  5026. hFile = (HANDLE)-1;
  5027. goto finally_exit;
  5028. }
  5029. else {
  5030. hFile = (HANDLE)1;
  5031. lpReOpenBuff->cBytes = sizeof(*lpReOpenBuff);
  5032. goto finally_exit;
  5033. }
  5034. }
  5035. }
  5036. if ( uStyle & OF_DELETE ) {
  5037. if ( DeleteFile(lpReOpenBuff->szPathName) ) {
  5038. lpReOpenBuff->nErrCode = 0;
  5039. lpReOpenBuff->cBytes = sizeof(*lpReOpenBuff);
  5040. hFile = (HANDLE)1;
  5041. goto finally_exit;
  5042. }
  5043. else {
  5044. lpReOpenBuff->nErrCode = ERROR_FILE_NOT_FOUND;
  5045. hFile = (HANDLE)-1;
  5046. goto finally_exit;
  5047. }
  5048. }
  5049. //
  5050. // Open the file
  5051. //
  5052. retry_open:
  5053. hFile = CreateFile(
  5054. lpReOpenBuff->szPathName,
  5055. DesiredAccess,
  5056. ShareMode,
  5057. NULL,
  5058. CreateDisposition,
  5059. 0,
  5060. NULL
  5061. );
  5062. if ( hFile == INVALID_HANDLE_VALUE ) {
  5063. if ( uStyle & OF_PROMPT
  5064. && !(GetErrorMode() & SEM_NOOPENFILEERRORBOX)
  5065. && !(RtlGetThreadErrorMode() & RTL_ERRORMODE_NOOPENFILEERRORBOX)) {
  5066. {
  5067. DWORD WinErrorStatus;
  5068. NTSTATUS st,HardErrorStatus;
  5069. ULONG_PTR ErrorParameter;
  5070. ULONG ErrorResponse;
  5071. ANSI_STRING AnsiString;
  5072. UNICODE_STRING UnicodeString;
  5073. WinErrorStatus = GetLastError();
  5074. if ( WinErrorStatus == ERROR_FILE_NOT_FOUND ) {
  5075. HardErrorStatus = STATUS_NO_SUCH_FILE;
  5076. }
  5077. else if ( WinErrorStatus == ERROR_PATH_NOT_FOUND ) {
  5078. HardErrorStatus = STATUS_OBJECT_PATH_NOT_FOUND;
  5079. }
  5080. else {
  5081. goto finally_exit;
  5082. }
  5083. //
  5084. // Hard error time
  5085. //
  5086. RtlInitAnsiString(&AnsiString,lpReOpenBuff->szPathName);
  5087. st = RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, TRUE);
  5088. if ( !NT_SUCCESS(st) ) {
  5089. goto finally_exit;
  5090. }
  5091. ErrorParameter = (ULONG_PTR)&UnicodeString;
  5092. HardErrorStatus = NtRaiseHardError(
  5093. HardErrorStatus | HARDERROR_OVERRIDE_ERRORMODE,
  5094. 1,
  5095. 1,
  5096. &ErrorParameter,
  5097. OptionRetryCancel,
  5098. &ErrorResponse
  5099. );
  5100. RtlFreeUnicodeString(&UnicodeString);
  5101. if ( NT_SUCCESS(HardErrorStatus) && ErrorResponse == ResponseRetry ) {
  5102. goto retry_open;
  5103. }
  5104. }
  5105. }
  5106. goto finally_exit;
  5107. }
  5108. if ( uStyle & OF_EXIST ) {
  5109. CloseHandle(hFile);
  5110. hFile = (HANDLE)1;
  5111. lpReOpenBuff->cBytes = sizeof(*lpReOpenBuff);
  5112. goto finally_exit;
  5113. }
  5114. //
  5115. // Determine if this is a hard disk.
  5116. //
  5117. Status = NtQueryVolumeInformationFile(
  5118. hFile,
  5119. &IoStatusBlock,
  5120. &DeviceInfo,
  5121. sizeof(DeviceInfo),
  5122. FileFsDeviceInformation
  5123. );
  5124. if ( !NT_SUCCESS(Status) ) {
  5125. CloseHandle(hFile);
  5126. BaseSetLastNTError(Status);
  5127. hFile = (HANDLE)-1;
  5128. goto finally_exit;
  5129. }
  5130. switch ( DeviceInfo.DeviceType ) {
  5131. case FILE_DEVICE_DISK:
  5132. case FILE_DEVICE_DISK_FILE_SYSTEM:
  5133. if ( DeviceInfo.Characteristics & FILE_REMOVABLE_MEDIA ) {
  5134. lpReOpenBuff->fFixedDisk = 0;
  5135. }
  5136. else {
  5137. lpReOpenBuff->fFixedDisk = 1;
  5138. }
  5139. break;
  5140. default:
  5141. lpReOpenBuff->fFixedDisk = 0;
  5142. break;
  5143. }
  5144. //
  5145. // Capture the last write time and save in the open struct.
  5146. //
  5147. b = GetFileTime(hFile,NULL,NULL,&LastWriteTime);
  5148. if ( !b ) {
  5149. lpReOpenBuff->Reserved1 = 0;
  5150. lpReOpenBuff->Reserved2 = 0;
  5151. }
  5152. else {
  5153. b = FileTimeToDosDateTime(
  5154. &LastWriteTime,
  5155. &lpReOpenBuff->Reserved1,
  5156. &lpReOpenBuff->Reserved2
  5157. );
  5158. if ( !b ) {
  5159. lpReOpenBuff->Reserved1 = 0;
  5160. lpReOpenBuff->Reserved2 = 0;
  5161. }
  5162. }
  5163. lpReOpenBuff->cBytes = sizeof(*lpReOpenBuff);
  5164. //
  5165. // The re-open buffer is completely filled in. Now
  5166. // see if we are quitting (parsing), verifying, or
  5167. // just returning with the file opened.
  5168. //
  5169. if ( uStyle & OF_VERIFY ) {
  5170. if ( OriginalReOpenBuff.Reserved1 == lpReOpenBuff->Reserved1 &&
  5171. OriginalReOpenBuff.Reserved2 == lpReOpenBuff->Reserved2 &&
  5172. !strcmp(OriginalReOpenBuff.szPathName,lpReOpenBuff->szPathName) ) {
  5173. goto finally_exit;
  5174. }
  5175. else {
  5176. *lpReOpenBuff = OriginalReOpenBuff;
  5177. CloseHandle(hFile);
  5178. hFile = (HANDLE)-1;
  5179. goto finally_exit;
  5180. }
  5181. }
  5182. finally_exit:;
  5183. }
  5184. finally {
  5185. lpReOpenBuff->nErrCode = (WORD)GetLastError();
  5186. }
  5187. return (HFILE)HandleToUlong(hFile);
  5188. }
  5189. /*++
  5190. Routine Description:
  5191. This is an internal routine that modifies the DACL so that
  5192. BasepCopySecurityInfo will copy over the CreatorOwner inherited ACE.
  5193. This is accomplished by finding the CreatorOwner ACE and marking
  5194. it as "not inherited".
  5195. ReplaceFile does not have enough privileges in a typical app to transfer
  5196. the owner from the previous file to the new copy. Consequently, the owner
  5197. can change after calling ReplaceFile, which can result in the previous
  5198. owner losing access to the new file, since inherited ACEs are not copied to
  5199. the new file, but are re-inherited from the parent directory.
  5200. If the previous owner had access to the file by the inherited ACE
  5201. CreatorOwner:F -> PreviousOwner:F, changing owners will result in
  5202. CreatorOwner:F -> NewOwner:F, and the previous owner's ACE is dropped.
  5203. By stripping the inherit flag off the previous owner's ACE, it will
  5204. be copied to the new file, and the previous owner will still have access.
  5205. Arguments:
  5206. Dacl - DACL to be modified
  5207. PreviousOwner - The current owner of the resource
  5208. NewOwner - The new to-be owner of the resource
  5209. Return Value:
  5210. NTSTATUS -- returns STATUS_SUCCESS if previous owner is the same as the new owner, or the previous owner's ACE was marked as "not inherited".
  5211. --*/
  5212. NTSTATUS BasepCopyCreatorOwnerACE (PACL Dacl,
  5213. PSID PreviousOwner,
  5214. PSID NewOwner)
  5215. {
  5216. NTSTATUS nts = STATUS_SUCCESS;
  5217. ACL_SIZE_INFORMATION aclSize;
  5218. PACCESS_ALLOWED_ACE pACE = NULL;
  5219. WORD wCount;
  5220. if (NULL == PreviousOwner || NULL == Dacl) {
  5221. nts = STATUS_INVALID_PARAMETER;
  5222. goto Err;
  5223. }
  5224. // If the new owner and the previous owner are the same
  5225. // There's no need to change the ACL, so return STATUS_SUCCESS
  5226. if (NewOwner != NULL && RtlEqualSid (NewOwner, PreviousOwner)) {
  5227. nts = STATUS_SUCCESS;
  5228. goto Err;
  5229. }
  5230. if (!NT_SUCCESS(nts = RtlQueryInformationAcl (Dacl, &aclSize,
  5231. sizeof(aclSize),
  5232. AclSizeInformation))) {
  5233. goto Err;
  5234. }
  5235. for (wCount = 0; wCount < aclSize.AceCount; wCount++) {
  5236. if (!NT_SUCCESS(nts = RtlGetAce (Dacl, wCount, (PVOID*) &pACE))) {
  5237. goto Err;
  5238. }
  5239. if (pACE->Header.AceType != ACCESS_ALLOWED_ACE_TYPE)
  5240. continue;
  5241. // Find the previous owner's ACE
  5242. // The previous owner must have full access to the file
  5243. if (RtlEqualSid (PreviousOwner, (PSID) &pACE->SidStart) &&
  5244. pACE->Mask == FILE_ALL_ACCESS) {
  5245. if (pACE->Header.AceFlags & INHERITED_ACE) // disable the flag
  5246. pACE->Header.AceFlags &= ~INHERITED_ACE;
  5247. break; // else if flag is not set, previous owner has full access
  5248. }
  5249. }
  5250. Err:
  5251. return nts;
  5252. }
  5253. typedef DWORD (WINAPI *GETSECURITYINFOPTR)(
  5254. IN LPCWSTR pObjectName,
  5255. IN SE_OBJECT_TYPE ObjectType,
  5256. IN SECURITY_INFORMATION SecurityInfo,
  5257. OUT PSID * ppsidOwner,
  5258. OUT PSID * ppsidGroup,
  5259. OUT PACL * ppDacl,
  5260. OUT PACL * ppSacl,
  5261. OUT PSECURITY_DESCRIPTOR * ppSecurityDescriptor
  5262. );
  5263. typedef DWORD (WINAPI *SETSECURITYINFOPTR)(
  5264. IN LPCWSTR pObjectName,
  5265. IN SE_OBJECT_TYPE ObjectType,
  5266. IN SECURITY_INFORMATION SecurityInfo,
  5267. IN PSID psidOwner,
  5268. IN PSID psidGroup,
  5269. IN PACL pDacl,
  5270. IN PACL pSacl
  5271. );
  5272. typedef BOOL (WINAPI *GETSECURITYDESCRIPTORCONTROLPTR)(
  5273. IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
  5274. OUT PSECURITY_DESCRIPTOR_CONTROL pControl,
  5275. OUT LPDWORD lpdwRevision
  5276. );
  5277. BOOL
  5278. BasepCopySecurityInformation( LPCWSTR lpExistingFileName,
  5279. HANDLE SourceFile,
  5280. ACCESS_MASK SourceFileAccess,
  5281. LPCWSTR lpNewFileName,
  5282. HANDLE DestFile,
  5283. ACCESS_MASK DestFileAccess,
  5284. SECURITY_INFORMATION SecurityInformation,
  5285. LPCOPYFILE_CONTEXT Context,
  5286. DWORD DestFileFsAttributes,
  5287. PBOOL DeleteDest,
  5288. BOOL CopyCreatorOwnerAce )
  5289. /*++
  5290. Routine Description:
  5291. This is an internal routine that copies one or more of the DACL,
  5292. SACL, owner, and group from the source to the dest file.
  5293. Arguments:
  5294. lpExistingFileName - Provides the name of the source file.
  5295. SourceFile - Provides a handle to that source file.
  5296. SourceFileAccess - The access flags that were used to open SourceFile.
  5297. lpNewFileName - Provides the name of the destination file.
  5298. DestFile - Provides a handle to that destination file.
  5299. DestFileAccess - The access flags that were used to open DestFile.
  5300. SecurityInformation - Specifies what security should be copied (bit
  5301. flag of the *_SECURITY_INFORMATION defines).
  5302. Context - All the information necessary to call the CopyFile callback routine.
  5303. DestFileFsAttributes - Provides the FILE_FS_ATTRIBUTE_INFORMATION.FileSystemAttributes
  5304. for the dest file's volume.
  5305. DeleteDest - Contains a pointer to a value that will be set to TRUE if this the dest
  5306. file should be deleted. This is the case if there is an error or the user
  5307. cancels the operation. If the user stops the operation, this routine still
  5308. returns an error, but the dest file is not deleted.
  5309. CopyCreatorOwnerAce - if TRUE, the ACE inherited from CREATOR_OWNER will be copied to the destination. Normally, inherited ACEs are not copied but are re-inherited when the ACL is applied to the destination.
  5310. Return Value:
  5311. TRUE - The operation was successful.
  5312. FALSE- The operation failed. Extended error status is available
  5313. using GetLastError.
  5314. --*/
  5315. {
  5316. BOOLEAN Succeeded = FALSE;
  5317. PACL Dacl = NULL;
  5318. PACL Sacl = NULL;
  5319. PSID Owner = NULL;
  5320. PSID Group = NULL;
  5321. PSID NewOwner = NULL;
  5322. PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
  5323. PSECURITY_DESCRIPTOR NewSecurityDescriptor = NULL;
  5324. DWORD dwError = 0;
  5325. HANDLE Advapi32 = NULL;
  5326. GETSECURITYINFOPTR GetSecurityInfoPtr = NULL;
  5327. SETSECURITYINFOPTR SetSecurityInfoPtr = NULL;
  5328. GETSECURITYDESCRIPTORCONTROLPTR GetSecurityDescriptorControlPtr = NULL;
  5329. SECURITY_DESCRIPTOR_CONTROL Control = 0;
  5330. DWORD dwRevision = 0;
  5331. SECURITY_INFORMATION SecInfoCreatorOwner = 0;
  5332. // If the source file isn't identified, there's nothing we can do.
  5333. if( lpExistingFileName == NULL || lpNewFileName == NULL ) {
  5334. Succeeded = TRUE;
  5335. goto Exit;
  5336. }
  5337. // If the destination doesn't support ACLs, assume it doesn't
  5338. // support any such security information (i.e. owner/group).
  5339. if( !(FILE_PERSISTENT_ACLS & DestFileFsAttributes ) ) {
  5340. if( BasepCopyFileCallback( TRUE, // Continue (ignore the problem) by default
  5341. ERROR_NOT_SUPPORTED,
  5342. Context,
  5343. NULL,
  5344. PRIVCALLBACK_SECURITY_INFORMATION_NOT_SUPPORTED,
  5345. SourceFile,
  5346. DestFile,
  5347. DeleteDest )) {
  5348. // The caller wants to coninue on despite this.
  5349. Succeeded = TRUE;
  5350. }
  5351. goto Exit;
  5352. }
  5353. // Check that DACL is copy-able if necessary
  5354. if( SecurityInformation & DACL_SECURITY_INFORMATION ) {
  5355. // We're supposed to copy the DACL. Do we have enough access?
  5356. if( !( SourceFileAccess & GENERIC_READ ) ||
  5357. !( DestFileAccess & WRITE_DAC ) ) {
  5358. SecurityInformation &= ~DACL_SECURITY_INFORMATION;
  5359. if( !BasepCopyFileCallback( TRUE, // Continue (ignore the problem) by default
  5360. ERROR_ACCESS_DENIED,
  5361. Context,
  5362. NULL,
  5363. PRIVCALLBACK_DACL_ACCESS_DENIED,
  5364. SourceFile,
  5365. DestFile,
  5366. DeleteDest )) {
  5367. goto Exit;
  5368. }
  5369. }
  5370. }
  5371. // Check that owner & group is copy-able if necessary
  5372. if( (SecurityInformation & OWNER_SECURITY_INFORMATION) ||
  5373. (SecurityInformation & GROUP_SECURITY_INFORMATION) ) {
  5374. // We're supposed to copy owner & group. Do we have enough access?
  5375. if( !( SourceFileAccess & GENERIC_READ ) ||
  5376. !( DestFileAccess & WRITE_OWNER ) ) {
  5377. SecurityInformation &= ~(OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION);
  5378. if( !BasepCopyFileCallback( TRUE, // Continue (ignore the problem) by default
  5379. ERROR_ACCESS_DENIED,
  5380. Context,
  5381. NULL,
  5382. PRIVCALLBACK_OWNER_GROUP_ACCESS_DENIED,
  5383. SourceFile,
  5384. DestFile,
  5385. DeleteDest )) {
  5386. goto Exit;
  5387. }
  5388. }
  5389. }
  5390. // Check that SACL is copy-able if necessary
  5391. if( SecurityInformation & SACL_SECURITY_INFORMATION ) {
  5392. // We're supposed to copy the SACL. Do we have enough rights?
  5393. if( !(SourceFileAccess & ACCESS_SYSTEM_SECURITY) ||
  5394. !(DestFileAccess & ACCESS_SYSTEM_SECURITY) ) {
  5395. SecurityInformation &= ~SACL_SECURITY_INFORMATION;
  5396. if( !BasepCopyFileCallback( TRUE, // Continue (ignore the problem) by default
  5397. ERROR_PRIVILEGE_NOT_HELD,
  5398. Context,
  5399. NULL,
  5400. PRIVCALLBACK_SACL_ACCESS_DENIED,
  5401. SourceFile,
  5402. DestFile,
  5403. DeleteDest )) {
  5404. goto Exit;
  5405. }
  5406. }
  5407. }
  5408. // If nothing was copyable (and all was ignorable), then we're done.
  5409. if( SecurityInformation == 0 ) {
  5410. Succeeded = TRUE;
  5411. goto Exit;
  5412. }
  5413. if (CopyCreatorOwnerAce) // need the previous owner
  5414. SecInfoCreatorOwner |= OWNER_SECURITY_INFORMATION;
  5415. // Get the advapi32 APIs.
  5416. Advapi32 = LoadLibraryW(AdvapiDllString);
  5417. if( NULL == Advapi32 ) {
  5418. *DeleteDest = TRUE;
  5419. goto Exit;
  5420. }
  5421. GetSecurityInfoPtr = (GETSECURITYINFOPTR) GetProcAddress( Advapi32,
  5422. "GetSecurityInfo" );
  5423. SetSecurityInfoPtr = (SETSECURITYINFOPTR) GetProcAddress( Advapi32,
  5424. "SetSecurityInfo" );
  5425. GetSecurityDescriptorControlPtr = (GETSECURITYDESCRIPTORCONTROLPTR) GetProcAddress( Advapi32,
  5426. "GetSecurityDescriptorControl" );
  5427. if( GetSecurityInfoPtr == NULL ||
  5428. GetSecurityDescriptorControlPtr == NULL ||
  5429. SetSecurityInfoPtr == NULL ) {
  5430. SetLastError( ERROR_INVALID_DLL );
  5431. *DeleteDest = TRUE;
  5432. goto Exit;
  5433. }
  5434. // Read in the security information from the source files
  5435. dwError = GetSecurityInfoPtr( SourceFile,
  5436. SE_FILE_OBJECT,
  5437. SecurityInformation|SecInfoCreatorOwner,
  5438. &Owner,
  5439. &Group,
  5440. &Dacl,
  5441. &Sacl,
  5442. &SecurityDescriptor );
  5443. if( dwError != ERROR_SUCCESS ) {
  5444. SetLastError( dwError );
  5445. *DeleteDest = TRUE;
  5446. goto Exit;
  5447. }
  5448. // We may have requested a DACL or SACL from a file that didn't have one. If so,
  5449. // don't try to set it (because it will cause a parameter error).
  5450. if( Dacl == NULL ) {
  5451. SecurityInformation &= ~DACL_SECURITY_INFORMATION;
  5452. }
  5453. if( Sacl == NULL ) {
  5454. SecurityInformation &= ~SACL_SECURITY_INFORMATION;
  5455. }
  5456. if (SecurityInformation & (DACL_SECURITY_INFORMATION |
  5457. SACL_SECURITY_INFORMATION)) {
  5458. if ( !GetSecurityDescriptorControlPtr( SecurityDescriptor, &Control, &dwRevision )) {
  5459. // GetSecurityDescriptorControl calls BaseSetLastNTError on error
  5460. *DeleteDest = TRUE;
  5461. goto Exit;
  5462. }
  5463. }
  5464. if (SecurityInformation & DACL_SECURITY_INFORMATION) {
  5465. if (Control & SE_DACL_PROTECTED) {
  5466. SecurityInformation |= PROTECTED_DACL_SECURITY_INFORMATION;
  5467. } else {
  5468. SecurityInformation |= UNPROTECTED_DACL_SECURITY_INFORMATION;
  5469. }
  5470. if (CopyCreatorOwnerAce) {
  5471. if (ERROR_SUCCESS != GetSecurityInfoPtr( DestFile,
  5472. SE_FILE_OBJECT,
  5473. OWNER_SECURITY_INFORMATION,
  5474. &NewOwner,
  5475. NULL,
  5476. NULL,
  5477. NULL,
  5478. &NewSecurityDescriptor ))
  5479. NewOwner = NULL;
  5480. BasepCopyCreatorOwnerACE (Dacl, Owner, NewOwner);
  5481. // continue even if CreatorOwner ACE cannot be transferred
  5482. }
  5483. }
  5484. if (SecurityInformation & SACL_SECURITY_INFORMATION) {
  5485. if (Control & SE_SACL_PROTECTED) {
  5486. SecurityInformation |= PROTECTED_SACL_SECURITY_INFORMATION;
  5487. } else {
  5488. SecurityInformation |= UNPROTECTED_SACL_SECURITY_INFORMATION;
  5489. }
  5490. }
  5491. // Set the security on the dest file. This loops because it may
  5492. // have to back off on what it requests.
  5493. while( TRUE && SecurityInformation != 0 ) {
  5494. dwError = SetSecurityInfoPtr( DestFile,
  5495. SE_FILE_OBJECT,
  5496. SecurityInformation,
  5497. Owner,
  5498. Group,
  5499. Dacl,
  5500. Sacl );
  5501. // Even if we have WRITE_OWNER access, the SID we're setting might not
  5502. // be valid. If so, see if we can retry without them.
  5503. if( dwError == ERROR_SUCCESS ) {
  5504. break;
  5505. } else {
  5506. if( SecurityInformation & (OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION) ) {
  5507. if( !BasepCopyFileCallback( TRUE, // Continue by default
  5508. dwError,
  5509. Context,
  5510. NULL,
  5511. PRIVCALLBACK_OWNER_GROUP_FAILED,
  5512. SourceFile,
  5513. DestFile,
  5514. DeleteDest )) {
  5515. goto Exit;
  5516. }
  5517. // It's OK to ignore the owner/group. Try again with them turned off.
  5518. SecurityInformation &= ~(OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION);
  5519. } else {
  5520. // Samba 2.x says that it supports ACLs, but returns not-supported.
  5521. if( !BasepCopyFileCallback( TRUE, // Continue by default
  5522. dwError,
  5523. Context,
  5524. NULL,
  5525. PRIVCALLBACK_SECURITY_INFORMATION_NOT_SUPPORTED,
  5526. SourceFile,
  5527. DestFile,
  5528. DeleteDest )) {
  5529. goto Exit;
  5530. }
  5531. SecurityInformation = 0;
  5532. }
  5533. }
  5534. } // while( TRUE && SecurityInformation != 0 )
  5535. Succeeded = TRUE;
  5536. Exit:
  5537. if( SecurityDescriptor != NULL ) {
  5538. LocalFree( SecurityDescriptor );
  5539. }
  5540. if( NewSecurityDescriptor != NULL ) {
  5541. LocalFree( NewSecurityDescriptor );
  5542. }
  5543. if( Advapi32 != NULL ) {
  5544. FreeLibrary( Advapi32 );
  5545. }
  5546. return( Succeeded );
  5547. }
  5548. BOOL
  5549. BasepCopyFileCallback( BOOL ContinueByDefault,
  5550. DWORD Win32ErrorOnStopOrCancel,
  5551. LPCOPYFILE_CONTEXT Context,
  5552. PLARGE_INTEGER StreamBytesCopied OPTIONAL,
  5553. DWORD CallbackReason,
  5554. HANDLE SourceFile,
  5555. HANDLE DestFile,
  5556. OPTIONAL PBOOL Canceled )
  5557. /*++
  5558. Routine Description:
  5559. During CopyFile, call the CopyFileProgressCallback routine.
  5560. Arguments:
  5561. ContinueByDefault - Value to use as the return code of this
  5562. function if there is no callback function or the callback
  5563. returns PROGRESS_REASON_NOT_HANDLED.
  5564. Win32ErrorOnStopOrCancel - If the callback returns PROGRESS_STOP
  5565. or PROGRESS_CANCEL set this as the last error.
  5566. Context - Structure with the information necessary to call
  5567. the callback.
  5568. StreamBytesCopied - If provided, passed to the callback. If not
  5569. provided, zero is passed.
  5570. CallbackReason - Passed to the callback as the dwReasonCode.
  5571. SourceFile - The source of the CopyFile.
  5572. DestFile - The destination of the CopyFile.
  5573. Canceled - Pointer to a bool that on return indicates that the copy operation
  5574. has been canceled by the user.
  5575. Return Value:
  5576. TRUE - The CopyFile should continue.
  5577. FALSE - The CopyFile should be aborted. The last error will be set
  5578. before this routine returns.
  5579. --*/
  5580. { // BasepCopyFileCallback
  5581. PLARGE_INTEGER StreamBytes;
  5582. LARGE_INTEGER Zero;
  5583. DWORD ReturnCode;
  5584. BOOL Continue = ContinueByDefault;
  5585. // If there's no callback context or it's been quieted, then
  5586. // there's nothing to do.
  5587. if( Context == NULL || Context->lpProgressRoutine == NULL )
  5588. return( Continue );
  5589. // If the caller didn't provide a StreamBytesCopied, use zero.
  5590. if( StreamBytesCopied == NULL ) {
  5591. StreamBytes = &Zero;
  5592. StreamBytes->QuadPart = 0;
  5593. } else {
  5594. StreamBytes = StreamBytesCopied;
  5595. }
  5596. // Call the callback
  5597. ReturnCode = Context->lpProgressRoutine(
  5598. Context->TotalFileSize,
  5599. Context->TotalBytesTransferred,
  5600. Context->TotalFileSize,
  5601. *StreamBytes,
  5602. Context->dwStreamNumber,
  5603. CallbackReason,
  5604. SourceFile,
  5605. DestFile,
  5606. Context->lpData
  5607. );
  5608. if( Canceled ) {
  5609. *Canceled = FALSE;
  5610. }
  5611. switch( ReturnCode )
  5612. {
  5613. case PROGRESS_QUIET:
  5614. Context->lpProgressRoutine = NULL;
  5615. Continue = TRUE;
  5616. break;
  5617. case PROGRESS_CANCEL:
  5618. if( Canceled ) {
  5619. *Canceled = TRUE;
  5620. }
  5621. // Fall through
  5622. case PROGRESS_STOP:
  5623. SetLastError( Win32ErrorOnStopOrCancel );
  5624. Continue = FALSE;
  5625. break;
  5626. case PROGRESS_CONTINUE:
  5627. Continue = TRUE;
  5628. break;
  5629. case PRIVPROGRESS_REASON_NOT_HANDLED:
  5630. default:
  5631. if( !Continue ) {
  5632. SetLastError( Win32ErrorOnStopOrCancel );
  5633. }
  5634. break;
  5635. }
  5636. return( Continue );
  5637. }
  5638. BOOL
  5639. WINAPI
  5640. ReplaceFileA(
  5641. LPCSTR lpReplacedFileName,
  5642. LPCSTR lpReplacementFileName,
  5643. LPCSTR lpBackupFileName OPTIONAL,
  5644. DWORD dwReplaceFlags,
  5645. LPVOID lpExclude,
  5646. LPVOID lpReserved
  5647. )
  5648. /*++
  5649. Routine Description:
  5650. ANSI thunk to ReplaceFileW
  5651. --*/
  5652. {
  5653. UNICODE_STRING DynamicUnicodeReplaced;
  5654. UNICODE_STRING DynamicUnicodeReplacement;
  5655. UNICODE_STRING DynamicUnicodeBackup;
  5656. BOOL b = FALSE;
  5657. //
  5658. // Parameter validation.
  5659. //
  5660. if(NULL == lpReplacedFileName || NULL == lpReplacementFileName ||
  5661. NULL != lpExclude || NULL != lpReserved ||
  5662. dwReplaceFlags & ~(REPLACEFILE_WRITE_THROUGH | REPLACEFILE_IGNORE_MERGE_ERRORS)) {
  5663. SetLastError(ERROR_INVALID_PARAMETER);
  5664. return FALSE;
  5665. }
  5666. if (!Basep8BitStringToDynamicUnicodeString( &DynamicUnicodeReplaced, lpReplacedFileName )) {
  5667. return FALSE;
  5668. }
  5669. if (!Basep8BitStringToDynamicUnicodeString( &DynamicUnicodeReplacement, lpReplacementFileName )) {
  5670. goto end1;
  5671. }
  5672. if (lpBackupFileName) {
  5673. if (!Basep8BitStringToDynamicUnicodeString( &DynamicUnicodeBackup, lpBackupFileName )) {
  5674. goto end2;
  5675. }
  5676. } else {
  5677. DynamicUnicodeBackup.Buffer = NULL;
  5678. }
  5679. b = ReplaceFileW(DynamicUnicodeReplaced.Buffer,
  5680. DynamicUnicodeReplacement.Buffer,
  5681. DynamicUnicodeBackup.Buffer,
  5682. dwReplaceFlags,
  5683. lpExclude,
  5684. lpReserved);
  5685. if(lpBackupFileName) {
  5686. RtlFreeUnicodeString(&DynamicUnicodeBackup);
  5687. }
  5688. end2:
  5689. RtlFreeUnicodeString(&DynamicUnicodeReplacement);
  5690. end1:
  5691. RtlFreeUnicodeString(&DynamicUnicodeReplaced);
  5692. return b;
  5693. }
  5694. BOOL
  5695. WINAPI
  5696. ReplaceFileW(
  5697. LPCWSTR lpReplacedFileName,
  5698. LPCWSTR lpReplacementFileName,
  5699. LPCWSTR lpBackupFileName OPTIONAL,
  5700. DWORD dwReplaceFlags,
  5701. LPVOID lpExclude,
  5702. LPVOID lpReserved
  5703. )
  5704. /*++
  5705. Routine Description:
  5706. Replace a file with a new file. The original file's attributes, alternate
  5707. data streams, oid, acl, compression/encryption are transfered to the new
  5708. file. If a backup file name is supplied, the original file is left at the
  5709. backup file specified. Object ID, Create time/date, and file shortnames are
  5710. tunneled by the system.
  5711. Arguments:
  5712. lpReplacementFileName - name of the new file.
  5713. lpReplacedFileName - name of the file to be replaced.
  5714. lpBackupFileName - optional. If not NULL, the original file can be found
  5715. under this name.
  5716. dwReplaceFlags - specifies how the file is to be replaced. Currently, the
  5717. possible values are:
  5718. REPLACEFILE_WRITE_THROUGH Setting this flag guarantees that any
  5719. tunneled information is flushed to disk
  5720. before the function returns.
  5721. REPLACEFILE_IGNORE_MERGE_ERRORS Setting this flag lets the routine
  5722. continue on with the operation even
  5723. when merge error occurs. If this flag
  5724. is set, GetLastError will not return
  5725. ERROR_UNABLE_TO_MERGE_DATA.
  5726. lpExclude - Reserved for future use. Must be set to NULL.
  5727. lpReserved - for future use. Must be set to NULL.
  5728. Return Value:
  5729. TRUE - The operation was successful.
  5730. FALSE - The operation failed. Extended error status is available
  5731. using GetLastError.
  5732. Error Code:
  5733. ERROR_UNABLE_TO_REMOVE_REPLACED The replacement file has inherited the
  5734. replaced file's attributes and streams.
  5735. the replaced file is unchanged. Both
  5736. files still exist under their original
  5737. names. No backup file exists.
  5738. ERROR_UNABLE_TO_MOVE_REPLACEMENT Same as above. Except that backup file
  5739. exists if requested.
  5740. ERROR_UNABLE_TO_MOVE_REPLACEMENT_2 The replacement file has inherited the
  5741. replaced file's attributes and streams.
  5742. It's still under its original name.
  5743. Replaced file exists under the name of
  5744. the backup file.
  5745. All other error codes Both replacement file and replaced file
  5746. exist under their original names. The
  5747. replacement file may have inherited
  5748. none of, or part of, or all of the
  5749. replaced file's attributes and streams.
  5750. No backup file exists.
  5751. --*/
  5752. {
  5753. HANDLE advapi32LibHandle = INVALID_HANDLE_VALUE;
  5754. ENCRYPTFILEWPTR EncryptFileWPtr = NULL;
  5755. DECRYPTFILEWPTR DecryptFileWPtr = NULL;
  5756. HANDLE ReplacedFile = INVALID_HANDLE_VALUE;
  5757. HANDLE ReplacementFile = INVALID_HANDLE_VALUE;
  5758. HANDLE StreamHandle = INVALID_HANDLE_VALUE;
  5759. HANDLE OutputStreamHandle = INVALID_HANDLE_VALUE;
  5760. UNICODE_STRING ReplacedFileNTName;
  5761. UNICODE_STRING ReplacementFileNTName;
  5762. UNICODE_STRING StreamNTName;
  5763. UNICODE_STRING BackupNTFileName;
  5764. OBJECT_ATTRIBUTES ReplacedObjAttr;
  5765. OBJECT_ATTRIBUTES ReplacementObjAttr;
  5766. OBJECT_ATTRIBUTES StreamObjAttr;
  5767. IO_STATUS_BLOCK IoStatusBlock;
  5768. NTSTATUS status;
  5769. BOOL fSuccess = FALSE;
  5770. BOOL fDoCopy;
  5771. PVOID ReplacedFreeBuffer = NULL;
  5772. PVOID ReplacementFreeBuffer = NULL;
  5773. FILE_BASIC_INFORMATION ReplacedBasicInfo;
  5774. FILE_BASIC_INFORMATION ReplacementBasicInfo;
  5775. DWORD ReplacementFileAccess;
  5776. DWORD ReplacedFileAccess;
  5777. FILE_COMPRESSION_INFORMATION ReplacedCompressionInfo;
  5778. PSECURITY_DESCRIPTOR ReplacedSecDescPtr = NULL;
  5779. DWORD dwSizeNeeded;
  5780. ULONG cInfo;
  5781. PFILE_STREAM_INFORMATION ReplacedStreamInfo = NULL;
  5782. PFILE_STREAM_INFORMATION ReplacementStreamInfo = NULL;
  5783. PFILE_STREAM_INFORMATION ScannerStreamInfoReplaced = NULL;
  5784. PFILE_STREAM_INFORMATION ScannerStreamInfoReplacement = NULL;
  5785. DWORD dwCopyFlags = COPY_FILE_FAIL_IF_EXISTS;
  5786. DWORD dwCopySize = 0;
  5787. PFILE_RENAME_INFORMATION BackupReplaceRenameInfo = NULL;
  5788. PFILE_RENAME_INFORMATION ReplaceRenameInfo = NULL;
  5789. LPCOPYFILE_CONTEXT context = NULL;
  5790. BOOL fQueryReplacedFileFail = FALSE;
  5791. BOOL fQueryReplacementFileFail = FALSE;
  5792. BOOL fReplacedFileIsEncrypted = FALSE;
  5793. BOOL fReplacedFileIsCompressed = FALSE;
  5794. BOOL fReplacementFileIsEncrypted = FALSE;
  5795. BOOL fReplacementFileIsCompressed = FALSE;
  5796. WCHAR * pwszTempBackupFile = NULL;
  5797. DWORD DestFileFsAttributes = 0;
  5798. WCHAR SavedLastChar;
  5799. struct {
  5800. FILE_FS_ATTRIBUTE_INFORMATION Info;
  5801. WCHAR Buffer[MAX_PATH];
  5802. } ReplacementFsAttrInfoBuffer;
  5803. //
  5804. // Initialization
  5805. //
  5806. RtlInitUnicodeString(&BackupNTFileName, NULL);
  5807. //
  5808. // Parameter validation.
  5809. //
  5810. if(NULL == lpReplacedFileName || NULL == lpReplacementFileName ||
  5811. NULL != lpExclude || NULL != lpReserved ||
  5812. dwReplaceFlags & ~(REPLACEFILE_WRITE_THROUGH | REPLACEFILE_IGNORE_MERGE_ERRORS)) {
  5813. SetLastError(ERROR_INVALID_PARAMETER);
  5814. goto Exit;
  5815. }
  5816. try {
  5817. //
  5818. // Open the to-be-replaced file
  5819. //
  5820. RtlInitUnicodeString(&ReplacedFileNTName, NULL);
  5821. if(!RtlDosPathNameToNtPathName_U(lpReplacedFileName,
  5822. &ReplacedFileNTName,
  5823. NULL,
  5824. NULL)) {
  5825. SetLastError(ERROR_PATH_NOT_FOUND);
  5826. leave;
  5827. }
  5828. ReplacedFreeBuffer = ReplacedFileNTName.Buffer;
  5829. InitializeObjectAttributes(&ReplacedObjAttr,
  5830. &ReplacedFileNTName,
  5831. OBJ_CASE_INSENSITIVE,
  5832. NULL,
  5833. NULL);
  5834. ReplacedFileAccess = GENERIC_READ | DELETE | SYNCHRONIZE | ACCESS_SYSTEM_SECURITY;
  5835. status = NtOpenFile(&ReplacedFile,
  5836. ReplacedFileAccess,
  5837. &ReplacedObjAttr,
  5838. &IoStatusBlock,
  5839. FILE_SHARE_READ |
  5840. FILE_SHARE_WRITE |
  5841. FILE_SHARE_DELETE,
  5842. FILE_NON_DIRECTORY_FILE |
  5843. FILE_SYNCHRONOUS_IO_NONALERT);
  5844. if (!NT_SUCCESS(status)) {
  5845. ReplacedFileAccess &= ~ACCESS_SYSTEM_SECURITY;
  5846. status = NtOpenFile(&ReplacedFile,
  5847. ReplacedFileAccess,
  5848. &ReplacedObjAttr,
  5849. &IoStatusBlock,
  5850. FILE_SHARE_READ |
  5851. FILE_SHARE_WRITE |
  5852. FILE_SHARE_DELETE,
  5853. FILE_NON_DIRECTORY_FILE |
  5854. FILE_SYNCHRONOUS_IO_NONALERT);
  5855. }
  5856. if(!NT_SUCCESS(status))
  5857. {
  5858. BaseSetLastNTError(status);
  5859. leave;
  5860. }
  5861. //
  5862. // Open the replacement file
  5863. //
  5864. if(!RtlDosPathNameToNtPathName_U(lpReplacementFileName,
  5865. &ReplacementFileNTName,
  5866. NULL,
  5867. NULL)) {
  5868. SetLastError(ERROR_PATH_NOT_FOUND);
  5869. leave;
  5870. }
  5871. ReplacementFreeBuffer = ReplacementFileNTName.Buffer;
  5872. InitializeObjectAttributes(&ReplacementObjAttr,
  5873. &ReplacementFileNTName,
  5874. OBJ_CASE_INSENSITIVE,
  5875. NULL,
  5876. NULL);
  5877. if ((ReplacedFileAccess & ACCESS_SYSTEM_SECURITY)) {
  5878. ReplacementFileAccess = SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE | DELETE | WRITE_DAC | ACCESS_SYSTEM_SECURITY;
  5879. status = NtOpenFile(&ReplacementFile,
  5880. ReplacementFileAccess,
  5881. &ReplacementObjAttr,
  5882. &IoStatusBlock,
  5883. 0,
  5884. FILE_NON_DIRECTORY_FILE |
  5885. FILE_SYNCHRONOUS_IO_NONALERT);
  5886. }
  5887. else status = STATUS_ACCESS_DENIED; // force the open
  5888. if (!NT_SUCCESS(status)) {
  5889. ReplacementFileAccess = SYNCHRONIZE | GENERIC_READ | GENERIC_WRITE | DELETE | WRITE_DAC;
  5890. status = NtOpenFile(&ReplacementFile,
  5891. ReplacementFileAccess,
  5892. &ReplacementObjAttr,
  5893. &IoStatusBlock,
  5894. 0,
  5895. FILE_NON_DIRECTORY_FILE |
  5896. FILE_SYNCHRONOUS_IO_NONALERT);
  5897. }
  5898. if (STATUS_ACCESS_DENIED == status &&
  5899. dwReplaceFlags & REPLACEFILE_IGNORE_MERGE_ERRORS) {
  5900. ReplacementFileAccess = SYNCHRONIZE | GENERIC_READ | DELETE | WRITE_DAC;
  5901. status = NtOpenFile(&ReplacementFile,
  5902. ReplacementFileAccess,
  5903. &ReplacementObjAttr,
  5904. &IoStatusBlock,
  5905. 0,
  5906. FILE_NON_DIRECTORY_FILE |
  5907. FILE_SYNCHRONOUS_IO_NONALERT);
  5908. }
  5909. if(STATUS_ACCESS_DENIED == status &&
  5910. dwReplaceFlags & REPLACEFILE_IGNORE_MERGE_ERRORS)
  5911. { // try again without WRITE_DAC access
  5912. ReplacementFileAccess = SYNCHRONIZE | GENERIC_READ | DELETE;
  5913. status = NtOpenFile(&ReplacementFile,
  5914. ReplacementFileAccess,
  5915. &ReplacementObjAttr,
  5916. &IoStatusBlock,
  5917. 0,
  5918. FILE_NON_DIRECTORY_FILE |
  5919. FILE_SYNCHRONOUS_IO_NONALERT);
  5920. }
  5921. if(!NT_SUCCESS(status))
  5922. {
  5923. BaseSetLastNTError(status);
  5924. leave;
  5925. }
  5926. //
  5927. // Get the attributes of the to-be-replaced file and set them on the
  5928. // replacement file. FILE_ATTRIBUTE_COMPRESSED and
  5929. // FILE_ATTRIBUTE_ENCRYPTED can be obtained by NtQueryInformationFile,
  5930. // but can't be set by NtSetInformationFile. Compression and
  5931. // encryption will be handled later.
  5932. //
  5933. status = NtQueryInformationFile(ReplacedFile,
  5934. &IoStatusBlock,
  5935. &ReplacedBasicInfo,
  5936. sizeof(ReplacedBasicInfo),
  5937. FileBasicInformation);
  5938. if(!NT_SUCCESS(status)) {
  5939. if(!(dwReplaceFlags & REPLACEFILE_IGNORE_MERGE_ERRORS)) {
  5940. BaseSetLastNTError(status);
  5941. leave;
  5942. }
  5943. fQueryReplacedFileFail = TRUE;
  5944. }
  5945. else {
  5946. // don't replace read-only files. See bug 38426
  5947. if ((ReplacedBasicInfo.FileAttributes & FILE_ATTRIBUTE_READONLY)) {
  5948. status = STATUS_ACCESS_DENIED;
  5949. BaseSetLastNTError(status); // ERROR_ACCESS_DENIED
  5950. leave;
  5951. }
  5952. status = NtQueryInformationFile(ReplacementFile,
  5953. &IoStatusBlock,
  5954. &ReplacementBasicInfo,
  5955. sizeof(ReplacementBasicInfo),
  5956. FileBasicInformation);
  5957. if(!NT_SUCCESS(status)) {
  5958. if(!(dwReplaceFlags & REPLACEFILE_IGNORE_MERGE_ERRORS)) {
  5959. BaseSetLastNTError(status);
  5960. leave;
  5961. }
  5962. fQueryReplacementFileFail = TRUE;
  5963. }
  5964. //
  5965. // Creation time is the only time we want to preserve. So zero out
  5966. // all the other times.
  5967. //
  5968. ReplacedBasicInfo.LastAccessTime.QuadPart = 0;
  5969. ReplacedBasicInfo.LastWriteTime.QuadPart = 0;
  5970. ReplacedBasicInfo.ChangeTime.QuadPart = 0;
  5971. status = NtSetInformationFile(ReplacementFile,
  5972. &IoStatusBlock,
  5973. &ReplacedBasicInfo,
  5974. sizeof(ReplacedBasicInfo),
  5975. FileBasicInformation);
  5976. if(!NT_SUCCESS(status) &&
  5977. !(dwReplaceFlags & REPLACEFILE_IGNORE_MERGE_ERRORS)) {
  5978. BaseSetLastNTError(status);
  5979. leave;
  5980. }
  5981. }
  5982. //
  5983. // Transfer ACLs from the to-be-replaced file to the replacement file.
  5984. //
  5985. status = NtQueryVolumeInformationFile(ReplacementFile,
  5986. &IoStatusBlock,
  5987. &ReplacementFsAttrInfoBuffer.Info,
  5988. sizeof(ReplacementFsAttrInfoBuffer),
  5989. FileFsAttributeInformation);
  5990. if(!NT_SUCCESS(status)) {
  5991. if(!(dwReplaceFlags & REPLACEFILE_IGNORE_MERGE_ERRORS)) {
  5992. BaseSetLastNTError(status);
  5993. leave;
  5994. }
  5995. }
  5996. else
  5997. {
  5998. BOOL Delete = FALSE;
  5999. if( !BasepCopySecurityInformation( lpReplacedFileName,
  6000. ReplacedFile,
  6001. ReplacedFileAccess,
  6002. lpReplacementFileName,
  6003. ReplacementFile,
  6004. ReplacementFileAccess,
  6005. DACL_SECURITY_INFORMATION |
  6006. SACL_SECURITY_INFORMATION,
  6007. NULL,
  6008. ReplacementFsAttrInfoBuffer.Info.FileSystemAttributes,
  6009. &Delete,
  6010. TRUE )) {
  6011. leave;
  6012. }
  6013. }
  6014. //
  6015. // If the to-be-replaced file has alternate data streams, and they do
  6016. // not exist in the replacement file, copy them into the replacement
  6017. // file.
  6018. //
  6019. cInfo = 4096;
  6020. do {
  6021. ReplacedStreamInfo = RtlAllocateHeap(RtlProcessHeap(),
  6022. MAKE_TAG(TMP_TAG),
  6023. cInfo);
  6024. if (!ReplacedStreamInfo) {
  6025. break;
  6026. }
  6027. status = NtQueryInformationFile(ReplacedFile,
  6028. &IoStatusBlock,
  6029. ReplacedStreamInfo,
  6030. cInfo,
  6031. FileStreamInformation);
  6032. if (!NT_SUCCESS(status)) {
  6033. RtlFreeHeap(RtlProcessHeap(), 0, ReplacedStreamInfo);
  6034. ReplacedStreamInfo = NULL;
  6035. cInfo *= 2;
  6036. }
  6037. } while(status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL);
  6038. if(NULL == ReplacedStreamInfo) {
  6039. if(status != STATUS_INVALID_PARAMETER &&
  6040. status != STATUS_NOT_IMPLEMENTED) {
  6041. if(!(dwReplaceFlags & REPLACEFILE_IGNORE_MERGE_ERRORS)) {
  6042. BaseSetLastNTError(status);
  6043. leave;
  6044. }
  6045. }
  6046. }
  6047. else {
  6048. if(!NT_SUCCESS(status)) {
  6049. if(!(dwReplaceFlags & REPLACEFILE_IGNORE_MERGE_ERRORS)) {
  6050. BaseSetLastNTError(status);
  6051. leave;
  6052. }
  6053. }
  6054. else {
  6055. // The outer loop enumerates streams in the to-be-replaced file.
  6056. ScannerStreamInfoReplaced = ReplacedStreamInfo;
  6057. while(TRUE) {
  6058. // Skip the default stream.
  6059. if(ScannerStreamInfoReplaced->StreamNameLength <= sizeof(WCHAR) ||
  6060. ScannerStreamInfoReplaced->StreamName[1] == ':') {
  6061. if(0 == ScannerStreamInfoReplaced->NextEntryOffset) {
  6062. break;
  6063. }
  6064. ScannerStreamInfoReplaced = (PFILE_STREAM_INFORMATION)((PCHAR)ScannerStreamInfoReplaced + ScannerStreamInfoReplaced->NextEntryOffset);
  6065. continue;
  6066. }
  6067. // Query replacement file stream information if we haven't done so.
  6068. // We wait until now to do this query because we don't want to do
  6069. // it unless it's absolutely necessary.
  6070. if(NULL == ReplacementStreamInfo) {
  6071. cInfo = 4096;
  6072. do {
  6073. ReplacementStreamInfo = RtlAllocateHeap(RtlProcessHeap(),
  6074. MAKE_TAG(TMP_TAG),
  6075. cInfo);
  6076. if (!ReplacementStreamInfo) {
  6077. break;
  6078. }
  6079. status = NtQueryInformationFile(ReplacementFile,
  6080. &IoStatusBlock,
  6081. ReplacementStreamInfo,
  6082. cInfo - sizeof( WCHAR ),
  6083. FileStreamInformation);
  6084. if (!NT_SUCCESS(status)) {
  6085. RtlFreeHeap(RtlProcessHeap(), 0, ReplacementStreamInfo);
  6086. ReplacementStreamInfo = NULL;
  6087. cInfo *= 2;
  6088. }
  6089. } while(status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL);
  6090. if(NULL == ReplacementStreamInfo ||
  6091. !NT_SUCCESS(status)) {
  6092. if(!(dwReplaceFlags & REPLACEFILE_IGNORE_MERGE_ERRORS)) {
  6093. BaseSetLastNTError(status);
  6094. leave;
  6095. }
  6096. break;
  6097. }
  6098. }
  6099. // The inner loop enumerates the replacement file streams.
  6100. ScannerStreamInfoReplacement = ReplacementStreamInfo;
  6101. fDoCopy = TRUE;
  6102. while(TRUE) {
  6103. if(ScannerStreamInfoReplaced->StreamNameLength == ScannerStreamInfoReplacement->StreamNameLength &&
  6104. _wcsnicmp(ScannerStreamInfoReplaced->StreamName, ScannerStreamInfoReplacement->StreamName, ScannerStreamInfoReplacement->StreamNameLength / sizeof(WCHAR)) == 0) {
  6105. // The stream already exists in the replacement file.
  6106. fDoCopy = FALSE;
  6107. break;
  6108. }
  6109. if(0 == ScannerStreamInfoReplacement->NextEntryOffset) {
  6110. // end of the stream information
  6111. break;
  6112. }
  6113. ScannerStreamInfoReplacement = (PFILE_STREAM_INFORMATION)((PCHAR)ScannerStreamInfoReplacement + ScannerStreamInfoReplacement->NextEntryOffset);
  6114. }
  6115. // We copy the stream if it doesn't exist in the replacement file.
  6116. if(TRUE == fDoCopy) {
  6117. StreamNTName.Buffer = &ScannerStreamInfoReplaced->StreamName[0];
  6118. StreamNTName.Length = (USHORT)ScannerStreamInfoReplaced->StreamNameLength;
  6119. StreamNTName.MaximumLength = StreamNTName.Length;
  6120. // Open the stream in the to-be-replaced file.
  6121. InitializeObjectAttributes(&StreamObjAttr,
  6122. &StreamNTName,
  6123. 0,
  6124. ReplacedFile,
  6125. NULL);
  6126. status = NtOpenFile(&StreamHandle,
  6127. SYNCHRONIZE |
  6128. GENERIC_READ,
  6129. &StreamObjAttr,
  6130. &IoStatusBlock,
  6131. FILE_SHARE_READ |
  6132. FILE_SHARE_WRITE |
  6133. FILE_SHARE_DELETE,
  6134. FILE_SYNCHRONOUS_IO_NONALERT |
  6135. FILE_SEQUENTIAL_ONLY);
  6136. if(!NT_SUCCESS(status)) {
  6137. if(!(dwReplaceFlags & REPLACEFILE_IGNORE_MERGE_ERRORS)) {
  6138. BaseSetLastNTError(status);
  6139. leave;
  6140. }
  6141. if(0 == ScannerStreamInfoReplaced->NextEntryOffset) {
  6142. break;
  6143. }
  6144. ScannerStreamInfoReplaced = (PFILE_STREAM_INFORMATION)((PCHAR)ScannerStreamInfoReplaced + ScannerStreamInfoReplaced->NextEntryOffset);
  6145. continue;
  6146. }
  6147. // Copy the stream;
  6148. SavedLastChar = StreamNTName.Buffer[StreamNTName.Length / sizeof( WCHAR )];
  6149. StreamNTName.Buffer[StreamNTName.Length / sizeof( WCHAR )] = L'\0';
  6150. OutputStreamHandle = INVALID_HANDLE_VALUE;
  6151. if(!BaseCopyStream(NULL,
  6152. StreamHandle,
  6153. SYNCHRONIZE | GENERIC_READ,
  6154. StreamNTName.Buffer,
  6155. ReplacementFile,
  6156. &ScannerStreamInfoReplaced->StreamSize,
  6157. &dwCopyFlags,
  6158. &OutputStreamHandle,
  6159. &dwCopySize,
  6160. &context,
  6161. NULL,
  6162. FALSE,
  6163. 0,
  6164. &DestFileFsAttributes )) {
  6165. StreamNTName.Buffer[StreamNTName.Length / sizeof( WCHAR )] = SavedLastChar;
  6166. if(!(dwReplaceFlags & REPLACEFILE_IGNORE_MERGE_ERRORS)) {
  6167. leave;
  6168. }
  6169. }
  6170. StreamNTName.Buffer[StreamNTName.Length / sizeof( WCHAR )] = SavedLastChar;
  6171. NtClose(StreamHandle);
  6172. StreamHandle = INVALID_HANDLE_VALUE;
  6173. if (INVALID_HANDLE_VALUE != OutputStreamHandle) {
  6174. NtClose(OutputStreamHandle);
  6175. OutputStreamHandle = INVALID_HANDLE_VALUE;
  6176. }
  6177. } // copy stream
  6178. if(0 == ScannerStreamInfoReplaced->NextEntryOffset) {
  6179. break;
  6180. }
  6181. ScannerStreamInfoReplaced = (PFILE_STREAM_INFORMATION)((PCHAR)ScannerStreamInfoReplaced + ScannerStreamInfoReplaced->NextEntryOffset);
  6182. } // outer loop
  6183. }
  6184. }
  6185. //
  6186. // Compression/Encryption.
  6187. //
  6188. // If we successfully read the to-be-replaced file's attributes, we
  6189. // do the necessary compression/encryption. Otherwise we do nothing.
  6190. // If we don't know the replacement files attributes
  6191. // (fQueryReplacementFileFail is TRUE), to be on the safe side, we will
  6192. // try to (un)compress/(un)encrypt it if the to-be-replaced file is
  6193. // (un)compressed/(un)encrypted.
  6194. if(!fQueryReplacedFileFail) {
  6195. fReplacedFileIsEncrypted = ReplacedBasicInfo.FileAttributes & FILE_ATTRIBUTE_ENCRYPTED;
  6196. fReplacedFileIsCompressed = ReplacedBasicInfo.FileAttributes & FILE_ATTRIBUTE_COMPRESSED;
  6197. if(!fQueryReplacementFileFail) {
  6198. fReplacementFileIsEncrypted = ReplacementBasicInfo.FileAttributes & FILE_ATTRIBUTE_ENCRYPTED;
  6199. fReplacementFileIsCompressed = ReplacementBasicInfo.FileAttributes & FILE_ATTRIBUTE_COMPRESSED;
  6200. }
  6201. else {
  6202. // If we don't know the file attributes of the replacement
  6203. // file, we'll assume the replacement file has opposite
  6204. // encryption/compression attributes as the replaced file
  6205. // so that encryption/compression operations will be forced
  6206. // on the replacement file.
  6207. fReplacementFileIsEncrypted = !fReplacedFileIsEncrypted;
  6208. fReplacementFileIsCompressed = !fReplacedFileIsCompressed;
  6209. }
  6210. //
  6211. // Encryption.
  6212. //
  6213. // If the to-be-replaced file is encrypted and either the
  6214. // replacement file is encrypted or we don't know it's encryption
  6215. // status, we try to encrypt the replacement file.
  6216. if(fReplacedFileIsEncrypted && !fReplacementFileIsEncrypted) {
  6217. NtClose(ReplacementFile);
  6218. ReplacementFile = INVALID_HANDLE_VALUE;
  6219. // There's no way to encrypt a file based on its handle. We
  6220. // must use the Win32 API (which calls over to the EFS service).
  6221. advapi32LibHandle = LoadLibraryW(AdvapiDllString);
  6222. if(NULL == advapi32LibHandle) {
  6223. if(!(dwReplaceFlags & REPLACEFILE_IGNORE_MERGE_ERRORS)) {
  6224. leave;
  6225. }
  6226. }
  6227. else {
  6228. EncryptFileWPtr = (ENCRYPTFILEWPTR)GetProcAddress(advapi32LibHandle, "EncryptFileW");
  6229. if(NULL == EncryptFileWPtr) {
  6230. if(!(dwReplaceFlags & REPLACEFILE_IGNORE_MERGE_ERRORS)) {
  6231. leave;
  6232. }
  6233. }
  6234. else {
  6235. if((EncryptFileWPtr)(lpReplacementFileName)) {
  6236. // Encryption operation automatically decompresses
  6237. // compressed files. We need this flag for the
  6238. // case when the replaced file is encrypted and
  6239. // the replacement file is compressed. At this
  6240. // point, the replacement file is encrypted.
  6241. // Because a file is automatically decompressed
  6242. // when it's encrypted, we don't want to
  6243. // decompress it again, otherwise we'll get an
  6244. // error.
  6245. fReplacementFileIsCompressed = FALSE;
  6246. } else if(!(dwReplaceFlags & REPLACEFILE_IGNORE_MERGE_ERRORS)) {
  6247. leave;
  6248. }
  6249. }
  6250. }
  6251. status = NtOpenFile(&ReplacementFile,
  6252. SYNCHRONIZE |
  6253. GENERIC_READ |
  6254. GENERIC_WRITE |
  6255. WRITE_DAC |
  6256. DELETE,
  6257. &ReplacementObjAttr,
  6258. &IoStatusBlock,
  6259. 0,
  6260. FILE_NON_DIRECTORY_FILE |
  6261. FILE_SYNCHRONOUS_IO_NONALERT);
  6262. if (STATUS_ACCESS_DENIED == status &&
  6263. dwReplaceFlags & REPLACEFILE_IGNORE_MERGE_ERRORS) {
  6264. status = NtOpenFile(&ReplacementFile,
  6265. SYNCHRONIZE |
  6266. GENERIC_READ |
  6267. DELETE |
  6268. WRITE_DAC,
  6269. &ReplacementObjAttr,
  6270. &IoStatusBlock,
  6271. 0,
  6272. FILE_NON_DIRECTORY_FILE |
  6273. FILE_SYNCHRONOUS_IO_NONALERT);
  6274. }
  6275. if(STATUS_ACCESS_DENIED == status &&
  6276. dwReplaceFlags & REPLACEFILE_IGNORE_MERGE_ERRORS) {
  6277. status = NtOpenFile(&ReplacementFile,
  6278. SYNCHRONIZE |
  6279. GENERIC_READ |
  6280. DELETE,
  6281. &ReplacementObjAttr,
  6282. &IoStatusBlock,
  6283. 0,
  6284. FILE_NON_DIRECTORY_FILE |
  6285. FILE_SYNCHRONOUS_IO_NONALERT);
  6286. }
  6287. // We leave without attempt to rename the files because we know
  6288. // we can't rename the replacement file without it being opened
  6289. // first.
  6290. if(!NT_SUCCESS(status)) {
  6291. BaseSetLastNTError(status);
  6292. leave;
  6293. }
  6294. }
  6295. else if(!fReplacedFileIsEncrypted && fReplacementFileIsEncrypted) {
  6296. // If the to-be-replaced file is not encrypted and the
  6297. // replacement file is encrypted, decrypt the replacement file.
  6298. NtClose(ReplacementFile);
  6299. ReplacementFile = INVALID_HANDLE_VALUE;
  6300. advapi32LibHandle = LoadLibraryW(AdvapiDllString);
  6301. if(NULL == advapi32LibHandle) {
  6302. if(!(dwReplaceFlags & REPLACEFILE_IGNORE_MERGE_ERRORS)) {
  6303. leave;
  6304. }
  6305. }
  6306. else {
  6307. DecryptFileWPtr = (DECRYPTFILEWPTR)GetProcAddress(advapi32LibHandle, "DecryptFileW");
  6308. if(NULL == DecryptFileWPtr) {
  6309. if(!(dwReplaceFlags & REPLACEFILE_IGNORE_MERGE_ERRORS)) {
  6310. leave;
  6311. }
  6312. }
  6313. else {
  6314. if((DecryptFileWPtr)(lpReplacementFileName, 0)) {
  6315. fReplacementFileIsEncrypted = FALSE;
  6316. } else if(!(dwReplaceFlags & REPLACEFILE_IGNORE_MERGE_ERRORS)) {
  6317. leave;
  6318. }
  6319. }
  6320. }
  6321. status = NtOpenFile(&ReplacementFile,
  6322. SYNCHRONIZE |
  6323. GENERIC_READ |
  6324. GENERIC_WRITE |
  6325. WRITE_DAC |
  6326. DELETE,
  6327. &ReplacementObjAttr,
  6328. &IoStatusBlock,
  6329. 0,
  6330. FILE_NON_DIRECTORY_FILE |
  6331. FILE_SYNCHRONOUS_IO_NONALERT);
  6332. if(STATUS_ACCESS_DENIED == status &&
  6333. dwReplaceFlags & REPLACEFILE_IGNORE_MERGE_ERRORS) {
  6334. status = NtOpenFile(&ReplacementFile,
  6335. SYNCHRONIZE |
  6336. GENERIC_READ |
  6337. DELETE |
  6338. WRITE_DAC,
  6339. &ReplacementObjAttr,
  6340. &IoStatusBlock,
  6341. 0,
  6342. FILE_NON_DIRECTORY_FILE |
  6343. FILE_SYNCHRONOUS_IO_NONALERT);
  6344. }
  6345. if(STATUS_ACCESS_DENIED == status &&
  6346. dwReplaceFlags & REPLACEFILE_IGNORE_MERGE_ERRORS) {
  6347. status = NtOpenFile(&ReplacementFile,
  6348. SYNCHRONIZE |
  6349. GENERIC_READ |
  6350. DELETE,
  6351. &ReplacementObjAttr,
  6352. &IoStatusBlock,
  6353. 0,
  6354. FILE_NON_DIRECTORY_FILE |
  6355. FILE_SYNCHRONOUS_IO_NONALERT);
  6356. }
  6357. // We leave without attempt to rename the files because we know
  6358. // we can't rename the replacement file without it being opened
  6359. // first.
  6360. if(!NT_SUCCESS(status)) {
  6361. BaseSetLastNTError(status);
  6362. leave;
  6363. }
  6364. }
  6365. //
  6366. // Compression.
  6367. //
  6368. // If the to-be-replaced file is compressed, and the replacement
  6369. // file is not, we compress the replacement file. In the case that
  6370. // we don't know if the replacement file is compressed or not
  6371. // (fQueryReplacementFileFail is TRUE), we will
  6372. // try to compress it anyway and ignore the error if it's already
  6373. // compressed.
  6374. if(fReplacedFileIsCompressed && !fReplacementFileIsCompressed) {
  6375. // Get the compression method mode.
  6376. status = NtQueryInformationFile(ReplacedFile,
  6377. &IoStatusBlock,
  6378. &ReplacedCompressionInfo,
  6379. sizeof(FILE_COMPRESSION_INFORMATION),
  6380. FileCompressionInformation);
  6381. if(!NT_SUCCESS(status)) {
  6382. // We couldn't get the compression method code. if the
  6383. // ignore merge error flag is on, we continue on to
  6384. // encryption. Otherwise, we set last error and leave.
  6385. if(!fQueryReplacementFileFail &&
  6386. !(dwReplaceFlags & REPLACEFILE_IGNORE_MERGE_ERRORS)) {
  6387. BaseSetLastNTError(status);
  6388. leave;
  6389. }
  6390. }
  6391. else {
  6392. // Do the compression. If we fail and ignore failure flag
  6393. // is not on, set error and leave. Otherwise continue on
  6394. // to encryption.
  6395. status = NtFsControlFile(ReplacementFile,
  6396. NULL,
  6397. NULL,
  6398. NULL,
  6399. &IoStatusBlock,
  6400. FSCTL_SET_COMPRESSION,
  6401. &ReplacedCompressionInfo.CompressionFormat,
  6402. sizeof(ReplacedCompressionInfo.CompressionFormat),
  6403. NULL,
  6404. 0);
  6405. if(!fQueryReplacementFileFail && !NT_SUCCESS(status) &&
  6406. !(dwReplaceFlags & REPLACEFILE_IGNORE_MERGE_ERRORS)) {
  6407. BaseSetLastNTError(status);
  6408. leave;
  6409. }
  6410. }
  6411. }
  6412. else if(!fReplacedFileIsCompressed && fReplacementFileIsCompressed && !fReplacementFileIsEncrypted) {
  6413. // The replaced file is not compressed, the replacement file
  6414. // is compressed (or that the query information for replacement
  6415. // file failed and we don't know if it's compressed or not),
  6416. // decompress the replacement file.
  6417. USHORT CompressionFormat = 0;
  6418. status = NtFsControlFile(ReplacementFile,
  6419. NULL,
  6420. NULL,
  6421. NULL,
  6422. &IoStatusBlock,
  6423. FSCTL_SET_COMPRESSION,
  6424. &CompressionFormat,
  6425. sizeof(CompressionFormat),
  6426. NULL,
  6427. 0);
  6428. if(!fQueryReplacementFileFail && !NT_SUCCESS(status) &&
  6429. !(dwReplaceFlags & REPLACEFILE_IGNORE_MERGE_ERRORS)) {
  6430. BaseSetLastNTError(status);
  6431. leave;
  6432. }
  6433. }
  6434. } // if querying replaced file attribute failed.
  6435. //
  6436. // Do the renames.
  6437. //
  6438. if (NULL == lpBackupFileName) {
  6439. HANDLE hFile = INVALID_HANDLE_VALUE;
  6440. DWORD dwCounter = 0;
  6441. DWORD dwReplacedFileLength = lstrlenW(lpReplacedFileName) *
  6442. sizeof(WCHAR);
  6443. WCHAR wcsSuffix [16];
  6444. pwszTempBackupFile = RtlAllocateHeap(RtlProcessHeap(),
  6445. MAKE_TAG(TMP_TAG),
  6446. dwReplacedFileLength + sizeof(wcsSuffix));
  6447. if(NULL == pwszTempBackupFile) {
  6448. SetLastError(ERROR_UNABLE_TO_REMOVE_REPLACED);
  6449. leave;
  6450. }
  6451. while (hFile == INVALID_HANDLE_VALUE && dwCounter < 16) {
  6452. swprintf (wcsSuffix, L"~RF%4x.TMP", dwCounter + GetTickCount());
  6453. lstrcpyW (pwszTempBackupFile, lpReplacedFileName);
  6454. lstrcatW (pwszTempBackupFile, wcsSuffix);
  6455. hFile = CreateFileW ( pwszTempBackupFile,
  6456. GENERIC_WRITE | DELETE, // file access
  6457. 0, // share mode
  6458. NULL, // SD
  6459. CREATE_NEW, // how to create
  6460. FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_TEMPORARY,
  6461. NULL); // handle to template file
  6462. dwCounter++;
  6463. }
  6464. if (hFile != INVALID_HANDLE_VALUE) {
  6465. CloseHandle (hFile); // immediately close temp file
  6466. } else {
  6467. SetLastError(ERROR_UNABLE_TO_REMOVE_REPLACED);
  6468. leave;
  6469. }
  6470. }
  6471. else {
  6472. pwszTempBackupFile = (WCHAR *) lpBackupFileName;
  6473. }
  6474. // If backup file requested, rename the to-be-replaced file to backup.
  6475. // Otherwise delete it.
  6476. if(!RtlDosPathNameToNtPathName_U(pwszTempBackupFile,
  6477. &BackupNTFileName,
  6478. NULL,
  6479. NULL)) {
  6480. SetLastError(ERROR_PATH_NOT_FOUND);
  6481. leave;
  6482. }
  6483. BackupReplaceRenameInfo = RtlAllocateHeap(RtlProcessHeap(),
  6484. MAKE_TAG(TMP_TAG),
  6485. BackupNTFileName.Length +
  6486. sizeof(*BackupReplaceRenameInfo));
  6487. if(NULL == BackupReplaceRenameInfo)
  6488. {
  6489. SetLastError(ERROR_UNABLE_TO_REMOVE_REPLACED);
  6490. leave;
  6491. }
  6492. BackupReplaceRenameInfo->ReplaceIfExists = TRUE;
  6493. BackupReplaceRenameInfo->RootDirectory = NULL;
  6494. BackupReplaceRenameInfo->FileNameLength = BackupNTFileName.Length;
  6495. RtlCopyMemory(BackupReplaceRenameInfo->FileName, BackupNTFileName.Buffer, BackupNTFileName.Length);
  6496. status = NtSetInformationFile(ReplacedFile,
  6497. &IoStatusBlock,
  6498. BackupReplaceRenameInfo,
  6499. BackupNTFileName.Length +
  6500. sizeof(*BackupReplaceRenameInfo),
  6501. FileRenameInformation);
  6502. if(!NT_SUCCESS(status)) {
  6503. SetLastError(ERROR_UNABLE_TO_REMOVE_REPLACED);
  6504. leave;
  6505. }
  6506. // Rename the replacement file to the replaced file.
  6507. ReplaceRenameInfo = RtlAllocateHeap(RtlProcessHeap(),
  6508. MAKE_TAG(TMP_TAG),
  6509. ReplacedFileNTName.Length +
  6510. sizeof(*ReplaceRenameInfo));
  6511. if(NULL == ReplaceRenameInfo)
  6512. {
  6513. SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT);
  6514. leave;
  6515. }
  6516. ReplaceRenameInfo->ReplaceIfExists = TRUE;
  6517. ReplaceRenameInfo->RootDirectory = NULL;
  6518. ReplaceRenameInfo->FileNameLength = ReplacedFileNTName.Length;
  6519. RtlCopyMemory(ReplaceRenameInfo->FileName, ReplacedFileNTName.Buffer, ReplacedFileNTName.Length);
  6520. status = NtSetInformationFile(ReplacementFile,
  6521. &IoStatusBlock,
  6522. ReplaceRenameInfo,
  6523. ReplacedFileNTName.Length +
  6524. sizeof(*ReplaceRenameInfo),
  6525. FileRenameInformation);
  6526. if(!NT_SUCCESS(status)) {
  6527. // If we failed to rename the replacement file, and a backup file
  6528. // for the original file exists, we try to restore the original
  6529. // file from the backup file.
  6530. if(lpBackupFileName) {
  6531. status = NtSetInformationFile(ReplacedFile,
  6532. &IoStatusBlock,
  6533. ReplaceRenameInfo,
  6534. ReplacedFileNTName.Length +
  6535. sizeof(*ReplaceRenameInfo),
  6536. FileRenameInformation);
  6537. if(!NT_SUCCESS(status)) {
  6538. SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT_2);
  6539. }
  6540. else {
  6541. SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT);
  6542. }
  6543. leave;
  6544. }
  6545. else {
  6546. SetLastError(ERROR_UNABLE_TO_MOVE_REPLACEMENT);
  6547. leave;
  6548. }
  6549. }
  6550. //
  6551. // All is well. We set the return code to TRUE. And flush the files if
  6552. // necessary.
  6553. //
  6554. if(dwReplaceFlags & REPLACEFILE_WRITE_THROUGH) {
  6555. NtFlushBuffersFile(ReplacedFile, &IoStatusBlock);
  6556. }
  6557. fSuccess = TRUE;
  6558. } finally {
  6559. if(INVALID_HANDLE_VALUE != advapi32LibHandle && NULL != advapi32LibHandle) {
  6560. FreeLibrary(advapi32LibHandle);
  6561. }
  6562. if(INVALID_HANDLE_VALUE != ReplacedFile) {
  6563. NtClose(ReplacedFile);
  6564. }
  6565. if(INVALID_HANDLE_VALUE != ReplacementFile) {
  6566. NtClose(ReplacementFile);
  6567. }
  6568. if(INVALID_HANDLE_VALUE != StreamHandle) {
  6569. NtClose(StreamHandle);
  6570. }
  6571. if(INVALID_HANDLE_VALUE != OutputStreamHandle) {
  6572. NtClose(OutputStreamHandle);
  6573. }
  6574. RtlFreeHeap(RtlProcessHeap(), 0, ReplacedFreeBuffer);
  6575. RtlFreeHeap(RtlProcessHeap(), 0, ReplacementFreeBuffer);
  6576. RtlFreeHeap(RtlProcessHeap(), 0, BackupNTFileName.Buffer);
  6577. RtlFreeHeap(RtlProcessHeap(), 0, ReplacedStreamInfo);
  6578. RtlFreeHeap(RtlProcessHeap(), 0, ReplacementStreamInfo);
  6579. RtlFreeHeap(RtlProcessHeap(), 0, ReplaceRenameInfo);
  6580. RtlFreeHeap(RtlProcessHeap(), 0, BackupReplaceRenameInfo);
  6581. if (pwszTempBackupFile != NULL &&
  6582. pwszTempBackupFile != lpBackupFileName) {
  6583. DeleteFileW (pwszTempBackupFile);
  6584. RtlFreeHeap(RtlProcessHeap(), 0, pwszTempBackupFile);
  6585. }
  6586. }
  6587. Exit:
  6588. return fSuccess;
  6589. }
  6590. VOID
  6591. BaseMarkFileForDelete(
  6592. HANDLE File,
  6593. DWORD FileAttributes
  6594. )
  6595. /*++
  6596. Routine Description:
  6597. This routine marks a file for delete, so that when the supplied handle
  6598. is closed, the file will actually be deleted.
  6599. Arguments:
  6600. File - Supplies a handle to the file that is to be marked for delete.
  6601. FileAttributes - Attributes for the file, if known. Zero indicates they
  6602. are unknown.
  6603. Return Value:
  6604. None.
  6605. --*/
  6606. {
  6607. #undef DeleteFile
  6608. FILE_DISPOSITION_INFORMATION DispositionInformation;
  6609. IO_STATUS_BLOCK IoStatus;
  6610. FILE_BASIC_INFORMATION BasicInformation;
  6611. if (!FileAttributes) {
  6612. BasicInformation.FileAttributes = 0;
  6613. NtQueryInformationFile(
  6614. File,
  6615. &IoStatus,
  6616. &BasicInformation,
  6617. sizeof(BasicInformation),
  6618. FileBasicInformation
  6619. );
  6620. FileAttributes = BasicInformation.FileAttributes;
  6621. }
  6622. if (FileAttributes & FILE_ATTRIBUTE_READONLY) {
  6623. RtlZeroMemory(&BasicInformation, sizeof(BasicInformation));
  6624. BasicInformation.FileAttributes = FILE_ATTRIBUTE_NORMAL;
  6625. NtSetInformationFile(
  6626. File,
  6627. &IoStatus,
  6628. &BasicInformation,
  6629. sizeof(BasicInformation),
  6630. FileBasicInformation
  6631. );
  6632. }
  6633. DispositionInformation.DeleteFile = TRUE;
  6634. NtSetInformationFile(
  6635. File,
  6636. &IoStatus,
  6637. &DispositionInformation,
  6638. sizeof(DispositionInformation),
  6639. FileDispositionInformation
  6640. );
  6641. }