Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

hivestat.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1991 Microsoft Corporation 00004 00005 Module Name: 00006 00007 hivestat.c 00008 00009 Abstract: 00010 00011 Dumps various statistics on hv (low) level structures in a hive. (See 00012 regstat for higher level stuff.) 00013 00014 Statistics: 00015 00016 Short: # of bins 00017 average bin size 00018 max bin size 00019 # of cells 00020 # of free cells 00021 # of allocated cells 00022 average free cell size 00023 total free size 00024 max free cell size 00025 average allocated size 00026 total allocated size 00027 max allocated cell size 00028 overhead summary (header, bin headers, cell headers) 00029 00030 Long: bin#, offset, size 00031 cell offset, size, allocated 00032 cell offset, size, free 00033 00034 00035 Usage: {[+|-][<option>]} <filename> 00036 (+ = on by default, - = off by default) 00037 +s = summary - all of the short statistics 00038 -t[bafc] = trace, line per entry, bin, allocated, free, all cells 00039 (+tbc == +tbaf) 00040 -c = cell type summary 00041 -a[kvs] = Access Export (key nodes, values, SDs) 00042 00043 Author: 00044 00045 Bryan M. Willman (bryanwi) 2-Sep-1992 00046 00047 Revision History: 00048 00049 --*/ 00050 00051 /* 00052 00053 NOTE: Unlike other hive/registry tools, this one will not read the 00054 entire hive into memory, but will instead read it in via 00055 file I/O. This makes it faster/easier to apply to very large 00056 hives. 00057 00058 */ 00059 #include "regutil.h" 00060 #include "edithive.h" 00061 00062 #include <stdio.h> 00063 #include <stdlib.h> 00064 #include <string.h> 00065 #include <windows.h> 00066 00067 UCHAR *helptext[] = { 00068 "hivestat: ", 00069 "Statistics: ", 00070 " Short: # of bins ", 00071 " average bin size ", 00072 " max bin size ", 00073 " # of cells ", 00074 " # of free cells ", 00075 " # of allocated cells ", 00076 " average free cell size ", 00077 " total free size ", 00078 " max free cell size ", 00079 " average allocated size ", 00080 " total allocated size ", 00081 " max allocated cell size ", 00082 " overhead summary (header, bin headers, cell headers) ", 00083 " Long: bin#, offset, size ", 00084 " cell offset, size, allocated ", 00085 " cell offset, size, free ", 00086 "Usage: {[+|-][<option>]} <filename> ", 00087 " (+ = on by default, - = off by default) ", 00088 " +s = summary - all of the short statistics ", 00089 " -t[bafc] = trace, line per entry, bin, allocated, free, all cells", 00090 " (+tbc == +tbaf) ", 00091 " -c = cell type summary ", 00092 " -a[kvs] = Access Export (key nodes, values, SDs) ", 00093 NULL 00094 }; 00095 00096 00097 VOID 00098 ParseArgs( 00099 int argc, 00100 char *argv[] 00101 ); 00102 00103 VOID 00104 ScanHive( 00105 VOID 00106 ); 00107 00108 VOID 00109 ScanCell( 00110 PHCELL Cell, 00111 ULONG CellSize 00112 ); 00113 00114 VOID 00115 ScanKeyNode( 00116 IN PCM_KEY_NODE Node, 00117 IN ULONG CellSize 00118 ); 00119 00120 VOID 00121 ScanKeyValue( 00122 IN PCM_KEY_VALUE Value, 00123 IN ULONG CellSize 00124 ); 00125 00126 VOID 00127 ScanKeySD( 00128 IN PCM_KEY_SECURITY Security, 00129 IN ULONG CellSize 00130 ); 00131 00132 VOID 00133 ScanKeyIndex( 00134 IN PCM_KEY_INDEX Index, 00135 IN ULONG CellSize 00136 ); 00137 00138 VOID 00139 ScanUnknown( 00140 IN PCELL_DATA Data, 00141 IN ULONG CellSize 00142 ); 00143 00144 00145 // 00146 // CONTROL ARGUMENTS 00147 // 00148 BOOLEAN DoCellType = FALSE; 00149 BOOLEAN DoSummary = TRUE; 00150 BOOLEAN DoTraceBin = FALSE; 00151 BOOLEAN DoTraceFree = FALSE; 00152 BOOLEAN DoTraceAlloc = FALSE; 00153 00154 BOOLEAN AccessKeys = FALSE; 00155 BOOLEAN AccessValues = FALSE; 00156 BOOLEAN AccessSD = FALSE; 00157 LPCTSTR FileName = NULL; 00158 00159 ULONG HiveVersion; 00160 00161 // 00162 // SUMMARY TOTALS 00163 // 00164 ULONG SizeKeyData=0; 00165 ULONG SizeValueData=0; 00166 ULONG SizeSDData=0; 00167 ULONG SizeIndexData=0; 00168 ULONG SizeUnknownData=0; 00169 00170 ULONG NumKeyData=0; 00171 ULONG NumValueData=0; 00172 ULONG NumSDData=0; 00173 ULONG NumIndexData=0; 00174 ULONG NumUnknownData=0; 00175 00176 void 00177 main( 00178 int argc, 00179 char *argv[] 00180 ) 00181 { 00182 ParseArgs(argc, argv); 00183 ScanHive(); 00184 exit(0); 00185 } 00186 00187 VOID 00188 ParseArgs( 00189 int argc, 00190 char *argv[] 00191 ) 00192 /*++ 00193 00194 Routine Description: 00195 00196 Read arguments and set control arguments and file name from them. 00197 00198 Arguments: 00199 00200 argc, argv, standard meaning 00201 00202 Return Value: 00203 00204 None. 00205 00206 --*/ 00207 { 00208 char *p; 00209 int i; 00210 BOOLEAN command; 00211 00212 if (argc == 1) { 00213 for (i = 0; helptext[i] != NULL; i++) { 00214 fprintf(stderr, "%s\n", helptext[i]); 00215 } 00216 exit(1); 00217 } 00218 00219 for (i = 1; i < argc; i++) { 00220 p = argv[i]; 00221 00222 if (*p == '+') { 00223 // switch something on 00224 command = TRUE; 00225 00226 } else if (*p == '-') { 00227 // switch something off 00228 command = FALSE; 00229 00230 } else { 00231 FileName = p; 00232 continue; 00233 } 00234 00235 p++; 00236 if (*p == '\0') 00237 continue; 00238 00239 switch (*p) { 00240 case 's': 00241 case 'S': 00242 DoSummary = command; 00243 break; 00244 00245 case 'c': 00246 case 'C': 00247 DoCellType = command; 00248 break; 00249 00250 case 'a': 00251 case 'A': 00252 p++; 00253 while (*p != '\0') { 00254 switch (*p) { 00255 case 'k': 00256 case 'K': 00257 AccessKeys = command; 00258 break; 00259 00260 case 's': 00261 case 'S': 00262 AccessSD = command; 00263 break; 00264 00265 case 'v': 00266 case 'V': 00267 AccessValues = command; 00268 break; 00269 00270 default: 00271 break; 00272 } 00273 p++; 00274 } 00275 break; 00276 00277 case 't': 00278 case 'T': 00279 p++; 00280 while (*p != '\0') { 00281 00282 switch (*p) { 00283 case 'b': 00284 case 'B': 00285 DoTraceBin = command; 00286 break; 00287 00288 case 'a': 00289 case 'A': 00290 DoTraceAlloc = command; 00291 break; 00292 00293 case 'f': 00294 case 'F': 00295 DoTraceFree = command; 00296 break; 00297 00298 case 'c': 00299 case 'C': 00300 DoTraceAlloc = command; 00301 DoTraceFree = command; 00302 break; 00303 00304 default: 00305 break; 00306 } 00307 00308 p++; 00309 } 00310 break; 00311 00312 default: 00313 break; 00314 } 00315 } 00316 return; 00317 } 00318 00319 VOID 00320 ScanHive( 00321 ) 00322 /*++ 00323 00324 Routine Description: 00325 00326 Scan the hive, report what we see, based on control arguments. 00327 00328 --*/ 00329 { 00330 static char buffer[HBLOCK_SIZE]; 00331 PHBASE_BLOCK bbp; 00332 HANDLE filehandle; 00333 BOOL rf; 00334 ULONG readcount; 00335 ULONG hivelength; 00336 ULONG hiveposition; 00337 PHCELL cp; 00338 PHCELL guard; 00339 PHBIN hbp; 00340 ULONG hoff; 00341 ULONG StatBinCount = 0; 00342 ULONG StatBinTotal = 0; 00343 ULONG StatBinMax = 0; 00344 ULONG StatFreeCount = 0; 00345 ULONG StatFreeTotal = 0; 00346 ULONG StatFreeMax = 0; 00347 ULONG StatAllocCount = 0; 00348 ULONG StatAllocTotal = 0; 00349 ULONG StatAllocMax = 0; 00350 ULONG binread; 00351 ULONG binsize; 00352 ULONG cellsize; 00353 ULONG boff; 00354 ULONG lboff; 00355 ULONG SizeTotal; 00356 00357 // 00358 // open the file 00359 // 00360 filehandle = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, NULL, 00361 OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); 00362 00363 if (filehandle == INVALID_HANDLE_VALUE) { 00364 fprintf(stderr, 00365 "hivestat: Could not open file '%s' error = %08lx\n", 00366 FileName, GetLastError() 00367 ); 00368 exit(1); 00369 } 00370 00371 00372 // 00373 // read the header 00374 // 00375 rf = ReadFile(filehandle, buffer, HBLOCK_SIZE, &readcount, NULL); 00376 if ( ( ! rf ) || (readcount != HBLOCK_SIZE) ) { 00377 fprintf(stderr, "hivestat: '%s' - cannot read base block!\n", FileName); 00378 exit(1); 00379 } 00380 00381 bbp = (PHBASE_BLOCK)(&(buffer[0])); 00382 00383 if ((bbp->Major != HSYS_MAJOR) || 00384 (bbp->Minor > HSYS_MINOR)) 00385 { 00386 fprintf(stderr, 00387 "hivestat: major/minor != %d/%d get newer hivestat\n", 00388 HSYS_MAJOR, HSYS_MINOR 00389 ); 00390 exit(1); 00391 } 00392 00393 HiveVersion = bbp->Minor; 00394 00395 hivelength = bbp->Length + HBLOCK_SIZE; 00396 hiveposition = HBLOCK_SIZE; 00397 hoff = 0; 00398 00399 printf("hivestat: '%s'\n", FileName); 00400 if (DoTraceBin || DoTraceFree || DoTraceAlloc) { 00401 printf("\nTrace\n"); 00402 printf("bi=bin, fr=free, al=allocated\n"); 00403 printf("offset is file offset, sub HBLOCK to get HCELL\n"); 00404 printf("type,offset,size\n"); 00405 printf("\n"); 00406 } 00407 00408 // 00409 // scan the hive 00410 // 00411 guard = (PHCELL)(&(buffer[0]) + HBLOCK_SIZE); 00412 00413 // 00414 // hiveposition is file relative offset of next block we will read 00415 // 00416 // hoff is the file relative offset of the last block we read 00417 // 00418 // hivelength is actual length of file (header's recorded length plus 00419 // the size of the header. 00420 // 00421 // cp is pointer into memory, within range of buffer, it's a cell pointer 00422 // 00423 while (hiveposition < hivelength) { 00424 00425 // 00426 // read in first block of bin, check signature, get bin stats 00427 // 00428 rf = ReadFile(filehandle, buffer, HBLOCK_SIZE, &readcount, NULL); 00429 if ( ( ! rf ) || (readcount != HBLOCK_SIZE) ) { 00430 fprintf(stderr, "hivestat: '%s' read error @%08lx\n", FileName, hiveposition); 00431 exit(1); 00432 } 00433 hbp = (PHBIN)(&(buffer[0])); 00434 00435 if (hbp->Signature != HBIN_SIGNATURE) { 00436 fprintf(stderr, 00437 "hivestat: '%s' bad bin sign. @%08lx\n", FileName, hiveposition); 00438 exit(1); 00439 } 00440 hiveposition += HBLOCK_SIZE; 00441 hoff += HBLOCK_SIZE; 00442 ASSERT(hoff+HBLOCK_SIZE == hiveposition); 00443 00444 StatBinCount++; 00445 binsize = hbp->Size; 00446 StatBinTotal += binsize; 00447 if (binsize > StatBinMax) { 00448 StatBinMax = binsize; 00449 } 00450 00451 if (DoTraceBin) { 00452 printf("bi,x%08lx,%ld\n", hoff, binsize); 00453 } 00454 00455 // 00456 // scan the bin 00457 // 00458 // cp = pointer to cell we are looking at 00459 // boff = offset within bin 00460 // lboff = last offset within bin, used only for consistency checks 00461 // binread = number of bytes of bin we've read so far 00462 // 00463 cp = (PHCELL)((PUCHAR)hbp + sizeof(HBIN)); 00464 boff = sizeof(HBIN); 00465 lboff = -1; 00466 binread = HBLOCK_SIZE; 00467 00468 while (binread <= binsize) { 00469 00470 // 00471 // if free, do free stuff 00472 // else do alloc stuff 00473 // do full stuff 00474 // 00475 if (cp->Size > 0) { 00476 // 00477 // free 00478 // 00479 cellsize = cp->Size; 00480 StatFreeCount++; 00481 StatFreeTotal += cellsize; 00482 if (cellsize > StatFreeMax) { 00483 StatFreeMax = cellsize; 00484 } 00485 00486 if (DoTraceFree) { 00487 printf("fr,x%08lx,%ld\n", 00488 hoff+((PUCHAR)cp - &(buffer[0])), cellsize); 00489 } 00490 00491 00492 } else { 00493 // 00494 // alloc 00495 // 00496 cellsize = -1 * cp->Size; 00497 StatAllocCount++; 00498 StatAllocTotal += cellsize; 00499 if (cellsize > StatAllocMax) { 00500 StatAllocMax = cellsize; 00501 } 00502 00503 if (DoTraceAlloc) { 00504 printf("al,x%08lx,%ld\n", 00505 hoff+((PUCHAR)cp - &(buffer[0])), cellsize); 00506 } 00507 00508 ScanCell(cp,cellsize); 00509 00510 } 00511 00512 // 00513 // do basic consistency check 00514 // 00515 #if 0 00516 if (cp->Last != lboff) { 00517 printf("e!,x%08lx bad LAST pointer %08lx\n", 00518 hoff+((PUCHAR)cp - &(buffer[0])), cp->Last); 00519 } 00520 #endif 00521 00522 // 00523 // advance to next cell 00524 // 00525 lboff = boff; 00526 cp = (PHCELL)((PUCHAR)cp + cellsize); 00527 boff += cellsize; 00528 00529 // 00530 // scan ahead in bin, if cp has reached off end of block, 00531 // AND there's bin left to read. 00532 // do this BEFORE breaking out for boff at end. 00533 // 00534 while ( (cp >= guard) && (binread < binsize) ) { 00535 00536 rf = ReadFile(filehandle, buffer, HBLOCK_SIZE, &readcount, NULL); 00537 if ( ( ! rf ) || (readcount != HBLOCK_SIZE) ) { 00538 fprintf(stderr, "hivestat: '%s' read error @%08lx\n", FileName, hiveposition); 00539 exit(1); 00540 } 00541 cp = (PHCELL)((PUCHAR)cp - HBLOCK_SIZE); 00542 hiveposition += HBLOCK_SIZE; 00543 hoff += HBLOCK_SIZE; 00544 binread += HBLOCK_SIZE; 00545 ASSERT(hoff+HBLOCK_SIZE == hiveposition); 00546 } 00547 00548 if (boff >= binsize) { 00549 break; // we are done with this bin 00550 } 00551 } 00552 } 00553 00554 // 00555 // Traces are done, stats gathered, print summary 00556 // 00557 if (DoSummary) { 00558 00559 printf("\nSummary:\n"); 00560 printf("type\tcount/max single/total space\n"); 00561 printf("%s\t%7ld\t%7ld\t%7ld\n", 00562 "bin", StatBinCount, StatBinMax, StatBinTotal); 00563 printf("%s\t%7ld\t%7ld\t%7ld\n", 00564 "free", StatFreeCount, StatFreeMax, StatFreeTotal); 00565 printf("%s\t%7ld\t%7ld\t%7ld\n", 00566 "alloc", StatAllocCount, StatAllocMax, StatAllocTotal); 00567 00568 } 00569 00570 if (DoSummary && DoCellType) { 00571 00572 printf("\n"); 00573 00574 SizeTotal = SizeKeyData + 00575 SizeValueData + 00576 SizeSDData + 00577 SizeIndexData + 00578 SizeUnknownData; 00579 00580 printf("Total Key Data %7d (%5.2f %%)\n", SizeKeyData, 00581 (float)SizeKeyData*100/SizeTotal); 00582 printf("Total Value Data %7d (%5.2f %%)\n", SizeValueData, 00583 (float)SizeValueData*100/SizeTotal); 00584 printf("Total SD Data %7d (%5.2f %%)\n", SizeSDData, 00585 (float)SizeSDData*100/SizeTotal); 00586 printf("Total Index Data %7d (%5.2f %%)\n", SizeIndexData, 00587 (float)SizeIndexData*100/SizeTotal); 00588 printf("Total Unknown Data %7d (%5.2f %%)\n", SizeUnknownData, 00589 (float)SizeUnknownData*100/SizeTotal); 00590 00591 printf("\n"); 00592 printf("Average Key Data %8.2f (%d cells)\n", 00593 (float)SizeKeyData/NumKeyData, 00594 NumKeyData); 00595 printf("Average Value Data %8.2f (%d cells)\n", 00596 (float)SizeValueData/NumValueData, 00597 NumValueData); 00598 printf("Average SD Data %8.2f (%d cells)\n", 00599 (float)SizeSDData/NumSDData, 00600 NumSDData); 00601 printf("Average Index Data %8.2f (%d cells)\n", 00602 (float)SizeIndexData/NumIndexData, 00603 NumIndexData); 00604 printf("Average Unknown Data %8.2f (%d cells)\n", 00605 (float)SizeUnknownData/NumUnknownData, 00606 NumUnknownData); 00607 } 00608 return; 00609 } 00610 00611 VOID 00612 ScanCell( 00613 IN PHCELL Cell, 00614 IN ULONG CellSize 00615 ) 00616 00617 /*++ 00618 00619 Routine Description: 00620 00621 Given a pointer to an HCELL, this tries to figure out what type 00622 of data is in it (key, value, SD, etc.) and gather interesting 00623 statistics about it. 00624 00625 Arguments: 00626 00627 Cell - Supplies a pointer to the HCELL 00628 00629 CellSize - Supplies the size of the HCELL 00630 00631 Return Value: 00632 00633 None, sets some global statistics depending on content of the cell. 00634 00635 --*/ 00636 00637 { 00638 PCELL_DATA Data; 00639 00640 if (!DoCellType) { 00641 return; 00642 } 00643 00644 if (HiveVersion==1) { 00645 Data = (PCELL_DATA)&Cell->u.OldCell.u.UserData; 00646 } else { 00647 Data = (PCELL_DATA)&Cell->u.NewCell.u.UserData; 00648 } 00649 00650 // 00651 // grovel through the data, see if we can figure out what it looks like 00652 // 00653 if ((Data->u.KeyNode.Signature == CM_KEY_NODE_SIGNATURE) && 00654 (CellSize > sizeof(CM_KEY_NODE))) { 00655 00656 // 00657 // probably a key node 00658 // 00659 ScanKeyNode(&Data->u.KeyNode, CellSize); 00660 00661 } else if ((Data->u.KeyValue.Signature == CM_KEY_VALUE_SIGNATURE) && 00662 (CellSize > sizeof(CM_KEY_VALUE))) { 00663 00664 // 00665 // probably a key value 00666 // 00667 ScanKeyValue(&Data->u.KeyValue, CellSize); 00668 00669 } else if ((Data->u.KeySecurity.Signature == CM_KEY_SECURITY_SIGNATURE) && 00670 (CellSize > sizeof(CM_KEY_SECURITY))) { 00671 00672 // 00673 // probably a security descriptor 00674 // 00675 ScanKeySD(&Data->u.KeySecurity, CellSize); 00676 00677 } else if ((Data->u.KeyIndex.Signature == CM_KEY_INDEX_ROOT) || 00678 (Data->u.KeyIndex.Signature == CM_KEY_INDEX_LEAF)) { 00679 // 00680 // probably a key index 00681 // 00682 ScanKeyIndex(&Data->u.KeyIndex, CellSize); 00683 00684 } else { 00685 // 00686 // Nothing with a signature, could be either 00687 // name 00688 // key list 00689 // value data 00690 // 00691 ScanUnknown(Data, CellSize); 00692 00693 } 00694 } 00695 00696 VOID 00697 ScanKeyNode( 00698 IN PCM_KEY_NODE Node, 00699 IN ULONG CellSize 00700 ) 00701 { 00702 int i; 00703 00704 SizeKeyData += CellSize; 00705 NumKeyData++; 00706 00707 if (AccessKeys) { 00708 printf("%d, %d, %d, %d, \"", 00709 Node->SubKeyCounts[Stable], 00710 Node->ValueList.Count, 00711 Node->NameLength, 00712 Node->ClassLength); 00713 00714 for (i=0; i < Node->NameLength/sizeof(WCHAR); i++) { 00715 printf("%c",(CHAR)Node->Name[i]); 00716 } 00717 printf("\"\n"); 00718 } 00719 00720 } 00721 VOID 00722 ScanKeyValue( 00723 IN PCM_KEY_VALUE Value, 00724 IN ULONG CellSize 00725 ) 00726 { 00727 int i; 00728 int DataLength; 00729 00730 SizeValueData += CellSize; 00731 NumValueData++; 00732 if (AccessValues) { 00733 DataLength = Value->DataLength; 00734 if (DataLength >= CM_KEY_VALUE_SPECIAL_SIZE) { 00735 DataLength -= CM_KEY_VALUE_SPECIAL_SIZE; 00736 } 00737 printf("%d, %d, \"", 00738 DataLength, 00739 Value->NameLength); 00740 00741 for (i=0; i < Value->NameLength/sizeof(WCHAR); i++) { 00742 printf("%c",(CHAR)Value->Name[i]); 00743 } 00744 printf("\"\n"); 00745 } 00746 00747 } 00748 VOID 00749 ScanKeySD( 00750 IN PCM_KEY_SECURITY Security, 00751 IN ULONG CellSize 00752 ) 00753 { 00754 SizeSDData += CellSize; 00755 NumSDData++; 00756 00757 if (AccessSD) { 00758 printf("%d,%d\n", 00759 Security->ReferenceCount, 00760 Security->DescriptorLength); 00761 } 00762 00763 } 00764 VOID 00765 ScanKeyIndex( 00766 IN PCM_KEY_INDEX Index, 00767 IN ULONG CellSize 00768 ) 00769 { 00770 SizeIndexData += CellSize; 00771 NumIndexData++; 00772 00773 } 00774 VOID 00775 ScanUnknown( 00776 IN PCELL_DATA Data, 00777 IN ULONG CellSize 00778 ) 00779 { 00780 SizeUnknownData += CellSize; 00781 NumUnknownData++; 00782 00783 } 00784 

Generated on Sat May 15 19:40:17 2004 for test by doxygen 1.3.7