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.

3131 lines
75 KiB

  1. //
  2. // Copyright (c) 1991 Microsoft Corporation & Maynard Electornics
  3. //
  4. // Module Name:
  5. //
  6. // backup.c
  7. //
  8. // Abstract:
  9. //
  10. // This module implements Win32 Backup APIs
  11. //
  12. // Author:
  13. //
  14. // Steve DeVos (@Maynard) 2 March, 1992 15:38:24
  15. //
  16. // Revision History:
  17. #include <basedll.h>
  18. #pragma hdrstop
  19. #include <windows.h>
  20. #define CWCMAX_STREAMNAME 512
  21. #define CB_NAMELESSHEADER FIELD_OFFSET(WIN32_STREAM_ID, cStreamName)
  22. typedef struct
  23. {
  24. DWORD BufferSize;
  25. DWORD AllocSize;
  26. BYTE *Buffer;
  27. } BUFFER;
  28. //
  29. // BACKUPCONTEXT is the structure used to note the state of the backup.
  30. //
  31. typedef struct
  32. {
  33. //
  34. // Public header describing current stream. Since this structure precedes
  35. // a variable-length stream name, we must reserve space for that name
  36. // following the header.
  37. //
  38. WIN32_STREAM_ID head;
  39. union {
  40. WCHAR awcName[CWCMAX_STREAMNAME];
  41. } ex ;
  42. LARGE_INTEGER cbSparseOffset ;
  43. //
  44. // Offset in the current segment of the backup stream. This includes
  45. // the size of the above header (including variable length name).
  46. //
  47. LONGLONG liStreamOffset;
  48. //
  49. // BackupRead machine state
  50. //
  51. DWORD StreamIndex;
  52. //
  53. // Calculated size of the above header.
  54. //
  55. DWORD cbHeader;
  56. //
  57. // Handle to alternate data stream
  58. //
  59. HANDLE hAlternate;
  60. //
  61. // Buffers
  62. //
  63. BUFFER DataBuffer; // Data buffer
  64. DWORD dwSparseMapSize ; // size of the sparse file map
  65. DWORD dwSparseMapOffset ; // offset into the sparse map
  66. BOOLEAN fSparseBlockStart ; // TRUE if start of sparse block
  67. BOOLEAN fSparseHandAlt ; // TRUE if sparse stream is alt stream
  68. DWORD iNameBuffer; // Offset into stream name buffer
  69. BUFFER StreamNameBuffer; // Stream name buffer
  70. BOOLEAN NamesReady; // TRUE if stream name buffer has data in it
  71. BOOLEAN fStreamStart; // TRUE if start of new stream
  72. BOOLEAN fMultiStreamType; // TRUE if stream type has > 1 stream hdr
  73. BOOLEAN fAccessError; // TRUE if access to a stream was denied
  74. DWORD fAttribs; // object attributes...
  75. } BACKUPCONTEXT;
  76. //
  77. // BACKUPIOFRAME describes the current user BackupRead/Write request
  78. //
  79. typedef struct
  80. {
  81. BYTE *pIoBuffer;
  82. DWORD *pcbTransferred;
  83. DWORD cbRequest;
  84. BOOLEAN fProcessSecurity;
  85. } BACKUPIOFRAME;
  86. #define CBMIN_BUFFER 1024
  87. #define BufferOverflow(s) \
  88. ((s) == STATUS_BUFFER_OVERFLOW || (s) == STATUS_BUFFER_TOO_SMALL)
  89. int mwStreamList[] =
  90. {
  91. BACKUP_SECURITY_DATA,
  92. BACKUP_REPARSE_DATA,
  93. BACKUP_DATA,
  94. BACKUP_EA_DATA,
  95. BACKUP_ALTERNATE_DATA,
  96. BACKUP_OBJECT_ID,
  97. BACKUP_INVALID,
  98. };
  99. __inline VOID *
  100. BackupAlloc (DWORD cb)
  101. /*++
  102. Routine Description:
  103. This is an internal routine that wraps heap allocation with tags.
  104. Arguments:
  105. cb - size of block to allocate
  106. Return Value:
  107. pointer to allocated memory or NULL
  108. --*/
  109. {
  110. return RtlAllocateHeap( RtlProcessHeap( ), MAKE_TAG( BACKUP_TAG ), cb );
  111. }
  112. __inline VOID
  113. BackupFree (IN VOID *pv)
  114. /*++
  115. Routine Description:
  116. This is an internal routine that wraps heap freeing.
  117. Arguments:
  118. pv - memory to be freed
  119. Return Value:
  120. None.
  121. --*/
  122. {
  123. RtlFreeHeap( RtlProcessHeap( ), 0, pv );
  124. }
  125. BOOL
  126. GrowBuffer (IN OUT BUFFER *Buffer, IN DWORD cbNew)
  127. /*++
  128. Routine Description:
  129. Attempt to grow the buffer in the backup context.
  130. Arguments:
  131. Buffer - pointer to buffer
  132. cbNew - size of buffer to allocate
  133. Return Value:
  134. TRUE if buffer was successfully allocated.
  135. --*/
  136. {
  137. VOID *pv;
  138. if ( Buffer->AllocSize < cbNew ) {
  139. pv = BackupAlloc( cbNew );
  140. if (pv == NULL) {
  141. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  142. return FALSE;
  143. }
  144. RtlCopyMemory( pv, Buffer->Buffer, Buffer->BufferSize );
  145. BackupFree( Buffer->Buffer );
  146. Buffer->Buffer = pv;
  147. Buffer->AllocSize = cbNew ;
  148. }
  149. Buffer->BufferSize = cbNew;
  150. return TRUE;
  151. }
  152. __inline VOID
  153. FreeBuffer (IN OUT BUFFER *Buffer)
  154. /*++
  155. Routine Description:
  156. Free the buffer
  157. Arguments:
  158. Buffer - pointer to buffer
  159. Return Value:
  160. Nothing
  161. --*/
  162. {
  163. if (Buffer->Buffer != NULL) {
  164. BackupFree( Buffer->Buffer );
  165. Buffer->Buffer = NULL;
  166. }
  167. }
  168. VOID ResetAccessDate( HANDLE hand )
  169. {
  170. LONGLONG tmp_time = -1 ;
  171. FILETIME *time_ptr ;
  172. time_ptr = (FILETIME *)(&tmp_time);
  173. if (hand != INVALID_HANDLE_VALUE) {
  174. SetFileTime( hand,
  175. time_ptr,
  176. time_ptr,
  177. time_ptr ) ;
  178. }
  179. }
  180. VOID
  181. FreeContext (IN OUT LPVOID *lpContext)
  182. /*++
  183. Routine Description:
  184. Free a backup context and release all resources assigned to it.
  185. Arguments:
  186. lpContext - pointer to pointer backup context
  187. Return Value:
  188. None.
  189. --*/
  190. {
  191. BACKUPCONTEXT *pbuc = *lpContext;
  192. if (pbuc != INVALID_HANDLE_VALUE) {
  193. FreeBuffer( &pbuc->DataBuffer );
  194. FreeBuffer( &pbuc->StreamNameBuffer );
  195. ResetAccessDate( pbuc->hAlternate ) ;
  196. if (pbuc->hAlternate != INVALID_HANDLE_VALUE) {
  197. CloseHandle( pbuc->hAlternate );
  198. }
  199. BackupFree(pbuc);
  200. *lpContext = INVALID_HANDLE_VALUE;
  201. }
  202. }
  203. BACKUPCONTEXT *
  204. AllocContext (IN DWORD cbBuffer)
  205. /*++
  206. Routine Description:
  207. Allocate a backup context with a buffer of a specified size
  208. Arguments:
  209. cbBuffer - desired length of the buffer
  210. Return Value:
  211. pointer to initialized backupcontext or NULL if out of memory.
  212. --*/
  213. {
  214. BACKUPCONTEXT *pbuc;
  215. pbuc = BackupAlloc( sizeof( *pbuc ));
  216. if (pbuc != NULL) {
  217. RtlZeroMemory( pbuc, sizeof( *pbuc ));
  218. pbuc->fStreamStart = TRUE;
  219. if (cbBuffer != 0 && !GrowBuffer( &pbuc->DataBuffer, cbBuffer )) {
  220. BackupFree( pbuc );
  221. pbuc = NULL;
  222. }
  223. }
  224. if (pbuc == NULL) {
  225. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  226. }
  227. return(pbuc);
  228. }
  229. LONGLONG
  230. ComputeRemainingSize (IN BACKUPCONTEXT *pbuc)
  231. /*++
  232. Routine Description:
  233. (Re)Compute the number of bytes required to store the current
  234. stream. This needs to take into account the header length as
  235. well.
  236. Arguments:
  237. pbuc - backup context
  238. Return Value:
  239. Amount of data still remaining to transfer. Includes header
  240. size.
  241. --*/
  242. {
  243. LARGE_INTEGER ret_size ;
  244. ret_size.QuadPart = pbuc->cbHeader + pbuc->head.Size.QuadPart
  245. - pbuc->liStreamOffset;
  246. //
  247. // since the internally we treat the sparse buffer offset
  248. // as part of the header and since the caller need to see it
  249. // as part of the data, this code make the internal correction.
  250. //
  251. if ( pbuc->head.dwStreamId == BACKUP_SPARSE_BLOCK ) {
  252. ret_size.QuadPart -= sizeof(LARGE_INTEGER) ;
  253. }
  254. return ret_size.QuadPart ;
  255. }
  256. DWORD
  257. ComputeRequestSize (BACKUPCONTEXT *pbuc, DWORD cbrequest)
  258. /*++
  259. Routine Description:
  260. Given a transfer size request, return the number of
  261. bytes remaining that can safely be returned to the
  262. caller
  263. Arguments:
  264. pbuc - context of call
  265. cbRequest - desired transfer size
  266. Return Value:
  267. amount of data available to return.
  268. --*/
  269. {
  270. LONGLONG licbRemain;
  271. licbRemain = ComputeRemainingSize( pbuc );
  272. return (DWORD) min( cbrequest, licbRemain );
  273. }
  274. VOID
  275. ReportTransfer(BACKUPCONTEXT *pbuc, BACKUPIOFRAME *pbif, DWORD cbtransferred)
  276. /*++
  277. Routine Description:
  278. Note that a transfer has occurred and update contexts
  279. Arguments:
  280. pbuc - context of call
  281. pbif - BACKUPIOFRAME of call detailing call
  282. cbtransferred - amount successfully transferred
  283. Return Value:
  284. None.
  285. --*/
  286. {
  287. pbuc->liStreamOffset += cbtransferred;
  288. *pbif->pcbTransferred += cbtransferred;
  289. pbif->cbRequest -= cbtransferred;
  290. pbif->pIoBuffer += cbtransferred;
  291. }
  292. VOID
  293. BackupReadBuffer (BACKUPCONTEXT *pbuc, BACKUPIOFRAME *pbif)
  294. /*++
  295. Routine Description:
  296. Perform a read to user buffer from the buffer in the backup
  297. context.
  298. Arguments:
  299. pbuc - context of call
  300. pbif - frame describing desired user BackupRead request
  301. Return Value:
  302. None.
  303. --*/
  304. {
  305. DWORD cbrequest;
  306. BYTE *pb;
  307. //
  308. // Determine size of allowable transfer and pointer to source
  309. // data
  310. //
  311. cbrequest = ComputeRequestSize( pbuc, pbif->cbRequest );
  312. pb = &pbuc->DataBuffer.Buffer[ pbuc->liStreamOffset - pbuc->cbHeader ];
  313. //
  314. // Move the data to the user's buffer
  315. //
  316. RtlCopyMemory(pbif->pIoBuffer, pb, cbrequest);
  317. //
  318. // Update statistics
  319. //
  320. ReportTransfer(pbuc, pbif, cbrequest);
  321. }
  322. BOOL
  323. BackupReadStream (HANDLE hFile, BACKUPCONTEXT *pbuc, BACKUPIOFRAME *pbif)
  324. /*++
  325. Routine Description:
  326. Perform a read to user buffer from the stream.
  327. Arguments:
  328. hFile - handle to file for transfer
  329. pbuc - context of call
  330. pbif - frame describing BackupRead request
  331. Return Value:
  332. True if transfer succeeded..
  333. --*/
  334. {
  335. DWORD cbrequest;
  336. DWORD cbtransferred;
  337. BOOL fSuccess;
  338. if (pbuc->fSparseBlockStart) {
  339. PFILE_ALLOCATED_RANGE_BUFFER range_buf ;
  340. LARGE_INTEGER licbFile ;
  341. range_buf = (PFILE_ALLOCATED_RANGE_BUFFER)(pbuc->DataBuffer.Buffer + pbuc->dwSparseMapOffset) ;
  342. pbuc->head.Size.QuadPart = range_buf->Length.QuadPart + sizeof(LARGE_INTEGER) ;
  343. pbuc->head.dwStreamId = BACKUP_SPARSE_BLOCK ;
  344. pbuc->head.dwStreamAttributes = STREAM_SPARSE_ATTRIBUTE;
  345. pbuc->head.dwStreamNameSize = 0;
  346. pbuc->cbHeader = CB_NAMELESSHEADER + sizeof( LARGE_INTEGER ) ;
  347. pbuc->cbSparseOffset = range_buf->FileOffset ;
  348. RtlCopyMemory( pbuc->head.cStreamName, &pbuc->cbSparseOffset, sizeof( LARGE_INTEGER ) ) ;
  349. pbuc->fSparseBlockStart = FALSE;
  350. licbFile.HighPart = 0;
  351. licbFile.HighPart = range_buf->FileOffset.HighPart;
  352. licbFile.LowPart = SetFilePointer( hFile,
  353. range_buf->FileOffset.LowPart,
  354. &licbFile.HighPart,
  355. FILE_BEGIN );
  356. if ( licbFile.QuadPart != range_buf->FileOffset.QuadPart ) {
  357. pbuc->fAccessError = TRUE;
  358. return FALSE ;
  359. } else {
  360. return TRUE ;
  361. }
  362. }
  363. if (pbuc->liStreamOffset < pbuc->cbHeader) {
  364. return TRUE ;
  365. }
  366. cbrequest = ComputeRequestSize( pbuc, pbif->cbRequest );
  367. fSuccess = ReadFile( hFile, pbif->pIoBuffer, cbrequest, &cbtransferred, NULL );
  368. if (cbtransferred != 0) {
  369. ReportTransfer( pbuc, pbif, cbtransferred );
  370. } else if (fSuccess && cbrequest != 0) {
  371. SetLastError( ERROR_IO_DEVICE );
  372. fSuccess = FALSE;
  373. }
  374. return(fSuccess);
  375. }
  376. BOOL
  377. BackupGetSparseMap (HANDLE hFile, BACKUPCONTEXT *pbuc, BACKUPIOFRAME *pbif)
  378. /*++
  379. Routine Description:
  380. Reads the sparse data map.
  381. Arguments:
  382. hFile - handle to file for transfer
  383. pbuc - context of call
  384. pbif - frame describing BackupRead request
  385. Return Value:
  386. True if transfer succeeded..
  387. --*/
  388. {
  389. FILE_ALLOCATED_RANGE_BUFFER req_buf ;
  390. PFILE_ALLOCATED_RANGE_BUFFER last_ret_buf ;
  391. DWORD out_buf_size ;
  392. DWORD data_size = 4096 ;
  393. IO_STATUS_BLOCK iosb ;
  394. LARGE_INTEGER file_size ;
  395. NTSTATUS Status ;
  396. BOOLEAN empty_file = FALSE ;
  397. req_buf.FileOffset.QuadPart = 0 ;
  398. pbuc->dwSparseMapSize = 0 ;
  399. pbuc->dwSparseMapOffset = 0 ;
  400. pbuc->fSparseBlockStart = FALSE ;
  401. req_buf.Length.LowPart = GetFileSize( hFile,
  402. &req_buf.Length.HighPart );
  403. file_size = req_buf.Length ;
  404. do {
  405. if ( GrowBuffer( &pbuc->DataBuffer,
  406. data_size ) ) {
  407. iosb.Information = 0 ;
  408. Status = NtFsControlFile( hFile,
  409. NULL, // overlapped event handle
  410. NULL, // Apc routine
  411. NULL, // overlapped structure
  412. &iosb,
  413. FSCTL_QUERY_ALLOCATED_RANGES,
  414. &req_buf,
  415. sizeof( req_buf ),
  416. pbuc->DataBuffer.Buffer + pbuc->dwSparseMapSize,
  417. pbuc->DataBuffer.AllocSize - pbuc->dwSparseMapSize ) ;
  418. out_buf_size = 0 ;
  419. if ((Status == STATUS_BUFFER_OVERFLOW) || NT_SUCCESS( Status ) ) {
  420. out_buf_size = (DWORD)iosb.Information ;
  421. if ( out_buf_size == 0 ) {
  422. empty_file = TRUE ;
  423. }
  424. }
  425. if ( out_buf_size != 0 ) {
  426. pbuc->dwSparseMapSize += out_buf_size ;
  427. last_ret_buf =
  428. (PFILE_ALLOCATED_RANGE_BUFFER)(pbuc->DataBuffer.Buffer +
  429. pbuc->dwSparseMapSize -
  430. sizeof(FILE_ALLOCATED_RANGE_BUFFER)) ;
  431. req_buf.FileOffset = last_ret_buf->FileOffset ;
  432. req_buf.FileOffset.QuadPart += last_ret_buf->Length.QuadPart ;
  433. //
  434. // if we can't fit any more in the buffer lets increase
  435. // the size and get more data otherwise assume were done.
  436. //
  437. if ( pbuc->dwSparseMapSize + sizeof(FILE_ALLOCATED_RANGE_BUFFER) >
  438. pbuc->DataBuffer.AllocSize ) {
  439. data_size += 4096 ;
  440. } else {
  441. break ;
  442. }
  443. } else {
  444. // reallocate for one more buffer entry
  445. if ( out_buf_size + sizeof(FILE_ALLOCATED_RANGE_BUFFER) > data_size ) {
  446. data_size += 4096 ;
  447. continue ;
  448. }
  449. break ;
  450. }
  451. } else {
  452. pbuc->dwSparseMapSize = 0 ;
  453. break ;
  454. }
  455. } while ( TRUE ) ;
  456. //
  457. // if there are RANGE_BUFFERS and it isn't simply the whole file, then
  458. // go into sparse read mode.
  459. //
  460. // hold on to your hat...
  461. // If there are no allocated ranges and the file is NOT 0 length
  462. // then we want to manufacture a record for the file length.
  463. //
  464. if ( (empty_file && ( file_size.QuadPart != 0 )) || (pbuc->dwSparseMapSize >= sizeof( FILE_ALLOCATED_RANGE_BUFFER) ) ) {
  465. last_ret_buf = (PFILE_ALLOCATED_RANGE_BUFFER)(pbuc->DataBuffer.Buffer ) ;
  466. if ( empty_file ||
  467. ( last_ret_buf->FileOffset.QuadPart != 0 ) ||
  468. ( last_ret_buf->Length.QuadPart != file_size.QuadPart ) ) {
  469. // first lets add a record for the EOF marker
  470. pbuc->dwSparseMapSize += sizeof(FILE_ALLOCATED_RANGE_BUFFER) ;
  471. last_ret_buf =
  472. (PFILE_ALLOCATED_RANGE_BUFFER)(pbuc->DataBuffer.Buffer +
  473. pbuc->dwSparseMapSize -
  474. sizeof(FILE_ALLOCATED_RANGE_BUFFER)) ;
  475. last_ret_buf->FileOffset.QuadPart = file_size.QuadPart ;
  476. last_ret_buf->Length.QuadPart = 0 ;
  477. pbuc->fSparseBlockStart = TRUE ;
  478. return TRUE ;
  479. }
  480. }
  481. pbuc->dwSparseMapSize = 0 ;
  482. return FALSE ;
  483. }
  484. BOOL
  485. BackupReadData (HANDLE hFile, BACKUPCONTEXT *pbuc, BACKUPIOFRAME *pbif)
  486. /*++
  487. Routine Description:
  488. Read default data for a user BackupRead request.
  489. Arguments:
  490. hFile - handle to file for transfer
  491. pbuc - context of call
  492. pbif - frame describing BackupRead request
  493. Return Value:
  494. True if transfer succeeded..
  495. --*/
  496. {
  497. LARGE_INTEGER licbFile ;
  498. //
  499. // If the context is not initialized for this transfer,
  500. // set up based on file size.
  501. //
  502. if (pbuc->fStreamStart) {
  503. if (pbuc->fAttribs & FILE_ATTRIBUTE_ENCRYPTED) {
  504. return TRUE;
  505. }
  506. if (pbuc->fAttribs & FILE_ATTRIBUTE_DIRECTORY) {
  507. return TRUE;
  508. }
  509. licbFile.LowPart = GetFileSize( hFile, &licbFile.HighPart );
  510. if (licbFile.QuadPart == 0) {
  511. return TRUE;
  512. }
  513. if (licbFile.LowPart == 0xffffffff && GetLastError() != NO_ERROR) {
  514. return FALSE;
  515. }
  516. pbuc->head.dwStreamId = BACKUP_DATA;
  517. pbuc->head.dwStreamAttributes = STREAM_NORMAL_ATTRIBUTE;
  518. pbuc->head.dwStreamNameSize = 0;
  519. pbuc->cbHeader = CB_NAMELESSHEADER;
  520. pbuc->fStreamStart = FALSE;
  521. if ( BackupGetSparseMap( hFile, pbuc, pbif ) ) {
  522. pbuc->head.Size.QuadPart = 0 ;
  523. pbuc->head.dwStreamAttributes = STREAM_SPARSE_ATTRIBUTE;
  524. } else {
  525. pbuc->head.Size = licbFile;
  526. licbFile.HighPart = 0;
  527. SetFilePointer( hFile, 0, &licbFile.HighPart, FILE_BEGIN );
  528. }
  529. return TRUE;
  530. }
  531. //
  532. // If there's more data for us to read, then go and
  533. // get it from the stream
  534. //
  535. return BackupReadStream( hFile, pbuc, pbif );
  536. }
  537. BOOL
  538. BackupReadAlternateData(HANDLE hFile, BACKUPCONTEXT *pbuc, BACKUPIOFRAME *pbif)
  539. /*++
  540. Routine Description:
  541. Perform a read to user buffer from alternate data streams.
  542. Arguments:
  543. hFile - handle to base file for transfer
  544. pbuc - context of call
  545. pbif - frame describing BackupRead request
  546. Return Value:
  547. True if transfer succeeded..
  548. --*/
  549. {
  550. //
  551. // If we haven't started transferring alternate data streams then
  552. // buffer all the stream information from the file system
  553. //
  554. if (pbuc->fStreamStart) {
  555. NTSTATUS Status;
  556. FILE_STREAM_INFORMATION *pfsi;
  557. IO_STATUS_BLOCK iosb;
  558. if (pbuc->fAttribs & FILE_ATTRIBUTE_ENCRYPTED) {
  559. if ( !(pbuc->fAttribs & FILE_ATTRIBUTE_DIRECTORY) ) {
  560. return TRUE;
  561. }
  562. }
  563. //
  564. // Loop, growing the names buffer, until it is large enough to
  565. // contain all the alternate data
  566. //
  567. if (!pbuc->NamesReady) {
  568. if (!GrowBuffer( &pbuc->StreamNameBuffer, 1024 ) ) {
  569. return FALSE;
  570. }
  571. while (TRUE) {
  572. //
  573. // Resize the buffer. If we cannot grow it, then fail.
  574. //
  575. Status = NtQueryInformationFile(
  576. hFile,
  577. &iosb,
  578. pbuc->StreamNameBuffer.Buffer,
  579. pbuc->StreamNameBuffer.BufferSize,
  580. FileStreamInformation);
  581. //
  582. // If we succeeded in reading some data, set the buffer
  583. // up and finish initializing
  584. //
  585. if (NT_SUCCESS(Status) && iosb.Information != 0) {
  586. pbuc->iNameBuffer = 0;
  587. pbuc->NamesReady = TRUE;
  588. break;
  589. }
  590. //
  591. // If the error was not due to overflow, then skip
  592. // all alternate streams
  593. //
  594. if (!BufferOverflow(Status)) {
  595. return TRUE;
  596. }
  597. //
  598. // simply inlarge the buffer and try again.
  599. //
  600. if (!GrowBuffer( &pbuc->StreamNameBuffer,
  601. pbuc->StreamNameBuffer.BufferSize * 2)) {
  602. return FALSE;
  603. }
  604. }
  605. }
  606. pbuc->hAlternate = INVALID_HANDLE_VALUE;
  607. pbuc->fStreamStart = FALSE;
  608. pfsi = (FILE_STREAM_INFORMATION *) &pbuc->StreamNameBuffer.Buffer[pbuc->iNameBuffer];
  609. //
  610. // Skip first stream if it is the default data stream. This
  611. // code is NTFS-specific and relies on behaviour not documented anywhere.
  612. //
  613. if (pfsi->StreamNameLength >= 2 * sizeof(WCHAR) &&
  614. pfsi->StreamName[1] == ':') {
  615. if (pfsi->NextEntryOffset == 0) {
  616. return TRUE; // No more, do next stream type
  617. }
  618. pbuc->iNameBuffer += pfsi->NextEntryOffset;
  619. }
  620. pbuc->head.Size.LowPart = 1;
  621. //
  622. // If we don't have an open stream
  623. //
  624. } else if (pbuc->hAlternate == INVALID_HANDLE_VALUE) {
  625. NTSTATUS Status;
  626. PFILE_STREAM_INFORMATION pfsi;
  627. UNICODE_STRING strName;
  628. OBJECT_ATTRIBUTES oa;
  629. IO_STATUS_BLOCK iosb;
  630. DWORD reparse_flg = 0 ;
  631. pbuc->head.Size.QuadPart = 0;
  632. //
  633. // Form the relative name of the stream and try to
  634. // open it relative to the base file
  635. //
  636. pfsi = (FILE_STREAM_INFORMATION *) &pbuc->StreamNameBuffer.Buffer[pbuc->iNameBuffer];
  637. strName.Length = (USHORT) pfsi->StreamNameLength;
  638. strName.MaximumLength = strName.Length;
  639. strName.Buffer = pfsi->StreamName;
  640. if (pbuc->fAttribs & FILE_ATTRIBUTE_REPARSE_POINT ) {
  641. reparse_flg = FILE_OPEN_REPARSE_POINT ;
  642. }
  643. InitializeObjectAttributes(
  644. &oa,
  645. &strName,
  646. OBJ_CASE_INSENSITIVE,
  647. hFile,
  648. NULL);
  649. Status = NtOpenFile(
  650. &pbuc->hAlternate,
  651. FILE_READ_DATA | SYNCHRONIZE,
  652. &oa,
  653. &iosb,
  654. FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
  655. FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | reparse_flg);
  656. //
  657. // If we did not succeed, skip this entry and set up for another stream
  658. //
  659. if (!NT_SUCCESS( Status )) {
  660. pbuc->iNameBuffer += pfsi->NextEntryOffset;
  661. if (pfsi->NextEntryOffset != 0) {
  662. pbuc->head.Size.LowPart = 1;
  663. pbuc->fMultiStreamType = TRUE; // more to come
  664. }
  665. SetLastError( ERROR_SHARING_VIOLATION );
  666. return FALSE;
  667. }
  668. // if we can't lock all records, return an error
  669. if (!LockFile( pbuc->hAlternate, 0, 0, 0xffffffff, 0xffffffff )) {
  670. SetLastError( ERROR_SHARING_VIOLATION );
  671. return FALSE;
  672. }
  673. //
  674. // Perform common header initialization
  675. //
  676. pbuc->head.dwStreamAttributes = STREAM_NORMAL_ATTRIBUTE;
  677. pbuc->head.dwStreamNameSize = pfsi->StreamNameLength;
  678. pbuc->cbHeader = CB_NAMELESSHEADER + pfsi->StreamNameLength;
  679. RtlCopyMemory(
  680. pbuc->head.cStreamName,
  681. pfsi->StreamName,
  682. pfsi->StreamNameLength);
  683. //
  684. // Advance to the next stream in the stream information block
  685. //
  686. if (pfsi->NextEntryOffset != 0) {
  687. pbuc->iNameBuffer += pfsi->NextEntryOffset;
  688. pbuc->fMultiStreamType = TRUE;
  689. }
  690. //
  691. // If we are a data stream, set up for data stream copy
  692. //
  693. if (BasepIsDataAttribute( pfsi->StreamNameLength, pfsi->StreamName )) {
  694. pbuc->head.dwStreamId = BACKUP_ALTERNATE_DATA;
  695. if ( BackupGetSparseMap( pbuc->hAlternate, pbuc, pbif ) ) {
  696. pbuc->head.Size.QuadPart = 0 ;
  697. pbuc->head.dwStreamAttributes = STREAM_SPARSE_ATTRIBUTE;
  698. } else {
  699. pbuc->head.Size.LowPart = GetFileSize(
  700. pbuc->hAlternate,
  701. &pbuc->head.Size.HighPart );
  702. }
  703. }
  704. //
  705. // If we need to return the name
  706. //
  707. } else if ( pbuc->liStreamOffset < pbuc->cbHeader) {
  708. return TRUE ;
  709. //
  710. // If there is more data in this stream to transfer
  711. //
  712. } else if ( (pbuc->head.dwStreamId == BACKUP_ALTERNATE_DATA) ||
  713. (pbuc->head.dwStreamId == BACKUP_SPARSE_BLOCK) ) {
  714. return BackupReadStream( pbuc->hAlternate, pbuc, pbif );
  715. }
  716. return TRUE;
  717. }
  718. BOOL
  719. BackupReadEaData(HANDLE hFile, BACKUPCONTEXT *pbuc, BACKUPIOFRAME *pbif)
  720. /*++
  721. Routine Description:
  722. Perform a read to user buffer from EA data.
  723. Arguments:
  724. hFile - handle to file with EAs
  725. pbuc - context of call
  726. pbif - frame describing BackupRead request
  727. Return Value:
  728. True if transfer succeeded..
  729. --*/
  730. {
  731. //
  732. // If we are just starting out on the EA data
  733. //
  734. if (pbuc->fStreamStart) {
  735. IO_STATUS_BLOCK iosb;
  736. //
  737. // Loop trying to read all EA data into the buffer and
  738. // resize the buffer if necessary
  739. //
  740. while (TRUE) {
  741. NTSTATUS Status;
  742. FILE_EA_INFORMATION fei;
  743. Status = NtQueryEaFile(
  744. hFile,
  745. &iosb,
  746. pbuc->DataBuffer.Buffer,
  747. pbuc->DataBuffer.BufferSize,
  748. FALSE,
  749. NULL,
  750. 0,
  751. 0,
  752. (BOOLEAN) TRUE );
  753. //
  754. // If we successfully read all the data, go complete
  755. // the initialization
  756. //
  757. if (NT_SUCCESS( Status ) && iosb.Information != 0) {
  758. pbuc->NamesReady = TRUE;
  759. break;
  760. }
  761. //
  762. // If we received a status OTHER than buffer overflow then
  763. // skip EA's altogether
  764. //
  765. if (!BufferOverflow(Status)) {
  766. return TRUE;
  767. }
  768. //
  769. // Get a stab at the total EA size
  770. //
  771. Status = NtQueryInformationFile(
  772. hFile,
  773. &iosb,
  774. &fei,
  775. sizeof(fei),
  776. FileEaInformation);
  777. //
  778. // This call should never have failed (since we were able to
  779. // QueryEaFile) above. However, if it does, skip EAs altogether
  780. //
  781. if (!NT_SUCCESS(Status)) {
  782. return TRUE;
  783. }
  784. //
  785. // Resize the buffer to something that seems reasonable. No guarantees
  786. // about whether this will work or not... If we couldn't grow the buffer
  787. // fail this call.
  788. //
  789. if (!GrowBuffer( &pbuc->DataBuffer, (fei.EaSize * 5) / 4)) {
  790. pbuc->fAccessError = TRUE;
  791. return FALSE;
  792. }
  793. }
  794. //
  795. // Set up the header for the EA stream
  796. //
  797. pbuc->head.dwStreamId = BACKUP_EA_DATA;
  798. pbuc->head.dwStreamAttributes = STREAM_NORMAL_ATTRIBUTE;
  799. pbuc->head.dwStreamNameSize = 0;
  800. pbuc->cbHeader = CB_NAMELESSHEADER;
  801. pbuc->head.Size.QuadPart = iosb.Information;
  802. pbuc->fStreamStart = FALSE;
  803. //
  804. // If we have more data in the buffer to read then go
  805. // copy it out.
  806. //
  807. } else if (pbuc->liStreamOffset >= pbuc->cbHeader) {
  808. BackupReadBuffer( pbuc, pbif );
  809. }
  810. return TRUE;
  811. }
  812. BOOL
  813. BackupReadObjectId(HANDLE hFile, BACKUPCONTEXT *pbuc, BACKUPIOFRAME *pbif)
  814. /*++
  815. Routine Description:
  816. Perform a read to user buffer from NtObject ID data.
  817. Arguments:
  818. hFile - handle to file with EAs
  819. pbuc - context of call
  820. pbif - frame describing BackupRead request
  821. Return Value:
  822. True if transfer succeeded..
  823. --*/
  824. {
  825. //
  826. // If we are just starting out on the Object ID data
  827. //
  828. if (pbuc->fStreamStart) {
  829. IO_STATUS_BLOCK iosb;
  830. NTSTATUS Status ;
  831. if (!GrowBuffer( &pbuc->DataBuffer, 1024 ) ) {
  832. pbuc->fAccessError = TRUE;
  833. return FALSE;
  834. }
  835. Status = NtFsControlFile( hFile,
  836. NULL, // overlapped event handle
  837. NULL, // Apc routine
  838. NULL, // overlapped structure
  839. &iosb,
  840. FSCTL_GET_OBJECT_ID,
  841. NULL,
  842. 0,
  843. pbuc->DataBuffer.Buffer,
  844. pbuc->DataBuffer.BufferSize ) ;
  845. if ( !NT_SUCCESS(Status) ) {
  846. return TRUE ;
  847. }
  848. //
  849. // Set up the header for the Object ID stream
  850. //
  851. pbuc->NamesReady = TRUE;
  852. pbuc->head.dwStreamId = BACKUP_OBJECT_ID ;
  853. pbuc->head.dwStreamAttributes = STREAM_NORMAL_ATTRIBUTE;
  854. pbuc->head.dwStreamNameSize = 0;
  855. pbuc->cbHeader = CB_NAMELESSHEADER;
  856. pbuc->head.Size.QuadPart = iosb.Information;
  857. pbuc->fStreamStart = FALSE;
  858. //
  859. // If we have more data in the buffer to read then go
  860. // copy it out.
  861. //
  862. } else if (pbuc->liStreamOffset >= pbuc->cbHeader) {
  863. BackupReadBuffer( pbuc, pbif );
  864. }
  865. return TRUE;
  866. }
  867. BOOL
  868. BackupReadReparseData(HANDLE hFile, BACKUPCONTEXT *pbuc, BACKUPIOFRAME *pbif)
  869. /*++
  870. Routine Description:
  871. Perform a read to user buffer from Reparse tag data.
  872. Arguments:
  873. hFile - handle to file with EAs
  874. pbuc - context of call
  875. pbif - frame describing BackupRead request
  876. Return Value:
  877. True if transfer succeeded..
  878. --*/
  879. {
  880. IO_STATUS_BLOCK iosb;
  881. PREPARSE_DATA_BUFFER rp_buf_ptr ;
  882. NTSTATUS Status ;
  883. struct RP_SUMMARY {
  884. USHORT tag ;
  885. USHORT rp_size ;
  886. } *rp_summary_ptr =(struct RP_SUMMARY*) &(iosb.Information) ;
  887. //
  888. // If the object is not a reparse then simply return
  889. //
  890. if ( !(pbuc->fAttribs & FILE_ATTRIBUTE_REPARSE_POINT) ) {
  891. return TRUE ;
  892. }
  893. //
  894. // If we are just starting out on the ReParse data
  895. //
  896. if (pbuc->fStreamStart) {
  897. //
  898. // Loop trying to read all EA data into the buffer and
  899. // resize the buffer if necessary
  900. //
  901. // for some reason a TOO_SMALL error is not setting the information
  902. // member of the iosb....
  903. rp_summary_ptr->rp_size = MAXIMUM_REPARSE_DATA_BUFFER_SIZE ;
  904. Status = NtFsControlFile( hFile,
  905. NULL, // overlapped event handle
  906. NULL, // Apc routine
  907. NULL, // overlapped structure
  908. &iosb,
  909. FSCTL_GET_REPARSE_POINT,
  910. NULL,
  911. 0,
  912. pbuc->DataBuffer.Buffer,
  913. pbuc->DataBuffer.BufferSize ) ;
  914. if ( BufferOverflow( Status ) ) {
  915. if ( rp_summary_ptr->rp_size == 0 ) {
  916. rp_summary_ptr->rp_size = MAXIMUM_REPARSE_DATA_BUFFER_SIZE ;
  917. }
  918. if (!GrowBuffer( &pbuc->DataBuffer,
  919. rp_summary_ptr->rp_size ) ) {
  920. pbuc->fAccessError = TRUE;
  921. return FALSE;
  922. }
  923. Status = NtFsControlFile( hFile,
  924. NULL, // overlapped event handle
  925. NULL, // Apc routine
  926. NULL, // overlapped structure
  927. &iosb,
  928. FSCTL_GET_REPARSE_POINT,
  929. NULL,
  930. 0,
  931. pbuc->DataBuffer.Buffer,
  932. pbuc->DataBuffer.BufferSize ) ;
  933. }
  934. //
  935. // If we successfully read all the data, go complete
  936. // the initialization
  937. //
  938. if ( !NT_SUCCESS( Status ) ) {
  939. return TRUE ;
  940. }
  941. //
  942. // Set up the header for the ReParse stream
  943. //
  944. rp_buf_ptr = (PREPARSE_DATA_BUFFER)(pbuc->DataBuffer.Buffer) ;
  945. pbuc->NamesReady = TRUE;
  946. pbuc->head.dwStreamId = BACKUP_REPARSE_DATA;
  947. pbuc->head.dwStreamAttributes = STREAM_NORMAL_ATTRIBUTE;
  948. pbuc->head.dwStreamNameSize = 0;
  949. pbuc->cbHeader = CB_NAMELESSHEADER;
  950. if ( IsReparseTagMicrosoft( rp_buf_ptr->ReparseTag ) ) {
  951. pbuc->head.Size.QuadPart = rp_buf_ptr->ReparseDataLength +
  952. FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) ;
  953. } else {
  954. pbuc->head.Size.QuadPart = rp_buf_ptr->ReparseDataLength +
  955. FIELD_OFFSET(REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer.DataBuffer) ;
  956. }
  957. pbuc->fStreamStart = FALSE;
  958. //
  959. // If we have more data in the buffer to read then go
  960. // copy it out.
  961. //
  962. } else if (pbuc->liStreamOffset >= pbuc->cbHeader) {
  963. BackupReadBuffer( pbuc, pbif );
  964. }
  965. return TRUE;
  966. }
  967. BOOL
  968. BackupReadSecurityData(HANDLE hFile, BACKUPCONTEXT *pbuc, BACKUPIOFRAME *pbif)
  969. {
  970. //
  971. // If we are to skip security then do so.
  972. //
  973. if (!pbif->fProcessSecurity) {
  974. return TRUE;
  975. }
  976. //
  977. // If we are just starting out on the security data
  978. //
  979. if (pbuc->fStreamStart) {
  980. //
  981. // Loop trying to read all security data into the buffer and
  982. // resize the buffer if necessary
  983. //
  984. while (TRUE) {
  985. NTSTATUS Status;
  986. DWORD cbSecurityInfo;
  987. RtlZeroMemory( pbuc->DataBuffer.Buffer, pbuc->DataBuffer.BufferSize );
  988. Status = NtQuerySecurityObject(
  989. hFile,
  990. OWNER_SECURITY_INFORMATION |
  991. GROUP_SECURITY_INFORMATION |
  992. DACL_SECURITY_INFORMATION |
  993. SACL_SECURITY_INFORMATION,
  994. pbuc->DataBuffer.Buffer,
  995. pbuc->DataBuffer.BufferSize,
  996. &cbSecurityInfo );
  997. //
  998. // If we failed but it wasn't due to buffer overflow
  999. //
  1000. if (!NT_SUCCESS( Status ) && !BufferOverflow( Status )) {
  1001. //
  1002. // Try reading everything but SACL
  1003. //
  1004. Status = NtQuerySecurityObject(
  1005. hFile,
  1006. OWNER_SECURITY_INFORMATION |
  1007. GROUP_SECURITY_INFORMATION |
  1008. DACL_SECURITY_INFORMATION,
  1009. pbuc->DataBuffer.Buffer,
  1010. pbuc->DataBuffer.BufferSize,
  1011. &cbSecurityInfo );
  1012. }
  1013. //
  1014. // If we got it all, then go continue initialization
  1015. //
  1016. if (NT_SUCCESS( Status )) {
  1017. pbuc->NamesReady = TRUE;
  1018. break;
  1019. }
  1020. //
  1021. // If not due to overflowing buffer, skip security altogether
  1022. //
  1023. if (!BufferOverflow( Status )) {
  1024. return TRUE;
  1025. }
  1026. //
  1027. // Resize the buffer to the expected size. If we fail, fail
  1028. // the entire call
  1029. //
  1030. if (!GrowBuffer( &pbuc->DataBuffer, cbSecurityInfo )) {
  1031. return FALSE;
  1032. }
  1033. }
  1034. //
  1035. // Initialize the stream header
  1036. //
  1037. pbuc->head.dwStreamId = BACKUP_SECURITY_DATA;
  1038. pbuc->head.dwStreamAttributes = STREAM_CONTAINS_SECURITY;
  1039. pbuc->head.dwStreamNameSize = 0;
  1040. pbuc->cbHeader = CB_NAMELESSHEADER;
  1041. pbuc->head.Size.QuadPart = RtlLengthSecurityDescriptor(pbuc->DataBuffer.Buffer);
  1042. pbuc->fStreamStart = FALSE;
  1043. //
  1044. // If there is more data in the buffer to transfer, go
  1045. // do it
  1046. //
  1047. } else if (pbuc->liStreamOffset >= pbuc->cbHeader) {
  1048. BackupReadBuffer( pbuc, pbif );
  1049. }
  1050. return TRUE;
  1051. }
  1052. VOID
  1053. BackupTestRestartStream(BACKUPCONTEXT *pbuc)
  1054. {
  1055. LONGLONG licbRemain;
  1056. licbRemain = ComputeRemainingSize( pbuc );
  1057. if (licbRemain == 0) {
  1058. if ( pbuc->dwSparseMapOffset != pbuc->dwSparseMapSize ) { // only true at backup
  1059. if ( !pbuc->fSparseBlockStart ) {
  1060. pbuc->dwSparseMapOffset += sizeof ( FILE_ALLOCATED_RANGE_BUFFER ) ;
  1061. }
  1062. }
  1063. if ( pbuc->dwSparseMapOffset != pbuc->dwSparseMapSize ) { // only true at backup
  1064. pbuc->fSparseBlockStart = TRUE ;
  1065. pbuc->cbHeader = 0 ;
  1066. pbuc->liStreamOffset = 0;
  1067. } else {
  1068. if ( !pbuc->fSparseHandAlt && (pbuc->hAlternate != NULL)) {
  1069. CloseHandle(pbuc->hAlternate); // releases any locks
  1070. pbuc->hAlternate = NULL;
  1071. }
  1072. pbuc->cbHeader = 0;
  1073. pbuc->fStreamStart = TRUE;
  1074. pbuc->fSparseBlockStart = TRUE;
  1075. pbuc->liStreamOffset = 0; // for BackupWrite
  1076. if (!pbuc->fMultiStreamType) { // for BackupRead
  1077. pbuc->StreamIndex++;
  1078. pbuc->head.dwStreamId = mwStreamList[pbuc->StreamIndex] ;
  1079. pbuc->NamesReady = FALSE;
  1080. }
  1081. }
  1082. }
  1083. }
  1084. // Routine Description:
  1085. //
  1086. // Data can be Backed up from an object using BackupRead.
  1087. //
  1088. // This API is used to read data from an object. After the
  1089. // read completes, the file pointer is adjusted by the number of bytes
  1090. // actually read. A return value of TRUE coupled with a bytes read of
  1091. // 0 indicates that end of file has been reached.
  1092. //
  1093. // Arguments:
  1094. //
  1095. // hFile - Supplies an open handle to a file that is to be read. The
  1096. // file handle must have been created with GENERIC_READ access.
  1097. //
  1098. // lpBuffer - Supplies the address of a buffer to receive the data read
  1099. // from the file.
  1100. //
  1101. // nNumberOfBytesToRead - Supplies the number of bytes to read from the
  1102. // file.
  1103. //
  1104. // lpNumberOfBytesRead - Returns the number of bytes read by this call.
  1105. // This parameter is always set to 0 before doing any IO or error
  1106. // checking.
  1107. //
  1108. // bAbort - If TRUE, then all resources associated with the context will
  1109. // be released.
  1110. //
  1111. // bProcessSecurity - If TRUE, then the NTFS ACL data will be read.
  1112. // If FALSE, then the ACL stream will be skipped.
  1113. //
  1114. // lpContext - Points to a buffer pointer setup and maintained by
  1115. // BackupRead.
  1116. //
  1117. //
  1118. // Return Value:
  1119. //
  1120. // TRUE - The operation was successul.
  1121. //
  1122. // FALSE - The operation failed. Extended error status is available
  1123. // using GetLastError.
  1124. //
  1125. //
  1126. // NOTE:
  1127. // The NT File Replication Service (NTFRS) performs an MD5 checksum on the
  1128. // stream of data returned by BackupRead(). If the sequence of file information
  1129. // returned changes then two machines, one downlevel and one uplevel will
  1130. // compute different MD5 checksums for the same file data. Under certain
  1131. // conditions this will cause needless file replication. Bear this in mind
  1132. // if a change in the returned data sequence is contemplated. The sources for
  1133. // NTFRS are in \nt\private\net\svcimgs\ntrepl.
  1134. //
  1135. BOOL WINAPI
  1136. BackupRead(
  1137. HANDLE hFile,
  1138. LPBYTE lpBuffer,
  1139. DWORD nNumberOfBytesToRead,
  1140. LPDWORD lpNumberOfBytesRead,
  1141. BOOL bAbort,
  1142. BOOL bProcessSecurity,
  1143. LPVOID *lpContext)
  1144. {
  1145. BACKUPCONTEXT *pbuc;
  1146. BACKUPIOFRAME bif;
  1147. BOOL fSuccess = FALSE;
  1148. IO_STATUS_BLOCK iosb ;
  1149. pbuc = *lpContext;
  1150. bif.pIoBuffer = lpBuffer;
  1151. bif.cbRequest = nNumberOfBytesToRead;
  1152. bif.pcbTransferred = lpNumberOfBytesRead;
  1153. bif.fProcessSecurity = (BOOLEAN)bProcessSecurity;
  1154. if (bAbort) {
  1155. if (pbuc != NULL) {
  1156. ResetAccessDate( hFile ) ;
  1157. FreeContext(lpContext);
  1158. }
  1159. return TRUE;
  1160. }
  1161. *bif.pcbTransferred = 0;
  1162. if (pbuc == INVALID_HANDLE_VALUE || bif.cbRequest == 0) {
  1163. return TRUE;
  1164. }
  1165. if (pbuc != NULL && mwStreamList[pbuc->StreamIndex] == BACKUP_INVALID) {
  1166. ResetAccessDate( hFile ) ;
  1167. FreeContext(lpContext);
  1168. return TRUE;
  1169. }
  1170. // Allocate our Context Control Block on first call.
  1171. if (pbuc == NULL) {
  1172. pbuc = AllocContext(CBMIN_BUFFER); // Alloc initial buffer
  1173. // ok, we allocated the context, Lets initialize it.
  1174. if (pbuc != NULL) {
  1175. NTSTATUS Status ;
  1176. FILE_BASIC_INFORMATION fbi;
  1177. Status = NtQueryInformationFile(
  1178. hFile,
  1179. &iosb,
  1180. &fbi,
  1181. sizeof(fbi),
  1182. FileBasicInformation );
  1183. if ( NT_SUCCESS( Status ) ) {
  1184. pbuc->fAttribs = fbi.FileAttributes ;
  1185. } else {
  1186. BaseSetLastNTError( Status );
  1187. return FALSE ;
  1188. }
  1189. }
  1190. }
  1191. if (pbuc != NULL) {
  1192. *lpContext = pbuc;
  1193. do {
  1194. if (pbuc->fStreamStart) {
  1195. pbuc->head.Size.QuadPart = 0;
  1196. pbuc->liStreamOffset = 0;
  1197. pbuc->dwSparseMapOffset = 0;
  1198. pbuc->dwSparseMapSize = 0;
  1199. pbuc->fMultiStreamType = FALSE;
  1200. }
  1201. fSuccess = TRUE;
  1202. switch (mwStreamList[pbuc->StreamIndex]) {
  1203. case BACKUP_DATA:
  1204. fSuccess = BackupReadData(hFile, pbuc, &bif);
  1205. break;
  1206. case BACKUP_ALTERNATE_DATA:
  1207. fSuccess = BackupReadAlternateData(hFile, pbuc, &bif);
  1208. break;
  1209. case BACKUP_EA_DATA:
  1210. fSuccess = BackupReadEaData(hFile, pbuc, &bif);
  1211. break;
  1212. case BACKUP_OBJECT_ID:
  1213. fSuccess = BackupReadObjectId(hFile, pbuc, &bif);
  1214. break;
  1215. case BACKUP_REPARSE_DATA:
  1216. fSuccess = BackupReadReparseData(hFile, pbuc, &bif);
  1217. break;
  1218. case BACKUP_SECURITY_DATA:
  1219. fSuccess = BackupReadSecurityData(hFile, pbuc, &bif);
  1220. break;
  1221. default:
  1222. pbuc->StreamIndex++;
  1223. pbuc->fStreamStart = TRUE;
  1224. break;
  1225. }
  1226. // if we're in the phase of reading the header, copy the header
  1227. if (pbuc->liStreamOffset < pbuc->cbHeader) {
  1228. DWORD cbrequest;
  1229. // Send the current stream header;
  1230. cbrequest =
  1231. (ULONG)min( pbuc->cbHeader - pbuc->liStreamOffset,
  1232. bif.cbRequest);
  1233. RtlCopyMemory(
  1234. bif.pIoBuffer,
  1235. (BYTE *) &pbuc->head + pbuc->liStreamOffset,
  1236. cbrequest);
  1237. ReportTransfer(pbuc, &bif, cbrequest);
  1238. }
  1239. //
  1240. // if we are at the end of a stream then
  1241. // start at the beginning of the next stream
  1242. //
  1243. if (pbuc->liStreamOffset >= pbuc->cbHeader) {
  1244. BackupTestRestartStream(pbuc);
  1245. }
  1246. } while (fSuccess &&
  1247. mwStreamList[pbuc->StreamIndex] != BACKUP_INVALID &&
  1248. bif.cbRequest != 0);
  1249. }
  1250. if (fSuccess && *bif.pcbTransferred == 0) {
  1251. ResetAccessDate( hFile ) ;
  1252. FreeContext(lpContext);
  1253. }
  1254. return(fSuccess);
  1255. }
  1256. // Routine Description:
  1257. //
  1258. // Data can be skiped during BackupRead or BackupWrite by using
  1259. // BackupSeek.
  1260. //
  1261. // This API is used to seek forward from the current position the
  1262. // specified number of bytes. This function does not seek over a
  1263. // stream header. The number of bytes actually seeked is returned.
  1264. // If a caller wants to seek to the start of the next stream it can
  1265. // pass 0xffffffff, 0xffffffff as the amount to seek. The number of
  1266. // bytes actually skiped over is returned.
  1267. //
  1268. // Arguments:
  1269. //
  1270. // hFile - Supplies an open handle to a file that is to be read. The
  1271. // file handle must have been created with GENERIC_READ or
  1272. // GENERIC_WRITE access.
  1273. //
  1274. // dwLowBytesToSeek - Specifies the low 32 bits of the number of bytes
  1275. // requested to seek.
  1276. //
  1277. // dwHighBytesToSeek - Specifies the high 32 bits of the number of bytes
  1278. // requested to seek.
  1279. //
  1280. // lpdwLowBytesSeeked - Points to the buffer where the low 32 bits of the
  1281. // actual number of bytes to seek is to be placed.
  1282. //
  1283. // lpdwHighBytesSeeked - Points to the buffer where the high 32 bits of the
  1284. // actual number of bytes to seek is to be placed.
  1285. //
  1286. // bAbort - If true, then all resources associated with the context will
  1287. // be released.
  1288. //
  1289. // lpContext - Points to a buffer pointer setup and maintained by
  1290. // BackupRead.
  1291. //
  1292. //
  1293. // Return Value:
  1294. //
  1295. // TRUE - The operation successfuly seeked the requested number of bytes.
  1296. //
  1297. // FALSE - The requested number of bytes could not be seeked. The number
  1298. // of bytes actually seeked is returned.
  1299. BOOL WINAPI
  1300. BackupSeek(
  1301. HANDLE hFile,
  1302. DWORD dwLowBytesToSeek,
  1303. DWORD dwHighBytesToSeek,
  1304. LPDWORD lpdwLowBytesSeeked,
  1305. LPDWORD lpdwHighBytesSeeked,
  1306. LPVOID *lpContext)
  1307. {
  1308. BACKUPCONTEXT *pbuc;
  1309. LONGLONG licbRemain;
  1310. LARGE_INTEGER licbRequest;
  1311. BOOL fSuccess;
  1312. LARGE_INTEGER sparse_bytes ;
  1313. pbuc = *lpContext;
  1314. sparse_bytes.QuadPart = 0 ;
  1315. *lpdwHighBytesSeeked = 0;
  1316. *lpdwLowBytesSeeked = 0;
  1317. if (pbuc == INVALID_HANDLE_VALUE || pbuc == NULL || pbuc->fStreamStart) {
  1318. return FALSE;
  1319. }
  1320. if (pbuc->liStreamOffset < pbuc->cbHeader) {
  1321. return FALSE;
  1322. }
  1323. //
  1324. // If we made it here, we are in the middle of a stream
  1325. //
  1326. licbRemain = ComputeRemainingSize( pbuc );
  1327. licbRequest.LowPart = dwLowBytesToSeek;
  1328. licbRequest.HighPart = dwHighBytesToSeek & 0x7fffffff;
  1329. if (licbRequest.QuadPart > licbRemain) {
  1330. licbRequest.QuadPart = licbRemain;
  1331. }
  1332. fSuccess = TRUE;
  1333. switch (pbuc->head.dwStreamId) {
  1334. case BACKUP_EA_DATA:
  1335. case BACKUP_SECURITY_DATA:
  1336. case BACKUP_OBJECT_ID :
  1337. case BACKUP_REPARSE_DATA :
  1338. // assume less than 2gig of data
  1339. break;
  1340. case BACKUP_SPARSE_BLOCK :
  1341. if ( pbuc->liStreamOffset < sizeof(LARGE_INTEGER) ) {
  1342. sparse_bytes.QuadPart = ( sizeof(LARGE_INTEGER) - pbuc->liStreamOffset ) ;
  1343. if ( sparse_bytes.QuadPart < licbRequest.QuadPart ) {
  1344. licbRequest.QuadPart -= sparse_bytes.QuadPart ;
  1345. } else {
  1346. licbRequest.QuadPart = 0 ;
  1347. }
  1348. }
  1349. case BACKUP_DATA:
  1350. case BACKUP_ALTERNATE_DATA:
  1351. {
  1352. LARGE_INTEGER liCurPos;
  1353. LARGE_INTEGER liNewPos;
  1354. HANDLE hf;
  1355. // set up the correct handle to seek with
  1356. if (pbuc->head.dwStreamId == BACKUP_DATA) {
  1357. hf = hFile;
  1358. }
  1359. else {
  1360. hf = pbuc->hAlternate;
  1361. }
  1362. // first, let's get the current position
  1363. liCurPos.HighPart = 0;
  1364. liCurPos.LowPart = SetFilePointer(
  1365. hf,
  1366. 0,
  1367. &liCurPos.HighPart,
  1368. FILE_CURRENT);
  1369. // Now seek the requested number of bytes
  1370. liNewPos.HighPart = licbRequest.HighPart;
  1371. liNewPos.LowPart = SetFilePointer(
  1372. hf,
  1373. licbRequest.LowPart,
  1374. &liNewPos.HighPart,
  1375. FILE_CURRENT);
  1376. // Assume that we seek the requested amount because if we do not,
  1377. // subsequent reads will fail and the caller will never be able
  1378. // to read to the next stream.
  1379. break;
  1380. }
  1381. default:
  1382. break;
  1383. }
  1384. if (dwHighBytesToSeek != (DWORD) licbRequest.HighPart ||
  1385. dwLowBytesToSeek != licbRequest.LowPart) {
  1386. fSuccess = FALSE;
  1387. }
  1388. licbRequest.QuadPart += sparse_bytes.QuadPart ;
  1389. pbuc->liStreamOffset += licbRequest.QuadPart ;
  1390. *lpdwLowBytesSeeked = licbRequest.LowPart;
  1391. *lpdwHighBytesSeeked = licbRequest.HighPart;
  1392. BackupTestRestartStream(pbuc);
  1393. if (!fSuccess) {
  1394. SetLastError(ERROR_SEEK);
  1395. }
  1396. return(fSuccess);
  1397. }
  1398. BOOL
  1399. BackupWriteHeader(BACKUPCONTEXT *pbuc, BACKUPIOFRAME *pbif, DWORD cbHeader)
  1400. /*++
  1401. Routine Description:
  1402. This is an internal routine that fills our internal backup header
  1403. from the user's data.
  1404. Arguments:
  1405. pbuc - CONTEXT of call
  1406. pbif - IOCONTEXT of call
  1407. cbHeader - size of header to fill
  1408. Return Value:
  1409. None.
  1410. --*/
  1411. {
  1412. //
  1413. // Determine how much data we can transfer into our header.
  1414. //
  1415. DWORD cbrequest =
  1416. (DWORD) min( pbif->cbRequest, cbHeader - pbuc->liStreamOffset );
  1417. //
  1418. // Copy from user buffer into header
  1419. //
  1420. if ( pbuc->liStreamOffset+cbrequest > CWCMAX_STREAMNAME + CB_NAMELESSHEADER ) {
  1421. return FALSE ;
  1422. }
  1423. RtlCopyMemory(
  1424. (CHAR *) &pbuc->head + pbuc->liStreamOffset,
  1425. pbif->pIoBuffer,
  1426. cbrequest);
  1427. //
  1428. // Update transfer statistics
  1429. //
  1430. ReportTransfer(pbuc, pbif, cbrequest);
  1431. //
  1432. // If we've filled up the header, mark the header as complete
  1433. // even though we might need more if names are present
  1434. //
  1435. if (pbuc->liStreamOffset == cbHeader) {
  1436. pbuc->cbHeader = cbHeader;
  1437. }
  1438. return TRUE ;
  1439. }
  1440. typedef enum {
  1441. BRB_FAIL,
  1442. BRB_DONE,
  1443. BRB_MORE,
  1444. } BUFFERSTATUS;
  1445. BUFFERSTATUS
  1446. BackupWriteBuffer(BACKUPCONTEXT *pbuc, BACKUPIOFRAME *pbif)
  1447. /*++
  1448. Routine Description:
  1449. This is an internal routine that fills our internal buffer
  1450. from the user's data.
  1451. Arguments:
  1452. pbuc - CONTEXT of call
  1453. pbif - IOCONTEXT of call
  1454. Return Value:
  1455. BRB_FAIL if an error occurred (out of memory)
  1456. BRB_DONE if buffer is full or was successfully filled
  1457. BRB_MORE if buffer is partially full
  1458. --*/
  1459. {
  1460. DWORD cbrequest;
  1461. //
  1462. // If we're starting out on the buffer, we make sure
  1463. // we have a buffer to contain all of the data since
  1464. // the Nt calls we'll use must have all the data
  1465. // present
  1466. //
  1467. if (pbuc->fStreamStart) {
  1468. pbuc->fStreamStart = FALSE;
  1469. if (pbuc->DataBuffer.BufferSize < pbuc->head.Size.QuadPart &&
  1470. !GrowBuffer( &pbuc->DataBuffer, pbuc->head.Size.LowPart )) {
  1471. return(BRB_FAIL);
  1472. }
  1473. }
  1474. //
  1475. // Determine how much data from the user buffer is
  1476. // needed to fill our buffer
  1477. //
  1478. cbrequest = ComputeRequestSize( pbuc, pbif->cbRequest );
  1479. //
  1480. // Fill in the next portion of the buffer
  1481. //
  1482. RtlCopyMemory(
  1483. pbuc->DataBuffer.Buffer + pbuc->liStreamOffset - pbuc->cbHeader,
  1484. pbif->pIoBuffer,
  1485. cbrequest);
  1486. //
  1487. // Update transfer statistics
  1488. //
  1489. ReportTransfer(pbuc, pbif, cbrequest);
  1490. //
  1491. // If we've entirely filled the buffer, let our caller know
  1492. //
  1493. return ComputeRemainingSize( pbuc ) == 0 ? BRB_DONE : BRB_MORE;
  1494. }
  1495. BOOL
  1496. BackupWriteSparse(HANDLE hFile, BACKUPCONTEXT *pbuc, BACKUPIOFRAME *pbif)
  1497. /*++
  1498. Routine Description:
  1499. This is an internal routine that writes sparse block of stream data from
  1500. the user's buffer into the output handle. The BACKUPCONTEXT contains
  1501. the total length of data to be output.
  1502. Arguments:
  1503. hFile - output file handle
  1504. pbuc - CONTEXT of call
  1505. pbif - IOCONTEXT of call
  1506. Return Value:
  1507. TRUE if data was successfully written, FALSE otherwise.
  1508. --*/
  1509. {
  1510. LARGE_INTEGER licbFile ;
  1511. DWORD cbrequest;
  1512. DWORD cbtransferred;
  1513. BOOL fSuccess;
  1514. if ( pbuc->fSparseBlockStart ) {
  1515. RtlCopyMemory( &pbuc->cbSparseOffset, pbuc->head.cStreamName, sizeof( LARGE_INTEGER ) ) ;
  1516. licbFile = pbuc->cbSparseOffset;
  1517. licbFile.LowPart = SetFilePointer( pbuc->fSparseHandAlt?pbuc->hAlternate:hFile,
  1518. licbFile.LowPart,
  1519. &licbFile.HighPart,
  1520. FILE_BEGIN );
  1521. if ( licbFile.QuadPart != pbuc->cbSparseOffset.QuadPart ) {
  1522. return FALSE ;
  1523. }
  1524. if ( pbuc->head.Size.QuadPart == sizeof( LARGE_INTEGER ) ) {
  1525. SetEndOfFile(pbuc->fSparseHandAlt?pbuc->hAlternate:hFile) ;
  1526. }
  1527. pbuc->fSparseBlockStart = FALSE ;
  1528. }
  1529. //
  1530. // Determine how much data from the user buffer is
  1531. // needed to be written into the stream and perform
  1532. // the transfer.
  1533. //
  1534. cbrequest = ComputeRequestSize(pbuc, pbif->cbRequest);
  1535. fSuccess = WriteFile(
  1536. pbuc->fSparseHandAlt?pbuc->hAlternate:hFile,
  1537. pbif->pIoBuffer,
  1538. cbrequest,
  1539. &cbtransferred,
  1540. NULL);
  1541. //
  1542. // Update transfer statistics
  1543. //
  1544. ReportTransfer(pbuc, pbif, cbtransferred);
  1545. return(fSuccess);
  1546. return TRUE ;
  1547. }
  1548. BOOL
  1549. BackupWriteStream(HANDLE hFile, BACKUPCONTEXT *pbuc, BACKUPIOFRAME *pbif)
  1550. /*++
  1551. Routine Description:
  1552. This is an internal routine that writes stream data from the user's
  1553. buffer into the output handle. The BACKUPCONTEXT contains the total
  1554. length of data to be output.
  1555. Arguments:
  1556. hFile - output file handle
  1557. pbuc - CONTEXT of call
  1558. pbif - IOCONTEXT of call
  1559. Return Value:
  1560. TRUE if data was successfully written, FALSE otherwise.
  1561. --*/
  1562. {
  1563. DWORD cbrequest;
  1564. DWORD cbtransferred;
  1565. BOOL fSuccess;
  1566. IO_STATUS_BLOCK iosb;
  1567. if ( pbuc->fStreamStart ) {
  1568. if ( pbuc->head.dwStreamAttributes & STREAM_SPARSE_ATTRIBUTE ) {
  1569. // if it was sparse when be backed it up make is sparse again.
  1570. NtFsControlFile( hFile,
  1571. NULL, // overlapped event handle
  1572. NULL, // Apc routine
  1573. NULL, // overlapped structure
  1574. &iosb,
  1575. FSCTL_SET_SPARSE ,
  1576. NULL,
  1577. 0,
  1578. NULL,
  1579. 0 ) ;
  1580. } else {
  1581. LARGE_INTEGER end_of_file ;
  1582. end_of_file.QuadPart = pbuc->head.Size.QuadPart ;
  1583. SetFilePointer( hFile,
  1584. end_of_file.LowPart,
  1585. &end_of_file.HighPart,
  1586. FILE_BEGIN );
  1587. SetEndOfFile(hFile) ;
  1588. end_of_file.QuadPart = 0 ;
  1589. SetFilePointer( hFile,
  1590. end_of_file.LowPart,
  1591. &end_of_file.HighPart,
  1592. FILE_BEGIN );
  1593. }
  1594. pbuc->fStreamStart = FALSE;
  1595. }
  1596. //
  1597. // Determine how much data from the user buffer is
  1598. // needed to be written into the stream and perform
  1599. // the transfer.
  1600. //
  1601. cbrequest = ComputeRequestSize(pbuc, pbif->cbRequest);
  1602. fSuccess = WriteFile(
  1603. hFile,
  1604. pbif->pIoBuffer,
  1605. cbrequest,
  1606. &cbtransferred,
  1607. NULL);
  1608. //
  1609. // Update transfer statistics
  1610. //
  1611. ReportTransfer(pbuc, pbif, cbtransferred);
  1612. return(fSuccess);
  1613. }
  1614. BOOL
  1615. BackupWriteAlternateData(HANDLE hFile, BACKUPCONTEXT *pbuc, BACKUPIOFRAME *pbif)
  1616. /*++
  1617. Routine Description:
  1618. This is an internal routine that overwrites an alternate data stream with
  1619. data from the user's buffer.
  1620. Arguments:
  1621. hFile - handle to the file itself. This is not the handle to the stream
  1622. being overwritten.
  1623. pbuc - CONTEXT of call. This contains the name of the stream.
  1624. pbif - IOCONTEXT of call
  1625. Return Value:
  1626. TRUE if data was successfully written, FALSE otherwise.
  1627. --*/
  1628. {
  1629. //
  1630. // If we are just starting out on this stream then attempt to
  1631. // overwrite the new stream.
  1632. //
  1633. if (pbuc->fStreamStart) {
  1634. NTSTATUS Status;
  1635. UNICODE_STRING strName;
  1636. OBJECT_ATTRIBUTES oa;
  1637. IO_STATUS_BLOCK iosb;
  1638. DWORD reparse_flg = 0 ;
  1639. strName.Length = (USHORT) pbuc->head.dwStreamNameSize;
  1640. strName.MaximumLength = strName.Length;
  1641. strName.Buffer = pbuc->head.cStreamName;
  1642. if (pbuc->hAlternate != INVALID_HANDLE_VALUE) {
  1643. CloseHandle(pbuc->hAlternate);
  1644. pbuc->hAlternate = INVALID_HANDLE_VALUE;
  1645. pbuc->fSparseHandAlt = FALSE ;
  1646. }
  1647. if (pbuc->fAttribs & FILE_ATTRIBUTE_REPARSE_POINT ) {
  1648. reparse_flg = FILE_OPEN_REPARSE_POINT ;
  1649. }
  1650. InitializeObjectAttributes(
  1651. &oa,
  1652. &strName,
  1653. OBJ_CASE_INSENSITIVE,
  1654. hFile,
  1655. NULL);
  1656. Status = NtCreateFile(
  1657. &pbuc->hAlternate,
  1658. FILE_WRITE_DATA | SYNCHRONIZE,
  1659. &oa,
  1660. &iosb,
  1661. NULL,
  1662. FILE_ATTRIBUTE_NORMAL,
  1663. FILE_SHARE_READ | FILE_SHARE_WRITE|FILE_SHARE_DELETE,
  1664. FILE_OVERWRITE_IF,
  1665. FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | reparse_flg,
  1666. NULL,
  1667. 0L);
  1668. //
  1669. // If we failed, map the error, record the failure, and return failure.
  1670. //
  1671. if (!NT_SUCCESS( Status )) {
  1672. BaseSetLastNTError( Status );
  1673. pbuc->fAccessError = TRUE;
  1674. return FALSE;
  1675. }
  1676. if ( pbuc->head.dwStreamAttributes & STREAM_SPARSE_ATTRIBUTE ) {
  1677. pbuc->fSparseHandAlt = TRUE ;
  1678. // if it was sparse when be backed it up make is sparse again.
  1679. NtFsControlFile( pbuc->hAlternate,
  1680. NULL, // overlapped event handle
  1681. NULL, // Apc routine
  1682. NULL, // overlapped structure
  1683. &iosb,
  1684. FSCTL_SET_SPARSE ,
  1685. NULL,
  1686. 0,
  1687. NULL,
  1688. 0 ) ;
  1689. }
  1690. // don't reset stream start because WriteStream will do it.
  1691. }
  1692. //
  1693. // If we have no handle for the transfer, record this failure
  1694. // and return failure.
  1695. //
  1696. if (pbuc->hAlternate == INVALID_HANDLE_VALUE) {
  1697. pbuc->fAccessError = TRUE;
  1698. return FALSE;
  1699. }
  1700. //
  1701. // Let the normal stream copy perform the transfer
  1702. //
  1703. return BackupWriteStream( pbuc->hAlternate, pbuc, pbif );
  1704. }
  1705. BOOL
  1706. BackupWriteEaData(HANDLE hFile, BACKUPCONTEXT *pbuc, BACKUPIOFRAME *pbif)
  1707. /*++
  1708. Routine Description:
  1709. This is an internal routine that writes EA data on the file from
  1710. the user's buffer
  1711. Arguments:
  1712. hFile - handle to output file
  1713. pbuc - CONTEXT of call
  1714. pbif - IOCONTEXT of call
  1715. Return Value:
  1716. TRUE if EA data was successfully written, FALSE otherwise.
  1717. --*/
  1718. {
  1719. NTSTATUS Status;
  1720. IO_STATUS_BLOCK iosb;
  1721. //
  1722. // Attempt to fill up the buffer from the input.
  1723. //
  1724. switch (BackupWriteBuffer( pbuc, pbif )) {
  1725. default:
  1726. case BRB_FAIL:
  1727. return FALSE;
  1728. case BRB_MORE:
  1729. return TRUE;
  1730. case BRB_DONE:
  1731. break;
  1732. }
  1733. //
  1734. // The buffer is now completely filled with our EA data. Set the
  1735. // EA data on the file.
  1736. //
  1737. Status = NtSetEaFile(
  1738. hFile,
  1739. &iosb,
  1740. pbuc->DataBuffer.Buffer,
  1741. pbuc->head.Size.LowPart );
  1742. //
  1743. // If we failed, map the error and return failure
  1744. //
  1745. if (!NT_SUCCESS( Status )) {
  1746. BaseSetLastNTError( Status );
  1747. return FALSE;
  1748. }
  1749. return TRUE;
  1750. }
  1751. BOOL
  1752. BackupWriteReparseData(HANDLE hFile, BACKUPCONTEXT *pbuc, BACKUPIOFRAME *pbif)
  1753. /*++
  1754. Routine Description:
  1755. This is an internal routine that writes Reparse data on the file from
  1756. the user's buffer
  1757. Arguments:
  1758. hFile - handle to output file
  1759. pbuc - CONTEXT of call
  1760. pbif - IOCONTEXT of call
  1761. Return Value:
  1762. TRUE if EA data was successfully written, FALSE otherwise.
  1763. --*/
  1764. {
  1765. NTSTATUS Status;
  1766. IO_STATUS_BLOCK iosb;
  1767. DWORD *rp_tag_ptr ;
  1768. //
  1769. // Attempt to fill up the buffer from the input.
  1770. //
  1771. switch (BackupWriteBuffer( pbuc, pbif )) {
  1772. default:
  1773. case BRB_FAIL:
  1774. return FALSE;
  1775. case BRB_MORE:
  1776. return TRUE;
  1777. case BRB_DONE:
  1778. break;
  1779. }
  1780. //
  1781. // The buffer is now completely filled with our Reparse data. Set the
  1782. // Reparse data on the file.
  1783. //
  1784. rp_tag_ptr = (DWORD *)(pbuc->DataBuffer.Buffer) ;
  1785. pbuc->fAttribs |= FILE_ATTRIBUTE_REPARSE_POINT ;
  1786. Status = NtFsControlFile( hFile,
  1787. NULL, // overlapped event handle
  1788. NULL, // Apc routine
  1789. NULL, // overlapped structure
  1790. &iosb,
  1791. FSCTL_SET_REPARSE_POINT,
  1792. pbuc->DataBuffer.Buffer,
  1793. pbuc->head.Size.LowPart,
  1794. NULL,
  1795. 0 ) ;
  1796. //
  1797. // If we failed, map the error and return failure
  1798. //
  1799. if (!NT_SUCCESS( Status )) {
  1800. BaseSetLastNTError( Status );
  1801. return FALSE;
  1802. }
  1803. return TRUE;
  1804. }
  1805. BOOL
  1806. BackupWriteObjectId(HANDLE hFile, BACKUPCONTEXT *pbuc, BACKUPIOFRAME *pbif)
  1807. /*++
  1808. Routine Description:
  1809. This is an internal routine that writes the Object IDa on the file from
  1810. the user's buffer. Birth ids are made reborn. i.e. the volume id component
  1811. of the birth id is changed to the current volume's id, and the object id
  1812. component of the birth id is changed to the current object id.
  1813. Arguments:
  1814. hFile - handle to output file
  1815. pbuc - CONTEXT of call
  1816. pbif - IOCONTEXT of call
  1817. Return Value:
  1818. TRUE if Object ID was successfully written, FALSE otherwise.
  1819. --*/
  1820. {
  1821. IO_STATUS_BLOCK iosb;
  1822. NTSTATUS Status ;
  1823. FILE_FS_OBJECTID_INFORMATION fsobOID;
  1824. GUID guidZero;
  1825. //
  1826. // Attempt to fill up the buffer from the input.
  1827. //
  1828. switch (BackupWriteBuffer( pbuc, pbif )) {
  1829. default:
  1830. case BRB_FAIL:
  1831. return FALSE;
  1832. case BRB_MORE:
  1833. return TRUE;
  1834. case BRB_DONE:
  1835. break;
  1836. }
  1837. //
  1838. // Zero out the birth ID (the extended 48 bytes)
  1839. //
  1840. memset(&pbuc->DataBuffer.Buffer[sizeof(GUID)], 0, 3*sizeof(GUID));
  1841. //
  1842. // Set the ID on the file.
  1843. //
  1844. Status = NtFsControlFile( hFile,
  1845. NULL, // overlapped event handle
  1846. NULL, // Apc routine
  1847. NULL, // overlapped structure
  1848. &iosb,
  1849. FSCTL_SET_OBJECT_ID,
  1850. pbuc->DataBuffer.Buffer,
  1851. pbuc->head.Size.LowPart,
  1852. NULL,
  1853. 0);
  1854. //
  1855. // Ignore errors
  1856. //
  1857. if (!NT_SUCCESS( Status )) {
  1858. BaseSetLastNTError( Status );
  1859. }
  1860. return( TRUE );
  1861. }
  1862. BOOL
  1863. BackupWriteSecurityData(HANDLE hFile, BACKUPCONTEXT *pbuc, BACKUPIOFRAME *pbif)
  1864. /*++
  1865. Routine Description:
  1866. This is an internal routine that sets security information on the
  1867. file from data in the user's buffer.
  1868. Arguments:
  1869. hFile - handle to output file
  1870. pbuc - CONTEXT of call
  1871. pbif - IOCONTEXT of call
  1872. Return Value:
  1873. TRUE if security was successfully written, FALSE otherwise.
  1874. --*/
  1875. {
  1876. NTSTATUS Status;
  1877. SECURITY_INFORMATION si;
  1878. //
  1879. // Attempt to fill up the buffer from the input.
  1880. //
  1881. switch (BackupWriteBuffer(pbuc, pbif)) {
  1882. default:
  1883. case BRB_FAIL:
  1884. return FALSE;
  1885. case BRB_MORE:
  1886. return TRUE;
  1887. case BRB_DONE:
  1888. break;
  1889. }
  1890. //
  1891. // The buffer is now completely filled with our security data. If we
  1892. // are to ignore it, then return success
  1893. //
  1894. if (!pbif->fProcessSecurity) {
  1895. return TRUE;
  1896. }
  1897. //
  1898. // Find out what security information is present so we know what to
  1899. // set.
  1900. si = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION;
  1901. if (((PISECURITY_DESCRIPTOR) pbuc->DataBuffer.Buffer)->Control & SE_DACL_PRESENT) {
  1902. si |= DACL_SECURITY_INFORMATION;
  1903. }
  1904. if (((PISECURITY_DESCRIPTOR) pbuc->DataBuffer.Buffer)->Control & SE_SACL_PRESENT) {
  1905. si |= SACL_SECURITY_INFORMATION;
  1906. }
  1907. //
  1908. // If the security descriptor has AUTO_INHERITED set, set the appropriate REQ bits.
  1909. //
  1910. if (((PISECURITY_DESCRIPTOR) pbuc->DataBuffer.Buffer)->Control & SE_DACL_AUTO_INHERITED) {
  1911. ((PISECURITY_DESCRIPTOR) pbuc->DataBuffer.Buffer)->Control |= SE_DACL_AUTO_INHERIT_REQ;
  1912. }
  1913. if (((PISECURITY_DESCRIPTOR) pbuc->DataBuffer.Buffer)->Control & SE_SACL_AUTO_INHERITED) {
  1914. ((PISECURITY_DESCRIPTOR) pbuc->DataBuffer.Buffer)->Control |= SE_SACL_AUTO_INHERIT_REQ;
  1915. }
  1916. Status = NtSetSecurityObject( hFile, si, pbuc->DataBuffer.Buffer );
  1917. if (!NT_SUCCESS( Status )) {
  1918. NTSTATUS Status2;
  1919. //
  1920. // If that didn't work, the caller is probably not running as Backup
  1921. // Operator, so we can't set the owner and group. Keep the current
  1922. // status code, and attempt to set the DACL and SACL while ignoring
  1923. // failures.
  1924. //
  1925. if (si & SACL_SECURITY_INFORMATION) {
  1926. NtSetSecurityObject(
  1927. hFile,
  1928. SACL_SECURITY_INFORMATION,
  1929. pbuc->DataBuffer.Buffer );
  1930. }
  1931. if (si & DACL_SECURITY_INFORMATION) {
  1932. Status = NtSetSecurityObject(
  1933. hFile,
  1934. DACL_SECURITY_INFORMATION,
  1935. pbuc->DataBuffer.Buffer);
  1936. }
  1937. Status2 = NtSetSecurityObject(
  1938. hFile,
  1939. OWNER_SECURITY_INFORMATION |
  1940. GROUP_SECURITY_INFORMATION,
  1941. pbuc->DataBuffer.Buffer);
  1942. if (NT_SUCCESS(Status)) {
  1943. Status = Status2;
  1944. }
  1945. }
  1946. if (!NT_SUCCESS(Status)) {
  1947. BaseSetLastNTError(Status);
  1948. return FALSE;
  1949. }
  1950. return TRUE;
  1951. }
  1952. BOOL
  1953. BackupWriteLinkData(HANDLE hFile, BACKUPCONTEXT *pbuc, BACKUPIOFRAME *pbif)
  1954. /*++
  1955. Routine Description:
  1956. This is an internal routine that establishes links based on the
  1957. user's data.
  1958. Arguments:
  1959. hFile - handle of file being restored
  1960. pbuc - CONTEXT of call
  1961. pbif - IOCONTEXT of call
  1962. Return Value:
  1963. TRUE if link was successfully established, FALSE otherwise.
  1964. --*/
  1965. {
  1966. FILE_LINK_INFORMATION *pfli;
  1967. WCHAR *pwc;
  1968. WCHAR *pwcSlash;
  1969. INT cbName;
  1970. INT cSlash;
  1971. WCHAR wcSave;
  1972. BOOL fSuccess;
  1973. //
  1974. // Attempt to fill up the buffer from the input.
  1975. //
  1976. switch (BackupWriteBuffer(pbuc, pbif)) {
  1977. default:
  1978. case BRB_FAIL:
  1979. return FALSE;
  1980. case BRB_MORE:
  1981. return TRUE;
  1982. case BRB_DONE:
  1983. break;
  1984. }
  1985. //
  1986. // The buffer is now completely filled with our link data.
  1987. // Find the last component of the name.
  1988. //
  1989. cSlash = 0;
  1990. pwcSlash = NULL;
  1991. pwc = (WCHAR *) pbuc->DataBuffer.Buffer;
  1992. cbName = sizeof(WCHAR);
  1993. while (*pwc != L'\0') {
  1994. if (*pwc == L'\\') {
  1995. pwcSlash = pwc;
  1996. cSlash++;
  1997. cbName = 0;
  1998. }
  1999. pwc++;
  2000. cbName += sizeof(WCHAR);
  2001. }
  2002. pfli = BackupAlloc( sizeof(*pfli) + cbName );
  2003. if (pfli == NULL) {
  2004. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  2005. return FALSE;
  2006. }
  2007. RtlCopyMemory( pfli->FileName, pwcSlash + 1, cbName );
  2008. pfli->FileNameLength = cbName - sizeof(WCHAR);
  2009. if (cSlash > 1) {
  2010. wcSave = L'\\';
  2011. }
  2012. else {
  2013. wcSave = *pwcSlash++;
  2014. }
  2015. *pwcSlash = L'\0';
  2016. //
  2017. // Open the parent of the link target
  2018. //
  2019. pfli->RootDirectory = CreateFileW(
  2020. (WCHAR *) pbuc->DataBuffer.Buffer,
  2021. GENERIC_WRITE | GENERIC_READ,
  2022. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  2023. NULL,
  2024. OPEN_EXISTING,
  2025. FILE_ATTRIBUTE_NORMAL| FILE_FLAG_BACKUP_SEMANTICS,
  2026. NULL );
  2027. *pwcSlash = wcSave;
  2028. pfli->ReplaceIfExists = TRUE;
  2029. fSuccess = TRUE;
  2030. if (pfli->RootDirectory == INVALID_HANDLE_VALUE) {
  2031. SetLastError( ERROR_FILE_NOT_FOUND );
  2032. fSuccess = FALSE;
  2033. }
  2034. else {
  2035. NTSTATUS Status;
  2036. IO_STATUS_BLOCK iosb;
  2037. Status = NtSetInformationFile(
  2038. hFile,
  2039. &iosb,
  2040. pfli,
  2041. sizeof(*pfli) + cbName,
  2042. FileLinkInformation );
  2043. CloseHandle( pfli->RootDirectory );
  2044. pfli->RootDirectory = INVALID_HANDLE_VALUE;
  2045. if (!NT_SUCCESS( Status )) {
  2046. BaseSetLastNTError( Status );
  2047. fSuccess = FALSE;
  2048. } else {
  2049. if (iosb.Information == FILE_OVERWRITTEN) {
  2050. SetLastError( ERROR_ALREADY_EXISTS );
  2051. } else {
  2052. SetLastError( 0 );
  2053. }
  2054. }
  2055. }
  2056. BackupFree( pfli );
  2057. return fSuccess;
  2058. }
  2059. // Routine Description:
  2060. //
  2061. // Data can be written to a file using BackupWrite.
  2062. //
  2063. // This API is used to Restore data to an object. After the
  2064. // write completes, the file pointer is adjusted by the number of bytes
  2065. // actually written.
  2066. //
  2067. // Unlike DOS, a NumberOfBytesToWrite value of zero does not truncate
  2068. // or extend the file. If this function is required, SetEndOfFile
  2069. // should be used.
  2070. //
  2071. // Arguments:
  2072. //
  2073. // hFile - Supplies an open handle to a file that is to be written. The
  2074. // file handle must have been created with GENERIC_WRITE access to
  2075. // the file.
  2076. //
  2077. // lpBuffer - Supplies the address of the data that is to be written to
  2078. // the file.
  2079. //
  2080. // nNumberOfBytesToWrite - Supplies the number of bytes to write to the
  2081. // file. Unlike DOS, a value of zero is interpreted a null write.
  2082. //
  2083. // lpNumberOfBytesWritten - Returns the number of bytes written by this
  2084. // call. Before doing any work or error processing, the API sets this
  2085. // to zero.
  2086. //
  2087. // bAbort - If true, then all resources associated with the context will
  2088. // be released.
  2089. //
  2090. // bProcessSecurity - If TRUE, then the NTFS ACL data will be written.
  2091. // If FALSE, then the ACL stream will be ignored.
  2092. //
  2093. // lpContext - Points to a buffer pointer setup and maintained by
  2094. // BackupRead.
  2095. //
  2096. //
  2097. // Return Value:
  2098. //
  2099. // TRUE - The operation was a success.
  2100. //
  2101. // FALSE - The operation failed. Extended error status is
  2102. // available using GetLastError.
  2103. BOOL WINAPI
  2104. BackupWrite(
  2105. HANDLE hFile,
  2106. LPBYTE lpBuffer,
  2107. DWORD nNumberOfBytesToWrite,
  2108. LPDWORD lpNumberOfBytesWritten,
  2109. BOOL bAbort,
  2110. BOOL bProcessSecurity,
  2111. LPVOID *lpContext)
  2112. {
  2113. BACKUPCONTEXT *pbuc;
  2114. BACKUPIOFRAME bif;
  2115. BOOL fSuccess = FALSE;
  2116. pbuc = *lpContext;
  2117. bif.pIoBuffer = lpBuffer;
  2118. bif.cbRequest = nNumberOfBytesToWrite;
  2119. bif.pcbTransferred = lpNumberOfBytesWritten;
  2120. bif.fProcessSecurity = (BOOLEAN)bProcessSecurity;
  2121. //
  2122. // Allocate our Context Control Block on first call.
  2123. //
  2124. if (bAbort) {
  2125. if (pbuc != NULL) {
  2126. FreeContext(lpContext);
  2127. }
  2128. return TRUE;
  2129. }
  2130. *bif.pcbTransferred = 0;
  2131. if (pbuc == INVALID_HANDLE_VALUE) {
  2132. return TRUE;
  2133. }
  2134. // Allocate our Context Control Block on first call.
  2135. if (pbuc == NULL) {
  2136. pbuc = AllocContext(0); // No initial buffer
  2137. //
  2138. // If we have no space then return failure
  2139. //
  2140. if (pbuc == NULL) {
  2141. return FALSE;
  2142. }
  2143. }
  2144. *lpContext = pbuc;
  2145. do {
  2146. DWORD cbrequest;
  2147. LONGLONG licbRemain;
  2148. //
  2149. // If we do not have a complete header, go
  2150. // fill it in.
  2151. //
  2152. if (pbuc->cbHeader == 0) {
  2153. pbuc->fMultiStreamType = TRUE ; //restore does not auto inc stream index.
  2154. pbuc->fStreamStart = TRUE ;
  2155. BackupWriteHeader(pbuc, &bif, CB_NAMELESSHEADER) ;
  2156. }
  2157. //
  2158. // If no more data, then exit
  2159. //
  2160. if (bif.cbRequest == 0) {
  2161. return TRUE;
  2162. }
  2163. //
  2164. // If a stream name was expected, go read it in
  2165. //
  2166. if (pbuc->cbHeader == CB_NAMELESSHEADER &&
  2167. pbuc->head.dwStreamNameSize != 0) {
  2168. if ( !BackupWriteHeader(
  2169. pbuc,
  2170. &bif,
  2171. pbuc->cbHeader + pbuc->head.dwStreamNameSize) )
  2172. {
  2173. SetLastError( ERROR_INVALID_DATA );
  2174. return FALSE ;
  2175. }
  2176. //
  2177. // If no more data then exit
  2178. //
  2179. if (bif.cbRequest == 0) {
  2180. return TRUE;
  2181. }
  2182. }
  2183. if ( ( pbuc->cbHeader == CB_NAMELESSHEADER ) &&
  2184. ( pbuc->head.dwStreamId == BACKUP_SPARSE_BLOCK ) ) {
  2185. BackupWriteHeader(
  2186. pbuc,
  2187. &bif,
  2188. pbuc->cbHeader + sizeof(LARGE_INTEGER) );
  2189. //
  2190. // If no more data then exit
  2191. //
  2192. if (bif.cbRequest == 0) {
  2193. if ( pbuc->cbHeader == CB_NAMELESSHEADER ) {
  2194. return TRUE;
  2195. }
  2196. }
  2197. }
  2198. //
  2199. // Determine amount of data remaining in user buffer
  2200. // that can be transferred as part of this section
  2201. // of the backup stream
  2202. //
  2203. cbrequest = ComputeRequestSize(pbuc, bif.cbRequest);
  2204. //
  2205. // Determine total amount of data left in this section
  2206. // of backup stream.
  2207. //
  2208. licbRemain = ComputeRemainingSize( pbuc );
  2209. //
  2210. // If we had an error in the transfer and we're done
  2211. // doing the transfer then pretend that we successfully
  2212. // completed the section.
  2213. //
  2214. if (pbuc->fAccessError && licbRemain == 0) {
  2215. ReportTransfer(pbuc, &bif, cbrequest);
  2216. continue;
  2217. }
  2218. //
  2219. // Begin or continue the transfer of data. We assume that there
  2220. // are no errors
  2221. //
  2222. pbuc->fAccessError = FALSE;
  2223. switch (pbuc->head.dwStreamId) {
  2224. case BACKUP_SPARSE_BLOCK :
  2225. fSuccess = BackupWriteSparse( hFile, pbuc, &bif ) ;
  2226. break ;
  2227. case BACKUP_DATA:
  2228. fSuccess = BackupWriteStream( hFile, pbuc, &bif );
  2229. break;
  2230. case BACKUP_ALTERNATE_DATA:
  2231. fSuccess = BackupWriteAlternateData( hFile, pbuc, &bif );
  2232. break;
  2233. case BACKUP_EA_DATA:
  2234. fSuccess = BackupWriteEaData( hFile, pbuc, &bif );
  2235. break;
  2236. case BACKUP_OBJECT_ID:
  2237. fSuccess = BackupWriteObjectId( hFile, pbuc, &bif );
  2238. break;
  2239. case BACKUP_REPARSE_DATA:
  2240. fSuccess = BackupWriteReparseData( hFile, pbuc, &bif );
  2241. break;
  2242. case BACKUP_SECURITY_DATA:
  2243. fSuccess = BackupWriteSecurityData( hFile, pbuc, &bif );
  2244. break;
  2245. case BACKUP_LINK:
  2246. fSuccess = BackupWriteLinkData( hFile, pbuc, &bif );
  2247. break;
  2248. default:
  2249. SetLastError(ERROR_INVALID_DATA);
  2250. fSuccess = FALSE;
  2251. break;
  2252. }
  2253. BackupTestRestartStream(pbuc);
  2254. } while (fSuccess && bif.cbRequest != 0);
  2255. if (fSuccess && *bif.pcbTransferred == 0) {
  2256. FreeContext(lpContext);
  2257. }
  2258. return(fSuccess);
  2259. }