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.

1243 lines
45 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 2000.
  5. //
  6. // File: propdump.cxx
  7. //
  8. // Contents: Property file dump utility
  9. //
  10. // History: 29 Oct 1996 KyleP Created
  11. //
  12. //--------------------------------------------------------------------------
  13. #include <pch.cxx>
  14. #pragma hdrstop
  15. #include <proprec.hxx>
  16. #include <propdesc.hxx>
  17. DECLARE_INFOLEVEL(ci)
  18. unsigned const SixtyFourK = 1024 * 64;
  19. unsigned const cMaxFields = 10;
  20. unsigned fVerbose = 0;
  21. enum eRecType
  22. {
  23. Virgin,
  24. Top,
  25. Overflow,
  26. Free
  27. };
  28. struct SmallInfo
  29. {
  30. ULONG Type;
  31. ULONG Length;
  32. ULONG ulPrev;
  33. ULONG ulNext;
  34. ULONG ulChainLength;
  35. };
  36. void Usage()
  37. {
  38. printf("Usage: PropDump [-?] [-v] [-m] [-f primary_field] [-s secondary_field] <primary file> [<secondary file>]\n");
  39. printf(" -? to dump this usage information.\n");
  40. printf(" -v to be verbose.\n");
  41. printf(" -m[o] to dump the metadata (o --> only. No integrity check).\n");
  42. printf(" -f field is used to dump a specific field in the primary store records.\n");
  43. printf(" -s field is used to dump a specific field in the secondary store records.\n");
  44. printf(" -c secWidPtrField is used to check for consistency between pri and sec stores. Param is usually 3.\n");
  45. printf(" -w[ps] <workid> dump only <workid> in primary/secondary store\n");
  46. printf(" <primary file> is the name of the primary file.\n");
  47. printf(" <secondary file> is the name of secondary file.\n");
  48. printf(" Specify primary and secondary for the two-level prop store.\n");
  49. printf(" If secondary is not specified, the primary will be construed as the name of the single store.\n");
  50. }
  51. char * pszPrimFile = 0;
  52. char * pszSecFile = 0;
  53. BOOL fReadMetadata = 0;
  54. BOOL fMetadataOnly = 0;
  55. unsigned cField1 = 0;
  56. unsigned cField2 = 0;
  57. int aiField1[cMaxFields];
  58. int aiField2[cMaxFields];
  59. BOOL fTwoLevel = FALSE;
  60. ULONG cPriRecPerBuf, cbPriRec, cPriTotal, cPriFixed;
  61. ULONG cSecRecPerBuf, cbSecRec, cSecTotal, cSecFixed;
  62. ULONG cMaxWidsInSecStore;
  63. int cWidPtrField = 0;
  64. ULONG widPrimary = 0xFFFFFFFF;
  65. ULONG widSecondary = 0xFFFFFFFF;
  66. const DWORD PrimaryStore = 0;
  67. const DWORD SecondaryStore = 1;
  68. void DumpStore(char *pszFile, unsigned cField, int *aiField, DWORD dwLevel, ULONG wid);
  69. void CheckConsistencyBetweenStores(char * pszPrimFile, char *pszSecFile);
  70. CPropDesc aFieldRec[cMaxFields];
  71. CPropDesc SecWidPtrFieldRec;
  72. int __cdecl main( int argc, char * argv[] )
  73. {
  74. if (argc < 2)
  75. {
  76. Usage();
  77. return 0;
  78. }
  79. for ( int i = 1; i < argc; i++ )
  80. {
  81. if ( argv[i][0] == '-' )
  82. {
  83. switch ( argv[i][1] )
  84. {
  85. case '?':
  86. Usage();
  87. return 0;
  88. case 'v':
  89. case 'V':
  90. fVerbose = 1;
  91. break;
  92. case 'm':
  93. case 'M':
  94. fReadMetadata = TRUE;
  95. if ( argv[i][2] == 'o' || argv[i][2] == 'O' )
  96. fMetadataOnly = TRUE;
  97. break;
  98. case 'f':
  99. case 'F':
  100. i++;
  101. if ( cField1 < cMaxFields )
  102. aiField1[cField1++] = strtol( argv[i], 0, 10 );
  103. break;
  104. case 's':
  105. case 'S':
  106. i++;
  107. if ( cField2 < cMaxFields )
  108. aiField2[cField2++] = strtol( argv[i], 0, 10 );
  109. break;
  110. case 'c':
  111. case 'C':
  112. i++;
  113. cWidPtrField = strtol(argv[i], 0, 10);
  114. // this works only if fReadMetadata is turned on
  115. fReadMetadata = TRUE;
  116. break;
  117. case 'w':
  118. case 'W':
  119. switch ( argv[i][2] )
  120. {
  121. case 'p':
  122. case 'P':
  123. case '\0':
  124. i++;
  125. widPrimary = strtol(argv[i], 0, 10);
  126. break;
  127. case 's':
  128. case 'S':
  129. i++;
  130. widSecondary = strtol(argv[i], 0, 10);
  131. break;
  132. }
  133. }
  134. }
  135. else
  136. {
  137. if (!pszPrimFile)
  138. pszPrimFile = argv[i];
  139. else
  140. {
  141. pszSecFile = argv[i];
  142. fTwoLevel = TRUE;
  143. }
  144. }
  145. }
  146. // If we don't have a primary file or a secondary file, look for them in the current directory.
  147. if (!pszPrimFile)
  148. {
  149. fTwoLevel = TRUE;
  150. pszPrimFile = "00000002.ps1";
  151. pszSecFile = "00000002.ps2";
  152. }
  153. // Verify that the propstore files are indeed available!
  154. if (0xFFFFFFFF == GetFileAttributesA(pszPrimFile))
  155. {
  156. printf("Can't find primary file %s for reason %d\n", pszPrimFile, GetLastError());
  157. return 0;
  158. }
  159. if (0xFFFFFFFF == GetFileAttributesA(pszSecFile))
  160. {
  161. printf("Can't find secondary file. Assuming single level property store\n");
  162. fTwoLevel = FALSE;
  163. }
  164. else
  165. fTwoLevel = TRUE;
  166. cPriRecPerBuf = cbPriRec = cSecRecPerBuf = cbSecRec = 0;
  167. //
  168. // CheckConsistencyBetweenStores relies on some of the information gathered
  169. // by calls to DumpStore, so they should be called before consistency check.
  170. //
  171. DumpStore(pszPrimFile, cField1, aiField1, PrimaryStore, widPrimary );
  172. if (fTwoLevel)
  173. {
  174. DumpStore(pszSecFile, cField2, aiField2, SecondaryStore, widSecondary);
  175. if (cWidPtrField > 0)
  176. {
  177. CheckConsistencyBetweenStores(pszPrimFile, pszSecFile);
  178. }
  179. }
  180. return 0;
  181. }
  182. void DumpStore(char *pszFile, unsigned cField, int *aiField, DWORD dwLevel, ULONG wid )
  183. {
  184. BYTE abTemp[SixtyFourK];
  185. //
  186. // First, read out the metadata
  187. //
  188. unsigned cFixed = 0;
  189. unsigned cTotal = 0;
  190. unsigned culFixed = 0;
  191. if ( fReadMetadata || cField != 0 )
  192. {
  193. //
  194. // Build path.
  195. //
  196. char szPath[MAX_PATH];
  197. strcpy( szPath, pszFile );
  198. char * pLastSlash = strrchr( szPath, '\\' );
  199. if (pLastSlash)
  200. pLastSlash++;
  201. else
  202. pLastSlash = szPath;
  203. if (fTwoLevel)
  204. {
  205. if (PrimaryStore == dwLevel)
  206. strcpy( pLastSlash, "CIP10000.001" );
  207. else
  208. strcpy( pLastSlash, "CIP20000.001" );
  209. }
  210. else
  211. strcpy( pLastSlash, "CIPS0000.001" );
  212. HANDLE h = CreateFileA( szPath,
  213. GENERIC_READ,
  214. FILE_SHARE_READ,
  215. 0,
  216. OPEN_EXISTING,
  217. 0,
  218. 0 );
  219. if ( INVALID_HANDLE_VALUE == h )
  220. {
  221. printf( "Can't open file %s. Error %u\n", szPath, GetLastError() );
  222. return;
  223. }
  224. ULONG cbRead;
  225. if ( ReadFile( h,
  226. abTemp,
  227. sizeof(abTemp),
  228. &cbRead,
  229. 0 ) )
  230. {
  231. //
  232. // Loop through records
  233. //
  234. CPropDesc * pPropDesc = (CPropDesc *)abTemp;
  235. if ( fReadMetadata )
  236. printf( "Record\t%-25s Type\t\tOffset\tSize\tOrdinal\tMask\n",
  237. " Pid" );
  238. for ( unsigned i = 0;
  239. i < cbRead/(sizeof(CPropDesc) + sizeof(ULONG));
  240. i++, pPropDesc = (CPropDesc *)(((BYTE *)pPropDesc) + sizeof(CPropDesc) + sizeof(ULONG)) )
  241. {
  242. if ( pPropDesc->Pid() != 0 )
  243. {
  244. if ( fReadMetadata )
  245. {
  246. char * pszPidName = 0;
  247. char * pszMarker = "";
  248. switch (pPropDesc->Pid())
  249. {
  250. case pidSecurity:
  251. pszPidName = "pidSecurity"; break;
  252. case pidDirectory:
  253. pszPidName = "pidDirectory"; break;
  254. case pidClassId:
  255. pszPidName = "pidClassId"; break;
  256. case pidStorageType:
  257. pszPidName = "pidStorageType"; break;
  258. case pidFileIndex:
  259. pszPidName = "pidFileIndex"; break;
  260. case pidVolumeId:
  261. pszPidName = "pidVolumeId"; break;
  262. case pidParentWorkId:
  263. pszPidName = "pidParentWorkId"; break;
  264. case pidLastChangeUsn:
  265. pszPidName = "pidLastChangeUsn"; break;
  266. case pidName:
  267. pszPidName = "pidName"; break;
  268. case pidSize:
  269. pszPidName = "pidSize"; break;
  270. case pidAttrib:
  271. pszPidName = "pidAttrib"; break;
  272. case pidWriteTime:
  273. pszPidName = "pidWriteTime"; break;
  274. case pidCreateTime:
  275. pszPidName = "pidCreateTime"; break;
  276. case pidAccessTime:
  277. pszPidName = "pidAccessTime"; break;
  278. case pidShortName:
  279. pszPidName = "pidShortName"; break;
  280. case pidWorkId:
  281. pszPidName = "pidWorkId"; break;
  282. case pidUnfiltered:
  283. pszPidName = "pidUnfiltered"; break;
  284. case pidRevName:
  285. pszPidName = "pidRevName"; break;
  286. case pidVirtualPath:
  287. pszPidName = "pidVirtualPath"; break;
  288. case pidLastSeenTime:
  289. pszPidName = "pidLastSeenTime"; break;
  290. case pidPath:
  291. pszPidName = "pidPath";
  292. pszMarker = "**";
  293. break;
  294. case pidSecondaryStorage:
  295. pszPidName = "pidSecondaryStorage";
  296. pszMarker = "*";
  297. break;
  298. }
  299. static char achBuf[20];
  300. if ( 0 == pszPidName )
  301. {
  302. sprintf( achBuf, " %d(0x%x)",
  303. pPropDesc->Pid(), pPropDesc->Pid() );
  304. }
  305. else
  306. {
  307. sprintf( achBuf, "%-3s%d(%s)",
  308. pszMarker, pPropDesc->Pid(), pszPidName );
  309. }
  310. printf( "%u:\t%-25s %u (0x%x)\t%d\t%u\t%u\t0x%x\n",
  311. pPropDesc->Record(),
  312. achBuf,
  313. pPropDesc->Type(), pPropDesc->Type(),
  314. pPropDesc->Offset(),
  315. pPropDesc->Size(),
  316. pPropDesc->Ordinal(),
  317. pPropDesc->Mask() );
  318. }
  319. cTotal++;
  320. if ( pPropDesc->Offset() != -1 )
  321. {
  322. cFixed++;
  323. culFixed += (pPropDesc->Size() / sizeof(DWORD));
  324. }
  325. // copy the description of the sec top-level wid ptr for later use
  326. if ( PrimaryStore == dwLevel && cWidPtrField && cWidPtrField == (int)pPropDesc->Record() )
  327. {
  328. memcpy( &SecWidPtrFieldRec, pPropDesc, sizeof(aFieldRec[0]) );
  329. }
  330. for ( unsigned j = 0; j < cField; j++ )
  331. {
  332. if ( aiField[j] == (int)pPropDesc->Record() )
  333. memcpy( &aFieldRec[j], pPropDesc, sizeof(aFieldRec[0]) );
  334. if (cWidPtrField && cWidPtrField == (int)j )
  335. {
  336. // verify that we are capturing the right property
  337. // description for the sec top-level wid ptr
  338. for (int k = 0; k < sizeof(aFieldRec[0]); k++)
  339. {
  340. Win4Assert(RtlEqualMemory(&aFieldRec[j], &SecWidPtrFieldRec, sizeof(SecWidPtrFieldRec)));
  341. }
  342. }
  343. }
  344. }
  345. }
  346. printf( "\n%u Properties, %u Fixed totaling %u bytes (* = Secondary link, ** = Path)\n\n",
  347. cTotal, cFixed, culFixed * sizeof(DWORD) );
  348. }
  349. else
  350. {
  351. printf( "Can't read file %s. Error %u\n", szPath, GetLastError() );
  352. return;
  353. }
  354. CloseHandle(h);
  355. if ( fMetadataOnly )
  356. return;
  357. }
  358. HANDLE h = CreateFileA( pszFile,
  359. GENERIC_READ,
  360. FILE_SHARE_READ,
  361. 0,
  362. OPEN_EXISTING,
  363. 0,
  364. 0 );
  365. if ( INVALID_HANDLE_VALUE == h &&
  366. ERROR_SHARING_VIOLATION == GetLastError() )
  367. {
  368. h = CreateFileA( pszFile,
  369. GENERIC_READ,
  370. FILE_SHARE_READ | FILE_SHARE_WRITE,
  371. 0,
  372. OPEN_EXISTING,
  373. 0,
  374. 0 );
  375. }
  376. if ( INVALID_HANDLE_VALUE == h )
  377. {
  378. printf( "Can't open file %s. Error %u\n", pszFile, GetLastError() );
  379. return;
  380. }
  381. BY_HANDLE_FILE_INFORMATION fi;
  382. if ( !GetFileInformationByHandle( h, &fi ) )
  383. {
  384. printf( "Error %u getting size from handle\n", GetLastError() );
  385. return;
  386. }
  387. ULONG oFile = 0;
  388. ULONG cbRec = 0;
  389. ULONG cRecPerBuf;
  390. ULONG cRecTotal;
  391. ULONG cTotalSections = 0;
  392. HANDLE hSmallInfo;
  393. SmallInfo * aSmallInfo = 0;
  394. ULONG iSection = 0;
  395. BOOL fFirst = TRUE;
  396. ULONG iCurrentPct = 0;
  397. ULONG cTopLevel = 0;
  398. ULONG cOverflow = 0;
  399. ULONG cFree = 0;
  400. ULONG cVirgin = 0;
  401. for (;;)
  402. {
  403. ULONG cbRead;
  404. if ( ReadFile( h,
  405. abTemp,
  406. sizeof(abTemp),
  407. &cbRead,
  408. 0 ) )
  409. {
  410. if (fVerbose)
  411. printf( "READ: 0x%x bytes, offset 0x%x\n", cbRead, oFile );
  412. if ( 0 == cbRead )
  413. break;
  414. if ( fFirst )
  415. {
  416. //
  417. // Determine record size
  418. //
  419. if ( abTemp[0] != 0 || abTemp[1] != 0 )
  420. {
  421. printf( "Record 0 not blank. File corrupt!\n" );
  422. break;
  423. }
  424. // First record should be all empty and only the first
  425. // record should be so. So counting all leading zeros gives us
  426. // the size of the record.
  427. for ( unsigned i = 0; i < cbRead && abTemp[i] == 0; i++ )
  428. continue;
  429. if ( i == cbRead )
  430. {
  431. printf( "First %uK segment all zero!. File corrupt!\n", sizeof(abTemp)/1024 );
  432. break;
  433. }
  434. switch ( *(USHORT *)&abTemp[i] )
  435. {
  436. case 0x5555:
  437. case 0xAAAA:
  438. case 0xBBBB:
  439. case 0xCCCC:
  440. case 0xDDDD:
  441. cbRec = i;
  442. if ( cbRec % 4 != 0 )
  443. {
  444. printf( "Record size (%u bytes) not DWORD aligned!\n\n", cbRec );
  445. return;
  446. }
  447. cRecPerBuf = sizeof(abTemp) / cbRec;
  448. printf( "Record size: %u bytes (%u / %uK)\n", i, cRecPerBuf, sizeof(abTemp)/1024 );
  449. cTotalSections = (fi.nFileSizeLow + sizeof(abTemp) - 1)/ sizeof abTemp;
  450. hSmallInfo = LocalAlloc( LMEM_MOVEABLE,
  451. ((fi.nFileSizeLow / sizeof(abTemp)) + 1) * cRecPerBuf * sizeof(SmallInfo) );
  452. aSmallInfo = (SmallInfo *)LocalLock( hSmallInfo );
  453. break;
  454. default:
  455. printf( "First non-zero byte is not a proper signature (%u)!\n", *(SHORT *)&abTemp[i] );
  456. return;
  457. }
  458. if (PrimaryStore == dwLevel)
  459. {
  460. cPriRecPerBuf = cRecPerBuf;
  461. cbPriRec = cbRec;
  462. cPriTotal = cTotal;
  463. cPriFixed = cFixed;
  464. }
  465. else
  466. {
  467. cSecRecPerBuf = cRecPerBuf;
  468. cbSecRec = cbRec;
  469. cSecTotal = cTotal;
  470. cSecFixed = cFixed;
  471. }
  472. fFirst = FALSE;
  473. }
  474. ULONG iRec = 0;
  475. while ( iRec < cRecPerBuf )
  476. {
  477. COnDiskPropertyRecord * pRec = new( iRec, abTemp, cbRec/4 ) COnDiskPropertyRecord;
  478. if ( !pRec->IsValidType() )
  479. {
  480. printf( "Record 0x%x (%u:%u) (file offset 0x%x) is corrupt!\n",
  481. iSection * cRecPerBuf + iRec,
  482. iSection, iRec,
  483. iSection * sizeof(abTemp) + iRec * cbRec );
  484. }
  485. if (fVerbose )
  486. printf( "%u:%u, %s, length = %u record(s)",
  487. iSection, iRec,
  488. pRec->IsNormalTopLevel() ? "Top Level Normal" :
  489. pRec->IsOverflow() ? "Overflow" :
  490. pRec->IsFreeRecord() ? "Free Normal" :
  491. pRec->IsTopLevel() ? "Top Level Lean":
  492. pRec->IsLeanFreeRecord() ? "Free Lean":
  493. "Virgin",
  494. pRec->CountRecords() );
  495. aSmallInfo[iSection*cRecPerBuf + iRec].ulChainLength = 0;
  496. BOOL fPrint = (0xFFFFFFFF == wid || iSection*cRecPerBuf + iRec == wid);
  497. if ( pRec->IsOverflow() )
  498. {
  499. aSmallInfo[iSection*cRecPerBuf + iRec].Type = Overflow;
  500. cOverflow++;
  501. for ( unsigned j = 0; j < cField; j++ )
  502. {
  503. PROPVARIANT var;
  504. BYTE abExtra[MAX_PATH * 5];
  505. unsigned cbExtra = sizeof(abExtra);
  506. if ( 0 == j && fPrint )
  507. printf( "%6u: ", iSection*cRecPerBuf + iRec );
  508. if ( aFieldRec[j].IsFixedSize() )
  509. continue;
  510. ULONG Ordinal = aFieldRec[j].Ordinal() - cFixed;
  511. DWORD Mask = (1 << ((Ordinal % 16) * 2) );
  512. BOOL fOk = pRec->ReadVariable( Ordinal,
  513. Mask,
  514. 0,
  515. cTotal - cFixed,
  516. 0,
  517. var,
  518. abExtra,
  519. &cbExtra );
  520. if ( fOk && fPrint )
  521. {
  522. switch ( var.vt )
  523. {
  524. case VT_LPSTR:
  525. printf( "%s ", var.pszVal );
  526. break;
  527. case VT_LPWSTR:
  528. printf( "%ws ", var.pwszVal );
  529. break;
  530. }
  531. }
  532. }
  533. if ( 0 != cField && fPrint )
  534. printf( "\n" );
  535. }
  536. else if ( pRec->IsNormalTopLevel() )
  537. {
  538. aSmallInfo[iSection*cRecPerBuf + iRec].Type = Top;
  539. aSmallInfo[iSection*cRecPerBuf + iRec].ulChainLength = pRec->GetOverflowChainLength();
  540. cTopLevel++;
  541. for ( unsigned j = 0; j < cField; j++ )
  542. {
  543. PROPVARIANT var;
  544. BYTE abExtra[MAX_PATH * 5];
  545. unsigned cbExtra = sizeof(abExtra);
  546. if ( 0 == j && fPrint )
  547. printf( "%6u: ", iSection*cRecPerBuf + iRec );
  548. if ( aFieldRec[j].IsFixedSize() )
  549. {
  550. pRec->ReadFixed( aFieldRec[j].Ordinal(),
  551. aFieldRec[j].Mask(),
  552. aFieldRec[j].Offset(),
  553. cTotal,
  554. aFieldRec[j].Type(),
  555. var,
  556. abExtra,
  557. &cbExtra,
  558. *((PStorage *)0) );
  559. if ( fPrint )
  560. {
  561. switch ( var.vt )
  562. {
  563. case VT_EMPTY:
  564. printf( "n/a " );
  565. break;
  566. case VT_I4:
  567. printf( "%8d ", var.lVal );
  568. break;
  569. case VT_UI4:
  570. printf( "%8u ", var.ulVal );
  571. break;
  572. case VT_FILETIME:
  573. {
  574. SYSTEMTIME stTime;
  575. FileTimeToSystemTime( &var.filetime, &stTime );
  576. WCHAR awcBuffer[100] = L"???";
  577. GetDateFormat( LOCALE_USER_DEFAULT, // locale
  578. 0, // flags
  579. &stTime, // time
  580. L"MM/dd/yy ", // format
  581. awcBuffer, // output
  582. sizeof(awcBuffer)/sizeof(awcBuffer[0]) );
  583. GetTimeFormat( LOCALE_USER_DEFAULT, // locale
  584. 0, // flags
  585. &stTime, // time
  586. L"hh:mmt", // format
  587. awcBuffer + 10, // output
  588. sizeof(awcBuffer)/sizeof(awcBuffer[0]) - 10 );
  589. awcBuffer[15] += 0x20; // lowercase
  590. printf( "%ws ", awcBuffer );
  591. }
  592. break;
  593. case VT_I8:
  594. printf( "%12hu ", var.hVal );
  595. break;
  596. case VT_UI8:
  597. printf( "0x%08lx%08lx ", (ULONG) (var.uhVal.QuadPart>>32), (ULONG) var.uhVal.QuadPart );
  598. break;
  599. }
  600. }
  601. }
  602. else
  603. {
  604. BOOL fOk = pRec->ReadVariable( aFieldRec[j].Ordinal(),
  605. aFieldRec[j].Mask(),
  606. culFixed,
  607. cTotal,
  608. cFixed,
  609. var,
  610. abExtra,
  611. &cbExtra );
  612. if ( fOk && fPrint )
  613. {
  614. switch ( var.vt )
  615. {
  616. case VT_LPSTR:
  617. printf( "%s ", var.pszVal );
  618. break;
  619. case VT_LPWSTR:
  620. printf( "%ws ", var.pwszVal );
  621. break;
  622. }
  623. }
  624. }
  625. }
  626. if ( 0 != cField && fPrint )
  627. printf( "\n" );
  628. }
  629. else if ( pRec->IsTopLevel() )
  630. {
  631. // This is a lean top level record
  632. aSmallInfo[iSection*cRecPerBuf + iRec].Type = Top;
  633. aSmallInfo[iSection*cRecPerBuf + iRec].ulChainLength = 0;
  634. cTopLevel++;
  635. for ( unsigned j = 0; j < cField; j++ )
  636. {
  637. PROPVARIANT var;
  638. BYTE abExtra[MAX_PATH * 5];
  639. unsigned cbExtra = sizeof(abExtra);
  640. if ( 0 == j && fPrint )
  641. printf( "%6u: ", iSection*cRecPerBuf + iRec );
  642. Win4Assert(aFieldRec[j].IsFixedSize());
  643. {
  644. pRec->ReadFixed( aFieldRec[j].Ordinal(),
  645. aFieldRec[j].Mask(),
  646. aFieldRec[j].Offset(),
  647. cTotal,
  648. aFieldRec[j].Type(),
  649. var,
  650. abExtra,
  651. &cbExtra,
  652. *((PStorage *)0) );
  653. if ( fPrint )
  654. {
  655. switch ( var.vt )
  656. {
  657. case VT_EMPTY:
  658. printf( "n/a " );
  659. break;
  660. case VT_I4:
  661. printf( "%8d ", var.lVal );
  662. break;
  663. case VT_UI4:
  664. printf( "%8u ", var.ulVal );
  665. break;
  666. case VT_FILETIME:
  667. {
  668. SYSTEMTIME stTime;
  669. FileTimeToSystemTime( &var.filetime, &stTime );
  670. WCHAR awcBuffer[100] = L"???";
  671. GetDateFormat( LOCALE_USER_DEFAULT, // locale
  672. 0, // flags
  673. &stTime, // time
  674. L"MM/dd/yy ", // format
  675. awcBuffer, // output
  676. sizeof(awcBuffer)/sizeof(awcBuffer[0]) );
  677. GetTimeFormat( LOCALE_USER_DEFAULT, // locale
  678. 0, // flags
  679. &stTime, // time
  680. L"hh:mmt", // format
  681. awcBuffer + 10, // output
  682. sizeof(awcBuffer)/sizeof(awcBuffer[0]) - 10 );
  683. awcBuffer[15] += 0x20; // lowercase
  684. printf( "%ws ", awcBuffer );
  685. }
  686. break;
  687. case VT_I8:
  688. printf( "%12hu ", var.hVal );
  689. break;
  690. case VT_UI8:
  691. printf( "0x%08lx%08lx ", (ULONG) (var.uhVal.QuadPart>>32), (ULONG) var.uhVal.QuadPart );
  692. break;
  693. }
  694. }
  695. }
  696. }
  697. if ( 0 != cField && fPrint )
  698. printf( "\n" );
  699. }
  700. else if ( pRec->IsFreeRecord() )
  701. {
  702. aSmallInfo[iSection*cRecPerBuf + iRec].Type = Free;
  703. cFree++;
  704. }
  705. else
  706. {
  707. aSmallInfo[iSection*cRecPerBuf + iRec].Type = Virgin;
  708. cVirgin++;
  709. }
  710. if (pRec->IsNormalTopLevel() || pRec->IsOverflow())
  711. {
  712. aSmallInfo[iSection*cRecPerBuf + iRec].ulPrev = pRec->ToplevelBlock();
  713. aSmallInfo[iSection*cRecPerBuf + iRec].ulNext = pRec->OverflowBlock();
  714. if ( pRec->OverflowBlock() != 0 )
  715. {
  716. /* printf( ", Overflow = %u:%u (file offset 0x%x)",
  717. pRec->OverflowBlock() / cRecPerBuf,
  718. pRec->OverflowBlock() % cRecPerBuf,
  719. (pRec->OverflowBlock() / cRecPerBuf) * sizeof(abTemp) +
  720. (pRec->OverflowBlock() % cRecPerBuf) * cbRec ); */
  721. }
  722. }
  723. else if (pRec->IsTopLevel())
  724. {
  725. aSmallInfo[iSection*cRecPerBuf + iRec].ulPrev = 0;
  726. aSmallInfo[iSection*cRecPerBuf + iRec].ulNext = 0;
  727. }
  728. else if (pRec->IsFreeRecord())
  729. {
  730. aSmallInfo[iSection*cRecPerBuf + iRec].ulPrev = pRec->GetPreviousFreeRecord();
  731. aSmallInfo[iSection*cRecPerBuf + iRec].ulNext = pRec->GetNextFreeRecord();
  732. }
  733. aSmallInfo[iSection*cRecPerBuf + iRec].Length = pRec->CountRecords();
  734. if ( pRec->CountRecords() == 0 )
  735. {
  736. printf( "Record %u (file offset 0x%x) is zero length!\n",
  737. iSection * cRecPerBuf + iRec,
  738. iSection * sizeof(abTemp) + iRec * cbRec );
  739. }
  740. if (fVerbose)
  741. printf( "\n" );
  742. if ( pRec->IsValidType() )
  743. iRec += pRec->CountRecords();
  744. else
  745. iRec++;
  746. ULONG iPct = (iSection * (100/5) / cTotalSections) * 5;
  747. if (iPct != iCurrentPct)
  748. {
  749. iCurrentPct = iPct;
  750. if (0 == wid)
  751. printf( "Read %u%%\n", iCurrentPct );
  752. }
  753. }
  754. iSection++;
  755. oFile += cbRead;
  756. }
  757. else
  758. {
  759. ULONG Status = GetLastError();
  760. if ( Status == ERROR_HANDLE_EOF )
  761. break;
  762. else
  763. {
  764. printf( "Error %u reading file.\n", Status );
  765. }
  766. }
  767. }
  768. if (SecondaryStore == dwLevel)
  769. cMaxWidsInSecStore = iSection * cRecPerBuf;
  770. if (wid == 0 || wid == 0xFFFFFFFF)
  771. {
  772. printf( "Read 100%%\n" );
  773. printf( "%6u Top-Level records\n"
  774. "%6u Overflow records\n"
  775. "%6u Free records\n"
  776. "%6u Virgin records\n", cTopLevel, cOverflow, cFree, cVirgin );
  777. }
  778. CloseHandle( h );
  779. //
  780. // Now check inter-record state
  781. //
  782. unsigned iRec = 0;
  783. unsigned iCurrentSection = 0;
  784. iCurrentPct = 0;
  785. while ( iRec < iSection * cRecPerBuf )
  786. {
  787. if ( aSmallInfo[iRec].Type == Top )
  788. {
  789. unsigned iOverflowRec = aSmallInfo[iRec].ulNext;
  790. unsigned cOverflowRec = 0;
  791. while ( 0 != iOverflowRec )
  792. {
  793. if ( aSmallInfo[iOverflowRec].Type != Overflow )
  794. {
  795. printf( "Record 0x%x (%u:%u) (file offset 0x%x) should be overflow and is not!\n Top level = 0x%x (%u:%u) (file offset 0x%x)\n",
  796. iOverflowRec,
  797. iOverflowRec / cRecPerBuf,
  798. iOverflowRec % cRecPerBuf,
  799. (iOverflowRec / cRecPerBuf) * sizeof(abTemp) +
  800. (iOverflowRec % cRecPerBuf) * cbRec,
  801. iRec,
  802. iRec / cRecPerBuf,
  803. iRec % cRecPerBuf,
  804. (iRec / cRecPerBuf) * sizeof(abTemp) +
  805. (iRec % cRecPerBuf) * cbRec );
  806. break;
  807. }
  808. iOverflowRec = aSmallInfo[iOverflowRec].ulNext;
  809. cOverflowRec++;
  810. if ( cOverflowRec > aSmallInfo[iRec].ulChainLength )
  811. break;
  812. }
  813. if ( aSmallInfo[iRec].ulChainLength != cOverflowRec )
  814. {
  815. printf( "Record 0x%x (%u:%u) (file offset 0x%x) chain length mismatch %d,%d!\n",
  816. iRec,
  817. iRec / cRecPerBuf,
  818. iRec % cRecPerBuf,
  819. (iRec / cRecPerBuf) * sizeof(abTemp) +
  820. (iRec % cRecPerBuf) * cbRec,
  821. aSmallInfo[iRec].ulChainLength, cOverflowRec );
  822. }
  823. }
  824. if (aSmallInfo[iRec].Length == 0)
  825. {
  826. printf( "%u:%u (file offset 0x%x) zero length record!\n",
  827. iRec / cRecPerBuf,
  828. iRec % cRecPerBuf,
  829. (iRec / cRecPerBuf) * sizeof(abTemp) +
  830. (iRec % cRecPerBuf) * cbRec );
  831. iRec++;
  832. } else {
  833. iRec += aSmallInfo[iRec].Length;
  834. }
  835. if ( (iRec / cRecPerBuf) != iCurrentSection )
  836. {
  837. if (fVerbose)
  838. printf( "Checked section %u\n", iCurrentSection );
  839. ULONG iPct = (iCurrentSection * (100/5) / iSection) * 5;
  840. if (iPct != iCurrentPct)
  841. {
  842. iCurrentPct = iPct;
  843. if (wid == 0 || wid == 0xFFFFFFFF)
  844. printf( "Checked %u%%\n", iCurrentPct );
  845. }
  846. iCurrentSection = (iRec / cRecPerBuf);
  847. }
  848. }
  849. if (wid == 0 || wid == 0xFFFFFFFF)
  850. printf( "Checked 100%%\n" );
  851. LocalUnlock( hSmallInfo );
  852. LocalFree( hSmallInfo );
  853. }
  854. void CheckConsistencyBetweenStores(char * pszPriFile, char *pszSecFile)
  855. {
  856. BYTE abTemp[SixtyFourK];
  857. BYTE abTemp2[SixtyFourK];
  858. ULONG iSection2 = 0, iTargetSection = 0, oFile = 0, iSection = 0;
  859. ULONG cInconsistencies = 0;
  860. ULONG cPriTotalSections = 0;
  861. ULONG cSecTotalSections = 0;
  862. ULONG iCurrentPct = 0;
  863. HANDLE hPri = CreateFileA( pszPriFile,
  864. GENERIC_READ,
  865. FILE_SHARE_READ,
  866. 0,
  867. OPEN_EXISTING,
  868. 0,
  869. 0 );
  870. if ( INVALID_HANDLE_VALUE == hPri )
  871. {
  872. printf( "Can't open file %s. Error %u\n", pszPriFile, GetLastError() );
  873. return;
  874. }
  875. HANDLE hSec = CreateFileA( pszSecFile,
  876. GENERIC_READ,
  877. FILE_SHARE_READ,
  878. 0,
  879. OPEN_EXISTING,
  880. 0,
  881. 0 );
  882. if ( INVALID_HANDLE_VALUE == hSec )
  883. {
  884. printf( "Can't open file %s. Error %u\n", pszSecFile, GetLastError() );
  885. return;
  886. }
  887. BY_HANDLE_FILE_INFORMATION fi;
  888. if ( GetFileInformationByHandle( hPri, &fi ) )
  889. {
  890. cPriTotalSections = (fi.nFileSizeLow + sizeof(abTemp) - 1)/ sizeof abTemp;
  891. }
  892. else
  893. {
  894. printf( "Error %u getting size from primary's handle\n", GetLastError() );
  895. return;
  896. }
  897. if ( GetFileInformationByHandle( hSec, &fi ) )
  898. {
  899. cSecTotalSections = (fi.nFileSizeLow + sizeof(abTemp) - 1)/ sizeof abTemp;
  900. }
  901. else
  902. {
  903. printf( "Error %u getting size from secondary's handle\n", GetLastError() );
  904. return;
  905. }
  906. ULONG ulSecWidPtr = widInvalid;
  907. // read the first large page of the secondary store into memory.
  908. DWORD cbRead2;
  909. ReadFile( hSec, abTemp2, sizeof(abTemp2), &cbRead2, 0 );
  910. for (;;)
  911. {
  912. ULONG cbRead;
  913. if ( ReadFile( hPri, abTemp, sizeof(abTemp), &cbRead, 0 ) )
  914. {
  915. if ( 0 == cbRead )
  916. break;
  917. ULONG iRec = 0;
  918. while ( iRec < cPriRecPerBuf )
  919. {
  920. COnDiskPropertyRecord * pRec = new( iRec, abTemp, cbPriRec/4 ) COnDiskPropertyRecord;
  921. if ( pRec->IsTopLevel() )
  922. {
  923. Win4Assert(!pRec->IsNormalTopLevel());
  924. PROPVARIANT var;
  925. BYTE abExtra[MAX_PATH * 5];
  926. unsigned cbExtra = sizeof(abExtra);
  927. Win4Assert(SecWidPtrFieldRec.IsFixedSize());
  928. {
  929. pRec->ReadFixed( SecWidPtrFieldRec.Ordinal(),
  930. SecWidPtrFieldRec.Mask(),
  931. SecWidPtrFieldRec.Offset(),
  932. cPriTotal,
  933. SecWidPtrFieldRec.Type(),
  934. var,
  935. abExtra,
  936. &cbExtra,
  937. *((PStorage *)0) );
  938. switch ( var.vt )
  939. {
  940. case VT_EMPTY:
  941. Win4Assert(!"Reading VT_EMPTY. Expect to read VT_UI4");
  942. break;
  943. case VT_I4:
  944. Win4Assert(!"Reading VT_I4. Expect to read VT_UI4");
  945. break;
  946. case VT_UI4:
  947. {
  948. // Do we need to read a new large page?
  949. iTargetSection = var.ulVal/cSecRecPerBuf;
  950. if (var.ulVal > cMaxWidsInSecStore) // ensure that it is a valid wid in secondary store.
  951. {
  952. printf("Wid %u (0x%x) is pointing to a non-existent wid %u (0x%x) in Secondary store.\n",
  953. iSection*cPriRecPerBuf + iRec, iSection*cPriRecPerBuf + iRec,
  954. var.ulVal, var.ulVal);
  955. continue;
  956. }
  957. if (iSection2 != iTargetSection)
  958. {
  959. // seek to the target section and read the large page into buffer.
  960. //SetFilePointer(hSec, (iTargetSection - iSection2)*SixtyFourK, 0, FILE_CURRENT);
  961. SetFilePointer(hSec, iTargetSection*SixtyFourK, 0, FILE_BEGIN);
  962. ReadFile( hSec, abTemp2, sizeof(abTemp2), &cbRead2, 0 );
  963. iSection2 = iTargetSection;
  964. }
  965. // Get the record in question.
  966. COnDiskPropertyRecord * pRec2 = new( var.ulVal % cSecRecPerBuf, abTemp2, cbSecRec/4 ) COnDiskPropertyRecord;
  967. // Now grill it!
  968. if (!pRec2->IsNormalTopLevel())
  969. {
  970. cInconsistencies++;
  971. // Invalid record type
  972. printf("Error: Wid %u (0x%x), (%u:%u) is pointing to a non-toplevel wid %u (0x%x), ",
  973. iSection*cPriRecPerBuf + iRec,
  974. iSection*cPriRecPerBuf + iRec,
  975. iSection, iRec,
  976. var.ulVal, var.ulVal);
  977. printf("(%u:%u), %s, length = %u record(s)\n",
  978. iSection2, var.ulVal % cSecRecPerBuf,
  979. pRec2->IsNormalTopLevel() ? "Top Level Normal" :
  980. pRec2->IsOverflow() ? "Overflow" :
  981. pRec2->IsFreeRecord() ? "Free Normal" :
  982. pRec2->IsTopLevel() ? "Top Level Lean":
  983. pRec2->IsLeanFreeRecord() ? "Free Lean":
  984. "Virgin",
  985. pRec2->CountRecords() );
  986. }
  987. break;
  988. }
  989. case VT_FILETIME:
  990. Win4Assert(!"Reading VT_FILETIME. Expect to read VT_UI4");
  991. break;
  992. case VT_I8:
  993. Win4Assert(!"Reading VT_I8. Expect to read VT_UI4");
  994. break;
  995. case VT_UI8:
  996. Win4Assert(!"Reading VT_UI8. Expect to read VT_UI4");
  997. break;
  998. }
  999. }
  1000. }
  1001. else if ( pRec->IsFreeRecord() )
  1002. {
  1003. }
  1004. else
  1005. {
  1006. }
  1007. if ( pRec->CountRecords() == 0 )
  1008. {
  1009. printf( "Record %u (file offset 0x%x) is zero length!\n",
  1010. iSection * cPriRecPerBuf + iRec,
  1011. iSection * sizeof(abTemp) + iRec * cbPriRec );
  1012. }
  1013. if ( pRec->IsValidType() )
  1014. iRec += pRec->CountRecords();
  1015. else
  1016. iRec++;
  1017. ULONG iPct = (iSection * (100/5) / cPriTotalSections) * 5;
  1018. if (iPct != iCurrentPct)
  1019. {
  1020. iCurrentPct = iPct;
  1021. printf( "Read %u%%\n", iCurrentPct );
  1022. }
  1023. }
  1024. iSection++;
  1025. oFile += cbRead;
  1026. }
  1027. else
  1028. {
  1029. ULONG Status = GetLastError();
  1030. if ( Status == ERROR_HANDLE_EOF )
  1031. break;
  1032. else
  1033. {
  1034. printf( "Error %u reading file.\n", Status );
  1035. }
  1036. }
  1037. }
  1038. CloseHandle( hPri );
  1039. CloseHandle( hSec );
  1040. if (cInconsistencies)
  1041. {
  1042. printf("%d inconsistencies were detected between the two stores.\n", cInconsistencies);
  1043. }
  1044. else
  1045. printf("No inconsistencies were detected between the two stores.\n");
  1046. }