Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1801 lines
54 KiB

  1. /*++
  2. Copyright (c) 1998-2000 Microsoft Corporation
  3. Module Name:
  4. copyfile.c
  5. Abstract:
  6. This is where the kernel mode copyfile is performed. Really it is more
  7. of a backup process then a copyfile.
  8. The main funcion is SrBackupFile. This is called in response to a
  9. file modification in order to preservce the old state of that file
  10. being modified.
  11. SrBackupFile was stolen from kernel32.dll:CopyFileExW. It was converted
  12. to kernel mode and stripped down to handle just the SR backup
  13. requirements.
  14. SrCopyStream was also stolen from kernel32.dll and converted to kernel
  15. mode. However the main data copy routing SrCopyDataBytes was written new.
  16. Author:
  17. Paul McDaniel (paulmcd) 03-Apr-2000
  18. Revision History:
  19. --*/
  20. #include "precomp.h"
  21. //
  22. // Private constants.
  23. //
  24. #define SR_CREATE_FLAGS (FILE_SEQUENTIAL_ONLY \
  25. | FILE_WRITE_THROUGH \
  26. | FILE_NO_INTERMEDIATE_BUFFERING \
  27. | FILE_NON_DIRECTORY_FILE \
  28. | FILE_OPEN_FOR_BACKUP_INTENT \
  29. | FILE_SYNCHRONOUS_IO_NONALERT)
  30. //
  31. // Private types.
  32. //
  33. #define IS_VALID_HANDLE_FILE_CHANGE_CONTEXT(pObject) \
  34. (((pObject) != NULL) && ((pObject)->Signature == SR_BACKUP_FILE_CONTEXT_TAG))
  35. typedef struct _SR_BACKUP_FILE_CONTEXT
  36. {
  37. //
  38. // NonPagedPool
  39. //
  40. //
  41. // = SR_BACKUP_FILE_CONTEXT_TAG
  42. //
  43. ULONG Signature;
  44. WORK_QUEUE_ITEM WorkItem;
  45. KEVENT Event;
  46. NTSTATUS Status;
  47. SR_EVENT_TYPE EventType;
  48. PFILE_OBJECT pFileObject;
  49. PUNICODE_STRING pFileName;
  50. PSR_DEVICE_EXTENSION pExtension;
  51. PUNICODE_STRING pDestFileName;
  52. BOOLEAN CopyDataStreams;
  53. PACCESS_TOKEN pThreadToken;
  54. } SR_BACKUP_FILE_CONTEXT, * PSR_BACKUP_FILE_CONTEXT;
  55. //
  56. // Private prototypes.
  57. //
  58. NTSTATUS
  59. SrMarkFileForDelete (
  60. HANDLE FileHandle
  61. );
  62. NTSTATUS
  63. SrCopyStream (
  64. IN HANDLE SourceFileHandle,
  65. IN PDEVICE_OBJECT pTargetDeviceObject,
  66. IN PUNICODE_STRING pDestFileName,
  67. IN HANDLE DestFileHandle OPTIONAL,
  68. IN PLARGE_INTEGER pFileSize,
  69. OUT PHANDLE pDestFileHandle
  70. );
  71. NTSTATUS
  72. SrCopyDataBytes (
  73. IN HANDLE SourceFile,
  74. IN HANDLE DestFile,
  75. IN PLARGE_INTEGER FileSize,
  76. IN ULONG SectorSize
  77. );
  78. BOOLEAN
  79. SrIsFileEncrypted (
  80. PSR_DEVICE_EXTENSION pExtension,
  81. PFILE_OBJECT pFileObject
  82. );
  83. //
  84. // linker commands
  85. //
  86. #ifdef ALLOC_PRAGMA
  87. #pragma alloc_text( PAGE, SrCopyDataBytes )
  88. #pragma alloc_text( PAGE, SrCopyStream )
  89. #pragma alloc_text( PAGE, SrBackupFile )
  90. #pragma alloc_text( PAGE, SrMarkFileForDelete )
  91. #pragma alloc_text( PAGE, SrBackupFileAndLog )
  92. #pragma alloc_text( PAGE, SrIsFileEncrypted )
  93. #endif // ALLOC_PRAGMA
  94. /***************************************************************************++
  95. Routine Description:
  96. This routine copies the all data from SourceFile to DestFile. To read
  97. the data from the SourceFile, the file is memory mapped so that we bypass
  98. any byte range locks that may be held on the file.
  99. Arguments:
  100. SourceFile - Handle to the file from which to copy.
  101. DestFile - Handle for the file into which to copy
  102. Length - the total size of the file (if it is less than the total size,
  103. more bytes might be copied than Length ).
  104. Return Value:
  105. status of the copy
  106. --***************************************************************************/
  107. NTSTATUS
  108. SrCopyDataBytes(
  109. IN HANDLE SourceFile,
  110. IN HANDLE DestFile,
  111. IN PLARGE_INTEGER pFileSize,
  112. IN ULONG SectorSize
  113. )
  114. {
  115. #define MM_MAP_ALIGNMENT (64 * 1024 /*VACB_MAPPING_GRANULARITY*/) // The file offset granularity that MM enforces.
  116. #define COPY_AMOUNT (64 * 1024) // How much we read or write at a time. Must be >= MM_MAP_ALIGNMENT
  117. NTSTATUS Status = STATUS_SUCCESS;
  118. IO_STATUS_BLOCK IoStatusBlock;
  119. LARGE_INTEGER ByteOffset;
  120. HANDLE SectionHandle = NULL;
  121. PAGED_CODE();
  122. ASSERT( SourceFile != NULL );
  123. ASSERT( DestFile != NULL );
  124. ASSERT( SectorSize > 0 );
  125. ASSERT( pFileSize != NULL );
  126. ASSERT( pFileSize->QuadPart > 0 );
  127. ASSERT( pFileSize->HighPart == 0 );
  128. Status = ZwCreateSection( &SectionHandle,
  129. SECTION_MAP_READ | SECTION_QUERY,
  130. NULL,
  131. pFileSize,
  132. PAGE_READONLY,
  133. SEC_COMMIT,
  134. SourceFile );
  135. if (!NT_SUCCESS(Status))
  136. {
  137. goto SrCopyDataBytes_Exit;
  138. }
  139. ByteOffset.QuadPart = 0;
  140. while (ByteOffset.QuadPart < pFileSize->QuadPart)
  141. {
  142. ULONG ValidBytes, BytesToCopy;
  143. PCHAR MappedBuffer = NULL;
  144. LARGE_INTEGER MappedOffset;
  145. SIZE_T ViewSize;
  146. PCHAR CopyIntoAddress;
  147. //
  148. // Set MappedOffset to the greatest, lower offset from ByteOffset that
  149. // is align to the valid alignment allowed by the memory manager.
  150. //
  151. MappedOffset.QuadPart = ByteOffset.QuadPart - (ByteOffset.QuadPart % MM_MAP_ALIGNMENT);
  152. ASSERT( (MappedOffset.QuadPart <= ByteOffset.QuadPart) &&
  153. ((MappedOffset.QuadPart + MM_MAP_ALIGNMENT) > ByteOffset.QuadPart) );
  154. if ((pFileSize->QuadPart - MappedOffset.QuadPart) > COPY_AMOUNT)
  155. {
  156. //
  157. // We can't map enough of the file to do the whole copy
  158. // here, so only map COPY_AMOUNT on this pass.
  159. //
  160. ViewSize = COPY_AMOUNT;
  161. }
  162. else
  163. {
  164. //
  165. // We can map all the way to the end of the file.
  166. //
  167. ViewSize = (ULONG)(pFileSize->QuadPart - MappedOffset.QuadPart);
  168. }
  169. //
  170. // Calculate the amount of the view size that contains valid data
  171. // based on any adjustments we needed to do to make sure that
  172. // the MappedOffset was correctly aligned.
  173. //
  174. ASSERT(ViewSize >=
  175. (ULONG_PTR)(ByteOffset.QuadPart - MappedOffset.QuadPart));
  176. ValidBytes = (ULONG)(ViewSize - (ULONG)(ByteOffset.QuadPart - MappedOffset.QuadPart));
  177. //
  178. // Now round ValidBytes up to a sector size.
  179. //
  180. BytesToCopy = ((ValidBytes + SectorSize - 1) / SectorSize) * SectorSize;
  181. ASSERT(BytesToCopy <= COPY_AMOUNT);
  182. //
  183. // Map in the region from which we're about to copy.
  184. //
  185. Status = ZwMapViewOfSection( SectionHandle,
  186. NtCurrentProcess(),
  187. &MappedBuffer,
  188. 0, // zero bits
  189. 0, // commit size (ignored for mapped files)
  190. &MappedOffset,
  191. &ViewSize,
  192. ViewUnmap,
  193. 0, // allocation type
  194. PAGE_READONLY);
  195. if (!NT_SUCCESS( Status ))
  196. {
  197. goto SrCopyDataBytes_Exit;
  198. }
  199. //
  200. // We should have enough space allocated for the rounded up read
  201. //
  202. ASSERT( ViewSize >= BytesToCopy );
  203. CopyIntoAddress = MappedBuffer + (ULONG)(ByteOffset.QuadPart - MappedOffset.QuadPart);
  204. //
  205. // Since this handle was opened synchronously, the IO Manager takes
  206. // care of waiting until the operation is complete.
  207. //
  208. Status = ZwWriteFile( DestFile,
  209. NULL,
  210. NULL,
  211. NULL,
  212. &IoStatusBlock,
  213. MappedBuffer,
  214. BytesToCopy,
  215. &ByteOffset,
  216. NULL );
  217. //
  218. // Whether or not we successfully wrote this block of data, we want
  219. // to unmap the current view of the section.
  220. //
  221. ZwUnmapViewOfSection( NtCurrentProcess(), MappedBuffer );
  222. NULLPTR( MappedBuffer );
  223. if (!NT_SUCCESS( IoStatusBlock.Status ))
  224. {
  225. goto SrCopyDataBytes_Exit;
  226. }
  227. ASSERT( IoStatusBlock.Information == BytesToCopy );
  228. ASSERT( BytesToCopy >= ValidBytes );
  229. //
  230. // Add in the number of valid data bytes that we actually copied
  231. // into the file.
  232. //
  233. ByteOffset.QuadPart += ValidBytes;
  234. //
  235. // Check to see if we copied more bytes than we had of valid data.
  236. // If we did, we need to truncate the file.
  237. //
  238. if (BytesToCopy > ValidBytes)
  239. {
  240. FILE_END_OF_FILE_INFORMATION EndOfFileInformation;
  241. //
  242. // Then truncate the file to this length.
  243. //
  244. EndOfFileInformation.EndOfFile.QuadPart = ByteOffset.QuadPart;
  245. Status = ZwSetInformationFile( DestFile,
  246. &IoStatusBlock,
  247. &EndOfFileInformation,
  248. sizeof(EndOfFileInformation),
  249. FileEndOfFileInformation );
  250. if (!NT_SUCCESS( Status ))
  251. goto SrCopyDataBytes_Exit;
  252. }
  253. }
  254. SrCopyDataBytes_Exit:
  255. if (SectionHandle != NULL) {
  256. ZwClose( SectionHandle );
  257. NULLPTR( SectionHandle );
  258. }
  259. return Status;
  260. #undef COPY_AMOUNT
  261. #undef MM_MAP_ALIGNMENT
  262. }
  263. /*++
  264. Routine Description:
  265. This is an internal routine that copies an entire file (default data stream
  266. only), or a single stream of a file. If the hTargetFile parameter is
  267. present, then only a single stream of the output file is copied. Otherwise,
  268. the entire file is copied.
  269. Arguments:
  270. SourceFileHandle - Provides a handle to the source file.
  271. pNewFileName - Provides a name for the target file/stream. this is the
  272. NT file name, not a win32 file name if a full name is passed,
  273. otherwise it's just the stream name.
  274. DestFileHandle - Optionally provides a handle to the target file. If the
  275. stream being copied is an alternate data stream, then this handle must
  276. be provided. NULL means it's not provided.
  277. pFileSize - Provides the size of the input stream.
  278. pDestFileHandle - Provides a variable to store the handle to the target file.
  279. Return Value:
  280. NTSTATUS code
  281. --*/
  282. NTSTATUS
  283. SrCopyStream(
  284. IN HANDLE SourceFileHandle,
  285. IN PDEVICE_OBJECT pTargetDeviceObject,
  286. IN PUNICODE_STRING pDestFileName,
  287. IN HANDLE DestFileHandle OPTIONAL,
  288. IN PLARGE_INTEGER pFileSize,
  289. OUT PHANDLE pDestFileHandle
  290. )
  291. {
  292. HANDLE DestFile = NULL;
  293. NTSTATUS Status;
  294. FILE_BASIC_INFORMATION FileBasicInformationData;
  295. FILE_END_OF_FILE_INFORMATION EndOfFileInformation;
  296. IO_STATUS_BLOCK IoStatus;
  297. ULONG DesiredAccess;
  298. ULONG DestFileAccess;
  299. ULONG SourceFileAttributes;
  300. OBJECT_ATTRIBUTES ObjectAttributes;
  301. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  302. PFILE_FULL_EA_INFORMATION EaBuffer = NULL;
  303. ULONG EaSize = 0;
  304. PAGED_CODE();
  305. ASSERT( SourceFileHandle != NULL );
  306. ASSERT( pTargetDeviceObject != NULL );
  307. ASSERT( pDestFileName != NULL );
  308. ASSERT( pFileSize != NULL );
  309. //
  310. // Get times and attributes for the file if the entire file is being
  311. // copied
  312. //
  313. Status = ZwQueryInformationFile( SourceFileHandle,
  314. &IoStatus,
  315. (PVOID) &FileBasicInformationData,
  316. sizeof(FileBasicInformationData),
  317. FileBasicInformation );
  318. SourceFileAttributes = NT_SUCCESS(Status) ?
  319. FileBasicInformationData.FileAttributes :
  320. 0;
  321. if (DestFileHandle == NULL)
  322. {
  323. if ( !NT_SUCCESS(Status) )
  324. {
  325. goto end;
  326. }
  327. }
  328. else
  329. {
  330. //
  331. // A zero in the file's attributes informs latter DeleteFile that
  332. // this code does not know what the actual file attributes are so
  333. // that this code does not actually have to retrieve them for each
  334. // stream, nor does it have to remember them across streams. The
  335. // error path will simply get them if needed.
  336. //
  337. FileBasicInformationData.FileAttributes = 0;
  338. }
  339. //
  340. // Create the destination file or alternate data stream
  341. //
  342. if (DestFileHandle == NULL)
  343. {
  344. ULONG CreateOptions = 0;
  345. PFILE_FULL_EA_INFORMATION EaBufferToUse = NULL;
  346. ULONG SourceFileFsAttributes = 0;
  347. ULONG EaSizeToUse = 0;
  348. ULONG DestFileAttributes = 0;
  349. FILE_BASIC_INFORMATION DestBasicInformation;
  350. // We're being called to copy the unnamed stream of the file, and
  351. // we need to create the file itself.
  352. //
  353. // Determine the create options
  354. //
  355. CreateOptions = FILE_SYNCHRONOUS_IO_NONALERT
  356. | FILE_WRITE_THROUGH
  357. | FILE_NO_INTERMEDIATE_BUFFERING
  358. | FILE_OPEN_FOR_BACKUP_INTENT ;
  359. if (SourceFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  360. CreateOptions |= FILE_DIRECTORY_FILE;
  361. else
  362. CreateOptions |= FILE_NON_DIRECTORY_FILE | FILE_SEQUENTIAL_ONLY;
  363. //
  364. // Determine what access is necessary based on what is being copied
  365. //
  366. DesiredAccess = SYNCHRONIZE
  367. | FILE_READ_ATTRIBUTES
  368. | GENERIC_WRITE
  369. | DELETE;
  370. if (SourceFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  371. {
  372. // We may or may not be able to get FILE_WRITE_DATA access,
  373. // necessary for setting compression.
  374. //
  375. DesiredAccess &= ~GENERIC_WRITE;
  376. DesiredAccess |= FILE_WRITE_DATA
  377. | FILE_WRITE_ATTRIBUTES
  378. | FILE_WRITE_EA
  379. | FILE_LIST_DIRECTORY;
  380. }
  381. //
  382. // We need read access for compression, write_dac for the DACL
  383. //
  384. DesiredAccess |= GENERIC_READ | WRITE_DAC;
  385. DesiredAccess |= WRITE_OWNER;
  386. //
  387. // we can get this as we always have SeSecurityPrivilege (kernelmode)
  388. //
  389. DesiredAccess |= ACCESS_SYSTEM_SECURITY;
  390. //
  391. // get the object attributes ready
  392. //
  393. InitializeObjectAttributes( &ObjectAttributes,
  394. pDestFileName,
  395. OBJ_KERNEL_HANDLE,
  396. NULL,
  397. NULL );
  398. SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  399. SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
  400. SecurityQualityOfService.EffectiveOnly = TRUE;
  401. SecurityQualityOfService.Length = sizeof( SECURITY_QUALITY_OF_SERVICE );
  402. ObjectAttributes.SecurityQualityOfService = &SecurityQualityOfService;
  403. //
  404. // Get the EAs
  405. //
  406. EaBuffer = NULL;
  407. EaSize = 0;
  408. //
  409. // paulmcd: 5/25/2000 remove ea support until we get it into ntifs.h
  410. // (the public header)
  411. //
  412. #ifdef EA_SUPPORT
  413. Status = ZwQueryInformationFile( SourceFileHandle,
  414. &IoStatus,
  415. &EaInfo,
  416. sizeof(EaInfo),
  417. FileEaInformation );
  418. if (NT_SUCCESS(Status) && EaInfo.EaSize > 0)
  419. {
  420. EaSize = EaInfo.EaSize;
  421. do
  422. {
  423. EaSize *= 2;
  424. EaBuffer = (PFILE_FULL_EA_INFORMATION)
  425. SR_ALLOCATE_ARRAY( PagedPool,
  426. UCHAR,
  427. EaSize,
  428. SR_EA_DATA_TAG );
  429. if (EaBuffer == NULL)
  430. {
  431. Status = STATUS_INSUFFICIENT_RESOURCES;
  432. goto end;
  433. }
  434. Status = ZwQueryEaFile( SourceFileHandle,
  435. &IoStatus,
  436. EaBuffer,
  437. EaSize,
  438. FALSE,
  439. (PVOID)NULL,
  440. 0,
  441. (PULONG)NULL,
  442. TRUE );
  443. if ( !NT_SUCCESS(Status) )
  444. {
  445. SR_FREE_POOL(EaBuffer, SR_EA_DATA_TAG);
  446. EaBuffer = NULL;
  447. IoStatus.Information = 0;
  448. }
  449. } while ( Status == STATUS_BUFFER_OVERFLOW ||
  450. Status == STATUS_BUFFER_TOO_SMALL );
  451. EaSize = (ULONG)IoStatus.Information;
  452. } // if ( NT_SUCCESS(Status) && EaInfo.EaSize )
  453. #endif // EA_SUPPORT
  454. //
  455. // Open the destination file.
  456. //
  457. DestFileAccess = DesiredAccess;
  458. EaBufferToUse = EaBuffer;
  459. EaSizeToUse = EaSize;
  460. //
  461. // Turn off FILE_ATTRIBUTE_OFFLINE for destination
  462. //
  463. SourceFileAttributes &= ~FILE_ATTRIBUTE_OFFLINE;
  464. while (DestFile == NULL)
  465. {
  466. //
  467. // Attempt to create the destination - if the file already
  468. // exists, we will overwrite it.
  469. //
  470. Status = SrIoCreateFile( &DestFile,
  471. DestFileAccess,
  472. &ObjectAttributes,
  473. &IoStatus,
  474. NULL,
  475. SourceFileAttributes
  476. & FILE_ATTRIBUTE_VALID_FLAGS,
  477. FILE_SHARE_READ|FILE_SHARE_WRITE,
  478. FILE_OVERWRITE_IF,
  479. CreateOptions,
  480. EaBufferToUse,
  481. EaSizeToUse,
  482. IO_IGNORE_SHARE_ACCESS_CHECK,
  483. pTargetDeviceObject );
  484. // If this was successful, then break out of this while loop.
  485. // The remaining code in this loop attempt to recover from the problem,
  486. // then it loops back to the top and attempt the NtCreateFile again.
  487. if (NT_SUCCESS(Status))
  488. {
  489. break; // while( TRUE )
  490. }
  491. //
  492. // If the destination has not been successfully created/opened,
  493. // see if it's because EAs aren't supported
  494. //
  495. if( EaBufferToUse != NULL &&
  496. Status == STATUS_EAS_NOT_SUPPORTED )
  497. {
  498. // Attempt the create again, but don't use the EAs
  499. EaBufferToUse = NULL;
  500. EaSizeToUse = 0;
  501. DestFileAccess = DesiredAccess;
  502. continue;
  503. } // if( EaBufferToUse != NULL ...
  504. //
  505. // completely failed! no more tricks.
  506. //
  507. DestFile = NULL;
  508. goto end;
  509. } // while (DestFile == NULL)
  510. //
  511. // If we reach this point, we've successfully opened the dest file.
  512. //
  513. //
  514. // Get the File & FileSys attributes for the target volume, plus
  515. // the FileSys attributes for the source volume.
  516. //
  517. SourceFileFsAttributes = 0;
  518. DestFileAttributes = 0;
  519. Status = ZwQueryInformationFile( DestFile,
  520. &IoStatus,
  521. &DestBasicInformation,
  522. sizeof(DestBasicInformation),
  523. FileBasicInformation );
  524. if (!NT_SUCCESS( Status ))
  525. goto end;
  526. DestFileAttributes = DestBasicInformation.FileAttributes;
  527. //
  528. // If the source file is encrypted, check that the target was successfully
  529. // set for encryption (e.g. it won't be for FAT).
  530. //
  531. if( (SourceFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) &&
  532. !(DestFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) )
  533. {
  534. //
  535. // CODEWORK: paulmcd.. need to figure out how to appropriately
  536. // handle the $EFS stream.
  537. //
  538. ASSERT(FALSE);
  539. SrTrace(NOTIFY, ("sr!SrCopyStream(%wZ):failed to copy encryption\n",
  540. pDestFileName ));
  541. } // if( SourceFileAttributes & FILE_ATTRIBUTE_ENCRYPTED ...
  542. }
  543. else // if (DestFileHandle == NULL)
  544. {
  545. // We're copying a named stream.
  546. //
  547. // Create the output stream relative to the file specified by the
  548. // DestFileHandle file handle.
  549. //
  550. InitializeObjectAttributes( &ObjectAttributes,
  551. pDestFileName,
  552. OBJ_KERNEL_HANDLE,
  553. DestFileHandle,
  554. (PSECURITY_DESCRIPTOR)NULL );
  555. DesiredAccess = GENERIC_WRITE | SYNCHRONIZE;
  556. Status = SrIoCreateFile( &DestFile,
  557. DesiredAccess,
  558. &ObjectAttributes,
  559. &IoStatus,
  560. pFileSize,
  561. SourceFileAttributes,
  562. FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
  563. FILE_OPEN_IF,
  564. SR_CREATE_FLAGS,
  565. NULL, // EaBuffer
  566. 0, // EaLength
  567. IO_IGNORE_SHARE_ACCESS_CHECK,
  568. pTargetDeviceObject );
  569. if (!NT_SUCCESS( Status ))
  570. {
  571. if (Status != STATUS_ACCESS_DENIED)
  572. goto end;
  573. //
  574. // Determine whether or not this failed because the file
  575. // is a readonly file. If so, change it to read/write,
  576. // re-attempt the open, and set it back to readonly again.
  577. //
  578. Status = ZwQueryInformationFile( DestFileHandle,
  579. &IoStatus,
  580. (PVOID) &FileBasicInformationData,
  581. sizeof(FileBasicInformationData),
  582. FileBasicInformation );
  583. if (!NT_SUCCESS( Status ))
  584. {
  585. goto end;
  586. }
  587. if (FileBasicInformationData.FileAttributes
  588. & FILE_ATTRIBUTE_READONLY)
  589. {
  590. ULONG attributes = FileBasicInformationData.FileAttributes;
  591. RtlZeroMemory( &FileBasicInformationData,
  592. sizeof(FileBasicInformationData) );
  593. FileBasicInformationData.FileAttributes
  594. = FILE_ATTRIBUTE_NORMAL;
  595. (VOID) ZwSetInformationFile( DestFileHandle,
  596. &IoStatus,
  597. &FileBasicInformationData,
  598. sizeof(FileBasicInformationData),
  599. FileBasicInformation );
  600. Status = SrIoCreateFile( &DestFile,
  601. DesiredAccess,
  602. &ObjectAttributes,
  603. &IoStatus,
  604. pFileSize,
  605. SourceFileAttributes,
  606. FILE_SHARE_READ|FILE_SHARE_WRITE,
  607. FILE_OPEN_IF,
  608. SR_CREATE_FLAGS,
  609. NULL, // EaBuffer
  610. 0, // EaLength
  611. IO_IGNORE_SHARE_ACCESS_CHECK,
  612. pTargetDeviceObject );
  613. FileBasicInformationData.FileAttributes = attributes;
  614. (VOID) ZwSetInformationFile( DestFileHandle,
  615. &IoStatus,
  616. &FileBasicInformationData,
  617. sizeof(FileBasicInformationData),
  618. FileBasicInformation );
  619. if (!NT_SUCCESS( Status ))
  620. goto end;
  621. }
  622. else
  623. {
  624. //
  625. // it wasn't read only... just fail, nothing else to try
  626. //
  627. goto end;
  628. }
  629. }
  630. } // else [if (DestFileHandle == NULL)]
  631. //
  632. // is there any stream data to copy?
  633. //
  634. if (pFileSize->QuadPart > 0)
  635. {
  636. //
  637. // Preallocate the size of this file/stream so that extends do not
  638. // occur.
  639. //
  640. EndOfFileInformation.EndOfFile = *pFileSize;
  641. Status = ZwSetInformationFile( DestFile,
  642. &IoStatus,
  643. &EndOfFileInformation,
  644. sizeof(EndOfFileInformation),
  645. FileEndOfFileInformation );
  646. if (!NT_SUCCESS( Status ))
  647. goto end;
  648. //
  649. // now copy the stream bits
  650. //
  651. Status = SrCopyDataBytes( SourceFileHandle,
  652. DestFile,
  653. pFileSize,
  654. pTargetDeviceObject->SectorSize );
  655. if (!NT_SUCCESS( Status ))
  656. goto end;
  657. }
  658. end:
  659. if (!NT_SUCCESS( Status ))
  660. {
  661. if (DestFile != NULL)
  662. {
  663. SrMarkFileForDelete(DestFile);
  664. ZwClose(DestFile);
  665. DestFile = NULL;
  666. }
  667. }
  668. //
  669. // set the callers pointer
  670. // (even if it's not valid, this clears the callers buffer)
  671. //
  672. *pDestFileHandle = DestFile;
  673. if ( EaBuffer )
  674. {
  675. SR_FREE_POOL(EaBuffer, SR_EA_DATA_TAG);
  676. }
  677. RETURN(Status);
  678. } // SrCopyStream
  679. /***************************************************************************++
  680. Routine Description:
  681. this routine will copy the source file to the dest file. the dest
  682. file is opened create so it must not already exist. if the
  683. CopyDataStreams is set all alternate streams are copied including the
  684. default data stream. the DACL is copied to the dest file but the dest
  685. file has the owner set to admins regardless of the source file object.
  686. if it fails it cleans up and deletes the dest file.
  687. it checks to make sure the volume has at least 50mb free prior to
  688. the copy.
  689. BUGBUG: paulmcd:8/2000: this routine does not copy the $EFS meta-data
  690. Arguments:
  691. pExtension - SR's device extension for the volume on which this file
  692. resides.
  693. pOriginalFileObject - the file object to which this operation is occuring.
  694. This file object could represent a name data stream on the file.
  695. pSourceFileName - The name of the file to backup (excluding any stream
  696. component).
  697. pDestFileName - The name of the destination file to which this file will
  698. be copied.
  699. CopyDataStreams - If TRUE, we should copy all the data streams of this
  700. file.
  701. pBytesWritten - Is set to the number of bytes written in the restore
  702. location as a result of backing up this file.
  703. pShortFileName - Is set to the short file name of the file we backed up
  704. if we were able to successfully back up the file and this file has
  705. a short name.
  706. Return Value:
  707. ULONG - Completion status.
  708. --***************************************************************************/
  709. NTSTATUS
  710. SrBackupFile(
  711. IN PSR_DEVICE_EXTENSION pExtension,
  712. IN PFILE_OBJECT pOriginalFileObject,
  713. IN PUNICODE_STRING pSourceFileName,
  714. IN PUNICODE_STRING pDestFileName,
  715. IN BOOLEAN CopyDataStreams,
  716. OUT PULONGLONG pBytesWritten OPTIONAL,
  717. OUT PUNICODE_STRING pShortFileName OPTIONAL
  718. )
  719. {
  720. HANDLE SourceFileHandle = NULL;
  721. HANDLE DestFile = NULL;
  722. NTSTATUS Status;
  723. HANDLE OutputStream;
  724. HANDLE StreamHandle;
  725. ULONG StreamInfoSize;
  726. OBJECT_ATTRIBUTES objAttr;
  727. OBJECT_ATTRIBUTES ObjectAttributes;
  728. IO_STATUS_BLOCK IoStatus;
  729. LARGE_INTEGER BytesToCopy;
  730. UNICODE_STRING StreamName;
  731. PFILE_OBJECT pSourceFileObject = NULL;
  732. FILE_STANDARD_INFORMATION FileInformation;
  733. FILE_BASIC_INFORMATION BasicInformation;
  734. PFILE_STREAM_INFORMATION StreamInfo;
  735. PFILE_STREAM_INFORMATION StreamInfoBase = NULL;
  736. struct {
  737. FILE_FS_ATTRIBUTE_INFORMATION Info;
  738. WCHAR Buffer[ 50 ];
  739. } FileFsAttrInfoBuffer;
  740. PAGED_CODE();
  741. ASSERT(pOriginalFileObject != NULL);
  742. ASSERT(pSourceFileName != NULL);
  743. try
  744. {
  745. if (pBytesWritten != NULL)
  746. {
  747. *pBytesWritten = 0;
  748. }
  749. //
  750. // First open a new handle to the source file so that we don't
  751. // interfere with the user's read offset.
  752. //
  753. InitializeObjectAttributes( &objAttr,
  754. pSourceFileName,
  755. OBJ_KERNEL_HANDLE,
  756. NULL,
  757. NULL );
  758. Status = SrIoCreateFile( &SourceFileHandle,
  759. GENERIC_READ,
  760. &objAttr,
  761. &IoStatus,
  762. NULL,
  763. FILE_ATTRIBUTE_NORMAL,
  764. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  765. FILE_OPEN,
  766. FILE_NON_DIRECTORY_FILE | FILE_COMPLETE_IF_OPLOCKED,
  767. NULL,
  768. 0,
  769. IO_IGNORE_SHARE_ACCESS_CHECK,
  770. pExtension->pTargetDevice );
  771. if (Status == STATUS_ACCESS_DENIED)
  772. {
  773. //
  774. // This may be a file that is in the process of getting decrypted.
  775. // Check to see if this file is currently encrypted. If so, we
  776. // we assume that we got STATUS_ACCESS_DENIED because the file is
  777. // in its transition state and keep going.
  778. //
  779. if (SrIsFileEncrypted( pExtension, pOriginalFileObject ))
  780. {
  781. Status = SR_STATUS_IGNORE_FILE;
  782. leave;
  783. }
  784. else
  785. {
  786. CHECK_STATUS( Status );
  787. leave;
  788. }
  789. }
  790. else if (Status == STATUS_FILE_IS_A_DIRECTORY)
  791. {
  792. //
  793. // We probably got to here because someone modified or deleted
  794. // a named datastream on a directory. We don't support that,
  795. // so we will just propagate this error up to the caller. They
  796. // will know whether or not this is a reasonable error.
  797. //
  798. leave;
  799. }
  800. else if (!NT_SUCCESS( Status )) {
  801. leave;
  802. }
  803. #if DBG
  804. if (CopyDataStreams)
  805. {
  806. SrTrace(NOTIFY, ("sr!SrBackupFile: copying\n\t%wZ\n\tto %ws\n",
  807. pSourceFileName,
  808. SrpFindFilePartW(pDestFileName->Buffer) ));
  809. }
  810. else
  811. {
  812. SrTrace(NOTIFY, ("sr!SrBackupFile: copying [no data]\n\t%ws\n\tto %wZ\n",
  813. SrpFindFilePartW(pSourceFileName->Buffer),
  814. pDestFileName ));
  815. }
  816. #endif
  817. //
  818. // Now we have our own handle to this file and all IOs on this handle
  819. // we start at our pTargetDevice.
  820. //
  821. //
  822. // check for free space, we don't want to bank on the fact that
  823. // the service is up and running to protect us from filling the disk
  824. //
  825. Status = SrCheckFreeDiskSpace( SourceFileHandle, pSourceFileName );
  826. if (!NT_SUCCESS( Status ))
  827. leave;
  828. //
  829. // does the caller want us to copy any actual $DATA?
  830. //
  831. if (CopyDataStreams)
  832. {
  833. //
  834. // Size the source file to determine how much data is to be copied
  835. //
  836. Status = ZwQueryInformationFile( SourceFileHandle,
  837. &IoStatus,
  838. (PVOID) &FileInformation,
  839. sizeof(FileInformation),
  840. FileStandardInformation );
  841. if (!NT_SUCCESS( Status ))
  842. leave;
  843. //
  844. // copy the entire file
  845. //
  846. BytesToCopy = FileInformation.EndOfFile;
  847. }
  848. else
  849. {
  850. //
  851. // don't copy anything
  852. //
  853. BytesToCopy.QuadPart = 0;
  854. }
  855. //
  856. // Get the timestamp info as well.
  857. //
  858. Status = ZwQueryInformationFile( SourceFileHandle,
  859. &IoStatus,
  860. (PVOID) &BasicInformation,
  861. sizeof(BasicInformation),
  862. FileBasicInformation );
  863. if (!NT_SUCCESS( Status ))
  864. leave;
  865. //
  866. // we don't support sparse or reparse points. If this
  867. // file is either sparse or contains a resparse point, just
  868. // skip it.
  869. //
  870. if (FlagOn( BasicInformation.FileAttributes,
  871. FILE_ATTRIBUTE_SPARSE_FILE | FILE_ATTRIBUTE_REPARSE_POINT )) {
  872. #if DBG
  873. if (FlagOn( BasicInformation.FileAttributes,
  874. FILE_ATTRIBUTE_SPARSE_FILE )) {
  875. SrTrace( NOTIFY, ("sr!SrBackupFile: Ignoring sparse file [%wZ]\n",
  876. pSourceFileName) );
  877. }
  878. if (FlagOn( BasicInformation.FileAttributes,
  879. FILE_ATTRIBUTE_REPARSE_POINT )) {
  880. SrTrace( NOTIFY, ("sr!SrBackupFile: Ignoring file with reparse point [%wZ]\n",
  881. pSourceFileName) );
  882. }
  883. #endif
  884. Status = SR_STATUS_IGNORE_FILE;
  885. leave;
  886. }
  887. //
  888. // are we supposed to copy the data? if so, check for the existence
  889. // of alternate streams
  890. //
  891. if (CopyDataStreams)
  892. {
  893. //
  894. // Obtain the full set of streams we have to copy. Since the Io
  895. // subsystem does not provide us a way to find out how much space
  896. // this information will take, we must iterate the call, doubling
  897. // the buffer size upon each failure.
  898. //
  899. // If the underlying file system does not support stream enumeration,
  900. // we end up with a NULL buffer. This is acceptable since we have
  901. // at least a default data stream,
  902. //
  903. StreamInfoSize = 4096;
  904. do
  905. {
  906. StreamInfoBase = (PFILE_STREAM_INFORMATION)
  907. SR_ALLOCATE_ARRAY( PagedPool,
  908. UCHAR,
  909. StreamInfoSize,
  910. SR_STREAM_DATA_TAG );
  911. if (StreamInfoBase == NULL)
  912. {
  913. Status = STATUS_INSUFFICIENT_RESOURCES;
  914. leave;
  915. }
  916. Status = ZwQueryInformationFile( SourceFileHandle,
  917. &IoStatus,
  918. (PVOID) StreamInfoBase,
  919. StreamInfoSize,
  920. FileStreamInformation );
  921. if (Status == STATUS_INVALID_PARAMETER ||
  922. !NT_SUCCESS( Status ))
  923. {
  924. //
  925. // We failed the call. Free up the previous buffer and
  926. // set up for another pass with a buffer twice as large
  927. //
  928. SR_FREE_POOL(StreamInfoBase, SR_STREAM_DATA_TAG);
  929. StreamInfoBase = NULL;
  930. StreamInfoSize *= 2;
  931. }
  932. else if( IoStatus.Information == 0 ) {
  933. //
  934. // There are no streams (SourceFileHandle must be a
  935. // directory).
  936. //
  937. SR_FREE_POOL(StreamInfoBase, SR_STREAM_DATA_TAG);
  938. StreamInfoBase = NULL;
  939. }
  940. } while ( Status == STATUS_BUFFER_OVERFLOW ||
  941. Status == STATUS_BUFFER_TOO_SMALL );
  942. //
  943. // ignore status, failing to read the streams probably means there
  944. // are no streams
  945. //
  946. Status = STATUS_SUCCESS;
  947. } // if (CopyDataStreams)
  948. //
  949. // Set the Basic Info to change only the filetimes
  950. //
  951. BasicInformation.FileAttributes = 0;
  952. //
  953. // Copy the default data stream, EAs, etc. to the output file
  954. //
  955. Status = SrCopyStream( SourceFileHandle,
  956. pExtension->pTargetDevice,
  957. pDestFileName,
  958. NULL,
  959. &BytesToCopy,
  960. &DestFile );
  961. //
  962. // the default stream copy failed!
  963. //
  964. if (!NT_SUCCESS( Status ))
  965. leave;
  966. //
  967. // remember how much we just copied
  968. //
  969. if (pBytesWritten != NULL)
  970. {
  971. *pBytesWritten += BytesToCopy.QuadPart;
  972. }
  973. //
  974. // If applicable, copy one or more of the the DACL, SACL, owner, and
  975. // group.
  976. //
  977. Status = ZwQueryVolumeInformationFile( SourceFileHandle,
  978. &IoStatus,
  979. &FileFsAttrInfoBuffer.Info,
  980. sizeof(FileFsAttrInfoBuffer),
  981. FileFsAttributeInformation );
  982. if (!NT_SUCCESS( Status ))
  983. leave;
  984. if (FileFsAttrInfoBuffer.Info.FileSystemAttributes & FILE_PERSISTENT_ACLS)
  985. {
  986. //
  987. // Set the appropriate ACL on our destination file. We will NOT copy
  988. // the ACL from the source file since we have that information
  989. // recorded in the change log.
  990. //
  991. Status = SrSetFileSecurity( DestFile, SrAclTypeRPFiles );
  992. if (!NT_SUCCESS( Status ))
  993. leave;
  994. }
  995. //
  996. // Attempt to determine whether or not this file has any alternate
  997. // data streams associated with it. If it does, attempt to copy each
  998. // to the output file. Note that the stream information may have
  999. // already been obtained if a progress routine was requested.
  1000. //
  1001. if (StreamInfoBase != NULL)
  1002. {
  1003. StreamInfo = StreamInfoBase;
  1004. while (TRUE)
  1005. {
  1006. Status = STATUS_SUCCESS;
  1007. //
  1008. // Skip the default data stream since we've already copied
  1009. // it. Alas, this code is NTFS specific and documented
  1010. // nowhere in the Io spec.
  1011. //
  1012. if (StreamInfo->StreamNameLength <= sizeof(WCHAR) ||
  1013. StreamInfo->StreamName[1] == ':')
  1014. {
  1015. if (StreamInfo->NextEntryOffset == 0)
  1016. break; // all done with streams
  1017. StreamInfo = (PFILE_STREAM_INFORMATION)((PCHAR) StreamInfo +
  1018. StreamInfo->NextEntryOffset);
  1019. continue; // Move on to the next stream
  1020. }
  1021. //
  1022. // Build a string descriptor for the name of the stream.
  1023. //
  1024. StreamName.Buffer = &StreamInfo->StreamName[0];
  1025. StreamName.Length = (USHORT) StreamInfo->StreamNameLength;
  1026. StreamName.MaximumLength = StreamName.Length;
  1027. //
  1028. // Open the source stream.
  1029. //
  1030. InitializeObjectAttributes( &ObjectAttributes,
  1031. &StreamName,
  1032. OBJ_KERNEL_HANDLE,
  1033. SourceFileHandle,
  1034. NULL );
  1035. Status = SrIoCreateFile( &StreamHandle,
  1036. GENERIC_READ
  1037. |FILE_GENERIC_READ,
  1038. &ObjectAttributes,
  1039. &IoStatus,
  1040. NULL,
  1041. 0,
  1042. FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
  1043. FILE_OPEN,
  1044. SR_CREATE_FLAGS,
  1045. NULL,
  1046. 0,
  1047. IO_IGNORE_SHARE_ACCESS_CHECK,
  1048. pExtension->pTargetDevice );
  1049. if (!NT_SUCCESS(Status))
  1050. leave;
  1051. OutputStream = NULL;
  1052. Status = SrCopyStream( StreamHandle,
  1053. pExtension->pTargetDevice,
  1054. &StreamName,
  1055. DestFile,
  1056. &StreamInfo->StreamSize,
  1057. &OutputStream );
  1058. ZwClose(StreamHandle);
  1059. StreamHandle = NULL;
  1060. if (OutputStream != NULL)
  1061. {
  1062. //
  1063. // We set the last write time on all streams
  1064. // since there is a problem with RDR caching
  1065. // open handles and closing them out of order.
  1066. //
  1067. if (NT_SUCCESS(Status))
  1068. {
  1069. Status = ZwSetInformationFile( OutputStream,
  1070. &IoStatus,
  1071. &BasicInformation,
  1072. sizeof(BasicInformation),
  1073. FileBasicInformation );
  1074. }
  1075. ZwClose(OutputStream);
  1076. }
  1077. if (!NT_SUCCESS( Status ))
  1078. leave;
  1079. //
  1080. // remember how much we just copied
  1081. //
  1082. if (pBytesWritten != NULL)
  1083. {
  1084. *pBytesWritten += StreamInfo->StreamSize.QuadPart;
  1085. }
  1086. //
  1087. // anymore streams?
  1088. //
  1089. if (StreamInfo->NextEntryOffset == 0)
  1090. {
  1091. break;
  1092. }
  1093. //
  1094. // move on to the next one
  1095. //
  1096. StreamInfo =
  1097. (PFILE_STREAM_INFORMATION)((PCHAR) StreamInfo +
  1098. StreamInfo->NextEntryOffset);
  1099. } // while (TRUE)
  1100. } // if ( StreamInfoBase != NULL )
  1101. //
  1102. // set the last write time for the default steam so that it matches the
  1103. // input file.
  1104. //
  1105. Status = ZwSetInformationFile( DestFile,
  1106. &IoStatus,
  1107. &BasicInformation,
  1108. sizeof(BasicInformation),
  1109. FileBasicInformation );
  1110. if (!NT_SUCCESS( Status ))
  1111. leave;
  1112. //
  1113. // Now get the short file name for the file that we have successfully
  1114. // backed up. If we are backing up this file in response to a
  1115. // modification of a named stream on this file, this is the only
  1116. // time we have a handle to the primary data stream.
  1117. //
  1118. if (pShortFileName != NULL)
  1119. {
  1120. Status = ObReferenceObjectByHandle( SourceFileHandle,
  1121. 0,
  1122. *IoFileObjectType,
  1123. KernelMode,
  1124. &pSourceFileObject,
  1125. NULL );
  1126. if (!NT_SUCCESS( Status ))
  1127. leave;
  1128. //
  1129. // Use the pSourceFileObject to get the short name.
  1130. //
  1131. Status = SrGetShortFileName( pExtension,
  1132. pSourceFileObject,
  1133. pShortFileName );
  1134. if (STATUS_OBJECT_NAME_NOT_FOUND == Status)
  1135. {
  1136. //
  1137. // This file doesn't have a short name.
  1138. //
  1139. Status = STATUS_SUCCESS;
  1140. }
  1141. else if (!NT_SUCCESS(Status))
  1142. {
  1143. //
  1144. // We hit an unexpected error, so leave.
  1145. //
  1146. leave;
  1147. }
  1148. }
  1149. } finally {
  1150. //
  1151. // check for unhandled exceptions
  1152. //
  1153. Status = FinallyUnwind(SrBackupFile, Status);
  1154. //
  1155. // did we fail?
  1156. //
  1157. if ((Status != SR_STATUS_IGNORE_FILE) &&
  1158. !NT_SUCCESS( Status ))
  1159. {
  1160. if (DestFile != NULL)
  1161. {
  1162. //
  1163. // delete the dest file
  1164. //
  1165. SrMarkFileForDelete(DestFile);
  1166. }
  1167. }
  1168. if (DestFile != NULL)
  1169. {
  1170. ZwClose(DestFile);
  1171. DestFile = NULL;
  1172. }
  1173. if (pSourceFileObject != NULL)
  1174. {
  1175. ObDereferenceObject( pSourceFileObject );
  1176. NULLPTR( pSourceFileObject );
  1177. }
  1178. if (SourceFileHandle != NULL)
  1179. {
  1180. ZwClose(SourceFileHandle);
  1181. SourceFileHandle = NULL;
  1182. }
  1183. if (StreamInfoBase != NULL)
  1184. {
  1185. SR_FREE_POOL(StreamInfoBase, SR_STREAM_DATA_TAG);
  1186. StreamInfoBase = NULL;
  1187. }
  1188. } // finally
  1189. #if DBG
  1190. if (Status == STATUS_FILE_IS_A_DIRECTORY)
  1191. {
  1192. return Status;
  1193. }
  1194. #endif
  1195. RETURN(Status);
  1196. } // SrBackupFile
  1197. /*++
  1198. Routine Description:
  1199. This routine marks a file for delete, so that when the supplied handle
  1200. is closed, the file will actually be deleted.
  1201. Arguments:
  1202. FileHandle - Supplies a handle to the file that is to be marked for delete.
  1203. Return Value:
  1204. None.
  1205. --*/
  1206. NTSTATUS
  1207. SrMarkFileForDelete(
  1208. HANDLE FileHandle
  1209. )
  1210. {
  1211. #undef DeleteFile
  1212. FILE_DISPOSITION_INFORMATION DispositionInformation;
  1213. IO_STATUS_BLOCK IoStatus;
  1214. FILE_BASIC_INFORMATION BasicInformation;
  1215. NTSTATUS Status;
  1216. PAGED_CODE();
  1217. BasicInformation.FileAttributes = 0;
  1218. Status = ZwQueryInformationFile( FileHandle,
  1219. &IoStatus,
  1220. &BasicInformation,
  1221. sizeof(BasicInformation),
  1222. FileBasicInformation );
  1223. if (!NT_SUCCESS( Status ))
  1224. goto end;
  1225. if (BasicInformation.FileAttributes & FILE_ATTRIBUTE_READONLY)
  1226. {
  1227. RtlZeroMemory(&BasicInformation, sizeof(BasicInformation));
  1228. BasicInformation.FileAttributes = FILE_ATTRIBUTE_NORMAL;
  1229. Status = ZwSetInformationFile( FileHandle,
  1230. &IoStatus,
  1231. &BasicInformation,
  1232. sizeof(BasicInformation),
  1233. FileBasicInformation );
  1234. if (!NT_SUCCESS( Status ))
  1235. goto end;
  1236. }
  1237. RtlZeroMemory(&DispositionInformation, sizeof(DispositionInformation));
  1238. DispositionInformation.DeleteFile = TRUE;
  1239. Status = ZwSetInformationFile( FileHandle,
  1240. &IoStatus,
  1241. &DispositionInformation,
  1242. sizeof(DispositionInformation),
  1243. FileDispositionInformation );
  1244. if (!NT_SUCCESS( Status ))
  1245. goto end;
  1246. end:
  1247. RETURN(Status);
  1248. } // SrMarkFileForDelete
  1249. /***************************************************************************++
  1250. Routine Description:
  1251. calls SrBackupFile then calls SrUpdateBytesWritten and SrLogEvent
  1252. Arguments:
  1253. EventType - the event that occurred
  1254. pFileObject - the file object that just changed
  1255. pFileName - the name of the file that changed
  1256. pDestFileName - the dest file to copy to
  1257. CopyDataStreams - should we copy the data streams.
  1258. Return Value:
  1259. NTSTATUS - Completion status.
  1260. --***************************************************************************/
  1261. NTSTATUS
  1262. SrBackupFileAndLog(
  1263. IN PSR_DEVICE_EXTENSION pExtension,
  1264. IN SR_EVENT_TYPE EventType,
  1265. IN PFILE_OBJECT pFileObject,
  1266. IN PUNICODE_STRING pFileName,
  1267. IN PUNICODE_STRING pDestFileName,
  1268. IN BOOLEAN CopyDataStreams
  1269. )
  1270. {
  1271. NTSTATUS Status;
  1272. ULONGLONG BytesWritten;
  1273. WCHAR ShortFileNameBuffer[SR_SHORT_NAME_CHARS+1];
  1274. UNICODE_STRING ShortFileName;
  1275. PAGED_CODE();
  1276. RtlInitEmptyUnicodeString( &ShortFileName,
  1277. ShortFileNameBuffer,
  1278. sizeof(ShortFileNameBuffer) );
  1279. //
  1280. // backup the file
  1281. //
  1282. Status = SrBackupFile( pExtension,
  1283. pFileObject,
  1284. pFileName,
  1285. pDestFileName,
  1286. CopyDataStreams,
  1287. &BytesWritten,
  1288. &ShortFileName );
  1289. if (Status == SR_STATUS_IGNORE_FILE)
  1290. {
  1291. //
  1292. // During the backup process we realized that we wanted to ignore
  1293. // this file, so change this status to STATUS_SUCCESS and don't
  1294. // try to log this operation.
  1295. //
  1296. Status = STATUS_SUCCESS;
  1297. goto SrBackupFileAndLog_Exit;
  1298. }
  1299. else if (!NT_SUCCESS_NO_DBGBREAK( Status ))
  1300. {
  1301. goto SrBackupFileAndLog_Exit;
  1302. }
  1303. //
  1304. // SrHandleFileOverwrite passes down SrEventInvalid which means it
  1305. // doesn't want it logged yet.
  1306. //
  1307. if (EventType != SrEventInvalid)
  1308. {
  1309. //
  1310. // Only update the bytes written if this is an event we want
  1311. // to log. Otherwise, this event doesn't affect the number
  1312. // of bytes in the store.
  1313. //
  1314. Status = SrUpdateBytesWritten(pExtension, BytesWritten);
  1315. if (!NT_SUCCESS( Status ))
  1316. {
  1317. goto SrBackupFileAndLog_Exit;
  1318. }
  1319. //
  1320. // Go ahead and log this event now.
  1321. //
  1322. Status = SrLogEvent( pExtension,
  1323. EventType,
  1324. pFileObject,
  1325. pFileName,
  1326. 0,
  1327. pDestFileName,
  1328. NULL,
  1329. 0,
  1330. &ShortFileName );
  1331. if (!NT_SUCCESS( Status ))
  1332. {
  1333. goto SrBackupFileAndLog_Exit;
  1334. }
  1335. }
  1336. SrBackupFileAndLog_Exit:
  1337. #if DBG
  1338. //
  1339. // When dealing with modifications to streams on directories, this
  1340. // is a valid error code to return.
  1341. //
  1342. if (Status == STATUS_FILE_IS_A_DIRECTORY)
  1343. {
  1344. return Status;
  1345. }
  1346. #endif
  1347. RETURN(Status);
  1348. } // SrBackupFileAndLog
  1349. BOOLEAN
  1350. SrIsFileEncrypted (
  1351. PSR_DEVICE_EXTENSION pExtension,
  1352. PFILE_OBJECT pFileObject
  1353. )
  1354. {
  1355. FILE_BASIC_INFORMATION fileBasicInfo;
  1356. NTSTATUS status;
  1357. PAGED_CODE();
  1358. //
  1359. // First do a quick check to see if this volume supports encryption
  1360. // if we already have the file system attributes cached.
  1361. //
  1362. if (pExtension->CachedFsAttributes)
  1363. {
  1364. if (!FlagOn( pExtension->FsAttributes, FILE_SUPPORTS_ENCRYPTION ))
  1365. {
  1366. //
  1367. // The file system doesn't support encryption, therefore this
  1368. // file cannot be encrypted.
  1369. return FALSE;
  1370. }
  1371. }
  1372. status = SrQueryInformationFile( pExtension->pTargetDevice,
  1373. pFileObject,
  1374. &fileBasicInfo,
  1375. sizeof( fileBasicInfo ),
  1376. FileBasicInformation,
  1377. NULL );
  1378. if (!NT_SUCCESS( status ))
  1379. {
  1380. //
  1381. // We couldn't read the basic information for this file, so we must
  1382. // assume that it is not encrypted.
  1383. //
  1384. return FALSE;
  1385. }
  1386. if (FlagOn( fileBasicInfo.FileAttributes, FILE_ATTRIBUTE_ENCRYPTED ))
  1387. {
  1388. return TRUE;
  1389. }
  1390. else
  1391. {
  1392. return FALSE;
  1393. }
  1394. }