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.

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