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.

3268 lines
106 KiB

  1. /*++
  2. (c) 1998 Seagate Software, Inc. All rights reserved.
  3. Module Name:
  4. fsaitemr.cpp
  5. Abstract:
  6. This class contains represents a scan item (i.e. file or directory) for NTFS 5.0.
  7. Author:
  8. Chuck Bardeen [cbardeen] 1-Dec-1996
  9. Revision History:
  10. Michael Lotz [lotz ] 13-Jan-1997
  11. --*/
  12. #include "stdafx.h"
  13. #define WSB_TRACE_IS WSB_TRACE_BIT_FSA
  14. #include "wsb.h"
  15. #include "fsa.h"
  16. #include "fsaitem.h"
  17. #include "rpdata.h"
  18. #include "rpio.h"
  19. #include "rpguid.h"
  20. #include "fsaitemr.h"
  21. #define SHARE_FLAGS (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE)
  22. #define EXCLUSIVE_FLAG ( 0 ) // exclusive open without sharing of the file
  23. //
  24. // Notice these two bits are NOT the same location????
  25. //
  26. #define BIT_FOR_TRUNCATED FILE_ATTRIBUTE_OFFLINE
  27. #define BIT_FOR_RP FILE_ATTRIBUTE_REPARSE_POINT
  28. //
  29. // File extensions that are treated as special cases for truncate
  30. //
  31. #define EXT_FOR_EXE L".exe"
  32. #define EXT_FOR_DLL L".dll"
  33. //
  34. // Macros and defines for exe and dll headers
  35. //
  36. #define SIZE_OF_NT_SIGNATURE sizeof(DWORD)
  37. //
  38. // Macros
  39. //
  40. /* Offset to PE file signature */
  41. #define NTSIGNATURE(a) ((LPVOID)((BYTE *)a + \
  42. ((PIMAGE_DOS_HEADER)a)->e_lfanew))
  43. /* MS-OS header identifies the NT PEFile signature dword;
  44. the PEFILE header exists just after that dword. */
  45. #define PEFHDROFFSET(a) ((LPVOID)((BYTE *)a + \
  46. ((PIMAGE_DOS_HEADER)a)->e_lfanew + \
  47. SIZE_OF_NT_SIGNATURE))
  48. /* PE optional header is immediately after PEFile header. */
  49. #define OPTHDROFFSET(a) ((LPVOID)((BYTE *)a + \
  50. ((PIMAGE_DOS_HEADER)a)->e_lfanew + \
  51. SIZE_OF_NT_SIGNATURE + \
  52. sizeof (IMAGE_FILE_HEADER)))
  53. /* Section headers are immediately after PE optional header. */
  54. #define SECHDROFFSET(a) ((LPVOID)((BYTE *)a + \
  55. ((PIMAGE_DOS_HEADER)a)->e_lfanew + \
  56. SIZE_OF_NT_SIGNATURE + \
  57. sizeof (IMAGE_FILE_HEADER) + \
  58. sizeof (IMAGE_OPTIONAL_HEADER)))
  59. HRESULT
  60. OpenObject (
  61. IN WCHAR const *pwszFile,
  62. IN ULONG CreateOptions,
  63. IN ULONG DesiredAccess,
  64. IN ULONG ShareAccess,
  65. IN ULONG CreateDisposition,
  66. OUT IO_STATUS_BLOCK *IoStatusBlock,
  67. OUT HANDLE *ObjectHandle
  68. )
  69. /*++
  70. Implements: A wrapper function for NtCreateFile
  71. OpenObject
  72. --*/
  73. //
  74. // Simple wrapper for NtCreateFile
  75. //
  76. {
  77. HRESULT hr = S_OK;
  78. NTSTATUS ntStatus;
  79. BOOL bStatus;
  80. OBJECT_ATTRIBUTES ObjectAttributes;
  81. UNICODE_STRING str;
  82. RTL_RELATIVE_NAME RelativeName;
  83. PVOID RelativeBuffer = NULL;
  84. PVOID StrBuffer = NULL;
  85. WsbTraceIn(OLESTR("OpenObject"), OLESTR(""));
  86. //
  87. // Null out the pointer so we know when it was allocated
  88. //
  89. str.Buffer = NULL;
  90. RelativeName.RelativeName.Buffer = NULL;
  91. try {
  92. //
  93. // Convert input name into special format with \??\
  94. //
  95. //bStatus = RtlDosPathNameToNtPathName_U( pwszFile,
  96. // &str,
  97. // NULL,
  98. // NULL );
  99. //WsbAffirm( bStatus, E_FAIL);
  100. bStatus = RtlDosPathNameToNtPathName_U(
  101. pwszFile,
  102. &str,
  103. NULL,
  104. &RelativeName
  105. );
  106. WsbAffirm( bStatus, E_FAIL);
  107. StrBuffer = str.Buffer;
  108. if ( RelativeName.RelativeName.Length ) {
  109. str = *(PUNICODE_STRING)&RelativeName.RelativeName;
  110. } else {
  111. RelativeName.ContainingDirectory = NULL;
  112. }
  113. RelativeBuffer = RelativeName.RelativeName.Buffer;
  114. InitializeObjectAttributes(
  115. &ObjectAttributes,
  116. &str,
  117. 0,
  118. RelativeName.ContainingDirectory,
  119. NULL
  120. );
  121. ntStatus = NtCreateFile(
  122. ObjectHandle,
  123. DesiredAccess | SYNCHRONIZE,
  124. &ObjectAttributes,
  125. IoStatusBlock,
  126. NULL, // pallocationsize (none!)
  127. FILE_ATTRIBUTE_NORMAL,
  128. ShareAccess,
  129. CreateDisposition,
  130. CreateOptions | FILE_OPEN_REPARSE_POINT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
  131. NULL, // EA buffer (none!)
  132. 0);
  133. //
  134. // Right now if the file is not a reparse point the above open
  135. // fails -- so now try it without the FILE_OPEN_REPARSE_POINT
  136. //
  137. if ( STATUS_NOT_A_REPARSE_POINT == ntStatus) {
  138. WsbAffirmNtStatus( NtCreateFile(
  139. ObjectHandle,
  140. DesiredAccess | SYNCHRONIZE,
  141. &ObjectAttributes,
  142. IoStatusBlock,
  143. NULL, // pallocationsize (none!)
  144. FILE_ATTRIBUTE_NORMAL,
  145. ShareAccess,
  146. CreateDisposition,
  147. CreateOptions | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT | FILE_FLAG_POSIX_SEMANTICS,
  148. NULL, // EA buffer (none!)
  149. 0 ) );
  150. } else {
  151. WsbAffirmNtStatus( ntStatus );
  152. }
  153. } WsbCatch( hr );
  154. //
  155. // Clean up the memory if we allocated it
  156. //
  157. if (NULL != RelativeBuffer)
  158. RtlFreeHeap(RtlProcessHeap(), 0, RelativeBuffer);
  159. if (NULL != StrBuffer) {
  160. RtlFreeHeap(RtlProcessHeap(), 0, StrBuffer);
  161. }
  162. //if( NULL == str.Buffer ) {
  163. // bStatus = RtlFreeHeap( RtlProcessHeap(), 0, str.Buffer );
  164. //}
  165. WsbTraceOut(OLESTR("OpenObject"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  166. return( hr );
  167. } // OpenObject
  168. HRESULT
  169. OpenDocView (
  170. IN WCHAR const *pwszFile,
  171. IN ULONG CreateOptions,
  172. IN ULONG DesiredAccess,
  173. IN ULONG ShareAccess,
  174. IN ULONG CreateDisposition,
  175. OUT IO_STATUS_BLOCK *IoStatusBlock,
  176. OUT HANDLE *ObjectHandle
  177. )
  178. /*++
  179. Implements: A wrapper function for NtCreateFile that gets a DOCVIEW of the file
  180. OpenDocView
  181. --*/
  182. //
  183. // Simple wrapper for NtCreateFile
  184. //
  185. {
  186. HRESULT hr = S_OK;
  187. NTSTATUS ntStatus;
  188. BOOL bStatus;
  189. OBJECT_ATTRIBUTES ObjectAttributes;
  190. UNICODE_STRING str;
  191. RTL_RELATIVE_NAME RelativeName;
  192. PVOID RelativeBuffer = NULL;
  193. PVOID StrBuffer = NULL;
  194. WsbTraceIn(OLESTR("OpenDocView"), OLESTR(""));
  195. //
  196. // Null out the pointer so we know when it was allocated
  197. //
  198. str.Buffer = NULL;
  199. RelativeName.RelativeName.Buffer = NULL;
  200. try {
  201. //
  202. bStatus = RtlDosPathNameToNtPathName_U(
  203. pwszFile,
  204. &str,
  205. NULL,
  206. &RelativeName
  207. );
  208. WsbAffirm( bStatus, E_FAIL);
  209. StrBuffer = str.Buffer;
  210. if ( RelativeName.RelativeName.Length ) {
  211. str = *(PUNICODE_STRING)&RelativeName.RelativeName;
  212. } else {
  213. RelativeName.ContainingDirectory = NULL;
  214. }
  215. RelativeBuffer = RelativeName.RelativeName.Buffer;
  216. InitializeObjectAttributes(
  217. &ObjectAttributes,
  218. &str,
  219. 0,
  220. RelativeName.ContainingDirectory,
  221. NULL
  222. );
  223. ntStatus = NtCreateFile(
  224. ObjectHandle,
  225. DesiredAccess | SYNCHRONIZE,
  226. &ObjectAttributes,
  227. IoStatusBlock,
  228. NULL, // pallocationsize (none!)
  229. FILE_ATTRIBUTE_NORMAL,
  230. ShareAccess,
  231. CreateDisposition,
  232. CreateOptions | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
  233. NULL, // EA buffer (none!)
  234. 0);
  235. WsbAffirmNtStatus( ntStatus );
  236. } WsbCatch( hr );
  237. //
  238. // Clean up the memory if we allocated it
  239. //
  240. if (NULL != RelativeBuffer)
  241. RtlFreeHeap(RtlProcessHeap(), 0, RelativeBuffer);
  242. if (NULL != StrBuffer) {
  243. RtlFreeHeap(RtlProcessHeap(), 0, StrBuffer);
  244. }
  245. WsbTraceOut(OLESTR("OpenDocView"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  246. return( hr );
  247. } // OpenDocView
  248. HRESULT
  249. CopyPlaceholderToRP (
  250. IN CONST FSA_PLACEHOLDER *pPlaceholder,
  251. OUT PREPARSE_DATA_BUFFER pReparseBuffer,
  252. IN BOOL bTruncated
  253. )
  254. /*++
  255. Implements: A wrapper function for copying the placeholder data into the reparse point
  256. CopyPlaceholderToRP
  257. --*/
  258. //
  259. // Simple wrapper moving the data from the scan item in-memory
  260. // placeholder information into a reparse point buffer
  261. //
  262. {
  263. HRESULT hr = S_OK;
  264. PRP_DATA pHsmData;
  265. WsbTraceIn(OLESTR("CopyPlaceholderToRP"), OLESTR(""));
  266. WsbTrace(OLESTR(" fileStart = %I64d, dataStart = %I64d, dataStreamStart = %I64d\n"),
  267. pPlaceholder->fileStart, pPlaceholder->dataStart,
  268. pPlaceholder->dataStreamStart);
  269. WsbTrace(OLESTR(" fileSize = %I64d, dataSize = %I64d, dataStreamSize = %I64d\n"),
  270. pPlaceholder->fileSize, pPlaceholder->dataSize,
  271. pPlaceholder->dataStreamSize);
  272. try {
  273. //
  274. // Validate the pointers passed in
  275. //
  276. WsbAssert( NULL != pPlaceholder, E_POINTER );
  277. WsbAssert( NULL != pReparseBuffer, E_POINTER );
  278. //
  279. // Setup the pointer to our hsm data
  280. //
  281. pHsmData = (PRP_DATA) &pReparseBuffer->GenericReparseBuffer.DataBuffer[0];
  282. //
  283. // Set the generic reparse point header information for the tag and size
  284. //
  285. pReparseBuffer->ReparseTag = IO_REPARSE_TAG_HSM ;
  286. pReparseBuffer->ReparseDataLength = sizeof(RP_DATA);
  287. pReparseBuffer->Reserved = 0 ;
  288. //
  289. // Set the private data that is the vendor id and version number
  290. //
  291. pHsmData->vendorId = RP_MSFT_VENDOR_ID;
  292. pHsmData->version = RP_VERSION;
  293. //
  294. // Assume for now that there is only one placeholder
  295. // This needs to be updated
  296. //
  297. pHsmData->numPrivateData = 1;
  298. pHsmData->fileIdentifier = GUID_NULL;
  299. ZeroMemory(pHsmData->data.reserved, RP_RESV_SIZE);
  300. //
  301. // If the file is to indicate the file is truncated then set the bit
  302. // otherwise make sure it is off
  303. //
  304. RP_INIT_BITFLAG( pHsmData->data.bitFlags );
  305. if( bTruncated ) {
  306. RP_SET_TRUNCATED_BIT( pHsmData->data.bitFlags );
  307. } else {
  308. RP_CLEAR_TRUNCATED_BIT( pHsmData->data.bitFlags );
  309. }
  310. //
  311. // Set the truncate on close bit as needed
  312. //
  313. if( pPlaceholder->truncateOnClose ) {
  314. RP_SET_TRUNCATE_ON_CLOSE_BIT( pHsmData->data.bitFlags );
  315. } else {
  316. RP_CLEAR_TRUNCATE_ON_CLOSE_BIT( pHsmData->data.bitFlags );
  317. }
  318. //
  319. // Set the Premigrate on close bit as needed
  320. //
  321. if( pPlaceholder->premigrateOnClose ) {
  322. RP_SET_PREMIGRATE_ON_CLOSE_BIT( pHsmData->data.bitFlags );
  323. } else {
  324. RP_CLEAR_PREMIGRATE_ON_CLOSE_BIT( pHsmData->data.bitFlags );
  325. }
  326. //
  327. // Set the global bit flags based on the placeholder data
  328. // For now since we are assuming one placeholder then set
  329. // them the same.
  330. pHsmData->globalBitFlags = pHsmData->data.bitFlags;
  331. //
  332. // Move over the data parts of the information
  333. //
  334. pHsmData->data.migrationTime.QuadPart = WsbFTtoLL( pPlaceholder->migrationTime );
  335. pHsmData->data.hsmId = pPlaceholder->hsmId;
  336. pHsmData->data.bagId = pPlaceholder->bagId;
  337. pHsmData->data.fileStart.QuadPart = pPlaceholder->fileStart;
  338. pHsmData->data.fileSize.QuadPart = pPlaceholder->fileSize;
  339. pHsmData->data.dataStart.QuadPart = pPlaceholder->dataStart;
  340. pHsmData->data.dataSize.QuadPart = pPlaceholder->dataSize;
  341. pHsmData->data.fileVersionId.QuadPart = pPlaceholder->fileVersionId;
  342. pHsmData->data.verificationData.QuadPart = pPlaceholder->verificationData;
  343. pHsmData->data.verificationType = pPlaceholder->verificationType;
  344. pHsmData->data.recallCount = pPlaceholder->recallCount;
  345. pHsmData->data.recallTime.QuadPart = WsbFTtoLL( pPlaceholder->recallTime );
  346. pHsmData->data.dataStreamStart.QuadPart = pPlaceholder->dataStreamStart;
  347. pHsmData->data.dataStreamSize.QuadPart = pPlaceholder->dataStreamSize;
  348. pHsmData->data.dataStream = pPlaceholder->dataStream;
  349. pHsmData->data.dataStreamCRCType = pPlaceholder->dataStreamCRCType;
  350. pHsmData->data.dataStreamCRC.QuadPart = pPlaceholder->dataStreamCRC;
  351. //
  352. // Lastly generate the check sum
  353. //
  354. RP_GEN_QUALIFIER(pHsmData, pHsmData->qualifier);
  355. //
  356. // Now set the bit that tells the filter that it is us setting the reparse point.
  357. // This is not included in the qualifier checksum generation.
  358. //
  359. RP_SET_ORIGINATOR_BIT( pHsmData->data.bitFlags );
  360. } WsbCatch(hr);
  361. WsbTraceOut(OLESTR("CopyPlaceholderToRP"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  362. return( hr );
  363. }
  364. HRESULT
  365. CopyRPDataToPlaceholder (
  366. IN CONST PRP_DATA pHsmData,
  367. OUT FSA_PLACEHOLDER *pPlaceholder
  368. )
  369. /*++
  370. Implements: A wrapper function for moving the Reparse Point into generic FSA_PLACEHOLDER format
  371. CopyRPDataToPlaceholder
  372. --*/
  373. {
  374. HRESULT hr = S_OK;
  375. ULONG qualifier; // Used to checksum the data
  376. WsbTraceIn(OLESTR("CopyRPDataToPlaceholder"), OLESTR(""));
  377. WsbTrace(OLESTR(" fileStart = %I64d, dataStart = %I64d, dataStreamStart = %I64d\n"),
  378. pHsmData->data.fileStart.QuadPart, pHsmData->data.dataStart.QuadPart,
  379. pHsmData->data.dataStreamStart.QuadPart);
  380. WsbTrace(OLESTR(" fileSize = %I64d, dataSize = %I64d, dataStreamSize = %I64d\n"),
  381. pHsmData->data.fileSize.QuadPart, pHsmData->data.dataSize.QuadPart,
  382. pHsmData->data.dataStreamSize.QuadPart);
  383. //
  384. // Simple wrapper moving the data from the reparse point buffer into the
  385. // generic placeholder information
  386. //
  387. try {
  388. //
  389. // Validate the pointers passed in
  390. //
  391. WsbAssert( NULL != pHsmData, E_POINTER );
  392. WsbAssert( NULL != pPlaceholder, E_POINTER );
  393. //
  394. // Just in case, we clear out the originator bit.
  395. //
  396. RP_CLEAR_ORIGINATOR_BIT( pHsmData->data.bitFlags );
  397. //
  398. // Verify the check sum and the key private fields
  399. //
  400. RP_GEN_QUALIFIER(pHsmData, qualifier);
  401. WsbAffirm( pHsmData->qualifier == qualifier, E_FAIL );
  402. WsbAffirm( RP_MSFT_VENDOR_ID == pHsmData->vendorId, E_FAIL );
  403. WsbAffirm( RP_VERSION == pHsmData->version, E_FAIL );
  404. //
  405. // Now that everything worked, save the values in our private data
  406. //
  407. pPlaceholder->migrationTime = WsbLLtoFT( pHsmData->data.migrationTime.QuadPart );
  408. pPlaceholder->hsmId = pHsmData->data.hsmId;
  409. pPlaceholder->bagId = pHsmData->data.bagId;
  410. pPlaceholder->fileStart = pHsmData->data.fileStart.QuadPart;
  411. pPlaceholder->fileSize = pHsmData->data.fileSize.QuadPart;
  412. pPlaceholder->dataStart = pHsmData->data.dataStart.QuadPart;
  413. pPlaceholder->dataSize = pHsmData->data.dataSize.QuadPart;
  414. pPlaceholder->fileVersionId = pHsmData->data.fileVersionId.QuadPart;
  415. pPlaceholder->verificationData = pHsmData->data.verificationData.QuadPart;
  416. pPlaceholder->verificationType = pHsmData->data.verificationType;
  417. pPlaceholder->recallCount = pHsmData->data.recallCount;
  418. pPlaceholder->recallTime = WsbLLtoFT( pHsmData->data.recallTime.QuadPart );
  419. pPlaceholder->dataStreamStart = pHsmData->data.dataStreamStart.QuadPart;
  420. pPlaceholder->dataStreamSize = pHsmData->data.dataStreamSize.QuadPart;
  421. pPlaceholder->dataStream = pHsmData->data.dataStream;
  422. pPlaceholder->dataStreamCRCType = pHsmData->data.dataStreamCRCType;
  423. pPlaceholder->dataStreamCRC = pHsmData->data.dataStreamCRC.QuadPart;
  424. //
  425. // Set placeholder bits
  426. //
  427. if( RP_FILE_IS_TRUNCATED( pHsmData->data.bitFlags ) ) {
  428. pPlaceholder->isTruncated = TRUE;
  429. } else {
  430. pPlaceholder->isTruncated = FALSE;
  431. }
  432. if( RP_FILE_DO_TRUNCATE_ON_CLOSE( pHsmData->data.bitFlags ) ) {
  433. pPlaceholder->truncateOnClose = TRUE;
  434. } else {
  435. pPlaceholder->truncateOnClose = FALSE;
  436. }
  437. if( RP_FILE_DO_PREMIGRATE_ON_CLOSE( pHsmData->data.bitFlags ) ) {
  438. pPlaceholder->premigrateOnClose = TRUE;
  439. } else {
  440. pPlaceholder->premigrateOnClose = FALSE;
  441. }
  442. } WsbCatch(hr);
  443. WsbTraceOut(OLESTR("CopyRPDataToPlaceholder"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  444. return( hr );
  445. }
  446. HRESULT
  447. CopyRPToPlaceholder (
  448. IN CONST PREPARSE_DATA_BUFFER pReparseBuffer,
  449. OUT FSA_PLACEHOLDER *pPlaceholder
  450. )
  451. /*++
  452. Implements: A wrapper function for moving the Reparse Point into generic FSA_PLACEHOLDER format
  453. CopyRPToPlaceholder
  454. --*/
  455. {
  456. HRESULT hr = S_OK;
  457. PRP_DATA pHsmData;
  458. WsbTraceIn(OLESTR("CopyRPToPlaceholder"), OLESTR(""));
  459. //
  460. // Simple wrapper moving the data from the reparse point buffer into the
  461. // generic placeholder information
  462. //
  463. try {
  464. //
  465. // Validate the pointers passed in
  466. //
  467. WsbAssert( NULL != pReparseBuffer, E_POINTER );
  468. WsbAssert( NULL != pPlaceholder, E_POINTER );
  469. //
  470. // Get the pointers setup correctly to this buffer because the
  471. // type REPARSE_DATA_BUFFER actually doesn't have any space
  472. // allocated for the data and that is our own type, so get pointers
  473. // pointing into the real allocated space so we can use them
  474. //
  475. pHsmData = (PRP_DATA) &pReparseBuffer->GenericReparseBuffer.DataBuffer[0];
  476. //
  477. // Validate the key public fields to make sure it is data we
  478. // understand
  479. //
  480. WsbAffirm( IO_REPARSE_TAG_HSM == pReparseBuffer->ReparseTag , S_FALSE );
  481. WsbAffirm( sizeof(RP_DATA) == pReparseBuffer->ReparseDataLength , S_FALSE );
  482. //
  483. // Copy over the RP_DATA information
  484. //
  485. WsbAffirmHr(CopyRPDataToPlaceholder(pHsmData, pPlaceholder));
  486. } WsbCatch(hr);
  487. WsbTraceOut(OLESTR("CopyRPToPlaceholder"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  488. return( hr );
  489. }
  490. HRESULT
  491. CFsaScanItem::CalculateCurrentCRCAndUSN(
  492. IN LONGLONG offset,
  493. IN LONGLONG size,
  494. OUT ULONG *pCurrentCRC,
  495. OUT LONGLONG *pUsn
  496. )
  497. {
  498. HRESULT hr = S_OK;
  499. HRESULT hrTest = S_OK;
  500. CWsbStringPtr path;
  501. IO_STATUS_BLOCK IoStatusBlock;
  502. HANDLE handle = INVALID_HANDLE_VALUE;
  503. FILE_BASIC_INFORMATION basicInformation;
  504. try {
  505. WsbTraceIn(OLESTR("CFsaScanItem::CalculateCurrentCRCAndUSN"), OLESTR("offset = <%I64d>, size = <%I64d>"),
  506. offset, size);
  507. //
  508. // Create the real file name we need to open, under the covers this
  509. // allocates the buffer since the path pointer is null
  510. //
  511. WsbAffirmHr( GetFullPathAndName( OLESTR("\\\\?\\"), NULL, &path, 0));
  512. //WsbAffirmHr( GetFullPathAndName( NULL, NULL, &path, 0));
  513. WsbTrace(OLESTR("CFsaScanItem::CalculateCurrentCRCAndUSN for file <%ls>"), (OLECHAR *)path);
  514. // Open the file.
  515. WsbAffirmHr( OpenObject( path,
  516. FILE_NON_DIRECTORY_FILE,
  517. FILE_READ_DATA | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES,
  518. EXCLUSIVE_FLAG,
  519. FILE_OPEN,
  520. &IoStatusBlock,
  521. &handle ) );
  522. //
  523. // The open worked, our handle should be valid but we check to be
  524. // safe and sure
  525. //
  526. WsbAssertHandle( handle );
  527. //
  528. // Get the current attributes of the file and the times
  529. //
  530. WsbAssertNtStatus( NtQueryInformationFile( handle,
  531. &IoStatusBlock,
  532. (PVOID)&basicInformation,
  533. sizeof( basicInformation ),
  534. FileBasicInformation ) );
  535. //
  536. // Set the time flags so that when we close the handle the
  537. // time are not updated on the file and the FileAttributes
  538. //
  539. basicInformation.CreationTime.QuadPart = -1;
  540. basicInformation.LastAccessTime.QuadPart = -1;
  541. basicInformation.LastWriteTime.QuadPart = -1;
  542. basicInformation.ChangeTime.QuadPart = -1;
  543. WsbAssertNtStatus( NtSetInformationFile( handle,
  544. &IoStatusBlock,
  545. (PVOID)&basicInformation,
  546. sizeof( basicInformation ),
  547. FileBasicInformation ) );
  548. //
  549. // Calculate the CRC
  550. //
  551. WsbAffirmHr(CalculateCurrentCRCInternal(handle, offset, size, pCurrentCRC));
  552. //
  553. // Calculate the USN
  554. //
  555. *pUsn = 0;
  556. hr = WsbGetUsnFromFileHandle(handle, FALSE, pUsn);
  557. if (S_OK != hr) {
  558. //
  559. // If we can't get the USN set it to 0 which is an invalid
  560. // USN and keep going.
  561. *pUsn = 0;
  562. hr = S_OK;
  563. }
  564. //
  565. // Close the file
  566. //
  567. NtClose( handle );
  568. handle = INVALID_HANDLE_VALUE;
  569. } WsbCatch( hr );
  570. //
  571. // Close the file for sure
  572. //
  573. if( INVALID_HANDLE_VALUE != handle) {
  574. NtClose( handle );
  575. }
  576. WsbTraceOut(OLESTR("CalculateCurrentCRCAndUSN"), OLESTR("hr = <%ls>, CRC is <%ls>, USN is <%ls>"),
  577. WsbHrAsString(hr), WsbPtrToUlongAsString(pCurrentCRC), WsbPtrToLonglongAsString(pUsn));
  578. return(hr);
  579. }
  580. HRESULT
  581. CFsaScanItem::CalculateCurrentCRCInternal(
  582. IN HANDLE handle,
  583. IN LONGLONG offset,
  584. IN LONGLONG size,
  585. ULONG *pCurrentCRC
  586. )
  587. {
  588. HRESULT hr = S_OK;
  589. HRESULT hrTest = S_OK;
  590. register ULONG crc32 = 0;
  591. LONGLONG bytesRemaining;
  592. LONGLONG bytesToRead;
  593. ULONG bufferSize;
  594. ULONG bytesRead;
  595. CHAR * pBuffer = 0;
  596. CHAR * pCurrent;
  597. IO_STATUS_BLOCK IoStatusBlock;
  598. try {
  599. WsbTraceIn(OLESTR("CFsaScanItem::CalculateCurrentCRCInternal"), OLESTR("offset = <%I64d>, size = <%I64d>"),
  600. offset, size);
  601. // set initial value of CRC to 'pre-conditioning value'
  602. INITIALIZE_CRC(crc32);
  603. //
  604. // Set up to read where we want to start
  605. //
  606. LARGE_INTEGER startPoint;
  607. startPoint.QuadPart = offset;
  608. // Get the size of the file.
  609. bytesToRead = size;
  610. //
  611. // Figure out the size of the buffer to create
  612. //
  613. if (bytesToRead < 1024*1024) {
  614. //
  615. // Allocate one buffer the size of the file
  616. //
  617. bufferSize = (ULONG)bytesToRead;
  618. } else {
  619. bufferSize = (1024 * 1024);
  620. }
  621. pBuffer = (CHAR *)malloc(bufferSize);
  622. if (0 == pBuffer) {
  623. //
  624. // Try again for half the space
  625. //
  626. bufferSize = bufferSize / 2;
  627. pBuffer = (CHAR *)malloc(bufferSize);
  628. if (0 == pBuffer) {
  629. WsbThrow( E_OUTOFMEMORY );
  630. }
  631. }
  632. // Start calculating CRC by processing a 'chunk' of the file at a time.
  633. // While there are still chunks left, read that amount. Otherwise read the amount left.
  634. for (bytesRemaining = bytesToRead; bytesRemaining > 0; bytesRemaining -= bytesRead) {
  635. // Read data from the file.
  636. WsbAssertNtStatus(NtReadFile(handle, NULL, NULL, NULL, &IoStatusBlock, pBuffer, bufferSize, &startPoint, NULL));
  637. bytesRead = (DWORD)IoStatusBlock.Information;
  638. startPoint.QuadPart += bytesRead;
  639. // Each byte needs to be added into the CRC.
  640. for (pCurrent = pBuffer; (pCurrent < (pBuffer + bytesRead)) && (S_OK == hr); pCurrent++) {
  641. hrTest = WsbCRCReadFile((UCHAR *)pCurrent, &crc32);
  642. if (S_OK != hrTest) {
  643. hr = S_FALSE;
  644. }
  645. }
  646. }
  647. // return ones-complement of the calc'd CRC value - this is the actual CRC
  648. FINIALIZE_CRC(crc32);
  649. *pCurrentCRC = crc32;
  650. } WsbCatch( hr );
  651. //
  652. // Make sure allocated memory is freed
  653. //
  654. if (0 != pBuffer) {
  655. free(pBuffer);
  656. }
  657. WsbTraceOut(OLESTR("CalculateCurrentCRCInternal"), OLESTR("hr = <%ls>, CRC is <%ls>"), WsbHrAsString(hr), WsbPtrToUlongAsString(pCurrentCRC));
  658. return(hr);
  659. }
  660. HRESULT
  661. CFsaScanItem::CreatePlaceholder(
  662. IN LONGLONG offset,
  663. IN LONGLONG size,
  664. IN FSA_PLACEHOLDER placeholder,
  665. IN BOOL checkUsn,
  666. IN LONGLONG usn,
  667. OUT LONGLONG *pUsn
  668. )
  669. /*++
  670. Implements:
  671. IFsaScanItem::CreatePlaceholder().
  672. --*/
  673. {
  674. HRESULT hr = S_OK;
  675. CWsbStringPtr path;
  676. HANDLE handle = INVALID_HANDLE_VALUE;
  677. ULONG DesiredAccess;
  678. IO_STATUS_BLOCK IoStatusBlock;
  679. PREPARSE_DATA_BUFFER pReparseBuffer;
  680. UCHAR ReparseBuffer[sizeof(REPARSE_DATA_BUFFER) + sizeof(RP_DATA) + 10];
  681. NTSTATUS ntStatus;
  682. FILE_BASIC_INFORMATION basicInformation;
  683. LONGLONG lastWriteTime;
  684. LONGLONG nowUsn = 0;
  685. CWsbStringPtr volName;
  686. ULONG attributes;
  687. WsbTraceIn(OLESTR("CFsaScanItem::CreatePlaceholder"), OLESTR("offset = <%I64d>, size = <%I64d>, checkUsn = <%ls>, usn = <%I64d>"),
  688. offset, size, WsbBoolAsString(checkUsn), usn);
  689. try {
  690. BOOL wasReadOnly = FALSE;
  691. //
  692. // Set the offset and size information
  693. //
  694. placeholder.dataStreamStart = offset;
  695. placeholder.dataStreamSize = size;
  696. //
  697. // Get the pointers setup correctly to this buffer because the
  698. // type REPARSE_DATA_BUFFER actually doesn't have any space
  699. // allocated for the data and that is our own type, so get pointers
  700. // pointing into the real allocated space so we can use them
  701. //
  702. pReparseBuffer = (PREPARSE_DATA_BUFFER)ReparseBuffer;
  703. WsbAffirmHr( CopyPlaceholderToRP( &placeholder, pReparseBuffer, placeholder.isTruncated ) );
  704. //
  705. // Create the real file name we need to open, under the covers this
  706. // allocates the buffer since the path pointer is null
  707. //
  708. WsbAffirmHr( GetFullPathAndName( OLESTR("\\\\?\\"), NULL, &path, 0));
  709. //WsbAffirmHr( GetFullPathAndName( NULL, NULL, &path, 0));
  710. // Save whether this was readonly for later
  711. if (S_OK == IsReadOnly()) {
  712. wasReadOnly = TRUE;
  713. }
  714. //
  715. // Make sure the file is read/write
  716. WsbAffirmHr( MakeReadWrite() );
  717. //
  718. // Open the file to put the placeholder information in the reparse point
  719. //
  720. DesiredAccess = FILE_READ_DATA | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES ;
  721. WsbAffirmHr( OpenObject( path,
  722. FILE_NON_DIRECTORY_FILE | FILE_NO_INTERMEDIATE_BUFFERING,
  723. DesiredAccess,
  724. EXCLUSIVE_FLAG,
  725. FILE_OPEN,
  726. &IoStatusBlock,
  727. &handle ) );
  728. //
  729. // The open worked, our handle should be valid but we check to be
  730. // safe and sure
  731. //
  732. WsbAssertHandle( handle );
  733. //
  734. // Tell the USN journal that we are the source of the changes.
  735. //
  736. WsbAffirmHr(m_pResource->GetPath(&volName, 0));
  737. WsbAffirmHr(WsbMarkUsnSource(handle, volName));
  738. //
  739. // Get the USN from the file now before any writes occur.
  740. // Note: NtSetInformationFile will not change the USN if you set the FileAttributes to 0
  741. // and the dates to -1. Setting the attributes to 0 leaves them unchanged.
  742. //
  743. // (For now we skip this check for read-only files because the call to MakeReadWrite
  744. // changes the USN. This needs to be fixed in the future.)
  745. //
  746. if (checkUsn && !wasReadOnly) {
  747. //
  748. // Get the current USN for this file
  749. //
  750. hr = WsbGetUsnFromFileHandle(handle, FALSE, &nowUsn);
  751. if (S_OK != hr) {
  752. nowUsn = 0;
  753. hr = S_OK;
  754. }
  755. }
  756. //
  757. // Get the current attributes of the file and the times
  758. //
  759. WsbAssertNtStatus( NtQueryInformationFile( handle,
  760. &IoStatusBlock,
  761. (PVOID)&basicInformation,
  762. sizeof( basicInformation ),
  763. FileBasicInformation ) );
  764. lastWriteTime = basicInformation.LastWriteTime.QuadPart;
  765. //
  766. // Set the time flags so that when we close the handle the
  767. // time are not updated on the file and the FileAttributes
  768. // indicate the file is offline. You must do this AFTER you
  769. // get the USN because the NtSetInformationFile changes the USN
  770. //
  771. basicInformation.CreationTime.QuadPart = -1;
  772. basicInformation.LastAccessTime.QuadPart = -1;
  773. basicInformation.LastWriteTime.QuadPart = -1;
  774. basicInformation.ChangeTime.QuadPart = -1;
  775. //
  776. // Set the attributes to 0 to avoid the usn change (the file attributes will remain unchanged).
  777. //
  778. attributes = basicInformation.FileAttributes;
  779. basicInformation.FileAttributes = 0; // No change to attributes
  780. WsbAssertNtStatus( NtSetInformationFile( handle,
  781. &IoStatusBlock,
  782. (PVOID)&basicInformation,
  783. sizeof( basicInformation ),
  784. FileBasicInformation ) );
  785. basicInformation.FileAttributes = attributes;
  786. //
  787. // Make sure that the modify time of the file matches that
  788. // of the placeholder data.
  789. //
  790. if (lastWriteTime != placeholder.fileVersionId) {
  791. //
  792. // The file has changed - don't put the reparse point on the file.
  793. //
  794. hr = FSA_E_REPARSE_NOT_WRITTEN_FILE_CHANGED;
  795. WsbLogEvent(FSA_MESSAGE_REPARSE_NOT_WRITTEN_FILE_CHANGED, 0, NULL, WsbAbbreviatePath(path, 120), WsbHrAsString(hr), NULL);
  796. WsbThrow( hr );
  797. } else if (checkUsn) {
  798. //
  799. // If we are to check the USN do it now
  800. //
  801. //
  802. // Rember if a USN is 0, it is not useful information so we can't
  803. // rely on it
  804. //
  805. WsbTrace(OLESTR("CFsaScanItem::CreatePlaceholder premig usn = <%I64d>, current usn <%I64d>\n"),
  806. usn, nowUsn);
  807. if ((0 != nowUsn) && (0 != usn) && (nowUsn != usn)) {
  808. //
  809. // The file has changed - don't put the reparse point on the file.
  810. //
  811. hr = FSA_E_REPARSE_NOT_WRITTEN_FILE_CHANGED;
  812. WsbLogEvent(FSA_MESSAGE_REPARSE_NOT_WRITTEN_FILE_CHANGED, 0, NULL, WsbAbbreviatePath(path, 120), WsbHrAsString(hr), NULL);
  813. WsbThrow( hr );
  814. }
  815. }
  816. //
  817. // Make the file able to be a sparse file
  818. // Note we assert only if the error is not a disk full error because we can get STATUS_NO_DISK_SPACE from this call and we
  819. // do not want to see the log for that error.
  820. // This is because the file must be padded out to a 16 cluster boundry before being made sparse.
  821. //
  822. // Note that this call does not affect the files data. It just enables "sparseness" for the file.
  823. //
  824. ntStatus = NtFsControlFile( handle,
  825. NULL,
  826. NULL,
  827. NULL,
  828. &IoStatusBlock,
  829. FSCTL_SET_SPARSE,
  830. NULL,
  831. 0,
  832. NULL,
  833. 0 );
  834. if (!NT_SUCCESS(ntStatus)) {
  835. if (STATUS_DISK_FULL == ntStatus) {
  836. hr = FSA_E_REPARSE_NOT_CREATED_DISK_FULL;
  837. } else {
  838. hr = HRESULT_FROM_NT(ntStatus);
  839. }
  840. WsbLogEvent(FSA_MESSAGE_REPARSE_NOT_CREATED, 0, NULL,
  841. WsbAbbreviatePath(path, 120), WsbHrAsString(hr), NULL);
  842. WsbThrow(hr);
  843. }
  844. //
  845. // Do the work of setting the Reparse Point
  846. //
  847. ntStatus = NtFsControlFile( handle,
  848. NULL,
  849. NULL,
  850. NULL,
  851. &IoStatusBlock,
  852. FSCTL_SET_REPARSE_POINT,
  853. pReparseBuffer,
  854. FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer)
  855. + pReparseBuffer->ReparseDataLength,
  856. NULL,
  857. 0 );
  858. //
  859. // Check the return code, if everything worked update the in memory flag
  860. //
  861. if (!NT_SUCCESS(ntStatus)) {
  862. if (STATUS_DISK_FULL == ntStatus) {
  863. hr = FSA_E_REPARSE_NOT_CREATED_DISK_FULL;
  864. } else {
  865. hr = HRESULT_FROM_NT(ntStatus);
  866. }
  867. WsbLogEvent(FSA_MESSAGE_REPARSE_NOT_CREATED, 0, NULL,
  868. WsbAbbreviatePath(path, 120), WsbHrAsString(hr), NULL);
  869. WsbThrow(hr);
  870. }
  871. //
  872. // Now that we change the bit, change the in memory flags for
  873. // this scan item
  874. //
  875. m_findData.dwFileAttributes |= BIT_FOR_RP;
  876. //
  877. // Set the OFFLINE attribute to indicate the correct status of
  878. // the file
  879. //
  880. if( placeholder.isTruncated ) {
  881. basicInformation.FileAttributes |= BIT_FOR_TRUNCATED;
  882. } else {
  883. basicInformation.FileAttributes &= ~BIT_FOR_TRUNCATED;
  884. }
  885. basicInformation.FileAttributes |= FILE_ATTRIBUTE_NORMAL; // Just in case result was zero (then no attributes would be set)
  886. WsbAssertNtStatus( NtSetInformationFile( handle,
  887. &IoStatusBlock,
  888. (PVOID)&basicInformation,
  889. sizeof( basicInformation ),
  890. FileBasicInformation ) );
  891. //
  892. // Get the current attributes of the file and the times
  893. //
  894. WsbAssertNtStatus( NtQueryInformationFile( handle,
  895. &IoStatusBlock,
  896. (PVOID)&basicInformation,
  897. sizeof( basicInformation ),
  898. FileBasicInformation ) );
  899. //
  900. // Set the in memory copy of the attributes to the right values
  901. //
  902. m_findData.dwFileAttributes = basicInformation.FileAttributes;
  903. //
  904. // Restore original attributes if required (must be done before retrieving the USN
  905. // since changing attributes changes the USN as well)
  906. //
  907. if (TRUE == m_changedAttributes) {
  908. RestoreAttributes();
  909. }
  910. //
  911. // Before we close the file, get the USN to return to the caller
  912. // Writing the reparse information will change the USN.
  913. //
  914. hr = WsbGetUsnFromFileHandle(handle, TRUE, pUsn);
  915. if (S_OK != hr) {
  916. *pUsn = 0;
  917. hr = S_OK;
  918. }
  919. //
  920. // Close the file since we are done with it and set the handle to invalid
  921. //
  922. WsbAssertNtStatus( NtClose( handle ) );
  923. handle = INVALID_HANDLE_VALUE;
  924. //
  925. // Now that everything worked change the in memory flags for
  926. // this scan item
  927. //
  928. m_placeholder = placeholder;
  929. m_gotPlaceholder = TRUE;
  930. WsbTrace( OLESTR("(CreatePlaceholder) Reparse CRC <%ls>\n"),
  931. WsbLonglongAsString( m_placeholder.dataStreamCRC ) );
  932. } WsbCatch(hr);
  933. //
  934. // if we opened the file we need to close it
  935. //
  936. if( INVALID_HANDLE_VALUE != handle) {
  937. NtClose( handle );
  938. }
  939. WsbTraceOut(OLESTR("CFsaScanItem::CreatePlaceholder"), OLESTR("hr = <%ls>, usn = <%ls>"),
  940. WsbHrAsString(hr), WsbPtrToLonglongAsString(pUsn));
  941. return(hr);
  942. }
  943. HRESULT
  944. CFsaScanItem::DeletePlaceholder(
  945. IN LONGLONG /*offset*/,
  946. IN LONGLONG /*size*/
  947. )
  948. /*++
  949. Implements:
  950. IFsaScanItem::DeletePlaceholder().
  951. --*/
  952. {
  953. HRESULT hr = S_OK;
  954. CWsbStringPtr path;
  955. HANDLE handle = INVALID_HANDLE_VALUE;
  956. ULONG DesiredAccess;
  957. IO_STATUS_BLOCK IoStatusBlock;
  958. PREPARSE_DATA_BUFFER pReparseBuffer;
  959. UCHAR ReparseBuffer[sizeof(REPARSE_DATA_BUFFER) + sizeof(RP_DATA) + 10];
  960. NTSTATUS ntStatus;
  961. FILE_BASIC_INFORMATION basicInformation;
  962. WsbTraceIn(OLESTR("CFsaScanItem::DeletePlaceholder"), OLESTR(""));
  963. //
  964. // Remove the Reparse Point off the file
  965. //
  966. try {
  967. //
  968. // Create the real file name we need to open, under the covers this
  969. // allocates the buffer since the path pointer is null
  970. //
  971. WsbAffirmHr( GetFullPathAndName( OLESTR("\\\\?\\"), NULL, &path, 0));
  972. //WsbAffirmHr( GetFullPathAndName( NULL, NULL, &path, 0));
  973. // Make sure it is read/write
  974. WsbAffirmHr( MakeReadWrite() );
  975. //
  976. // Open the file to remove the placeholder information in the reparse point
  977. //
  978. DesiredAccess = FILE_READ_DATA | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES ;
  979. WsbAffirmHr( OpenObject( path,
  980. FILE_NON_DIRECTORY_FILE | FILE_NO_INTERMEDIATE_BUFFERING,
  981. DesiredAccess,
  982. EXCLUSIVE_FLAG,
  983. FILE_OPEN,
  984. &IoStatusBlock,
  985. &handle ) );
  986. //
  987. // The open worked, our handle should be valid but we check to be
  988. // safe and sure
  989. //
  990. WsbAssertHandle( handle );
  991. //
  992. // Get the current attributes of the file and the times
  993. //
  994. WsbAssertNtStatus( NtQueryInformationFile( handle,
  995. &IoStatusBlock,
  996. (PVOID)&basicInformation,
  997. sizeof( basicInformation ),
  998. FileBasicInformation ) );
  999. //
  1000. // Set the time flags so that when we close the handle the
  1001. // time are not updated on the file and the FileAttributes
  1002. // indicate the file is offline
  1003. //
  1004. basicInformation.CreationTime.QuadPart = -1;
  1005. basicInformation.LastAccessTime.QuadPart = -1;
  1006. basicInformation.LastWriteTime.QuadPart = -1;
  1007. basicInformation.ChangeTime.QuadPart = -1;
  1008. basicInformation.FileAttributes &= ~BIT_FOR_TRUNCATED;
  1009. basicInformation.FileAttributes |= FILE_ATTRIBUTE_NORMAL; // Just in case result was zero (then no attributes would be set)
  1010. WsbAssertNtStatus( NtSetInformationFile( handle,
  1011. &IoStatusBlock,
  1012. (PVOID)&basicInformation,
  1013. sizeof( basicInformation ),
  1014. FileBasicInformation ) );
  1015. m_findData.dwFileAttributes &= ~BIT_FOR_TRUNCATED;
  1016. m_originalAttributes &= ~BIT_FOR_TRUNCATED;
  1017. //
  1018. // Get the pointers setup correctly to this buffer because the
  1019. // type REPARSE_DATA_BUFFER actually doesn't have any space
  1020. // allocated for the data and that is our own type, so get pointers
  1021. // pointing into the real allocated space so we can use them
  1022. //
  1023. pReparseBuffer = (PREPARSE_DATA_BUFFER)ReparseBuffer;
  1024. pReparseBuffer->ReparseTag = IO_REPARSE_TAG_HSM ;
  1025. pReparseBuffer->ReparseDataLength = 0 ;
  1026. pReparseBuffer->Reserved = 0 ;
  1027. //
  1028. // Do the work of deleting the Reparse Point
  1029. //
  1030. ntStatus = NtFsControlFile( handle,
  1031. NULL,
  1032. NULL,
  1033. NULL,
  1034. &IoStatusBlock,
  1035. FSCTL_DELETE_REPARSE_POINT,
  1036. pReparseBuffer,
  1037. FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer),
  1038. NULL,
  1039. 0 );
  1040. //
  1041. // Check the return code - verify this is the correct way to check
  1042. //
  1043. WsbAssertNtStatus( ntStatus );
  1044. //
  1045. // Close the file since we are done with it and set the handle to invalid
  1046. //
  1047. WsbAssertNtStatus( NtClose( handle ) );
  1048. handle = INVALID_HANDLE_VALUE;
  1049. //
  1050. // Now that everything worked change the in memory flags for
  1051. // this scan item
  1052. //
  1053. m_findData.dwFileAttributes &= ~BIT_FOR_RP;
  1054. m_gotPlaceholder = FALSE;
  1055. } WsbCatch(hr);
  1056. //
  1057. // if we opened the file we need to close it
  1058. //
  1059. if( INVALID_HANDLE_VALUE != handle) {
  1060. NtClose( handle );
  1061. }
  1062. WsbTraceOut(OLESTR("CFsaScanItem::DeletePlaceholder"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1063. return(hr);
  1064. }
  1065. HRESULT
  1066. CFsaScanItem::GetFromRPIndex(
  1067. BOOL first
  1068. )
  1069. /*
  1070. Get file information from the Reparse Point Index
  1071. --*/
  1072. {
  1073. HRESULT hr = S_OK;
  1074. BOOLEAN bFirst;
  1075. bFirst = (BOOLEAN)( first ? TRUE : FALSE );
  1076. WsbTraceIn(OLESTR("CFsaScanItem::GetFromRPIndex"), OLESTR(""));
  1077. try {
  1078. HRESULT hrFindFileId;
  1079. IO_STATUS_BLOCK IoStatusBlock;
  1080. IFsaScanItem * pScanItem;
  1081. FILE_REPARSE_POINT_INFORMATION ReparsePointInfo;
  1082. NTSTATUS Status;
  1083. WsbAssert(0 != m_handleRPI, E_FAIL);
  1084. try_again:
  1085. Status = NtQueryDirectoryFile(m_handleRPI,
  1086. NULL, // Event
  1087. NULL, // ApcRoutine
  1088. NULL, // ApcContext
  1089. &IoStatusBlock,
  1090. &ReparsePointInfo,
  1091. sizeof(ReparsePointInfo),
  1092. FileReparsePointInformation,
  1093. TRUE, // ReturnSingleEntry
  1094. NULL, // FileName
  1095. bFirst ); // RestartScan
  1096. if (Status != STATUS_SUCCESS) {
  1097. WsbTrace(OLESTR("CFsaScanItem::GetFromRPIndex: CreateFileW failed, GetLastError = %ld\n"),
  1098. GetLastError());
  1099. WsbThrow(WSB_E_NOTFOUND);
  1100. }
  1101. // Reset some items in case this isn't the first call to
  1102. // FindFileId
  1103. if (INVALID_HANDLE_VALUE != m_handle) {
  1104. FindClose(m_handle);
  1105. m_handle = INVALID_HANDLE_VALUE;
  1106. }
  1107. if (TRUE == m_changedAttributes) {
  1108. RestoreAttributes();
  1109. }
  1110. // Find the file from the ID (not efficient or elegant, perhaps, but
  1111. // the code is already there).
  1112. pScanItem = this;
  1113. hrFindFileId = m_pResource->FindFileId(ReparsePointInfo.FileReference,
  1114. m_pSession, &pScanItem);
  1115. // If the FindFileId failed, we just skip that item and get the
  1116. // next one. This is to keep the scan from just stopping on this
  1117. // item. FindFileId could fail because the file has been deleted
  1118. // already or the NT code could have a bug that prevents finding
  1119. // the file name from the ID when the ID ends with 0x5C.
  1120. if (!SUCCEEDED(hrFindFileId)) {
  1121. bFirst = FALSE;
  1122. goto try_again;
  1123. }
  1124. WsbAffirmHr(pScanItem->Release()); // Get rid of extra ref. count
  1125. } WsbCatch(hr);
  1126. WsbTraceOut(OLESTR("CFsaScanItem::GetFromRPIndex"),
  1127. OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1128. return(hr);
  1129. }
  1130. HRESULT
  1131. CFsaScanItem::CheckUsnJournalForChanges(
  1132. LONGLONG StartUsn,
  1133. LONGLONG StopUsn,
  1134. BOOL* pChanged
  1135. )
  1136. /*
  1137. Check the USN Journal for changes to the unnamed data stream for this
  1138. file between the given USNs.
  1139. --*/
  1140. {
  1141. HRESULT hr = S_OK;
  1142. WsbTraceIn(OLESTR("CFsaScanItem::CheckUsnJournalForChanges"), OLESTR(""));
  1143. *pChanged = FALSE;
  1144. try {
  1145. LONGLONG fileId;
  1146. CWsbStringPtr volName;
  1147. WsbAffirm(StartUsn <= StopUsn, E_UNEXPECTED);
  1148. WsbAffirmHr(m_pResource->GetPath(&volName, 0));
  1149. WsbAffirmHr(GetFileId(&fileId));
  1150. WsbAffirmHr(WsbCheckUsnJournalForChanges(volName, fileId, StartUsn,
  1151. StopUsn, pChanged));
  1152. } WsbCatch(hr);
  1153. WsbTraceOut(OLESTR("CFsaScanItem::CheckUsnJournalForChanges"),
  1154. OLESTR("changed = %ls, hr = <%ls>"), WsbBoolAsString(*pChanged),
  1155. WsbHrAsString(hr));
  1156. return(hr);
  1157. }
  1158. HRESULT
  1159. CFsaScanItem::FindFirstInRPIndex(
  1160. IN IFsaResource* pResource,
  1161. IN IHsmSession* pSession
  1162. )
  1163. /*++
  1164. Implements:
  1165. IFsaResource::FindFirstInRPIndex
  1166. --*/
  1167. {
  1168. HRESULT hr = S_OK;
  1169. WsbTraceIn(OLESTR("CFsaScanItem::FindFirstInRPIndex"), OLESTR(""));
  1170. try {
  1171. CWsbStringPtr path;
  1172. WsbAssert(0 != pResource, E_POINTER);
  1173. // Store off some of the scan information.
  1174. m_pResource = pResource;
  1175. m_pSession = pSession;
  1176. // Generate the Reparse Point Index directory name for this volume
  1177. WsbAffirmHr(pResource->GetPath(&path, 0));
  1178. WsbAffirmHr(path.Prepend("\\\\?\\"));
  1179. WsbAffirmHr(path.Append("$Extend\\$Reparse:$R:$INDEX_ALLOCATION"));
  1180. WsbTrace(OLESTR("CFsaScanItem::FindFirstInRPIndex: path = <%ls>\n"),
  1181. static_cast<WCHAR*>(path));
  1182. // Open the Reparse Point Index
  1183. m_handleRPI = CreateFileW(static_cast<WCHAR*>(path),
  1184. GENERIC_READ,
  1185. FILE_SHARE_READ,
  1186. NULL,
  1187. OPEN_EXISTING,
  1188. FILE_FLAG_BACKUP_SEMANTICS | SECURITY_IMPERSONATION,
  1189. NULL );
  1190. if (INVALID_HANDLE_VALUE == m_handleRPI) {
  1191. WsbTrace(OLESTR("CFsaScanItem::FindFirstInRPIndex: CreateFileW failed, GetLastError = %ld\n"),
  1192. GetLastError());
  1193. WsbThrow(WSB_E_NOTFOUND);
  1194. }
  1195. // Get file information
  1196. WsbAffirmHr(GetFromRPIndex(TRUE));
  1197. } WsbCatch(hr);
  1198. WsbTraceOut(OLESTR("CFsaScanItem::FindFirstInRPIndex"),
  1199. OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1200. return(hr);
  1201. }
  1202. HRESULT
  1203. CFsaScanItem::FindFirstPlaceholder(
  1204. IN OUT LONGLONG* pOffset,
  1205. IN OUT LONGLONG* pSize,
  1206. IN OUT FSA_PLACEHOLDER* pPlaceholder
  1207. )
  1208. /*++
  1209. Implements:
  1210. IFsaScanItem::FindFirstPlaceholder().
  1211. --*/
  1212. {
  1213. HRESULT hr = S_OK;
  1214. WsbTraceIn(OLESTR("CFsaScanItem::FindFirstPlaceholder"), OLESTR(""));
  1215. try {
  1216. WsbAssert(0 != pOffset, E_POINTER);
  1217. WsbAssert(0 != pSize, E_POINTER);
  1218. WsbAssert(0 != pPlaceholder, E_POINTER);
  1219. // Until these routines get rewritten, assume that the first placeholder is the one for the
  1220. // who file that is returned by GetPlaceholder().
  1221. *pOffset = 0;
  1222. WsbAffirmHr(GetLogicalSize(pSize));
  1223. // The code above assumes that a WSB_E_NOTFOUND error will be returned if there is no
  1224. // reparse point.
  1225. try {
  1226. WsbAffirmHr(GetPlaceholder(*pOffset, *pSize, pPlaceholder));
  1227. } WsbCatchAndDo(hr, if (E_UNEXPECTED == hr) {hr = WSB_E_NOTFOUND;});
  1228. } WsbCatch(hr);
  1229. WsbTraceOut(OLESTR("CFsaScanItem::FindFirstPlaceholder"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1230. return(hr);
  1231. }
  1232. HRESULT
  1233. CFsaScanItem::FindNextInRPIndex(
  1234. void
  1235. )
  1236. /*++
  1237. Implements:
  1238. IFsaResource::FindNextInRPIndex
  1239. --*/
  1240. {
  1241. HRESULT hr = S_OK;
  1242. WsbTraceIn(OLESTR("CFsaScanItem::FindNextInRPIndex"), OLESTR(""));
  1243. try {
  1244. WsbAssert(0 != m_handleRPI, E_FAIL);
  1245. // Get file information
  1246. WsbAffirmHr(GetFromRPIndex(FALSE));
  1247. } WsbCatch(hr);
  1248. WsbTraceOut(OLESTR("CFsaScanItem::FindNextInRPIndex"),
  1249. OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1250. return(hr);
  1251. }
  1252. HRESULT
  1253. CFsaScanItem::FindNextPlaceholder(
  1254. IN OUT LONGLONG* pOffset,
  1255. IN OUT LONGLONG* pSize,
  1256. IN OUT FSA_PLACEHOLDER* pPlaceholder
  1257. )
  1258. /*++
  1259. Implements:
  1260. IFsaScanItem::FindNextPlaceholder().
  1261. --*/
  1262. {
  1263. HRESULT hr = S_OK;
  1264. WsbTraceIn(OLESTR("CFsaScanItem::FindNext"), OLESTR(""));
  1265. try {
  1266. WsbAssert(0 != pOffset, E_POINTER);
  1267. WsbAssert(0 != pSize, E_POINTER);
  1268. WsbAssert(0 != pPlaceholder, E_POINTER);
  1269. // Until these routines get rewritten, assume there is only one placeholder.
  1270. hr = WSB_E_NOTFOUND;
  1271. } WsbCatch(hr);
  1272. WsbTraceOut(OLESTR("CFsaScanItem::FindNextPlaceholder"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1273. return(hr);
  1274. }
  1275. HRESULT
  1276. CFsaScanItem::GetFileId(
  1277. OUT LONGLONG* pFileId
  1278. )
  1279. /*++
  1280. Implements:
  1281. IFsaScanItem::GetFileId().
  1282. --*/
  1283. {
  1284. HANDLE handle = INVALID_HANDLE_VALUE;
  1285. HRESULT hr = S_OK;
  1286. WsbTraceIn(OLESTR("CFsaScanItem::GetFileId"), OLESTR(""));
  1287. try {
  1288. ULONG DesiredAccess;
  1289. FILE_INTERNAL_INFORMATION iInfo;
  1290. IO_STATUS_BLOCK IoStatusBlock;
  1291. CWsbStringPtr path;
  1292. WsbAssert(0 != pFileId, E_POINTER);
  1293. //
  1294. // Create the real file name we need to open, under the covers this
  1295. // allocates the buffer since the path pointer is null
  1296. //
  1297. WsbAffirmHr( GetFullPathAndName( OLESTR("\\\\?\\"), NULL, &path, 0));
  1298. //WsbAffirmHr( GetFullPathAndName( NULL, NULL, &path, 0));
  1299. WsbTrace(OLESTR("CFsaScanItem::GetFileId, full Path = <%ls>\n"),
  1300. static_cast<WCHAR*>(path));
  1301. //
  1302. // Open the file
  1303. //
  1304. DesiredAccess = FILE_READ_ATTRIBUTES ;
  1305. WsbAffirmHr( OpenObject( path,
  1306. FILE_NON_DIRECTORY_FILE,
  1307. DesiredAccess,
  1308. SHARE_FLAGS,
  1309. FILE_OPEN,
  1310. &IoStatusBlock,
  1311. &handle ) );
  1312. //
  1313. // The open worked, our handle should be valid but we check to be
  1314. // safe and sure
  1315. //
  1316. WsbAssertHandle( handle );
  1317. // Get the internal information
  1318. WsbAssertNtStatus( NtQueryInformationFile( handle,
  1319. &IoStatusBlock,
  1320. &iInfo,
  1321. sizeof(FILE_INTERNAL_INFORMATION),
  1322. FileInternalInformation ));
  1323. // Get the file id
  1324. *pFileId = iInfo.IndexNumber.QuadPart;
  1325. //
  1326. // Close the file since we are done with it and set the handle to invalid
  1327. //
  1328. WsbAssertNtStatus( NtClose( handle ) );
  1329. handle = INVALID_HANDLE_VALUE;
  1330. } WsbCatchAndDo(hr,
  1331. WsbTrace(OLESTR("CFsaScanItem::GetFileId, GetLastError = %lx\n"),
  1332. GetLastError());
  1333. );
  1334. //
  1335. // if we opened the file we need to close it
  1336. //
  1337. if( INVALID_HANDLE_VALUE != handle) {
  1338. NtClose( handle );
  1339. }
  1340. WsbTraceOut(OLESTR("CFsaScanItem::GetFileId"), OLESTR("Hr = <%ls>, FileId = %I64x"),
  1341. WsbHrAsString(hr), *pFileId);
  1342. return(hr);
  1343. }
  1344. HRESULT
  1345. CFsaScanItem::GetFileUsn(
  1346. OUT LONGLONG* pFileUsn
  1347. )
  1348. /*++
  1349. Routine Description:
  1350. Get the current USN Journal number for this file.
  1351. Arguments:
  1352. pFileUsn - Pointer to File USN to be returned.
  1353. Return Value:
  1354. S_OK - success
  1355. --*/
  1356. {
  1357. HANDLE handle = INVALID_HANDLE_VALUE;
  1358. HRESULT hr = S_OK;
  1359. WsbTraceIn(OLESTR("CFsaScanItem::GetFileUsn"), OLESTR(""));
  1360. try {
  1361. ULONG DesiredAccess;
  1362. IO_STATUS_BLOCK IoStatusBlock;
  1363. CWsbStringPtr path;
  1364. WsbAssert(pFileUsn, E_POINTER);
  1365. //
  1366. // Create the real file name we need to open, under the covers this
  1367. // allocates the buffer since the path pointer is null
  1368. //
  1369. WsbAffirmHr( GetFullPathAndName( OLESTR("\\\\?\\"), NULL, &path, 0));
  1370. WsbTrace(OLESTR("CFsaScanItem::GetFileUsn, full Path = <%ls>\n"),
  1371. static_cast<WCHAR*>(path));
  1372. //
  1373. // Open the file
  1374. //
  1375. DesiredAccess = FILE_READ_ATTRIBUTES ;
  1376. WsbAffirmHr( OpenObject( path,
  1377. FILE_NON_DIRECTORY_FILE | FILE_NO_INTERMEDIATE_BUFFERING,
  1378. DesiredAccess,
  1379. SHARE_FLAGS,
  1380. FILE_OPEN,
  1381. &IoStatusBlock,
  1382. &handle ) );
  1383. //
  1384. // The open worked, our handle should be valid but we check to be
  1385. // safe and sure
  1386. //
  1387. WsbAssertHandle( handle );
  1388. // Get the internal information
  1389. WsbAffirmHr(WsbGetUsnFromFileHandle(handle, FALSE, pFileUsn));
  1390. //
  1391. // Close the file since we are done with it and set the handle to invalid
  1392. //
  1393. WsbAssertNtStatus( NtClose( handle ) );
  1394. handle = INVALID_HANDLE_VALUE;
  1395. } WsbCatchAndDo(hr,
  1396. WsbTrace(OLESTR("CFsaScanItem::GetFileUsn, GetLastError = %lx\n"),
  1397. GetLastError());
  1398. );
  1399. //
  1400. // if we opened the file we need to close it
  1401. //
  1402. if( INVALID_HANDLE_VALUE != handle) {
  1403. NtClose( handle );
  1404. }
  1405. WsbTraceOut(OLESTR("CFsaScanItem::GetFileUsn"), OLESTR("Hr = <%ls>, FileUsn = %I64d"),
  1406. WsbHrAsString(hr), *pFileUsn);
  1407. return(hr);
  1408. }
  1409. HRESULT
  1410. CFsaScanItem::GetPlaceholder(
  1411. IN LONGLONG offset,
  1412. IN LONGLONG size,
  1413. OUT FSA_PLACEHOLDER* pPlaceholder
  1414. )
  1415. /*++
  1416. Implements:
  1417. IFsaScanItem::GetPlaceholder().
  1418. --*/
  1419. {
  1420. WsbTraceIn(OLESTR("CFsaScanItem::GetPlaceholder"), OLESTR(""));
  1421. HRESULT hr = S_OK;
  1422. //
  1423. // If we already have the placeholder information just return it
  1424. //
  1425. try {
  1426. //
  1427. // Validate the file is managed. If it is the affirm will succeed.
  1428. // If the file is not managed then we can only tell the caller the
  1429. // problem.
  1430. //
  1431. WsbAffirmHr(hr = IsManaged(offset, size));
  1432. //
  1433. // Make sure the file is managed - will return S_OK
  1434. //
  1435. WsbAffirm( S_OK == hr, FSA_E_NOTMANAGED );
  1436. //
  1437. // Assert that the internal flag for the data is set, should
  1438. // always be on if the hr was S_OK above
  1439. //
  1440. WsbAssert( m_gotPlaceholder, E_UNEXPECTED );
  1441. //
  1442. // Copy the data to the callers structure
  1443. //
  1444. *pPlaceholder = m_placeholder;
  1445. } WsbCatch(hr);
  1446. WsbTraceOut(OLESTR("CFsaScanItem::GetPlaceholder"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1447. return(hr);
  1448. }
  1449. HRESULT
  1450. CFsaScanItem::HasExtendedAttributes(
  1451. void
  1452. )
  1453. /*++
  1454. Implements:
  1455. IFsaScanItem::HasExtendedAttributes().
  1456. --*/
  1457. {
  1458. HRESULT hr = S_FALSE;
  1459. HANDLE handle = INVALID_HANDLE_VALUE;
  1460. CWsbStringPtr path;
  1461. ULONG desiredAccess;
  1462. IO_STATUS_BLOCK ioStatusBlock;
  1463. FILE_EA_INFORMATION eaInformation;
  1464. try {
  1465. // Create the real file name we need to open, under the covers this
  1466. // allocates the buffer since the path pointer is null
  1467. WsbAffirmHr(GetFullPathAndName(OLESTR("\\\\?\\"), NULL, &path, 0));
  1468. //WsbAffirmHr(GetFullPathAndName(NULL, NULL, &path, 0));
  1469. // Open the file to get the attributes
  1470. desiredAccess = FILE_READ_ATTRIBUTES;
  1471. WsbAffirmHr(OpenObject(path, FILE_NON_DIRECTORY_FILE | FILE_NO_INTERMEDIATE_BUFFERING, desiredAccess, SHARE_FLAGS,
  1472. FILE_OPEN, &ioStatusBlock, &handle));
  1473. // The open worked, our handle should be valid but we check to be
  1474. // safe and sure
  1475. WsbAssertHandle(handle);
  1476. // Get the current attributes of the file.
  1477. WsbAssertNtStatus(NtQueryInformationFile(handle, &ioStatusBlock, (VOID*) &eaInformation, sizeof(eaInformation ), FileEaInformation));
  1478. // Close the file since we are done with it and set the handle to invalid
  1479. WsbAssertNtStatus(NtClose(handle));
  1480. handle = INVALID_HANDLE_VALUE;
  1481. // Are there any EAs present?
  1482. if (eaInformation.EaSize != 0) {
  1483. hr = S_OK;
  1484. }
  1485. } WsbCatch(hr);
  1486. // if we opened the file we need to close it
  1487. if (INVALID_HANDLE_VALUE != handle) {
  1488. NtClose(handle);
  1489. }
  1490. return(hr);
  1491. }
  1492. HRESULT
  1493. CFsaScanItem::IsALink(
  1494. void
  1495. )
  1496. /*++
  1497. Implements:
  1498. IFsaScanItem::IsALink().
  1499. --*/
  1500. {
  1501. HRESULT hr = S_FALSE;
  1502. LONGLONG size;
  1503. //
  1504. // The file is a link if it is a reparse point and it is not our
  1505. // type.
  1506. //
  1507. WsbAffirmHr(GetLogicalSize(&size));
  1508. if (((m_findData.dwFileAttributes & BIT_FOR_RP) != 0) &&
  1509. (!(IsManaged(0, size) == S_OK))) {
  1510. hr = S_OK;
  1511. }
  1512. return(hr);
  1513. }
  1514. HRESULT
  1515. CFsaScanItem::IsManaged(
  1516. IN LONGLONG /*offset*/,
  1517. IN LONGLONG /*size*/
  1518. )
  1519. /*++
  1520. Implements:
  1521. IFsaScanItem::IsManaged().
  1522. --*/
  1523. {
  1524. HRESULT hr = S_FALSE;
  1525. CWsbStringPtr path;
  1526. HANDLE handle = INVALID_HANDLE_VALUE;
  1527. IO_STATUS_BLOCK IoStatusBlock;
  1528. UCHAR ReparseBuffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
  1529. NTSTATUS ntStatus;
  1530. ULONG DesiredAccess;
  1531. BOOL actualOfflineStatus = FALSE;
  1532. BOOL readReparseData = FALSE; // Used to know if we got an error reading the reparse data
  1533. BOOL changeOfflineStatus = FALSE;
  1534. FILE_BASIC_INFORMATION basicInformation;
  1535. CWsbStringPtr volName;
  1536. HRESULT saveHr;
  1537. WsbTraceIn(OLESTR("CFsaScanItem::IsManaged"), OLESTR(""));
  1538. //
  1539. // If the file has a reparse point then we need to get the information
  1540. // so we can tell if it is our type. Whether it is premigrated or
  1541. // truncate is not for this function to care, if it is either then
  1542. // the return is S_OK.
  1543. //
  1544. //
  1545. // If we already know we manage this file and have the placeholder
  1546. // information then tell caller
  1547. //
  1548. if ( m_gotPlaceholder) {
  1549. hr = S_OK;
  1550. actualOfflineStatus = m_placeholder.isTruncated;
  1551. readReparseData = TRUE;
  1552. //
  1553. // We don't know the answer so lets first check the reparse point bit.
  1554. // If it is not set then this is not managed by us
  1555. //
  1556. } else if ( (m_findData.dwFileAttributes & BIT_FOR_RP) == 0) {
  1557. hr = S_FALSE;
  1558. actualOfflineStatus = FALSE;
  1559. readReparseData = TRUE;
  1560. //
  1561. // So we know it has a reparse point but do not know what kind so
  1562. // lets get the data and fill in our global if we need
  1563. //
  1564. } else {
  1565. try {
  1566. //
  1567. // If the reparse point is not our type we get out now. This avoids a problem with SIS keeping
  1568. // the backing file open when one of their link files is open. Once we open the link file the backing file is
  1569. // opened by their filter and held open. If we attempt to migrate it later we get an error because it is open exclusive.
  1570. // This bit of code prevents us from being the one to trigger this condition - there is nothing we can do if some other
  1571. // process caused it to happen.
  1572. //
  1573. if (m_findData.dwReserved0 != IO_REPARSE_TAG_HSM) {
  1574. readReparseData = TRUE;
  1575. WsbThrow(S_FALSE);
  1576. }
  1577. //
  1578. // Create the real file name we need to open, under the
  1579. // covers this allocates the buffer since the path pointer
  1580. // is null
  1581. //
  1582. WsbAffirmHr( GetFullPathAndName( OLESTR("\\\\?\\"), NULL, &path, 0));
  1583. //WsbAffirmHr( GetFullPathAndName( NULL, NULL, &path, 0));
  1584. //
  1585. // Open the file to read the placeholder information in the reparse point
  1586. //
  1587. //DesiredAccess = FILE_READ_DATA | FILE_READ_ATTRIBUTES ;
  1588. DesiredAccess = FILE_READ_ATTRIBUTES ;
  1589. WsbAffirmHr( OpenObject( path,
  1590. FILE_NON_DIRECTORY_FILE | FILE_NO_INTERMEDIATE_BUFFERING,
  1591. DesiredAccess,
  1592. SHARE_FLAGS,
  1593. FILE_OPEN,
  1594. &IoStatusBlock,
  1595. &handle ) );
  1596. //
  1597. // The open worked, our handle should be valid but we check to be
  1598. // safe and sure
  1599. //
  1600. WsbAssertHandle( handle );
  1601. //
  1602. // Read the placeholder information
  1603. //
  1604. ntStatus = NtFsControlFile( handle,
  1605. NULL,
  1606. NULL,
  1607. NULL,
  1608. &IoStatusBlock,
  1609. FSCTL_GET_REPARSE_POINT,
  1610. NULL,
  1611. 0,
  1612. &ReparseBuffer,
  1613. sizeof( ReparseBuffer ) );
  1614. //
  1615. // Verify that the get really worked. NOTE: If the reparse
  1616. // point is not there, it could be that it has been deleted since
  1617. // we last got the bits. We should just indicate that the file
  1618. // is not managed.
  1619. //
  1620. if (STATUS_NOT_A_REPARSE_POINT == ntStatus) {
  1621. readReparseData = TRUE;
  1622. WsbThrow(S_FALSE);
  1623. }
  1624. WsbAssertNtStatus( ntStatus );
  1625. //
  1626. // Close the file since we are done with it
  1627. //
  1628. WsbAssertNtStatus( NtClose( handle ) );
  1629. handle = INVALID_HANDLE_VALUE;
  1630. readReparseData = TRUE;
  1631. //
  1632. // Get the pointers setup correctly to this buffer because the
  1633. // type REPARSE_DATA_BUFFER actually doesn't have any space
  1634. // allocated for the data and that is our own type, so get pointers
  1635. // pointing into the real allocated space so we can use them
  1636. //
  1637. WsbAffirmHrOk( CopyRPToPlaceholder( (PREPARSE_DATA_BUFFER)ReparseBuffer, &m_placeholder ) );
  1638. actualOfflineStatus = m_placeholder.isTruncated;
  1639. //
  1640. // Set flag indicating placeholder found and information in memory
  1641. //
  1642. m_gotPlaceholder = TRUE;
  1643. hr = S_OK;
  1644. } WsbCatch(hr);
  1645. //
  1646. // if we opened the file we need to close it
  1647. //
  1648. if( INVALID_HANDLE_VALUE != handle) {
  1649. NtClose( handle );
  1650. }
  1651. }
  1652. saveHr = hr;
  1653. // Check the actual offline status against the offline bit and fix it if necessary.
  1654. if (readReparseData) { // If there was no error getting the reparse data
  1655. WsbTrace(OLESTR("CFsaScanItem::IsManaged: Checking offline status %x - actual = %x\n"),
  1656. m_findData.dwFileAttributes & BIT_FOR_TRUNCATED, actualOfflineStatus );
  1657. switch (actualOfflineStatus) {
  1658. case TRUE:
  1659. if (!(m_findData.dwFileAttributes & BIT_FOR_TRUNCATED)) {
  1660. // Offline bit is not set and should be - set it.
  1661. m_findData.dwFileAttributes |= BIT_FOR_TRUNCATED;
  1662. m_originalAttributes |= BIT_FOR_TRUNCATED; // Just in case we have changed to read/write;
  1663. changeOfflineStatus = TRUE;
  1664. }
  1665. break;
  1666. case FALSE:
  1667. if (m_findData.dwFileAttributes & BIT_FOR_TRUNCATED) {
  1668. // Offline bit is set and should not be - clear it.
  1669. m_findData.dwFileAttributes &= ~BIT_FOR_TRUNCATED;
  1670. m_originalAttributes &= ~BIT_FOR_TRUNCATED; // Just in case we have changed to read/write;
  1671. changeOfflineStatus = TRUE;
  1672. }
  1673. break;
  1674. }
  1675. if (changeOfflineStatus) {
  1676. // Set the new attribute
  1677. WsbTrace(OLESTR("CFsaScanItem::IsManaged: Changing offline status %x - actual = %x\n"),
  1678. m_findData.dwFileAttributes & BIT_FOR_TRUNCATED, actualOfflineStatus );
  1679. try {
  1680. //
  1681. // Create the real file name we need to open, under the
  1682. // covers this allocates the buffer since the path pointer
  1683. // is null
  1684. //
  1685. WsbAffirmHr( GetFullPathAndName( OLESTR("\\\\?\\"), NULL, &path, 0));
  1686. //
  1687. // Open the file to set attributes
  1688. //
  1689. DesiredAccess = FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES;
  1690. WsbAffirmHr( OpenObject( path,
  1691. FILE_NON_DIRECTORY_FILE | FILE_NO_INTERMEDIATE_BUFFERING,
  1692. DesiredAccess,
  1693. SHARE_FLAGS,
  1694. FILE_OPEN,
  1695. &IoStatusBlock,
  1696. &handle ) );
  1697. //
  1698. // The open worked, our handle should be valid but we check to be
  1699. // safe and sure
  1700. //
  1701. WsbAssertHandle( handle );
  1702. WsbAffirmHr(m_pResource->GetPath(&volName, 0));
  1703. WsbAffirmHr(WsbMarkUsnSource(handle, volName));
  1704. // Set the time flags so that when we close the handle the
  1705. // time are not updated on the file and the FileAttributes
  1706. basicInformation.CreationTime.QuadPart = -1;
  1707. basicInformation.LastAccessTime.QuadPart = -1;
  1708. basicInformation.LastWriteTime.QuadPart = -1;
  1709. basicInformation.ChangeTime.QuadPart = -1;
  1710. basicInformation.FileAttributes = m_findData.dwFileAttributes;
  1711. WsbAffirmNtStatus(NtSetInformationFile(handle, &IoStatusBlock, (PVOID)&basicInformation, sizeof(basicInformation), FileBasicInformation));
  1712. //
  1713. // Close the file since we are done with it
  1714. //
  1715. WsbAssertNtStatus( NtClose( handle ) );
  1716. handle = INVALID_HANDLE_VALUE;
  1717. } WsbCatch(hr);
  1718. //
  1719. // if we opened the file we need to close it
  1720. //
  1721. if( INVALID_HANDLE_VALUE != handle) {
  1722. NtClose( handle );
  1723. }
  1724. }
  1725. }
  1726. hr = saveHr;
  1727. WsbTraceOut(OLESTR("CFsaScanItem::IsManaged"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1728. return(hr);
  1729. }
  1730. HRESULT
  1731. CFsaScanItem::IsPremigrated(
  1732. IN LONGLONG offset,
  1733. IN LONGLONG size
  1734. )
  1735. /*++
  1736. Implements:
  1737. IFsaScanItem::IsPremigrated().
  1738. --*/
  1739. {
  1740. HRESULT hr = S_FALSE;
  1741. HRESULT hrTest = S_FALSE;
  1742. WsbTraceIn(OLESTR("CFsaScanItem::IsPremigrated"), OLESTR(""));
  1743. // We really need to look at the placeholder information to figure
  1744. // this out (is offline, and is out type of HSM.
  1745. //
  1746. // If the file is NOT truncated AND is a reparse point and is a
  1747. // managed one then the file is a premigrated file
  1748. //
  1749. // if ( !(m_findData.dwFileAttributes & BIT_FOR_TRUNCATED) &&
  1750. // m_findData.dwFileAttributes & BIT_FOR_RP &&
  1751. // IsManaged() == S_OK) {
  1752. try {
  1753. if ( m_findData.dwFileAttributes & BIT_FOR_RP ) {
  1754. WsbAffirmHr(hrTest = IsManaged(offset, size));
  1755. if ((S_OK == hrTest) &&
  1756. ( !m_placeholder.isTruncated )) {
  1757. hr = S_OK;
  1758. }
  1759. }
  1760. } WsbCatch (hr);
  1761. WsbTraceOut(OLESTR("CFsaScanItem::IsPremigrated"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1762. return(hr);
  1763. }
  1764. HRESULT
  1765. CFsaScanItem::IsTruncated(
  1766. IN LONGLONG offset,
  1767. IN LONGLONG size
  1768. )
  1769. /*++
  1770. Implements:
  1771. IFsaScanItem::IsTruncated().
  1772. --*/
  1773. {
  1774. HRESULT hr = S_FALSE;
  1775. HRESULT hrTest = S_FALSE;
  1776. WsbTraceIn(OLESTR("CFsaScanItem::IsTruncated"), OLESTR(""));
  1777. //
  1778. // If the bit is on that indicates we have truncated the file AND
  1779. // the file is a reparse point AND the reparse point is one of
  1780. // our types (i.e. it really is our information stuffed away in
  1781. // there the it really is a truncated file
  1782. //
  1783. // if ( // ???? m_findData.dwFileAttributes & BIT_FOR_TRUNCATED &&
  1784. // m_findData.dwFileAttributes & BIT_FOR_RP &&
  1785. // IsManaged() == S_OK && RP_FILE_IS_TRUNCATED( m_placeholder.bitFlags ) ) {
  1786. try {
  1787. if ( m_findData.dwFileAttributes & BIT_FOR_RP ) {
  1788. WsbAffirmHr(hrTest = IsManaged(offset, size));
  1789. if ((S_OK == hrTest) &&
  1790. ( m_placeholder.isTruncated )) {
  1791. hr = S_OK;
  1792. }
  1793. }
  1794. } WsbCatch (hr);
  1795. WsbTraceOut(OLESTR("CFsaScanItem::IsTruncated"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1796. return(hr);
  1797. }
  1798. HRESULT
  1799. CFsaScanItem::GetVersionId(
  1800. LONGLONG *fileVersionId
  1801. )
  1802. /*++
  1803. Implements:
  1804. IFsaScanItem::GetVersionId().
  1805. --*/
  1806. {
  1807. HRESULT hr = E_FAIL;
  1808. HANDLE handle = INVALID_HANDLE_VALUE;
  1809. CWsbStringPtr path;
  1810. ULONG DesiredAccess;
  1811. IO_STATUS_BLOCK IoStatusBlock;
  1812. FILE_BASIC_INFORMATION basicInformation;
  1813. try {
  1814. //
  1815. // Create the real file name we need to open, under the covers this
  1816. // allocates the buffer since the path pointer is null
  1817. //
  1818. WsbAffirmHr( GetFullPathAndName( OLESTR("\\\\?\\"), NULL, &path, 0));
  1819. //WsbAffirmHr( GetFullPathAndName( NULL, NULL, &path, 0));
  1820. //
  1821. // Open the file to get the attributes
  1822. //
  1823. DesiredAccess = FILE_READ_ATTRIBUTES ;
  1824. WsbAffirmHr( OpenObject( path,
  1825. FILE_NON_DIRECTORY_FILE | FILE_NO_INTERMEDIATE_BUFFERING,
  1826. DesiredAccess,
  1827. SHARE_FLAGS,
  1828. FILE_OPEN,
  1829. &IoStatusBlock,
  1830. &handle ) );
  1831. //
  1832. // The open worked, our handle should be valid but we check to be
  1833. // safe and sure
  1834. //
  1835. WsbAssertHandle( handle );
  1836. //
  1837. // Get the current attributes of the file and the times
  1838. //
  1839. WsbAssertNtStatus( NtQueryInformationFile( handle,
  1840. &IoStatusBlock,
  1841. (PVOID)&basicInformation,
  1842. sizeof( basicInformation ),
  1843. FileBasicInformation ) );
  1844. //
  1845. // Close the file since we are done with it and set the handle to invalid
  1846. //
  1847. WsbAssertNtStatus( NtClose( handle ) );
  1848. handle = INVALID_HANDLE_VALUE;
  1849. *fileVersionId = basicInformation.LastWriteTime.QuadPart;
  1850. hr = S_OK;
  1851. } WsbCatch( hr );
  1852. //
  1853. // if we opened the file we need to close it
  1854. //
  1855. if( INVALID_HANDLE_VALUE != handle) {
  1856. NtClose( handle );
  1857. }
  1858. return( hr );
  1859. }
  1860. HRESULT
  1861. CFsaScanItem::MakeReadWrite(
  1862. )
  1863. /*++
  1864. Routine Description:
  1865. Make the file attributes read/write if they aren't already.
  1866. Arguments:
  1867. pUsn - Pointer to File USN to check (if != 0) and to be returned after the change.
  1868. Return Value:
  1869. S_OK - success
  1870. --*/
  1871. {
  1872. HRESULT hr = S_OK;
  1873. CWsbStringPtr path;
  1874. IO_STATUS_BLOCK IoStatusBlock;
  1875. HANDLE handle = INVALID_HANDLE_VALUE;
  1876. FILE_BASIC_INFORMATION basicInformation;
  1877. if (S_OK == IsReadOnly()) {
  1878. try {
  1879. // NOTE: MakeReadOnly(), IsReadOnly(), and RestoreAttributes() seem like dangerous implementations, since
  1880. // the used cached information and reset all the attirbutes. It is also assuming that the
  1881. // application wants the file reset to read only after FindNext() or the destructor. This
  1882. // may not be true for a general purpose application. Unfortunately, it seems to risky to
  1883. // try to change this implementation now.
  1884. // Create the real file name we need to open, under the covers this
  1885. // allocates the buffer since the path pointer is null
  1886. WsbAffirmHr(GetFullPathAndName(OLESTR("\\\\?\\"), NULL, &path, 0));
  1887. // Open the file.
  1888. WsbAffirmHr(OpenObject(path, FILE_NON_DIRECTORY_FILE, FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES, EXCLUSIVE_FLAG, FILE_OPEN, &IoStatusBlock, &handle));
  1889. // The open worked, our handle should be valid but we check to be
  1890. // safe and sure
  1891. WsbAffirmHandle(handle);
  1892. // Get the current attributes of the file and the times
  1893. WsbAffirmNtStatus(NtQueryInformationFile(handle, &IoStatusBlock, (PVOID)&basicInformation, sizeof(basicInformation), FileBasicInformation));
  1894. // Make sure it is still read only.
  1895. if ((basicInformation.FileAttributes & FILE_ATTRIBUTE_READONLY) != 0) {
  1896. m_originalAttributes = basicInformation.FileAttributes;
  1897. // Set the time flags so that when we close the handle the
  1898. // time are not updated on the file and the FileAttributes
  1899. basicInformation.CreationTime.QuadPart = -1;
  1900. basicInformation.LastAccessTime.QuadPart = -1;
  1901. basicInformation.LastWriteTime.QuadPart = -1;
  1902. basicInformation.ChangeTime.QuadPart = -1;
  1903. basicInformation.FileAttributes &= ~FILE_ATTRIBUTE_READONLY;
  1904. basicInformation.FileAttributes |= FILE_ATTRIBUTE_NORMAL; // Just in case result was zero (then no attributes would be set)
  1905. WsbAffirmNtStatus(NtSetInformationFile(handle, &IoStatusBlock, (PVOID)&basicInformation, sizeof(basicInformation), FileBasicInformation));
  1906. m_changedAttributes = TRUE;
  1907. }
  1908. // Close the file
  1909. NtClose(handle);
  1910. handle = INVALID_HANDLE_VALUE;
  1911. } WsbCatch(hr);
  1912. // Close the file for sure
  1913. if (INVALID_HANDLE_VALUE != handle) {
  1914. NtClose(handle);
  1915. }
  1916. }
  1917. return(hr);
  1918. }
  1919. HRESULT
  1920. CFsaScanItem::PrepareForManage(
  1921. IN LONGLONG offset,
  1922. IN LONGLONG size
  1923. )
  1924. /*++
  1925. Implements:
  1926. IFsaScanItem::PrepareForManage().
  1927. --*/
  1928. {
  1929. UNREFERENCED_PARAMETER(offset);
  1930. UNREFERENCED_PARAMETER(size);
  1931. return S_OK;
  1932. }
  1933. HRESULT
  1934. CFsaScanItem::RestoreAttributes(
  1935. )
  1936. /*++
  1937. Implements:
  1938. IFsaScanItem::RestoreAttributes
  1939. --*/
  1940. {
  1941. HRESULT hr = E_FAIL;
  1942. CWsbStringPtr path;
  1943. IO_STATUS_BLOCK IoStatusBlock;
  1944. HANDLE handle = INVALID_HANDLE_VALUE;
  1945. FILE_BASIC_INFORMATION basicInformation;
  1946. try {
  1947. // NOTE: MakeReadOnly(), IsReadOnly(), and RestoreAttributes() seem like dangerous implementations, since
  1948. // the used cached information and reset all the attirbutes. It is also assuming that the
  1949. // application wants the file reset to read only after FindNext() or the destructor. This
  1950. // may not be true for a general purpose application. Unfortunately, it seems to risky to
  1951. // try to change this implementation now.
  1952. // Create the real file name we need to open, under the covers this
  1953. // allocates the buffer since the path pointer is null
  1954. WsbTrace(OLESTR("CFsaScanItem::RestoreAttributes - Restoring attributes to %x"), m_originalAttributes);
  1955. WsbAffirmHr(GetFullPathAndName( OLESTR("\\\\?\\"), NULL, &path, 0));
  1956. // Open the file.
  1957. WsbAffirmHr(OpenObject(path, FILE_NON_DIRECTORY_FILE, FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES, EXCLUSIVE_FLAG, FILE_OPEN, &IoStatusBlock, &handle));
  1958. // The open worked, our handle should be valid but we check to be
  1959. // safe and sure
  1960. WsbAffirmHandle(handle);
  1961. // Get the current attributes of the file and the times
  1962. WsbAffirmNtStatus(NtQueryInformationFile(handle, &IoStatusBlock, (PVOID)&basicInformation, sizeof(basicInformation), FileBasicInformation));
  1963. // Set the time flags so that when we close the handle the
  1964. // time are not updated on the file and the FileAttributes
  1965. basicInformation.CreationTime.QuadPart = -1;
  1966. basicInformation.LastAccessTime.QuadPart = -1;
  1967. basicInformation.LastWriteTime.QuadPart = -1;
  1968. basicInformation.ChangeTime.QuadPart = -1;
  1969. basicInformation.FileAttributes = m_originalAttributes;
  1970. WsbAffirmNtStatus(NtSetInformationFile(handle, &IoStatusBlock, (PVOID)&basicInformation, sizeof(basicInformation), FileBasicInformation));
  1971. // Close the file
  1972. NtClose(handle);
  1973. handle = INVALID_HANDLE_VALUE;
  1974. m_changedAttributes = FALSE;
  1975. } WsbCatch(hr);
  1976. // Close the file for sure
  1977. if (INVALID_HANDLE_VALUE != handle) {
  1978. NtClose(handle);
  1979. }
  1980. return(hr);
  1981. }
  1982. HRESULT
  1983. CFsaScanItem::Truncate(
  1984. IN LONGLONG offset,
  1985. IN LONGLONG size
  1986. )
  1987. /*++
  1988. Implements:
  1989. IFsaScanItem::Truncate().
  1990. --*/
  1991. {
  1992. HRESULT hr = S_OK;
  1993. BOOL fileIsTruncated = FALSE;
  1994. LONGLONG usn = 0;
  1995. WsbTraceIn(OLESTR("CFsaScanItem::Truncate"), OLESTR(""));
  1996. try {
  1997. // call the engine
  1998. if (IsManaged(offset, size) == S_OK) {
  1999. WsbAffirmHr(m_pResource->ValidateForTruncate((IFsaScanItem*) this, offset, size, usn));
  2000. }
  2001. } WsbCatch(hr);
  2002. WsbTraceOut(OLESTR("CFsaScanItem::Truncate"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2003. return(hr);
  2004. }
  2005. HRESULT
  2006. CFsaScanItem::TruncateValidated(
  2007. IN LONGLONG offset,
  2008. IN LONGLONG size
  2009. )
  2010. /*++
  2011. Implements:
  2012. IFsaScanItem::TruncateValidated().
  2013. --*/
  2014. {
  2015. HRESULT hr = S_OK;
  2016. HRESULT truncateHr = S_OK;
  2017. WsbTraceIn(OLESTR("CFsaScanItem::TruncateValidated"), OLESTR(""));
  2018. try {
  2019. IFsaScanItem* pMe = this;
  2020. truncateHr = TruncateInternal(offset, size);
  2021. //
  2022. // Note: Must check for S_OK since TruncateInternal may return FSA_E_ITEMCHANGED or FSA_E_ITEMINUSE
  2023. // Both are "Success hr", but imply no truncation was done
  2024. //
  2025. if (S_OK == truncateHr) {
  2026. WsbAffirmHr(m_pResource->RemovePremigrated(pMe, offset, size));
  2027. WsbAffirmHr(m_pResource->AddTruncated(pMe, offset, size));
  2028. }
  2029. } WsbCatch(hr);
  2030. // The important hr to return to the caller is the actual result of the truncation
  2031. hr = truncateHr;
  2032. WsbTraceOut(OLESTR("CFsaScanItem::TruncateValidated"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2033. return(hr);
  2034. }
  2035. HRESULT
  2036. CFsaScanItem::TruncateInternal(
  2037. IN LONGLONG offset,
  2038. IN LONGLONG size
  2039. )
  2040. /*++
  2041. Implements:
  2042. IFsaScanItem::TruncateInternal().
  2043. --*/
  2044. {
  2045. HRESULT hr = E_FAIL;
  2046. CWsbStringPtr path;
  2047. ULONG DesiredAccess;
  2048. IO_STATUS_BLOCK IoStatusBlock;
  2049. NTSTATUS ntStatus;
  2050. FILE_END_OF_FILE_INFORMATION sizeInformation;
  2051. FILE_BASIC_INFORMATION basicInformation;
  2052. PREPARSE_DATA_BUFFER pReparseBuffer;
  2053. UCHAR ReparseBuffer[sizeof(REPARSE_DATA_BUFFER) + sizeof(RP_DATA) + 10];
  2054. CWsbStringPtr fileName;
  2055. CWsbStringPtr jobName;
  2056. LONGLONG fileVersionId;
  2057. ULONG i = 0;
  2058. CWsbStringPtr volName;
  2059. WsbTraceIn(OLESTR("CFsaScanItem::TruncateInternal"), OLESTR(""));
  2060. // Putting these statistics in the registry is probably not the best
  2061. // place for them, but it's the easiest solution for now
  2062. #define TEMPORARY_TRUNCATE_STATISTICS 1
  2063. #if defined(TEMPORARY_TRUNCATE_STATISTICS)
  2064. // Try to increment the truncate-attempt count in the registry
  2065. WsbIncRegistryValueDWORD(NULL, FSA_REGISTRY_PARMS,
  2066. OLESTR("TruncateCalls"));
  2067. #endif
  2068. // Get strings for tracing and error logging (ignore errors?!)
  2069. GetFullPathAndName( 0, 0, &fileName, 0);
  2070. m_pSession->GetName(&jobName, 0);
  2071. m_handleVerify = INVALID_HANDLE_VALUE;
  2072. try {
  2073. LONGLONG fileUsn1 = 0, fileUsn2 = 0;
  2074. // If the file is not migrated, then we can't truncate it
  2075. if (S_OK != IsPremigrated(offset, size)) {
  2076. if (S_OK != IsManaged(offset, size)) {
  2077. hr = FSA_E_NOTMANAGED;
  2078. WsbLogEvent(FSA_MESSAGE_TRUNCSKIPPED_ISNOTMANAGED, 0, NULL,
  2079. (OLECHAR*) jobName, WsbAbbreviatePath(fileName, 120),
  2080. WsbHrAsString(hr), NULL);
  2081. WsbThrow(hr);
  2082. } else {
  2083. //
  2084. // Do not bother to log an event here as this should only
  2085. // happen if someone uses rstest or some other program
  2086. // to truncate a file that is already truncated.
  2087. WsbThrow(FSA_E_FILE_ALREADY_MANAGED);
  2088. }
  2089. }
  2090. WsbAssert( m_gotPlaceholder, E_UNEXPECTED );
  2091. //
  2092. // Setup the reparse point data with that which was on the file
  2093. // with the bit in the data indicating it is truncated
  2094. //
  2095. pReparseBuffer = (PREPARSE_DATA_BUFFER)ReparseBuffer;
  2096. WsbAffirmHr( CopyPlaceholderToRP( &m_placeholder, pReparseBuffer, TRUE ) );
  2097. //
  2098. // Create the real file name we need to open, under the covers this
  2099. // allocates the buffer since the path pointer is null
  2100. //
  2101. WsbAffirmHr( GetFullPathAndName( OLESTR("\\\\?\\"), NULL, &path, 0));
  2102. //
  2103. // Open the file exclusively for read-only so we can get the usn before and after
  2104. // making the file R/W, without letting anybody to make a "real" change in the middle
  2105. //
  2106. DesiredAccess = FILE_READ_DATA | FILE_READ_ATTRIBUTES;
  2107. WsbAffirmHr( OpenObject( path,
  2108. FILE_NON_DIRECTORY_FILE,
  2109. DesiredAccess,
  2110. EXCLUSIVE_FLAG,
  2111. FILE_OPEN,
  2112. &IoStatusBlock,
  2113. &m_handleVerify ) );
  2114. WsbAssertHandle( m_handleVerify );
  2115. //
  2116. // Get usn before making R/W
  2117. // This usn is used to compare with the usn which we kept in the premigrated list.
  2118. // MakeReadWrite may chnage the usn so we need to get it before
  2119. //
  2120. if (S_OK != WsbGetUsnFromFileHandle(m_handleVerify, FALSE, &fileUsn1)) {
  2121. fileUsn1 = 0;
  2122. }
  2123. // Make sure it is read/write
  2124. WsbAffirmHr( MakeReadWrite() );
  2125. //
  2126. // Get usn after making R/W
  2127. // This usn will be use to compare with the usn of the file after we'll open it for R/W. We need
  2128. // this comparison in order to ensure that nobody changed the file before we opened it again for R/W.
  2129. //
  2130. if (S_OK != WsbGetUsnFromFileHandle(m_handleVerify, TRUE, &fileUsn2)) {
  2131. fileUsn2 = 0;
  2132. }
  2133. // Close the file
  2134. NtClose( m_handleVerify );
  2135. m_handleVerify = INVALID_HANDLE_VALUE;
  2136. //
  2137. // Open the file (for R/W)
  2138. //
  2139. DesiredAccess = FILE_READ_DATA | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES ;
  2140. WsbAffirmHr( OpenObject( path,
  2141. FILE_NON_DIRECTORY_FILE | FILE_WRITE_THROUGH,
  2142. DesiredAccess,
  2143. EXCLUSIVE_FLAG,
  2144. FILE_OPEN,
  2145. &IoStatusBlock,
  2146. &m_handleVerify ) );
  2147. //
  2148. // The open worked, our handle should be valid but we check to be
  2149. // safe and sure
  2150. //
  2151. WsbAssertHandle( m_handleVerify );
  2152. //
  2153. // Tell the USN journal that we are the source of the changes.
  2154. //
  2155. WsbAffirmHr(m_pResource->GetPath(&volName, 0));
  2156. WsbAffirmHr(WsbMarkUsnSource(m_handleVerify, volName));
  2157. //
  2158. // Get the current attributes of the file and the times
  2159. //
  2160. WsbAffirmNtStatus( NtQueryInformationFile( m_handleVerify,
  2161. &IoStatusBlock,
  2162. (PVOID)&basicInformation,
  2163. sizeof( basicInformation ),
  2164. FileBasicInformation ) );
  2165. fileVersionId = basicInformation.LastWriteTime.QuadPart;
  2166. //
  2167. // Set the time flags so that when we close the handle the
  2168. // times are not updated on the file and the FileAttributes
  2169. // indicate the file is offline
  2170. //
  2171. basicInformation.CreationTime.QuadPart = -1;
  2172. basicInformation.LastAccessTime.QuadPart = -1;
  2173. basicInformation.LastWriteTime.QuadPart = -1;
  2174. basicInformation.ChangeTime.QuadPart = -1;
  2175. basicInformation.FileAttributes = 0; // Do not change attributes yet
  2176. WsbAffirmNtStatus( NtSetInformationFile( m_handleVerify,
  2177. &IoStatusBlock,
  2178. (PVOID)&basicInformation,
  2179. sizeof( basicInformation ),
  2180. FileBasicInformation ) );
  2181. //
  2182. // Do the check to see if the file changed
  2183. //
  2184. hr = VerifyInternal(offset, size, fileUsn1, fileUsn2);
  2185. //
  2186. // Note: Must check for S_OK since VerifyInternal may return FSA_E_ITEMCHANGED or FSA_E_ITEMINUSE
  2187. // Both are "Success hr", but should cause no truncation !!
  2188. //
  2189. if (S_OK != hr) {
  2190. WsbThrow(hr);
  2191. }
  2192. //
  2193. // Change the in memory flags for this scan item
  2194. //
  2195. m_findData.dwFileAttributes |= BIT_FOR_TRUNCATED;
  2196. //
  2197. // Rewrite the reparse point with the new flag
  2198. //
  2199. ntStatus = NtFsControlFile( m_handleVerify,
  2200. NULL,
  2201. NULL,
  2202. NULL,
  2203. &IoStatusBlock,
  2204. FSCTL_SET_REPARSE_POINT,
  2205. pReparseBuffer,
  2206. FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer)
  2207. + pReparseBuffer->ReparseDataLength,
  2208. NULL,
  2209. 0 );
  2210. //
  2211. // Check the return code
  2212. //
  2213. WsbAffirmNtStatus( ntStatus );
  2214. //
  2215. // It really happened so we need to flip the in memory copy of the
  2216. // isTruncated flag so it reflects reality
  2217. //
  2218. m_placeholder.isTruncated = TRUE;
  2219. //
  2220. // Set the file size to zero to truncate the file
  2221. sizeInformation.EndOfFile.QuadPart = 0 ;
  2222. WsbAffirmNtStatus( NtSetInformationFile( m_handleVerify,
  2223. &IoStatusBlock,
  2224. &sizeInformation,
  2225. sizeof( sizeInformation ),
  2226. FileEndOfFileInformation ) );
  2227. //
  2228. // Set the logical file size to the original size
  2229. sizeInformation.EndOfFile.QuadPart = m_placeholder.dataStreamSize;
  2230. WsbAffirmNtStatus( NtSetInformationFile( m_handleVerify,
  2231. &IoStatusBlock,
  2232. &sizeInformation,
  2233. sizeof( sizeInformation ),
  2234. FileEndOfFileInformation ) );
  2235. //
  2236. // Now that the truncation is complete we set the OFFLINE attribute.
  2237. //
  2238. basicInformation.CreationTime.QuadPart = -1; // Make sure we do nothing with dates
  2239. basicInformation.LastAccessTime.QuadPart = -1;
  2240. basicInformation.LastWriteTime.QuadPart = -1;
  2241. basicInformation.ChangeTime.QuadPart = -1;
  2242. basicInformation.FileAttributes = m_findData.dwFileAttributes;
  2243. WsbAffirmNtStatus(NtSetInformationFile( m_handleVerify,
  2244. &IoStatusBlock,
  2245. (PVOID)&basicInformation,
  2246. sizeof( basicInformation ),
  2247. FileBasicInformation ));
  2248. // Since we have restored the original attributes we can reset the flag that was possibly set by MakeReadWrite
  2249. m_changedAttributes = FALSE;
  2250. hr = S_OK;
  2251. } WsbCatch(hr);
  2252. //
  2253. // if we opened the file we need to close it
  2254. //
  2255. if( INVALID_HANDLE_VALUE != m_handleVerify) {
  2256. NtClose( m_handleVerify );
  2257. m_handleVerify = INVALID_HANDLE_VALUE;
  2258. }
  2259. // If the file data had changed (so we didn't truncate it) log event and
  2260. // remove placeholder info
  2261. if (FSA_E_ITEMCHANGED == hr) {
  2262. WsbLogEvent(FSA_MESSAGE_TRUNCSKIPPED_ISCHANGED, 0, NULL,
  2263. (OLECHAR*) jobName, WsbAbbreviatePath(fileName, 80),
  2264. WsbHrAsString(hr), NULL);
  2265. DeletePlaceholder(offset, size);
  2266. }
  2267. WsbTraceOut(OLESTR("CFsaScanItem::TruncateInternal"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2268. return(hr);
  2269. }
  2270. HRESULT
  2271. CFsaScanItem::Verify(
  2272. IN LONGLONG offset,
  2273. IN LONGLONG size
  2274. )
  2275. /*++
  2276. Implements:
  2277. IFsaScanItem::Verify().
  2278. --*/
  2279. {
  2280. HRESULT hr = E_FAIL;
  2281. CWsbStringPtr path;
  2282. ULONG DesiredAccess;
  2283. IO_STATUS_BLOCK IoStatusBlock;
  2284. WsbTraceIn(OLESTR("CFsaScanItem::Verify"), OLESTR(""));
  2285. m_handleVerify = INVALID_HANDLE_VALUE;
  2286. try {
  2287. WsbAssert( m_gotPlaceholder, E_UNEXPECTED );
  2288. //
  2289. // Create the real file name we need to open, under the covers this
  2290. // allocates the buffer since the path pointer is null
  2291. //
  2292. WsbAffirmHr( GetFullPathAndName( OLESTR("\\\\?\\"), NULL, &path, 0));
  2293. //
  2294. // Open the file
  2295. //
  2296. DesiredAccess = FILE_READ_DATA | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_READ_ATTRIBUTES ;
  2297. WsbAffirmHr( OpenObject( path,
  2298. FILE_NON_DIRECTORY_FILE | FILE_WRITE_THROUGH,
  2299. DesiredAccess,
  2300. EXCLUSIVE_FLAG,
  2301. FILE_OPEN,
  2302. &IoStatusBlock,
  2303. &m_handleVerify ) );
  2304. //
  2305. // The open worked, our handle should be valid but we check to be
  2306. // safe and sure
  2307. //
  2308. WsbAssertHandle( m_handleVerify );
  2309. //
  2310. // Do the check to see if the file changed
  2311. // Note that it throws rather than affirms because FSA_E_ITEMCHANGED is a success
  2312. WsbThrow(VerifyInternal(offset, size, 0, 0));
  2313. } WsbCatch(hr);
  2314. //
  2315. // if we opened the file we need to close it
  2316. //
  2317. if( INVALID_HANDLE_VALUE != m_handleVerify) {
  2318. NtClose( m_handleVerify );
  2319. m_handleVerify = INVALID_HANDLE_VALUE;
  2320. }
  2321. WsbTraceOut(OLESTR("CFsaScanItem::Verify"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2322. return(hr);
  2323. }
  2324. HRESULT
  2325. CFsaScanItem::VerifyInternal(
  2326. IN LONGLONG offset,
  2327. IN LONGLONG size,
  2328. IN LONGLONG compareUsn1,
  2329. IN LONGLONG compareUsn2
  2330. )
  2331. /*++
  2332. Implements:
  2333. IFsaScanItem::VerifyInternal().
  2334. Note: This requires that m_handleVerify is set up with a handle to the file being verified.
  2335. --*/
  2336. {
  2337. HRESULT hr = E_FAIL;
  2338. IO_STATUS_BLOCK IoStatusBlock;
  2339. FILE_BASIC_INFORMATION basicInformation;
  2340. CWsbStringPtr fileName;
  2341. CWsbStringPtr jobName;
  2342. LONGLONG fileVersionId;
  2343. ULONG i = 0;
  2344. CWsbStringPtr volName;
  2345. LONGLONG realFileSize;
  2346. RP_MSG in, out;
  2347. DWORD outSize;
  2348. WsbTraceIn(OLESTR("CFsaScanItem::VerifyInternal"), OLESTR(""));
  2349. // Get strings for tracing and error logging (ignore errors?!)
  2350. GetFullPathAndName( 0, 0, &fileName, 0);
  2351. m_pSession->GetName(&jobName, 0);
  2352. try {
  2353. BOOL DoCRC = FALSE;
  2354. BOOL DoUsnCheck = FALSE;
  2355. LONGLONG premigListUsn;
  2356. LONGLONG fileUsn;
  2357. WsbAffirmHr(GetLogicalSize(&realFileSize));
  2358. //
  2359. // Currently, avoid offset and size verification:
  2360. // - Since we are not doing partial file migration, offset is always 0.
  2361. // - Size in Validate would always be the same since it is taken from GetLogicalSize as well.
  2362. // - Size in case of auto-truncation is not reliable since it is taken from the premigrated db,
  2363. // where there could be bogus records from previous migrations of the file
  2364. //
  2365. /*** if ( (realFileSize != size) || (offset != 0) ) {
  2366. WsbThrow(FSA_E_ITEMCHANGED);
  2367. } ***/
  2368. //
  2369. WsbAssertHandle( m_handleVerify );
  2370. //
  2371. // Get the USN from the premigration list and the USN from the file.
  2372. // We need to get the USN from the file now, before any NtSetInformationFile
  2373. // is called because this changes the USN value.
  2374. // If we have trouble getting the USN, just set them
  2375. // to 0 and go on, we check for 0 as a special case.
  2376. //
  2377. if (S_OK != GetPremigratedUsn(&premigListUsn)) {
  2378. premigListUsn = 0;
  2379. }
  2380. if (S_OK != WsbGetUsnFromFileHandle(m_handleVerify, FALSE, &fileUsn)) {
  2381. fileUsn = 0;
  2382. }
  2383. WsbTrace(OLESTR("CFsaScanItem::VerifyInternal: premig USN <%I64d>, file USN <%I64d>\n"),
  2384. premigListUsn, fileUsn );
  2385. WsbTrace(OLESTR("CFsaScanItem::VerifyInternal: Compare1 USN <%I64d>, Compare2 USN <%I64d>\n"),
  2386. compareUsn1, compareUsn2 );
  2387. //
  2388. // Get the current attributes of the file and the times
  2389. //
  2390. WsbAssertNtStatus( NtQueryInformationFile( m_handleVerify,
  2391. &IoStatusBlock,
  2392. (PVOID)&basicInformation,
  2393. sizeof( basicInformation ),
  2394. FileBasicInformation ) );
  2395. fileVersionId = basicInformation.LastWriteTime.QuadPart;
  2396. //
  2397. // Verify that the modify date & time has not changed since we
  2398. // took the data
  2399. //
  2400. if( fileVersionId != m_placeholder.fileVersionId ) {
  2401. WsbThrow(FSA_E_ITEMCHANGED);
  2402. }
  2403. //
  2404. // If the file is memory mapped by another process and the original handle was closed we
  2405. // are still able to open it for exclusive access here. We have to determine if the file
  2406. // is mapped and if so we cannot truncate it. The only way to do this is from kernel
  2407. // mode so we call our filter to do the check.
  2408. //
  2409. in.inout.command = RP_CHECK_HANDLE;
  2410. WsbAssertStatus(DeviceIoControl(m_handleVerify, FSCTL_HSM_MSG, &in,
  2411. sizeof(RP_MSG), &out, sizeof(RP_MSG), &outSize, NULL));
  2412. if (!out.msg.hRep.canTruncate) {
  2413. hr = FSA_E_ITEMINUSE;
  2414. WsbLogEvent(FSA_MESSAGE_TRUNCSKIPPED_ISMAPPED, 0, NULL, (OLECHAR*) jobName, WsbAbbreviatePath(fileName, 120), WsbHrAsString(hr), NULL);
  2415. WsbThrow(hr);
  2416. }
  2417. // If the USN's don't match, then we need to check the
  2418. // journal for changes
  2419. // premigListUsn: The usn of the file immediately after it was migrated
  2420. // compareUsn1: If not 0, the usn of the file before we (possibly) removed a read-only attribute
  2421. // compareUsn2: If not 0,
  2422. //
  2423. if ((0 == fileUsn) || (0 == premigListUsn)) {
  2424. // We don't have USN Journal info so force a CRC comparison
  2425. DoCRC = TRUE;
  2426. } else if ((compareUsn1 != 0) && (compareUsn2 != 0)) {
  2427. // Need to compare with these input usn instead of a direct compare
  2428. if ((premigListUsn != compareUsn1) || (fileUsn != compareUsn2)) {
  2429. DoUsnCheck = TRUE;
  2430. }
  2431. } else if (fileUsn != premigListUsn) {
  2432. DoUsnCheck = TRUE;
  2433. }
  2434. // Current usn indicates that file may have changed
  2435. if (DoUsnCheck) {
  2436. BOOL UsnChanged = FALSE;
  2437. hr = CheckUsnJournalForChanges(premigListUsn, fileUsn, &UsnChanged);
  2438. if (S_OK == hr) {
  2439. if (UsnChanged) {
  2440. // File changed, skip it
  2441. WsbThrow(FSA_E_ITEMCHANGED);
  2442. }
  2443. } else {
  2444. // Something failed, force a CRC comparison
  2445. DoCRC = TRUE;
  2446. WsbLogEvent(FSA_MESSAGE_USN_CHECK_FAILED, 0, NULL,
  2447. WsbAbbreviatePath(fileName,120),
  2448. WsbHrAsString(hr), NULL);
  2449. hr = S_OK;
  2450. }
  2451. }
  2452. // If the USNJ indicated a possible change, then we need to CRC
  2453. // the data.
  2454. if (DoCRC) {
  2455. //
  2456. // Check to be sure that the CRC in the placeholder matches
  2457. // that of the file
  2458. //
  2459. ULONG currentCRC;
  2460. #if defined(TEMPORARY_TRUNCATE_STATISTICS)
  2461. // Try to increment the truncate-CRC count in the registry
  2462. WsbIncRegistryValueDWORD(NULL, FSA_REGISTRY_PARMS,
  2463. OLESTR("TruncateCRCs"));
  2464. #endif
  2465. WsbAffirmHr(CalculateCurrentCRCInternal(m_handleVerify, offset, size, &currentCRC));
  2466. WsbTrace(OLESTR("CFsaScanItem::VerifyInternal: Current CRC <%ul>, Reparse CRC <%ls>\n"),
  2467. currentCRC, WsbLonglongAsString( m_placeholder.dataStreamCRC ) );
  2468. if (currentCRC != m_placeholder.dataStreamCRC) {
  2469. //
  2470. // The file has changed since we migrated it so
  2471. // don't truncate it.
  2472. WsbThrow(FSA_E_ITEMCHANGED);
  2473. }
  2474. }
  2475. hr = S_OK;
  2476. } WsbCatch(hr);
  2477. // If the file data had changed (so we didn't truncate it) log event
  2478. // (cannot remove placeholder with DeletePlaceholder since the file is already opened exclusively
  2479. if (FSA_E_ITEMCHANGED == hr) {
  2480. WsbLogEvent(FSA_MESSAGE_TRUNCSKIPPED_ISCHANGED, 0, NULL,
  2481. (OLECHAR*) jobName, WsbAbbreviatePath(fileName, 120),
  2482. WsbHrAsString(hr), NULL);
  2483. }
  2484. WsbTraceOut(OLESTR("CFsaScanItem::VerifyInternal"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2485. return(hr);
  2486. }
  2487. HRESULT
  2488. CFsaScanItem::CheckIfSparse(
  2489. IN LONGLONG offset,
  2490. IN LONGLONG size
  2491. )
  2492. /*++
  2493. Implements:
  2494. IFsaScanItem::CheckIfSparse()
  2495. Determines if the specified section is on disk or not (is sparse)
  2496. FSA_E_FILE_IS_TOTALLY_SPARSE - There are no resident portions of the section
  2497. FSA_E_FILE_IS_PARTIALLY_SPARSE - The section of the file has some resident/some sparse
  2498. sections
  2499. FSA_E_FILE_IS_NOT_SPARSE - The section is totally resident
  2500. any others - error and we don't know the state of the file
  2501. --*/
  2502. {
  2503. HRESULT hr = E_FAIL;
  2504. HANDLE handle = INVALID_HANDLE_VALUE;
  2505. CWsbStringPtr path;
  2506. ULONG DesiredAccess;
  2507. IO_STATUS_BLOCK IoStatusBlock;
  2508. NTSTATUS ntStatus;
  2509. FILE_ALLOCATED_RANGE_BUFFER inRange;
  2510. #define NUM_RANGE 10
  2511. FILE_ALLOCATED_RANGE_BUFFER outRange[NUM_RANGE];
  2512. PFILE_ALLOCATED_RANGE_BUFFER cRange;
  2513. int idx;
  2514. WsbTraceIn(OLESTR("CFsaScanItem::CheckIfSparse"), OLESTR("offset = <%I64d>, size = <%I64d>"),
  2515. offset, size);
  2516. //
  2517. // If the file is really managed then we can check the allocation map
  2518. // Otherwise we indicate that the data is all resident
  2519. //
  2520. try {
  2521. //
  2522. // Create the real file name we need to open, under the covers this
  2523. // allocates the buffer since the path pointer is null
  2524. //
  2525. WsbAffirmHr( GetFullPathAndName( OLESTR("\\\\?\\"), NULL, &path, 0));
  2526. //WsbAffirmHr( GetFullPathAndName( NULL, NULL, &path, 0));
  2527. //
  2528. // Open the file to check the allocation
  2529. //
  2530. DesiredAccess = FILE_READ_ATTRIBUTES | FILE_READ_DATA;
  2531. WsbAffirmHr( OpenObject( path,
  2532. FILE_NON_DIRECTORY_FILE | FILE_NO_INTERMEDIATE_BUFFERING,
  2533. DesiredAccess,
  2534. SHARE_FLAGS,
  2535. FILE_OPEN,
  2536. &IoStatusBlock,
  2537. &handle ) );
  2538. //
  2539. // The open worked, our handle should be valid but we check to be
  2540. // safe and sure
  2541. //
  2542. WsbAssertHandle( handle );
  2543. memset(&outRange, 0, sizeof(FILE_ALLOCATED_RANGE_BUFFER) * NUM_RANGE);
  2544. //
  2545. // Check the allocation of the specified range
  2546. //
  2547. inRange.FileOffset.QuadPart = offset;
  2548. inRange.Length.QuadPart = size;
  2549. ntStatus = NtFsControlFile( handle,
  2550. NULL,
  2551. NULL,
  2552. NULL,
  2553. &IoStatusBlock,
  2554. FSCTL_QUERY_ALLOCATED_RANGES,
  2555. &inRange,
  2556. sizeof(FILE_ALLOCATED_RANGE_BUFFER),
  2557. &outRange,
  2558. sizeof(FILE_ALLOCATED_RANGE_BUFFER) * NUM_RANGE);
  2559. //
  2560. // Check the return code but STATUS_SUCCESS or STATUS_BUFFER_OVERFLOW are valid
  2561. //
  2562. if ( STATUS_SUCCESS != ntStatus && STATUS_BUFFER_OVERFLOW != ntStatus ) {
  2563. WsbAssertNtStatus( ntStatus );
  2564. }
  2565. cRange = (PFILE_ALLOCATED_RANGE_BUFFER) &outRange;
  2566. for (idx = 0; idx < NUM_RANGE; idx++) {
  2567. if (cRange->Length.QuadPart != 0) {
  2568. WsbTrace(OLESTR("CFsaScanItem::CheckIfSparse - Resident range %u Offset: %I64u, length: %I64u\n"),
  2569. idx, cRange->FileOffset.QuadPart, cRange->Length.QuadPart);
  2570. }
  2571. cRange++;
  2572. }
  2573. //
  2574. // Close the file since we are done with it and set the handle to invalid
  2575. //
  2576. NtClose(handle);
  2577. handle = INVALID_HANDLE_VALUE;
  2578. //
  2579. // If the initial allocated range does begin where we said to start and the length of the
  2580. // allocated area is equal to the length we asked about then none of the data is sparse
  2581. //
  2582. if ( (outRange[0].FileOffset.QuadPart == offset) && (outRange[0].Length.QuadPart == size) ) {
  2583. hr = FSA_E_FILE_IS_NOT_SPARSE;
  2584. } else if (outRange[0].Length.QuadPart == 0) {
  2585. hr = FSA_E_FILE_IS_TOTALLY_SPARSE;
  2586. } else {
  2587. hr = FSA_E_FILE_IS_PARTIALLY_SPARSE;
  2588. }
  2589. } WsbCatch(hr);
  2590. //
  2591. // if we opened the file we need to close it
  2592. //
  2593. if( INVALID_HANDLE_VALUE != handle) {
  2594. NtClose( handle );
  2595. }
  2596. WsbTraceOut(OLESTR("CFsaScanItem::CheckIfSparse"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  2597. return(hr);
  2598. }