Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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