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.

1443 lines
43 KiB

  1. /*
  2. Copyright (c) 2000-2001 Microsoft Corporation
  3. Module Name:
  4. extattr.cpp
  5. Abstract:
  6. Get's additional file attributes beyond what you get with
  7. FindFirstFile/FindNextFile.
  8. Author:
  9. Stefan R. Steiner [ssteiner] 02-27-2000
  10. Revision History:
  11. --*/
  12. #include "stdafx.h"
  13. #include <ntioapi.h>
  14. #include <aclapi.h>
  15. #include <sddl.h>
  16. #include "direntrs.h"
  17. #include "extattr.h"
  18. #include "hardlink.h"
  19. #define READ_BUF_SIZE ( 1024 * 1024 )
  20. #define FSD_SHARE_MODE ( FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE )
  21. #define FSD_MS_HSM_REPARSE_TAG 0xC0000004
  22. static VOID
  23. eaGetSecurityInfo(
  24. IN CDumpParameters *pcParams,
  25. IN const CBsString &cwsFileName,
  26. OUT SFileExtendedInfo *psExtendedInfo
  27. );
  28. static VOID
  29. eaGetFileInformationByHandle(
  30. IN CDumpParameters *pcParams,
  31. IN const CBsString &cwsFileName,
  32. IN OUT SDirectoryEntry *psDirEntry,
  33. OUT SFileExtendedInfo *psExtendedInfo
  34. );
  35. static VOID
  36. eaGetAlternateStreamInfo(
  37. IN CDumpParameters *pcParams,
  38. IN const CBsString &cwsFileName,
  39. OUT SFileExtendedInfo *psExtendedInfo
  40. );
  41. static VOID
  42. eaGetReparsePointInfo(
  43. IN CDumpParameters *pcParams,
  44. IN const CBsString &cwsFileName,
  45. IN OUT ULONGLONG *pullBytesChecksummed,
  46. IN OUT SDirectoryEntry *psDirEntry,
  47. OUT SFileExtendedInfo *psExtendedInfo
  48. );
  49. static BOOL
  50. eaChecksumRawEncryptedData(
  51. IN CDumpParameters *pcParams,
  52. IN const CBsString& cwsFileName,
  53. IN OUT SFileExtendedInfo *psExtendedInfo
  54. );
  55. static BOOL
  56. eaChecksumStream(
  57. IN const CBsString& cwsStreamPath,
  58. IN OUT ULONGLONG *pullBytesChecksummed,
  59. IN OUT DWORD *pdwRunningCheckSum
  60. );
  61. static DWORD
  62. eaChecksumBlock(
  63. IN DWORD dwRunningChecksum,
  64. IN LPBYTE pBuffer,
  65. IN DWORD dwBufSize
  66. );
  67. static VOID
  68. eaConvertUserSidToString (
  69. IN CDumpParameters *pcParams,
  70. IN PSID pSid,
  71. OUT CBsString *pcwsSid
  72. );
  73. static VOID
  74. eaConvertGroupSidToString (
  75. IN CDumpParameters *pcParams,
  76. IN PSID pSid,
  77. OUT CBsString *pcwsSid
  78. );
  79. static VOID
  80. eaConvertSidToString (
  81. IN CDumpParameters *pcParams,
  82. IN PSID pSid,
  83. OUT CBsString *pcwsSid
  84. );
  85. static DWORD
  86. eaChecksumHSMReparsePoint(
  87. IN CDumpParameters *pcParams,
  88. IN PREPARSE_DATA_BUFFER pReparseData,
  89. IN DWORD dwTotalSize // Size of reparse point data
  90. );
  91. static VOID
  92. eaGetObjectIdInfo(
  93. IN CDumpParameters *pcParams,
  94. IN const CBsString &cwsFileName,
  95. IN OUT ULONGLONG *pullBytesChecksummed,
  96. IN OUT SDirectoryEntry *psDirEntry,
  97. IN OUT SFileExtendedInfo *psExtendedInfo
  98. );
  99. /*++
  100. Routine Description:
  101. Performs all of the checksums, and retrieves the security info for one file.
  102. Arguments:
  103. Return Value:
  104. --*/
  105. VOID
  106. GetExtendedFileInfo(
  107. IN CDumpParameters *pcParams,
  108. IN CFsdVolumeState *pcFsdVolState,
  109. IN const CBsString& cwsDirPath,
  110. IN BOOL bSingleEntryOutput,
  111. IN OUT SDirectoryEntry *psDirEntry,
  112. OUT SFileExtendedInfo *psExtendedInfo
  113. )
  114. {
  115. CBsString cwsFullPath( cwsDirPath );
  116. //
  117. // If we are dumping an individual file's data, cwsDirPath has the complete
  118. // path to the file, otherwise glue the filename from the find data structure
  119. // to the path.
  120. //
  121. if ( !bSingleEntryOutput )
  122. {
  123. cwsFullPath += psDirEntry->GetFileName();
  124. }
  125. //
  126. // Get the information that retrieved from GetFileInformationByHandle
  127. //
  128. ::eaGetFileInformationByHandle( pcParams, cwsFullPath, psDirEntry, psExtendedInfo );
  129. if ( psExtendedInfo->lNumberOfLinks > 1 && pcParams->m_eFsDumpType != eFsDumpFile )
  130. {
  131. if ( pcFsdVolState->IsHardLinkInList(
  132. psExtendedInfo->ullFileIndex,
  133. cwsDirPath,
  134. psDirEntry->GetFileName(),
  135. &psDirEntry->m_sFindData,
  136. psExtendedInfo ) )
  137. {
  138. //
  139. // Found the link in the list, return with the previous link's information, except
  140. // zero out the number of bytes checksummed so that total counts remain accurate.
  141. //
  142. psExtendedInfo->ullTotalBytesChecksummed = 0;
  143. psExtendedInfo->ullTotalBytesNamedDataStream = 0;
  144. return;
  145. }
  146. }
  147. //
  148. // Get the security information.
  149. //
  150. ::eaGetSecurityInfo( pcParams, cwsFullPath, psExtendedInfo );
  151. eaGetObjectIdInfo(
  152. pcParams,
  153. cwsFullPath,
  154. &psExtendedInfo->ullTotalBytesChecksummed,
  155. psDirEntry,
  156. psExtendedInfo );
  157. //
  158. // Get the reparse point information if necessary
  159. //
  160. if ( psDirEntry->m_sFindData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT )
  161. ::eaGetReparsePointInfo(
  162. pcParams,
  163. cwsFullPath,
  164. &psExtendedInfo->ullTotalBytesChecksummed,
  165. psDirEntry,
  166. psExtendedInfo );
  167. //
  168. // Get the raw encryption data checksum if necessary
  169. //
  170. if ( !pcParams->m_bNoChecksums
  171. && psDirEntry->m_sFindData.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED
  172. && !( psDirEntry->m_sFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) )
  173. ::eaChecksumRawEncryptedData(
  174. pcParams,
  175. cwsFullPath,
  176. psExtendedInfo );
  177. //
  178. // Checksum the unnamed datastream if this is not a directory
  179. //
  180. if ( !pcParams->m_bNoChecksums
  181. && !( psDirEntry->m_sFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) )
  182. {
  183. DWORD dwChecksum = 0;
  184. ULONGLONG ullFileSize = ( ( ULONGLONG )( psDirEntry->m_sFindData.nFileSizeHigh ) << 32 ) + psDirEntry->m_sFindData.nFileSizeLow;
  185. if ( ullFileSize == 0 )
  186. {
  187. //
  188. // In this case the default value for checksum of -------- is correct.
  189. //
  190. }
  191. else if ( psDirEntry->m_sFindData.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE
  192. && pcParams->m_bDontChecksumHighLatencyData )
  193. {
  194. psExtendedInfo->cwsUnnamedStreamChecksum = L"HighLtcy";
  195. }
  196. else if ( ::eaChecksumStream( cwsFullPath,
  197. &psExtendedInfo->ullTotalBytesChecksummed,
  198. &dwChecksum ) )
  199. {
  200. psExtendedInfo->cwsUnnamedStreamChecksum.Format( pcParams->m_pwszULongHexFmt, dwChecksum );
  201. }
  202. else
  203. {
  204. psExtendedInfo->cwsUnnamedStreamChecksum.Format( L"<%6d>", ::GetLastError() );
  205. }
  206. }
  207. //
  208. // Get info on and checksum the named data streams
  209. //
  210. ::eaGetAlternateStreamInfo( pcParams, cwsFullPath, psExtendedInfo );
  211. //
  212. // If this file is multiply linked, add it to the hard-link file list
  213. //
  214. if ( psExtendedInfo->lNumberOfLinks > 1 && pcParams->m_eFsDumpType != eFsDumpFile )
  215. {
  216. pcFsdVolState->AddHardLinkToList(
  217. psExtendedInfo->ullFileIndex,
  218. cwsDirPath,
  219. psDirEntry->GetFileName(),
  220. &psDirEntry->m_sFindData,
  221. psExtendedInfo );
  222. }
  223. }
  224. /*++
  225. Routine Description:
  226. Gets the security information for a file
  227. Arguments:
  228. Return Value:
  229. --*/
  230. static VOID
  231. eaGetSecurityInfo(
  232. IN CDumpParameters *pcParams,
  233. IN const CBsString &cwsFileName,
  234. OUT SFileExtendedInfo *psExtendedInfo
  235. )
  236. {
  237. //
  238. // Now get the security information
  239. //
  240. PACL psDacl = NULL, psSacl = NULL;
  241. PSID pOwnerSid = NULL, pGroupSid = NULL;
  242. DWORD dwRet;
  243. DWORD dwSaclErrorRetCode = ERROR_SUCCESS;
  244. PSECURITY_DESCRIPTOR pDesc = NULL;
  245. try
  246. {
  247. dwRet = ::GetNamedSecurityInfoW(
  248. ( LPWSTR )cwsFileName.c_str(), // strange API, should ask for const
  249. SE_FILE_OBJECT,
  250. DACL_SECURITY_INFORMATION
  251. | SACL_SECURITY_INFORMATION
  252. | OWNER_SECURITY_INFORMATION
  253. | GROUP_SECURITY_INFORMATION,
  254. &pOwnerSid,
  255. &pGroupSid,
  256. &psDacl,
  257. &psSacl,
  258. &pDesc );
  259. //
  260. // If it didn't work, try again without the Sacl information
  261. //
  262. if ( dwRet != ERROR_SUCCESS )
  263. {
  264. dwSaclErrorRetCode = dwRet;
  265. psSacl = NULL;
  266. dwRet = ::GetNamedSecurityInfoW(
  267. ( LPWSTR )cwsFileName.c_str(), // strange API, should ask for const
  268. SE_FILE_OBJECT,
  269. DACL_SECURITY_INFORMATION
  270. | OWNER_SECURITY_INFORMATION
  271. | GROUP_SECURITY_INFORMATION,
  272. &pOwnerSid,
  273. &pGroupSid,
  274. &psDacl,
  275. NULL,
  276. &pDesc );
  277. }
  278. #if 0
  279. //
  280. // Test code to find security API problem
  281. //
  282. pDesc = ::LocalAlloc( LMEM_FIXED, 4096 );
  283. DWORD dwLengthNeeded;
  284. dwRet = ERROR_SUCCESS;
  285. if ( !::GetFileSecurityW(
  286. cwsFileName,
  287. // DACL_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION,
  288. DACL_SECURITY_INFORMATION, // | GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION,
  289. pDesc,
  290. 4096,
  291. &dwLengthNeeded ) )
  292. dwRet = ::GetLastError();
  293. if ( dwRet == ERROR_SUCCESS )
  294. wprintf( L"Got security descripter for '%s'\n", cwsFileName.c_str() );
  295. else
  296. wprintf( L"Error getting descripter for '%s', dwRet: %d\n", cwsFileName.c_str(), dwRet );
  297. #endif
  298. if ( dwRet == ERROR_SUCCESS )
  299. {
  300. if ( pDesc && pcParams->m_bEnableSDCtrlWordDump )
  301. {
  302. SECURITY_DESCRIPTOR_CONTROL sdc;
  303. DWORD dwDescRevision;
  304. if ( ::GetSecurityDescriptorControl( pDesc, &sdc, &dwDescRevision ) )
  305. psExtendedInfo->wSecurityDescriptorControl = ( WORD )( sdc & ~SE_SELF_RELATIVE );
  306. else
  307. psExtendedInfo->wSecurityDescriptorControl = -1;
  308. }
  309. else
  310. psExtendedInfo->wSecurityDescriptorControl = -1;
  311. if ( psDacl )
  312. {
  313. psExtendedInfo->lNumDACEs = 0;
  314. psExtendedInfo->wDACLSize = 0;
  315. //
  316. // Checksum the DACL data if necessary.
  317. // n.b. We only take into account ACEs that are inherited.
  318. //
  319. if ( psDacl->AclSize > 0 )
  320. {
  321. DWORD dwChecksum = 0;
  322. //
  323. // The first ACE is right after the ACL header
  324. //
  325. PACE_HEADER pAceHeader = ( PACE_HEADER )( psDacl + 1 );
  326. for ( USHORT aceNum = 0; aceNum < psDacl->AceCount; ++aceNum )
  327. {
  328. //
  329. // Skip if an inherited ACE
  330. //
  331. if ( !( pAceHeader->AceFlags & INHERITED_ACE ) )
  332. {
  333. dwChecksum += ::eaChecksumBlock(
  334. dwChecksum,
  335. ( LPBYTE )pAceHeader,
  336. pAceHeader->AceSize );
  337. ++psExtendedInfo->lNumDACEs;
  338. psExtendedInfo->wDACLSize += pAceHeader->AceSize;
  339. if ( pcParams->m_bPrintDebugInfo )
  340. wprintf( L"\t%d: f: %04x, t: %04x, s: %u\n", aceNum,
  341. pAceHeader->AceFlags, pAceHeader->AceType, pAceHeader->AceSize );
  342. }
  343. pAceHeader = ( PACE_HEADER )( ( ( LPBYTE )pAceHeader ) + pAceHeader->AceSize );
  344. }
  345. if ( psExtendedInfo->wDACLSize > 0 )
  346. {
  347. psExtendedInfo->cwsDACLChecksum.Format( pcParams->m_pwszULongHexFmt, dwChecksum );
  348. psExtendedInfo->ullTotalBytesChecksummed += psExtendedInfo->wDACLSize;
  349. }
  350. }
  351. }
  352. else
  353. psExtendedInfo->lNumDACEs = 0; // probably FAT or CDROM fs
  354. if ( psSacl )
  355. {
  356. psExtendedInfo->lNumSACEs = 0;
  357. psExtendedInfo->wSACLSize = 0;
  358. //
  359. // Checksum the SACL data if necessary
  360. // n.b. We only take into account ACEs that are inherited.
  361. //
  362. if ( psSacl->AclSize > 0 )
  363. {
  364. DWORD dwChecksum = 0;
  365. //
  366. // The first ACE is right after the ACL header
  367. //
  368. PACE_HEADER pAceHeader = ( PACE_HEADER )( psSacl + 1 );
  369. for ( USHORT aceNum = 0; aceNum < psSacl->AceCount; ++aceNum )
  370. {
  371. //
  372. // Skip if an inherited ACE
  373. //
  374. if ( !( pAceHeader->AceFlags & INHERITED_ACE ) )
  375. {
  376. dwChecksum += ::eaChecksumBlock(
  377. dwChecksum,
  378. ( LPBYTE )pAceHeader,
  379. pAceHeader->AceSize );
  380. ++psExtendedInfo->lNumSACEs;
  381. psExtendedInfo->wSACLSize += pAceHeader->AceSize;
  382. if ( pcParams->m_bPrintDebugInfo )
  383. wprintf( L"\ts%d: f: %04x, t: %04x, s: %u\n", aceNum,
  384. ( DWORD)( pAceHeader->AceFlags ), pAceHeader->AceType, (DWORD)( pAceHeader->AceSize ) );
  385. }
  386. pAceHeader = ( PACE_HEADER )( ( ( LPBYTE )pAceHeader ) + pAceHeader->AceSize );
  387. }
  388. if ( psExtendedInfo->wSACLSize > 0 )
  389. {
  390. psExtendedInfo->cwsSACLChecksum.Format( pcParams->m_pwszULongHexFmt, dwChecksum );
  391. psExtendedInfo->ullTotalBytesChecksummed += psExtendedInfo->wSACLSize;
  392. }
  393. }
  394. }
  395. else if ( dwSaclErrorRetCode != ERROR_SUCCESS )
  396. {
  397. psExtendedInfo->lNumSACEs = -1;
  398. psExtendedInfo->wSACLSize = -1;
  399. psExtendedInfo->cwsSACLChecksum.Format( L"<%6d>", dwSaclErrorRetCode );
  400. }
  401. else
  402. psExtendedInfo->lNumSACEs = 0; // none
  403. eaConvertUserSidToString( pcParams, pOwnerSid, &psExtendedInfo->cwsOwnerSid );
  404. eaConvertGroupSidToString( pcParams, pGroupSid, &psExtendedInfo->cwsGroupSid );
  405. ::LocalFree( pDesc );
  406. }
  407. else
  408. {
  409. //
  410. // Error getting security information
  411. //
  412. psExtendedInfo->lNumDACEs = -1;
  413. psExtendedInfo->lNumSACEs = -1;
  414. psExtendedInfo->wDACLSize = -1;
  415. psExtendedInfo->wSACLSize = -1;
  416. psExtendedInfo->cwsDACLChecksum.Format( L"<%6d>", dwRet );
  417. psExtendedInfo->cwsSACLChecksum.Format( L"<%6d>", dwRet );
  418. psExtendedInfo->cwsOwnerSid.Format( L"<%6d>", dwRet );
  419. psExtendedInfo->cwsGroupSid.Format( L"<%6d>", dwRet );
  420. }
  421. }
  422. catch( ... )
  423. {
  424. psExtendedInfo->lNumDACEs = -1;
  425. psExtendedInfo->lNumSACEs = -1;
  426. psExtendedInfo->wDACLSize = -1;
  427. psExtendedInfo->wSACLSize = -1;
  428. psExtendedInfo->cwsOwnerSid.Format( L"<%6d>", ::GetLastError() );
  429. psExtendedInfo->cwsGroupSid.Format( L"<%6d>", ::GetLastError() );
  430. }
  431. }
  432. static VOID
  433. eaGetFileInformationByHandle(
  434. IN CDumpParameters *pcParams,
  435. IN const CBsString &cwsFileName,
  436. IN OUT SDirectoryEntry *psDirEntry,
  437. OUT SFileExtendedInfo *psExtendedInfo
  438. )
  439. {
  440. HANDLE hFile;
  441. //
  442. // Note that while we do have to open the file, not even read access is needed
  443. //
  444. hFile = ::CreateFileW(
  445. cwsFileName,
  446. 0,
  447. FSD_SHARE_MODE,
  448. NULL,
  449. OPEN_EXISTING,
  450. FILE_FLAG_BACKUP_SEMANTICS,
  451. NULL );
  452. if ( hFile == INVALID_HANDLE_VALUE )
  453. {
  454. psExtendedInfo->lNumberOfLinks = -1;
  455. return;
  456. }
  457. //
  458. // Now get the additional attributes
  459. //
  460. BY_HANDLE_FILE_INFORMATION sFileInfo;
  461. if ( ::GetFileInformationByHandle( hFile, &sFileInfo ) )
  462. {
  463. psExtendedInfo->lNumberOfLinks = ( LONG )sFileInfo.nNumberOfLinks;
  464. psExtendedInfo->ullFileIndex = ( ( ULONGLONG )sFileInfo.nFileIndexHigh << 32 ) + sFileInfo.nFileIndexLow;
  465. if ( psExtendedInfo->lNumberOfLinks > 1 || psDirEntry->m_sFindData.ftLastWriteTime.dwLowDateTime == 0 )
  466. {
  467. //
  468. // Expect that the FindFirst/NextFile dir entry is stale or non-existant. Use information
  469. // from this call.
  470. //
  471. psDirEntry->m_sFindData.dwFileAttributes = sFileInfo.dwFileAttributes;
  472. psDirEntry->m_sFindData.ftCreationTime = sFileInfo.ftCreationTime;
  473. psDirEntry->m_sFindData.ftLastAccessTime = sFileInfo.ftLastAccessTime;
  474. psDirEntry->m_sFindData.ftLastWriteTime = sFileInfo.ftLastWriteTime;
  475. psDirEntry->m_sFindData.nFileSizeHigh = sFileInfo.nFileSizeHigh;
  476. psDirEntry->m_sFindData.nFileSizeLow = sFileInfo.nFileSizeLow;
  477. }
  478. }
  479. else
  480. psExtendedInfo->lNumberOfLinks = -1;
  481. ::CloseHandle( hFile );
  482. }
  483. static VOID
  484. eaGetAlternateStreamInfo(
  485. IN CDumpParameters *pcParams,
  486. IN const CBsString &cwsFileName,
  487. OUT SFileExtendedInfo *psExtendedInfo
  488. )
  489. {
  490. NTSTATUS Status;
  491. HANDLE hFile;
  492. //
  493. // Note that while we do have to open the file, not even read access is needed
  494. //
  495. hFile = CreateFileW(
  496. cwsFileName,
  497. FILE_GENERIC_READ, // | ACCESS_SYSTEM_SECURITY,
  498. FSD_SHARE_MODE,
  499. NULL,
  500. OPEN_EXISTING,
  501. FILE_FLAG_BACKUP_SEMANTICS,
  502. NULL );
  503. if ( hFile == INVALID_HANDLE_VALUE )
  504. {
  505. psExtendedInfo->lNumNamedDataStreams = -1;
  506. psExtendedInfo->lNumPropertyStreams = -1;
  507. psExtendedInfo->cwsNamedDataStreamChecksum.Format( L"<%6d>", ::GetLastError() );
  508. return;
  509. }
  510. //
  511. // Loop until we read the file information
  512. //
  513. LPBYTE pBuffer = NULL;
  514. ULONG ulBuffSize = 1024;
  515. IO_STATUS_BLOCK iosb;
  516. static const WCHAR * const pwszDefaultStreamName = L"::$DATA";
  517. static const ULONG ulDefaultStreamNameLength = 7;
  518. while ( TRUE )
  519. {
  520. pBuffer = new BYTE[ ulBuffSize ];
  521. if ( pBuffer == NULL )
  522. throw E_OUTOFMEMORY;
  523. Status = ::NtQueryInformationFile(
  524. hFile,
  525. &iosb,
  526. pBuffer,
  527. ulBuffSize,
  528. FileStreamInformation );
  529. //
  530. // If we succeeded in getting data, when have the data so party on and get out of
  531. // the loop
  532. //
  533. if ( NT_SUCCESS( Status ) && iosb.Information != 0 )
  534. {
  535. break;
  536. }
  537. //
  538. // If the error isn't overflow, get out
  539. //
  540. if ( Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_BUFFER_TOO_SMALL )
  541. {
  542. //
  543. // NOTE: If status is successful, we didn't get any data but it's not
  544. // an error. Happens a lot with directories since they don't have a default
  545. // unnamed stream.
  546. //
  547. if ( !NT_SUCCESS( Status ) )
  548. {
  549. //
  550. // Another kind of error
  551. // BUGBUG: if not NTFS, C000000D occurs. Should not try this on
  552. // a non-NTFS volume
  553. //psExtendedInfo->lNumNamedDataStreams = -1;
  554. //psExtendedInfo->dwNamedDataStreamChecksum = ::GetLastError();
  555. //psExtendedInfo->bNamedDataStreamHadError = TRUE;
  556. }
  557. delete [] pBuffer;
  558. ::CloseHandle( hFile );
  559. return;
  560. }
  561. //
  562. // Increase the size of the buffer
  563. //
  564. ulBuffSize <<= 1; // double it each try
  565. delete [] pBuffer;
  566. pBuffer = NULL;
  567. }
  568. //
  569. // If we are here, we have a valid FileStreamInformation buffer
  570. //
  571. ::CloseHandle( hFile );
  572. PFILE_STREAM_INFORMATION pFSI;
  573. pFSI = ( PFILE_STREAM_INFORMATION ) pBuffer;
  574. BOOL bHadError = FALSE;
  575. DWORD dwChecksum = 0;
  576. //
  577. // Now loop through the named streams.
  578. //
  579. while ( TRUE )
  580. {
  581. if ( pFSI->StreamNameLength != sizeof( WCHAR ) * ulDefaultStreamNameLength ||
  582. wcsncmp( pFSI->StreamName, pwszDefaultStreamName, ulDefaultStreamNameLength ) != 0 )
  583. {
  584. LPWSTR pwszDataStr;
  585. pwszDataStr = ::wcsstr( pFSI->StreamName, L":$DATA" );
  586. if ( pwszDataStr != NULL )
  587. {
  588. pwszDataStr[0] = L'\0'; // Strip off the :$DATA off of name
  589. ++psExtendedInfo->lNumNamedDataStreams;
  590. // wprintf( L" %8I64u '%-*.*s' : %d\n", pFSI->StreamSize, pFSI->StreamNameLength / 2,
  591. // pFSI->StreamNameLength / 2, pFSI->StreamName, pFSI->StreamNameLength );
  592. psExtendedInfo->ullTotalBytesNamedDataStream += ( ULONGLONG )pFSI->StreamSize.QuadPart;
  593. if ( !pcParams->m_bNoChecksums && !bHadError )
  594. {
  595. //
  596. // Put into the checksum the name of the stream
  597. //
  598. dwChecksum = ::eaChecksumBlock(
  599. dwChecksum,
  600. ( LPBYTE )pFSI->StreamName,
  601. ::wcslen( pFSI->StreamName ) * sizeof WCHAR );
  602. //
  603. // Now checksum the data in the stream
  604. //
  605. if ( ::eaChecksumStream( cwsFileName + pFSI->StreamName,
  606. &psExtendedInfo->ullTotalBytesChecksummed,
  607. &dwChecksum ) )
  608. {
  609. psExtendedInfo->cwsNamedDataStreamChecksum.Format( pcParams->m_pwszULongHexFmt, dwChecksum );
  610. }
  611. else
  612. {
  613. psExtendedInfo->cwsNamedDataStreamChecksum.Format( L"<%6d>", ::GetLastError() );
  614. bHadError = TRUE;
  615. }
  616. }
  617. }
  618. else
  619. {
  620. //
  621. // Not an named data stream, probably a property stream
  622. // BUGBUG: need to verify that this is a property stream
  623. //
  624. ++psExtendedInfo->lNumPropertyStreams;
  625. }
  626. }
  627. if ( pFSI->NextEntryOffset == 0 )
  628. break;
  629. pFSI = ( PFILE_STREAM_INFORMATION )( pFSI->NextEntryOffset + ( PBYTE ) pFSI );
  630. }
  631. if ( !bHadError && !pcParams->m_bNoChecksums && psExtendedInfo->lNumNamedDataStreams > 0 )
  632. {
  633. psExtendedInfo->cwsNamedDataStreamChecksum.Format( pcParams->m_pwszULongHexFmt, dwChecksum );
  634. }
  635. if ( pBuffer != NULL )
  636. delete [] pBuffer;
  637. }
  638. static VOID
  639. eaGetReparsePointInfo(
  640. IN CDumpParameters *pcParams,
  641. IN const CBsString &cwsFileName,
  642. IN OUT ULONGLONG *pullBytesChecksummed,
  643. IN OUT SDirectoryEntry *psDirEntry,
  644. IN OUT SFileExtendedInfo *psExtendedInfo
  645. )
  646. {
  647. HANDLE hFile = INVALID_HANDLE_VALUE;
  648. BOOL bRet = TRUE;
  649. LPBYTE pReadBuffer = NULL;
  650. DWORD dwChecksum = 0;
  651. try
  652. {
  653. //
  654. // Now get the reparse point data buffer
  655. //
  656. pReadBuffer = ( LPBYTE )::VirtualAlloc(
  657. NULL,
  658. MAXIMUM_REPARSE_DATA_BUFFER_SIZE,
  659. MEM_COMMIT,
  660. PAGE_READWRITE );
  661. if ( pReadBuffer == NULL )
  662. {
  663. bRet = FALSE;
  664. goto EXIT;
  665. }
  666. //
  667. // Open the file in order to read reparse point data
  668. //
  669. hFile = ::CreateFileW(
  670. cwsFileName,
  671. GENERIC_READ,
  672. FSD_SHARE_MODE,
  673. NULL,
  674. OPEN_EXISTING,
  675. FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
  676. NULL );
  677. if ( hFile == INVALID_HANDLE_VALUE )
  678. {
  679. bRet = FALSE;
  680. goto EXIT;
  681. }
  682. //
  683. // Now get the reparse point data
  684. //
  685. DWORD dwBytesReturned;
  686. if ( !::DeviceIoControl(
  687. hFile,
  688. FSCTL_GET_REPARSE_POINT,
  689. NULL, // lpInBuffer; must be NULL
  690. 0, // nInBufferSize; must be zero
  691. ( LPVOID )pReadBuffer, // pointer to output buffer
  692. MAXIMUM_REPARSE_DATA_BUFFER_SIZE, // size of output buffer
  693. &dwBytesReturned, // receives number of bytes returned
  694. NULL // pointer to OVERLAPPED structure
  695. ) )
  696. {
  697. bRet = FALSE;
  698. goto EXIT;
  699. }
  700. PREPARSE_DATA_BUFFER pReparseData;
  701. pReparseData = ( PREPARSE_DATA_BUFFER )pReadBuffer ;
  702. psExtendedInfo->ulReparsePointTag = pReparseData->ReparseTag;
  703. psExtendedInfo->wReparsePointDataSize = ( WORD )dwBytesReturned;
  704. if ( !pcParams->m_bNoSpecialReparsePointProcessing &&
  705. psExtendedInfo->ulReparsePointTag == FSD_MS_HSM_REPARSE_TAG )
  706. {
  707. //
  708. // To make sure that dumps don't get many miscompares we
  709. // need to tweak the attributes. Raid #153050
  710. //
  711. if ( pcParams->m_bDontChecksumHighLatencyData )
  712. {
  713. //
  714. // Need to always make this file look like it is offline.
  715. // In this case, we need to always enable the FILE_ATTRIBUTE_OFFLINE
  716. // flag.
  717. //
  718. psDirEntry->m_sFindData.dwFileAttributes |= FILE_ATTRIBUTE_OFFLINE;
  719. }
  720. else
  721. {
  722. //
  723. // Need to always make this file look like it is cached.
  724. // In this case, we need to always disable the FILE_ATTRIBUTE_OFFLINE
  725. // flag.
  726. //
  727. psDirEntry->m_sFindData.dwFileAttributes &= ~FILE_ATTRIBUTE_OFFLINE;
  728. }
  729. //
  730. // Call a special HSM checksum function which filters out certain
  731. // dynamic fields before checksumming the data.
  732. //
  733. dwChecksum = eaChecksumHSMReparsePoint( pcParams, pReparseData, dwBytesReturned );
  734. }
  735. else
  736. {
  737. //
  738. // Now checksum all of the reparse point data
  739. //
  740. dwChecksum = ::eaChecksumBlock( 0, pReadBuffer, dwBytesReturned );
  741. }
  742. psExtendedInfo->cwsReparsePointDataChecksum.Format( pcParams->m_pwszULongHexFmt, dwChecksum );
  743. *pullBytesChecksummed += dwBytesReturned;
  744. }
  745. catch( ... )
  746. {
  747. bRet = FALSE;
  748. }
  749. EXIT:
  750. if ( pReadBuffer != NULL )
  751. ::VirtualFree( pReadBuffer, 0, MEM_RELEASE );
  752. if ( hFile != INVALID_HANDLE_VALUE )
  753. ::CloseHandle( hFile );
  754. if ( bRet == FALSE )
  755. psExtendedInfo->cwsReparsePointDataChecksum.Format( L"<%6d>", ::GetLastError() );
  756. }
  757. static BOOL
  758. eaChecksumStream(
  759. IN const CBsString& cwsStreamPath,
  760. IN OUT ULONGLONG *pullBytesChecksummed,
  761. IN OUT DWORD *pdwRunningCheckSum
  762. )
  763. {
  764. LPBYTE pReadBuffer;
  765. BOOL bRet = TRUE;
  766. pReadBuffer = ( LPBYTE )::VirtualAlloc( NULL, READ_BUF_SIZE, MEM_COMMIT, PAGE_READWRITE );
  767. if ( pReadBuffer == NULL )
  768. return FALSE;
  769. //
  770. // Open file with NO_BUFFERING.
  771. //
  772. HANDLE hFile = INVALID_HANDLE_VALUE;
  773. try
  774. {
  775. hFile = ::CreateFileW(
  776. cwsStreamPath,
  777. GENERIC_READ,
  778. FSD_SHARE_MODE,
  779. NULL,
  780. OPEN_EXISTING,
  781. FILE_FLAG_NO_BUFFERING
  782. | FILE_FLAG_BACKUP_SEMANTICS
  783. | FILE_FLAG_OPEN_NO_RECALL
  784. | FILE_FLAG_SEQUENTIAL_SCAN,
  785. NULL );
  786. if ( hFile == INVALID_HANDLE_VALUE )
  787. {
  788. bRet = FALSE;
  789. goto EXIT;
  790. }
  791. DWORD dwBytesRead;
  792. while ( ::ReadFile(
  793. hFile,
  794. pReadBuffer,
  795. READ_BUF_SIZE,
  796. &dwBytesRead,
  797. NULL ) )
  798. {
  799. if ( dwBytesRead == 0 )
  800. break;
  801. *pdwRunningCheckSum = ::eaChecksumBlock(
  802. *pdwRunningCheckSum,
  803. pReadBuffer,
  804. dwBytesRead );
  805. *pullBytesChecksummed += dwBytesRead;
  806. }
  807. if ( ::GetLastError() != ERROR_SUCCESS )
  808. bRet = FALSE;
  809. }
  810. catch( ... )
  811. {
  812. bRet = FALSE;
  813. }
  814. EXIT:
  815. if ( hFile != INVALID_HANDLE_VALUE )
  816. ::CloseHandle( hFile );
  817. ::VirtualFree( pReadBuffer, 0, MEM_RELEASE );
  818. return bRet;
  819. }
  820. //
  821. // This class maintains the encryption context
  822. //
  823. class CFsdEncryptionContext
  824. {
  825. public:
  826. CFsdEncryptionContext()
  827. : m_hDoneEvent( NULL ),
  828. m_dwChecksum( 0 ),
  829. m_ullBytesRead( 0 )
  830. {
  831. m_hDoneEvent = ::CreateEventW( NULL, TRUE, FALSE, NULL );
  832. if ( m_hDoneEvent == NULL )
  833. throw ::GetLastError();
  834. }
  835. ~CFsdEncryptionContext()
  836. {
  837. if ( m_hDoneEvent != NULL )
  838. ::CloseHandle( m_hDoneEvent );
  839. }
  840. DWORD WaitForDoneEvent()
  841. {
  842. DWORD dwRet;
  843. dwRet = ::WaitForSingleObject( m_hDoneEvent, INFINITE );
  844. if ( dwRet == WAIT_OBJECT_0 )
  845. return ERROR_SUCCESS;
  846. else if ( dwRet == WAIT_TIMEOUT )
  847. return ERROR_TIMEOUT;
  848. return ::GetLastError();
  849. }
  850. VOID FireDoneEvent()
  851. {
  852. ::SetEvent( m_hDoneEvent );
  853. }
  854. DWORD GetChecksum()
  855. {
  856. return m_dwChecksum;
  857. }
  858. ULONGLONG GetBytesRead()
  859. {
  860. return m_ullBytesRead;
  861. }
  862. static DWORD WINAPI ExportCallback(
  863. IN PBYTE pbData,
  864. IN PVOID pvCallbackContext,
  865. IN ULONG ulLength
  866. )
  867. {
  868. CFsdEncryptionContext *pcThis =
  869. static_cast< CFsdEncryptionContext * >( pvCallbackContext );
  870. pcThis->m_dwChecksum = ::eaChecksumBlock(
  871. pcThis->m_dwChecksum,
  872. pbData,
  873. ulLength );
  874. pcThis->m_ullBytesRead += ulLength;
  875. return ERROR_SUCCESS;
  876. }
  877. private:
  878. HANDLE m_hDoneEvent;
  879. DWORD m_dwChecksum;
  880. ULONGLONG m_ullBytesRead;
  881. };
  882. static BOOL
  883. eaChecksumRawEncryptedData(
  884. IN CDumpParameters *pcParams,
  885. IN const CBsString& cwsFileName,
  886. IN OUT SFileExtendedInfo *psExtendedInfo
  887. )
  888. {
  889. PVOID pvContext = NULL;
  890. DWORD dwRet = ERROR_SUCCESS;
  891. CFsdEncryptionContext cEncryptionContext;
  892. try
  893. {
  894. //
  895. // Open this puppy up
  896. //
  897. dwRet = ::OpenEncryptedFileRawW( cwsFileName, 0, &pvContext );
  898. if ( dwRet == ERROR_SUCCESS )
  899. {
  900. //wprintf( L"**** Opened encrypted file '%s'\n", cwsFileName.c_str() );
  901. dwRet = ::ReadEncryptedFileRaw( CFsdEncryptionContext::ExportCallback, &cEncryptionContext, pvContext );
  902. if ( dwRet == ERROR_SUCCESS )
  903. {
  904. //wprintf( L"**** Called read on encrypted file, bytes read: %u, checksum: %u\n",
  905. // cEncryptionContext.GetBytesRead(), cEncryptionContext.GetChecksum() );
  906. psExtendedInfo->cwsEncryptedRawDataChecksum.Format( pcParams->m_pwszULongHexFmt,
  907. cEncryptionContext.GetChecksum() );
  908. psExtendedInfo->ullTotalBytesChecksummed += cEncryptionContext.GetBytesRead();
  909. }
  910. }
  911. }
  912. catch( ... )
  913. {
  914. dwRet = ERROR_EXCEPTION_IN_SERVICE; // ???
  915. }
  916. if ( pvContext != NULL )
  917. ::CloseEncryptedFileRaw( pvContext );
  918. if ( dwRet != ERROR_SUCCESS )
  919. psExtendedInfo->cwsEncryptedRawDataChecksum.Format( L"<%6d>", dwRet );
  920. return dwRet == ERROR_SUCCESS;
  921. }
  922. /*++
  923. Routine Description:
  924. Checksums a block of data. The block needs to be DWORD aligned for performance and
  925. correctness since this function assumes it can zero out up to 3 bytes beyond the
  926. end of the buffer. Also, only the last buffer in a series of buffers can have
  927. unaligned data at the end of the buffer.
  928. Arguments:
  929. dwRunningChecksum - The previous checksum from a previous call. Should be zero if
  930. this is the first block to checksum in a series of blocks.
  931. pBuffer - Pointer to the buffer to checksum.
  932. dwBufSize - This should always be a multiple of a DWORD, except for the last block
  933. in a series.
  934. Return Value:
  935. The checksum.
  936. --*/
  937. static DWORD
  938. eaChecksumBlock(
  939. IN DWORD dwRunningChecksum,
  940. IN LPBYTE pBuffer,
  941. IN DWORD dwBufSize
  942. )
  943. {
  944. //
  945. // Need to zero out any additional bytes not aligned.
  946. //
  947. DWORD dwBytesToZero;
  948. DWORD dwBufSizeInDWords;
  949. dwBytesToZero = dwBufSize % sizeof( DWORD );
  950. dwBufSizeInDWords = ( dwBufSize + ( sizeof( DWORD ) - 1 ) ) / sizeof( DWORD ); // int div
  951. while ( dwBytesToZero-- )
  952. pBuffer[ dwBufSize + dwBytesToZero ] = 0;
  953. LPDWORD pdwBuf = ( LPDWORD )pBuffer;
  954. // BUGBUG: Need better checksum
  955. for ( DWORD dwIdx = 0; dwIdx < dwBufSizeInDWords; ++dwIdx )
  956. dwRunningChecksum += ( dwRunningChecksum << 1 ) | pdwBuf[ dwIdx ];
  957. return dwRunningChecksum;
  958. }
  959. /*++
  960. Routine Description:
  961. Converts a user SID to a string. Has a simple one element cache to speed
  962. up conversions. This is especially useful when the user wants the symbolic
  963. DOMAIN\ACCOUNT strings.
  964. Arguments:
  965. Return Value:
  966. NONE
  967. --*/
  968. static VOID
  969. eaConvertUserSidToString (
  970. IN CDumpParameters *pcParams,
  971. IN PSID pSid,
  972. OUT CBsString *pcwsSid
  973. )
  974. {
  975. static CBsString cwsCachedSidString;
  976. static PSID pCachedSid = NULL;
  977. //
  978. // Is the cached SID the same as the passed in one. If so,
  979. // return the cached sid string.
  980. //
  981. if ( pCachedSid != NULL
  982. && ::EqualSid( pSid, pCachedSid ) )
  983. {
  984. *pcwsSid = cwsCachedSidString;
  985. return;
  986. }
  987. //
  988. // Convert the SID into a string
  989. //
  990. ::eaConvertSidToString( pcParams, pSid, pcwsSid );
  991. //
  992. // Now cache the sid
  993. //
  994. cwsCachedSidString = *pcwsSid;
  995. if ( pCachedSid != NULL )
  996. free( pCachedSid );
  997. size_t cSidLength = ( size_t )::GetLengthSid( pSid );
  998. pCachedSid = ( PSID )malloc( cSidLength );
  999. if ( pCachedSid == NULL ) // prefix #171666
  1000. {
  1001. pcParams->ErrPrint( L"eaConvertUserSidToString - Can't allocate memory, out of memory" );
  1002. throw E_OUTOFMEMORY;
  1003. }
  1004. ::CopySid( ( DWORD )cSidLength, pCachedSid, pSid );
  1005. }
  1006. /*++
  1007. Routine Description:
  1008. Converts a group SID to a string. Has a simple one element cache to speed
  1009. up conversions. This is especially useful when the user wants the symbolic
  1010. DOMAIN\ACCOUNT strings.
  1011. Arguments:
  1012. Return Value:
  1013. NONE
  1014. --*/
  1015. static VOID
  1016. eaConvertGroupSidToString (
  1017. IN CDumpParameters *pcParams,
  1018. IN PSID pSid,
  1019. OUT CBsString *pcwsSid
  1020. )
  1021. {
  1022. static CBsString cwsCachedSidString;
  1023. static PSID pCachedSid = NULL;
  1024. //
  1025. // Is the cached SID the same as the passed in one. If so,
  1026. // return the cached sid string.
  1027. //
  1028. if ( pCachedSid != NULL
  1029. && ::EqualSid( pSid, pCachedSid ) )
  1030. {
  1031. *pcwsSid = cwsCachedSidString;
  1032. return;
  1033. }
  1034. //
  1035. // Convert the SID into a string
  1036. //
  1037. ::eaConvertSidToString( pcParams, pSid, pcwsSid );
  1038. //
  1039. // Now cache the sid
  1040. //
  1041. cwsCachedSidString = *pcwsSid;
  1042. if ( pCachedSid != NULL )
  1043. free( pCachedSid );
  1044. size_t cSidLength = ( size_t )::GetLengthSid( pSid );
  1045. pCachedSid = ( PSID )malloc( cSidLength );
  1046. if ( pCachedSid == NULL ) // prefix #171665
  1047. {
  1048. pcParams->ErrPrint( L"eaConvertGroupSidToString - Can't allocate memory, out of memory" );
  1049. throw E_OUTOFMEMORY;
  1050. }
  1051. ::CopySid( ( DWORD )cSidLength, pCachedSid, pSid );
  1052. }
  1053. /*++
  1054. Routine Description:
  1055. Converts a SID to a string.
  1056. Arguments:
  1057. Return Value:
  1058. NONE
  1059. --*/
  1060. static VOID
  1061. eaConvertSidToString (
  1062. IN CDumpParameters *pcParams,
  1063. IN PSID pSid,
  1064. OUT CBsString *pcwsSid
  1065. )
  1066. {
  1067. if ( pcParams->m_bShowSymbolicSIDNames )
  1068. {
  1069. CBsString cwsAccountName;
  1070. CBsString cwsDomainName;
  1071. SID_NAME_USE eSidNameUse;
  1072. DWORD dwAccountNameSize = 1024;
  1073. DWORD dwDomainNameSize = 1024;
  1074. if ( ::LookupAccountSidW(
  1075. NULL,
  1076. pSid,
  1077. cwsAccountName.GetBufferSetLength( dwAccountNameSize ),
  1078. &dwAccountNameSize,
  1079. cwsDomainName.GetBufferSetLength( dwDomainNameSize ),
  1080. &dwDomainNameSize,
  1081. &eSidNameUse ) )
  1082. {
  1083. cwsAccountName.ReleaseBuffer();
  1084. cwsDomainName.ReleaseBuffer();
  1085. *pcwsSid = L"'";
  1086. *pcwsSid += cwsDomainName;
  1087. *pcwsSid += L"\\";
  1088. *pcwsSid += cwsAccountName;
  1089. *pcwsSid += L"'";
  1090. return;
  1091. }
  1092. }
  1093. LPWSTR pwszSid;
  1094. if ( ::ConvertSidToStringSid( pSid, &pwszSid ) )
  1095. {
  1096. *pcwsSid = pwszSid;
  1097. ::LocalFree( pwszSid );
  1098. }
  1099. else
  1100. {
  1101. pcwsSid->Format( L"<%6d>", ::GetLastError() );
  1102. }
  1103. }
  1104. ///////////////////////////////////////////////////////////////////////////
  1105. //
  1106. // FROM: base\fs\hsm\inc\rpdata.h
  1107. //
  1108. //////////////////////////////////////////////////////////////////////////
  1109. #define RP_RESV_SIZE 52
  1110. //
  1111. // Placeholder data - all versions unioned together
  1112. //
  1113. typedef struct _RP_PRIVATE_DATA {
  1114. CHAR reserved[RP_RESV_SIZE]; // Must be 0
  1115. ULONG bitFlags; // bitflags indicating status of the segment
  1116. LARGE_INTEGER migrationTime; // When migration occurred
  1117. GUID hsmId;
  1118. GUID bagId;
  1119. LARGE_INTEGER fileStart;
  1120. LARGE_INTEGER fileSize;
  1121. LARGE_INTEGER dataStart;
  1122. LARGE_INTEGER dataSize;
  1123. LARGE_INTEGER fileVersionId;
  1124. LARGE_INTEGER verificationData;
  1125. ULONG verificationType;
  1126. ULONG recallCount;
  1127. LARGE_INTEGER recallTime;
  1128. LARGE_INTEGER dataStreamStart;
  1129. LARGE_INTEGER dataStreamSize;
  1130. ULONG dataStream;
  1131. ULONG dataStreamCRCType;
  1132. LARGE_INTEGER dataStreamCRC;
  1133. } RP_PRIVATE_DATA, *PRP_PRIVATE_DATA;
  1134. typedef struct _RP_DATA {
  1135. GUID vendorId; // Unique HSM vendor ID -- This is first to match REPARSE_GUID_DATA_BUFFER
  1136. ULONG qualifier; // Used to checksum the data
  1137. ULONG version; // Version of the structure
  1138. ULONG globalBitFlags; // bitflags indicating status of the file
  1139. ULONG numPrivateData; // number of private data entries
  1140. GUID fileIdentifier; // Unique file ID
  1141. RP_PRIVATE_DATA data; // Vendor specific data
  1142. } RP_DATA, *PRP_DATA;
  1143. //
  1144. // This function specifically zero's out certain HSM reparse point
  1145. // fields before computing the checksum. The fields which are
  1146. // zero'ed out are dynamic values and can cause miscompares.
  1147. //
  1148. static DWORD
  1149. eaChecksumHSMReparsePoint(
  1150. IN CDumpParameters *pcParams,
  1151. IN PREPARSE_DATA_BUFFER pReparseData,
  1152. IN DWORD dwTotalSize // Size of reparse point data
  1153. )
  1154. {
  1155. if ( dwTotalSize >= 8 && pReparseData->ReparseDataLength >= sizeof RP_DATA )
  1156. {
  1157. //
  1158. // If structure is not at least as large as the HSM RP_DATA structure,
  1159. // then it doesn't appear to be a valid HSM RP_DATA structure.
  1160. //
  1161. PRP_DATA pRpData = ( PRP_DATA ) pReparseData->GenericReparseBuffer.DataBuffer;
  1162. //
  1163. // Zero out the proper fields
  1164. //
  1165. pRpData->qualifier = 0;
  1166. pRpData->globalBitFlags = 0;
  1167. pRpData->data.bitFlags = 0;
  1168. pRpData->data.recallCount = 0;
  1169. pRpData->data.recallTime.LowPart = 0;
  1170. pRpData->data.recallTime.HighPart = 0;
  1171. }
  1172. else
  1173. {
  1174. pcParams->ErrPrint( L"Warning, HSM reparse point not valid, size: %u\n", dwTotalSize );
  1175. }
  1176. return ::eaChecksumBlock( 0, ( LPBYTE )pReparseData, dwTotalSize );
  1177. }
  1178. static VOID
  1179. eaGetObjectIdInfo(
  1180. IN CDumpParameters *pcParams,
  1181. IN const CBsString &cwsFileName,
  1182. IN OUT ULONGLONG *pullBytesChecksummed,
  1183. IN OUT SDirectoryEntry *psDirEntry,
  1184. IN OUT SFileExtendedInfo *psExtendedInfo
  1185. )
  1186. {
  1187. HANDLE hFile = INVALID_HANDLE_VALUE;
  1188. BOOL bRet = TRUE;
  1189. DWORD dwChecksum = 0;
  1190. try
  1191. {
  1192. //
  1193. // Open the file in order to read the object id
  1194. //
  1195. hFile = ::CreateFileW(
  1196. cwsFileName,
  1197. GENERIC_READ,
  1198. FSD_SHARE_MODE,
  1199. NULL,
  1200. OPEN_EXISTING,
  1201. FILE_FLAG_BACKUP_SEMANTICS,
  1202. NULL );
  1203. if ( hFile == INVALID_HANDLE_VALUE )
  1204. {
  1205. bRet = FALSE;
  1206. goto EXIT;
  1207. }
  1208. FILE_OBJECTID_BUFFER sObjIdBuffer;
  1209. DWORD dwBytesReturned;
  1210. //
  1211. // Now get the object id info
  1212. //
  1213. if ( !::DeviceIoControl(
  1214. hFile,
  1215. FSCTL_GET_OBJECT_ID,
  1216. NULL, // lpInBuffer; must be NULL
  1217. 0, // nInBufferSize; must be zero
  1218. ( LPVOID )&sObjIdBuffer, // pointer to output buffer
  1219. sizeof FILE_OBJECTID_BUFFER,// size of output buffer
  1220. &dwBytesReturned, // receives number of bytes returned
  1221. NULL // pointer to OVERLAPPED structure
  1222. ) )
  1223. {
  1224. bRet = FALSE;
  1225. goto EXIT;
  1226. }
  1227. //
  1228. // Load up the object id
  1229. //
  1230. LPWSTR pwszObjIdGuid;
  1231. // Check for RPC_S_OK added for Prefix bug #192596
  1232. if ( ::UuidToStringW( (GUID *)sObjIdBuffer.ObjectId,
  1233. ( unsigned short ** )&pwszObjIdGuid ) == RPC_S_OK )
  1234. {
  1235. psExtendedInfo->cwsObjectId = pwszObjIdGuid;
  1236. ::RpcStringFreeW( ( unsigned short ** )&pwszObjIdGuid );
  1237. }
  1238. //
  1239. // Now checksum all of the extended object id data if necessary
  1240. //
  1241. if ( pcParams->m_bEnableObjectIdExtendedDataChecksums )
  1242. {
  1243. dwChecksum = ::eaChecksumBlock( 0, sObjIdBuffer.ExtendedInfo, sizeof( sObjIdBuffer.ExtendedInfo ) );
  1244. psExtendedInfo->cwsObjectIdExtendedDataChecksum.Format( pcParams->m_pwszULongHexFmt, dwChecksum );
  1245. *pullBytesChecksummed += sizeof( sObjIdBuffer.ExtendedInfo );
  1246. }
  1247. }
  1248. catch( ... )
  1249. {
  1250. bRet = FALSE;
  1251. }
  1252. EXIT:
  1253. if ( hFile != INVALID_HANDLE_VALUE )
  1254. ::CloseHandle( hFile );
  1255. // if ( bRet == FALSE )
  1256. // psExtendedInfo->cwsReparsePointDataChecksum.Format( L"<%6d>", ::GetLastError() );
  1257. }