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.

783 lines
20 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. hivestat.c
  5. Abstract:
  6. Dumps various statistics on hv (low) level structures in a hive. (See
  7. regstat for higher level stuff.)
  8. Statistics:
  9. Short: # of bins
  10. average bin size
  11. max bin size
  12. # of cells
  13. # of free cells
  14. # of allocated cells
  15. average free cell size
  16. total free size
  17. max free cell size
  18. average allocated size
  19. total allocated size
  20. max allocated cell size
  21. overhead summary (header, bin headers, cell headers)
  22. Long: bin#, offset, size
  23. cell offset, size, allocated
  24. cell offset, size, free
  25. Usage: {[+|-][<option>]} <filename>
  26. (+ = on by default, - = off by default)
  27. +s = summary - all of the short statistics
  28. -t[bafc] = trace, line per entry, bin, allocated, free, all cells
  29. (+tbc == +tbaf)
  30. -c = cell type summary
  31. -a[kvs] = Access Export (key nodes, values, SDs)
  32. Author:
  33. Bryan M. Willman (bryanwi) 2-Sep-1992
  34. Revision History:
  35. --*/
  36. /*
  37. NOTE: Unlike other hive/registry tools, this one will not read the
  38. entire hive into memory, but will instead read it in via
  39. file I/O. This makes it faster/easier to apply to very large
  40. hives.
  41. */
  42. #include "regutil.h"
  43. #include "edithive.h"
  44. #include <stdio.h>
  45. #include <stdlib.h>
  46. #include <string.h>
  47. #include <windows.h>
  48. UCHAR *helptext[] = {
  49. "hivestat: ",
  50. "Statistics: ",
  51. " Short: # of bins ",
  52. " average bin size ",
  53. " max bin size ",
  54. " # of cells ",
  55. " # of free cells ",
  56. " # of allocated cells ",
  57. " average free cell size ",
  58. " total free size ",
  59. " max free cell size ",
  60. " average allocated size ",
  61. " total allocated size ",
  62. " max allocated cell size ",
  63. " overhead summary (header, bin headers, cell headers) ",
  64. " Long: bin#, offset, size ",
  65. " cell offset, size, allocated ",
  66. " cell offset, size, free ",
  67. "Usage: {[+|-][<option>]} <filename> ",
  68. " (+ = on by default, - = off by default) ",
  69. " +s = summary - all of the short statistics ",
  70. " -t[bafc] = trace, line per entry, bin, allocated, free, all cells",
  71. " (+tbc == +tbaf) ",
  72. " -c = cell type summary ",
  73. " -a[kvs] = Access Export (key nodes, values, SDs) ",
  74. NULL
  75. };
  76. VOID
  77. ParseArgs(
  78. int argc,
  79. char *argv[]
  80. );
  81. VOID
  82. ScanHive(
  83. VOID
  84. );
  85. VOID
  86. ScanCell(
  87. PHCELL Cell,
  88. ULONG CellSize
  89. );
  90. VOID
  91. ScanKeyNode(
  92. IN PCM_KEY_NODE Node,
  93. IN ULONG CellSize
  94. );
  95. VOID
  96. ScanKeyValue(
  97. IN PCM_KEY_VALUE Value,
  98. IN ULONG CellSize
  99. );
  100. VOID
  101. ScanKeySD(
  102. IN PCM_KEY_SECURITY Security,
  103. IN ULONG CellSize
  104. );
  105. VOID
  106. ScanKeyIndex(
  107. IN PCM_KEY_INDEX Index,
  108. IN ULONG CellSize
  109. );
  110. VOID
  111. ScanUnknown(
  112. IN PCELL_DATA Data,
  113. IN ULONG CellSize
  114. );
  115. //
  116. // CONTROL ARGUMENTS
  117. //
  118. BOOLEAN DoCellType = FALSE;
  119. BOOLEAN DoSummary = TRUE;
  120. BOOLEAN DoTraceBin = FALSE;
  121. BOOLEAN DoTraceFree = FALSE;
  122. BOOLEAN DoTraceAlloc = FALSE;
  123. BOOLEAN AccessKeys = FALSE;
  124. BOOLEAN AccessValues = FALSE;
  125. BOOLEAN AccessSD = FALSE;
  126. LPCTSTR FileName = NULL;
  127. ULONG HiveVersion;
  128. //
  129. // SUMMARY TOTALS
  130. //
  131. ULONG SizeKeyData=0;
  132. ULONG SizeValueData=0;
  133. ULONG SizeSDData=0;
  134. ULONG SizeIndexData=0;
  135. ULONG SizeUnknownData=0;
  136. ULONG NumKeyData=0;
  137. ULONG NumValueData=0;
  138. ULONG NumSDData=0;
  139. ULONG NumIndexData=0;
  140. ULONG NumUnknownData=0;
  141. void
  142. main(
  143. int argc,
  144. char *argv[]
  145. )
  146. {
  147. ParseArgs(argc, argv);
  148. ScanHive();
  149. exit(0);
  150. }
  151. VOID
  152. ParseArgs(
  153. int argc,
  154. char *argv[]
  155. )
  156. /*++
  157. Routine Description:
  158. Read arguments and set control arguments and file name from them.
  159. Arguments:
  160. argc, argv, standard meaning
  161. Return Value:
  162. None.
  163. --*/
  164. {
  165. char *p;
  166. int i;
  167. BOOLEAN command;
  168. if (argc == 1) {
  169. for (i = 0; helptext[i] != NULL; i++) {
  170. fprintf(stderr, "%s\n", helptext[i]);
  171. }
  172. exit(1);
  173. }
  174. for (i = 1; i < argc; i++) {
  175. p = argv[i];
  176. if (*p == '+') {
  177. // switch something on
  178. command = TRUE;
  179. } else if (*p == '-') {
  180. // switch something off
  181. command = FALSE;
  182. } else {
  183. FileName = p;
  184. continue;
  185. }
  186. p++;
  187. if (*p == '\0')
  188. continue;
  189. switch (*p) {
  190. case 's':
  191. case 'S':
  192. DoSummary = command;
  193. break;
  194. case 'c':
  195. case 'C':
  196. DoCellType = command;
  197. break;
  198. case 'a':
  199. case 'A':
  200. p++;
  201. while (*p != '\0') {
  202. switch (*p) {
  203. case 'k':
  204. case 'K':
  205. AccessKeys = command;
  206. break;
  207. case 's':
  208. case 'S':
  209. AccessSD = command;
  210. break;
  211. case 'v':
  212. case 'V':
  213. AccessValues = command;
  214. break;
  215. default:
  216. break;
  217. }
  218. p++;
  219. }
  220. break;
  221. case 't':
  222. case 'T':
  223. p++;
  224. while (*p != '\0') {
  225. switch (*p) {
  226. case 'b':
  227. case 'B':
  228. DoTraceBin = command;
  229. break;
  230. case 'a':
  231. case 'A':
  232. DoTraceAlloc = command;
  233. break;
  234. case 'f':
  235. case 'F':
  236. DoTraceFree = command;
  237. break;
  238. case 'c':
  239. case 'C':
  240. DoTraceAlloc = command;
  241. DoTraceFree = command;
  242. break;
  243. default:
  244. break;
  245. }
  246. p++;
  247. }
  248. break;
  249. default:
  250. break;
  251. }
  252. }
  253. return;
  254. }
  255. VOID
  256. ScanHive(
  257. )
  258. /*++
  259. Routine Description:
  260. Scan the hive, report what we see, based on control arguments.
  261. --*/
  262. {
  263. static char buffer[HBLOCK_SIZE];
  264. PHBASE_BLOCK bbp;
  265. HANDLE filehandle;
  266. BOOL rf;
  267. ULONG readcount;
  268. ULONG hivelength;
  269. ULONG hiveposition;
  270. PHCELL cp;
  271. PHCELL guard;
  272. PHBIN hbp;
  273. ULONG hoff;
  274. ULONG StatBinCount = 0;
  275. ULONG StatBinTotal = 0;
  276. ULONG StatBinMax = 0;
  277. ULONG StatFreeCount = 0;
  278. ULONG StatFreeTotal = 0;
  279. ULONG StatFreeMax = 0;
  280. ULONG StatAllocCount = 0;
  281. ULONG StatAllocTotal = 0;
  282. ULONG StatAllocMax = 0;
  283. ULONG binread;
  284. ULONG binsize;
  285. ULONG cellsize;
  286. ULONG boff;
  287. ULONG lboff;
  288. ULONG SizeTotal;
  289. //
  290. // open the file
  291. //
  292. filehandle = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL,
  293. OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
  294. if (filehandle == INVALID_HANDLE_VALUE) {
  295. fprintf(stderr,
  296. "hivestat: Could not open file '%s' error = %08lx\n",
  297. FileName, GetLastError()
  298. );
  299. exit(1);
  300. }
  301. //
  302. // read the header
  303. //
  304. rf = ReadFile(filehandle, buffer, HBLOCK_SIZE, &readcount, NULL);
  305. if ( ( ! rf ) || (readcount != HBLOCK_SIZE) ) {
  306. fprintf(stderr, "hivestat: '%s' - cannot read base block!\n", FileName);
  307. exit(1);
  308. }
  309. bbp = (PHBASE_BLOCK)(&(buffer[0]));
  310. if ((bbp->Major != HSYS_MAJOR) ||
  311. (bbp->Minor > HSYS_MINOR))
  312. {
  313. fprintf(stderr,
  314. "hivestat: major/minor != %d/%d get newer hivestat\n",
  315. HSYS_MAJOR, HSYS_MINOR
  316. );
  317. exit(1);
  318. }
  319. HiveVersion = bbp->Minor;
  320. hivelength = bbp->Length + HBLOCK_SIZE;
  321. hiveposition = HBLOCK_SIZE;
  322. hoff = 0;
  323. printf("hivestat: '%s'\n", FileName);
  324. if (DoTraceBin || DoTraceFree || DoTraceAlloc) {
  325. printf("\nTrace\n");
  326. printf("bi=bin, fr=free, al=allocated\n");
  327. printf("offset is file offset, sub HBLOCK to get HCELL\n");
  328. printf("type,offset,size\n");
  329. printf("\n");
  330. }
  331. //
  332. // scan the hive
  333. //
  334. guard = (PHCELL)(&(buffer[0]) + HBLOCK_SIZE);
  335. //
  336. // hiveposition is file relative offset of next block we will read
  337. //
  338. // hoff is the file relative offset of the last block we read
  339. //
  340. // hivelength is actual length of file (header's recorded length plus
  341. // the size of the header.
  342. //
  343. // cp is pointer into memory, within range of buffer, it's a cell pointer
  344. //
  345. while (hiveposition < hivelength) {
  346. //
  347. // read in first block of bin, check signature, get bin stats
  348. //
  349. rf = ReadFile(filehandle, buffer, HBLOCK_SIZE, &readcount, NULL);
  350. if ( ( ! rf ) || (readcount != HBLOCK_SIZE) ) {
  351. fprintf(stderr, "hivestat: '%s' read error @%08lx\n", FileName, hiveposition);
  352. exit(1);
  353. }
  354. hbp = (PHBIN)(&(buffer[0]));
  355. if (hbp->Signature != HBIN_SIGNATURE) {
  356. fprintf(stderr,
  357. "hivestat: '%s' bad bin sign. @%08lx\n", FileName, hiveposition);
  358. exit(1);
  359. }
  360. hiveposition += HBLOCK_SIZE;
  361. hoff += HBLOCK_SIZE;
  362. ASSERT(hoff+HBLOCK_SIZE == hiveposition);
  363. StatBinCount++;
  364. binsize = hbp->Size;
  365. StatBinTotal += binsize;
  366. if (binsize > StatBinMax) {
  367. StatBinMax = binsize;
  368. }
  369. if (DoTraceBin) {
  370. printf("bi,x%08lx,%ld\n", hoff, binsize);
  371. }
  372. //
  373. // scan the bin
  374. //
  375. // cp = pointer to cell we are looking at
  376. // boff = offset within bin
  377. // lboff = last offset within bin, used only for consistency checks
  378. // binread = number of bytes of bin we've read so far
  379. //
  380. cp = (PHCELL)((PUCHAR)hbp + sizeof(HBIN));
  381. boff = sizeof(HBIN);
  382. lboff = -1;
  383. binread = HBLOCK_SIZE;
  384. while (binread <= binsize) {
  385. //
  386. // if free, do free stuff
  387. // else do alloc stuff
  388. // do full stuff
  389. //
  390. if (cp->Size > 0) {
  391. //
  392. // free
  393. //
  394. cellsize = cp->Size;
  395. StatFreeCount++;
  396. StatFreeTotal += cellsize;
  397. if (cellsize > StatFreeMax) {
  398. StatFreeMax = cellsize;
  399. }
  400. if (DoTraceFree) {
  401. printf("fr,x%08lx,%ld\n",
  402. hoff+((PUCHAR)cp - &(buffer[0])), cellsize);
  403. }
  404. } else {
  405. //
  406. // alloc
  407. //
  408. cellsize = -1 * cp->Size;
  409. StatAllocCount++;
  410. StatAllocTotal += cellsize;
  411. if (cellsize > StatAllocMax) {
  412. StatAllocMax = cellsize;
  413. }
  414. if (DoTraceAlloc) {
  415. printf("al,x%08lx,%ld\n",
  416. hoff+((PUCHAR)cp - &(buffer[0])), cellsize);
  417. }
  418. ScanCell(cp,cellsize);
  419. }
  420. //
  421. // do basic consistency check
  422. //
  423. #if 0
  424. if (cp->Last != lboff) {
  425. printf("e!,x%08lx bad LAST pointer %08lx\n",
  426. hoff+((PUCHAR)cp - &(buffer[0])), cp->Last);
  427. }
  428. #endif
  429. //
  430. // advance to next cell
  431. //
  432. lboff = boff;
  433. cp = (PHCELL)((PUCHAR)cp + cellsize);
  434. boff += cellsize;
  435. //
  436. // scan ahead in bin, if cp has reached off end of block,
  437. // AND there's bin left to read.
  438. // do this BEFORE breaking out for boff at end.
  439. //
  440. while ( (cp >= guard) && (binread < binsize) ) {
  441. rf = ReadFile(filehandle, buffer, HBLOCK_SIZE, &readcount, NULL);
  442. if ( ( ! rf ) || (readcount != HBLOCK_SIZE) ) {
  443. fprintf(stderr, "hivestat: '%s' read error @%08lx\n", FileName, hiveposition);
  444. exit(1);
  445. }
  446. cp = (PHCELL)((PUCHAR)cp - HBLOCK_SIZE);
  447. hiveposition += HBLOCK_SIZE;
  448. hoff += HBLOCK_SIZE;
  449. binread += HBLOCK_SIZE;
  450. ASSERT(hoff+HBLOCK_SIZE == hiveposition);
  451. }
  452. if (boff >= binsize) {
  453. break; // we are done with this bin
  454. }
  455. }
  456. }
  457. //
  458. // Traces are done, stats gathered, print summary
  459. //
  460. if (DoSummary) {
  461. printf("\nSummary:\n");
  462. printf("type\tcount/max single/total space\n");
  463. printf("%s\t%7ld\t%7ld\t%7ld\n",
  464. "bin", StatBinCount, StatBinMax, StatBinTotal);
  465. printf("%s\t%7ld\t%7ld\t%7ld\n",
  466. "free", StatFreeCount, StatFreeMax, StatFreeTotal);
  467. printf("%s\t%7ld\t%7ld\t%7ld\n",
  468. "alloc", StatAllocCount, StatAllocMax, StatAllocTotal);
  469. }
  470. if (DoSummary && DoCellType) {
  471. printf("\n");
  472. SizeTotal = SizeKeyData +
  473. SizeValueData +
  474. SizeSDData +
  475. SizeIndexData +
  476. SizeUnknownData;
  477. printf("Total Key Data %7d (%5.2f %%)\n", SizeKeyData,
  478. (float)SizeKeyData*100/SizeTotal);
  479. printf("Total Value Data %7d (%5.2f %%)\n", SizeValueData,
  480. (float)SizeValueData*100/SizeTotal);
  481. printf("Total SD Data %7d (%5.2f %%)\n", SizeSDData,
  482. (float)SizeSDData*100/SizeTotal);
  483. printf("Total Index Data %7d (%5.2f %%)\n", SizeIndexData,
  484. (float)SizeIndexData*100/SizeTotal);
  485. printf("Total Unknown Data %7d (%5.2f %%)\n", SizeUnknownData,
  486. (float)SizeUnknownData*100/SizeTotal);
  487. printf("\n");
  488. printf("Average Key Data %8.2f (%d cells)\n",
  489. (float)SizeKeyData/NumKeyData,
  490. NumKeyData);
  491. printf("Average Value Data %8.2f (%d cells)\n",
  492. (float)SizeValueData/NumValueData,
  493. NumValueData);
  494. printf("Average SD Data %8.2f (%d cells)\n",
  495. (float)SizeSDData/NumSDData,
  496. NumSDData);
  497. printf("Average Index Data %8.2f (%d cells)\n",
  498. (float)SizeIndexData/NumIndexData,
  499. NumIndexData);
  500. printf("Average Unknown Data %8.2f (%d cells)\n",
  501. (float)SizeUnknownData/NumUnknownData,
  502. NumUnknownData);
  503. }
  504. return;
  505. }
  506. VOID
  507. ScanCell(
  508. IN PHCELL Cell,
  509. IN ULONG CellSize
  510. )
  511. /*++
  512. Routine Description:
  513. Given a pointer to an HCELL, this tries to figure out what type
  514. of data is in it (key, value, SD, etc.) and gather interesting
  515. statistics about it.
  516. Arguments:
  517. Cell - Supplies a pointer to the HCELL
  518. CellSize - Supplies the size of the HCELL
  519. Return Value:
  520. None, sets some global statistics depending on content of the cell.
  521. --*/
  522. {
  523. PCELL_DATA Data;
  524. if (!DoCellType) {
  525. return;
  526. }
  527. if (HiveVersion==1) {
  528. Data = (PCELL_DATA)&Cell->u.OldCell.u.UserData;
  529. } else {
  530. Data = (PCELL_DATA)&Cell->u.NewCell.u.UserData;
  531. }
  532. //
  533. // grovel through the data, see if we can figure out what it looks like
  534. //
  535. if ((Data->u.KeyNode.Signature == CM_KEY_NODE_SIGNATURE) &&
  536. (CellSize > sizeof(CM_KEY_NODE))) {
  537. //
  538. // probably a key node
  539. //
  540. ScanKeyNode(&Data->u.KeyNode, CellSize);
  541. } else if ((Data->u.KeyValue.Signature == CM_KEY_VALUE_SIGNATURE) &&
  542. (CellSize > sizeof(CM_KEY_VALUE))) {
  543. //
  544. // probably a key value
  545. //
  546. ScanKeyValue(&Data->u.KeyValue, CellSize);
  547. } else if ((Data->u.KeySecurity.Signature == CM_KEY_SECURITY_SIGNATURE) &&
  548. (CellSize > sizeof(CM_KEY_SECURITY))) {
  549. //
  550. // probably a security descriptor
  551. //
  552. ScanKeySD(&Data->u.KeySecurity, CellSize);
  553. } else if ((Data->u.KeyIndex.Signature == CM_KEY_INDEX_ROOT) ||
  554. (Data->u.KeyIndex.Signature == CM_KEY_INDEX_LEAF)) {
  555. //
  556. // probably a key index
  557. //
  558. ScanKeyIndex(&Data->u.KeyIndex, CellSize);
  559. } else {
  560. //
  561. // Nothing with a signature, could be either
  562. // name
  563. // key list
  564. // value data
  565. //
  566. ScanUnknown(Data, CellSize);
  567. }
  568. }
  569. VOID
  570. ScanKeyNode(
  571. IN PCM_KEY_NODE Node,
  572. IN ULONG CellSize
  573. )
  574. {
  575. int i;
  576. SizeKeyData += CellSize;
  577. NumKeyData++;
  578. if (AccessKeys) {
  579. printf("%d, %d, %d, %d, \"",
  580. Node->SubKeyCounts[Stable],
  581. Node->ValueList.Count,
  582. Node->NameLength,
  583. Node->ClassLength);
  584. for (i=0; i < Node->NameLength/sizeof(WCHAR); i++) {
  585. printf("%c",(CHAR)Node->Name[i]);
  586. }
  587. printf("\"\n");
  588. }
  589. }
  590. VOID
  591. ScanKeyValue(
  592. IN PCM_KEY_VALUE Value,
  593. IN ULONG CellSize
  594. )
  595. {
  596. int i;
  597. int DataLength;
  598. SizeValueData += CellSize;
  599. NumValueData++;
  600. if (AccessValues) {
  601. DataLength = Value->DataLength;
  602. if (DataLength >= CM_KEY_VALUE_SPECIAL_SIZE) {
  603. DataLength -= CM_KEY_VALUE_SPECIAL_SIZE;
  604. }
  605. printf("%d, %d, \"",
  606. DataLength,
  607. Value->NameLength);
  608. for (i=0; i < Value->NameLength/sizeof(WCHAR); i++) {
  609. printf("%c",(CHAR)Value->Name[i]);
  610. }
  611. printf("\"\n");
  612. }
  613. }
  614. VOID
  615. ScanKeySD(
  616. IN PCM_KEY_SECURITY Security,
  617. IN ULONG CellSize
  618. )
  619. {
  620. SizeSDData += CellSize;
  621. NumSDData++;
  622. if (AccessSD) {
  623. printf("%d,%d\n",
  624. Security->ReferenceCount,
  625. Security->DescriptorLength);
  626. }
  627. }
  628. VOID
  629. ScanKeyIndex(
  630. IN PCM_KEY_INDEX Index,
  631. IN ULONG CellSize
  632. )
  633. {
  634. SizeIndexData += CellSize;
  635. NumIndexData++;
  636. }
  637. VOID
  638. ScanUnknown(
  639. IN PCELL_DATA Data,
  640. IN ULONG CellSize
  641. )
  642. {
  643. SizeUnknownData += CellSize;
  644. NumUnknownData++;
  645. }
  646.