windows-nt/Source/XPSP1/NT/base/ntos/config/chkreg/regmain.c
2020-09-26 16:20:57 +08:00

415 lines
11 KiB
C

/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
regmain.c
Abstract:
Main module. Data definitions.
Author:
Dragos C. Sambotin (dragoss) 30-Dec-1998
Revision History:
--*/
#include "chkreg.h"
// check the hive structure.
BOOLEAN CheckHive = TRUE;
// compact the hive.
BOOLEAN CompactHive = FALSE;
// check for lost space (marked as used but not reffered).
BOOLEAN LostSpace = FALSE;
// repair damaged hives.
BOOLEAN FixHive = FALSE;
// repair damaged hives.
BOOLEAN SpaceUsage = FALSE;
// maximum level to dump
ULONG MaxLevel = 0;
// bin to examine space display
LONG BinIndex = -1;
// the hive file name
TCHAR *Hive = NULL;
// the root of the hive
HCELL_INDEX RootCell;
// Usage string
char *Usage="\
Checks a hive file and perform repairs, compacts or displays a status report.\n\n\
CHKREG /F <filename[.<LOG>]> [/H] [/D [<level>] [/S [<bin>]] [/C] [/L] [/R]\n\n\
<filename> FileName of hive to be analyzed\n\
/H This manual\n\
/D [<level>] Dump subkeys up to level <level>. If level is not\n\
specified, dumps the entire hive. No checks are done\n\
when dumping.\n\
/S [<bin>] Displays space usage for the bin <bin>. When bin is\n\
not specified, displays usage for the entire hive.\n\
/C Compacts the hive. Bad hives cannot be compacted.\n\
The compacted hive will be written to <filename>.BAK\n\
/L Lost space detection.\n\
/R Repair the hive.\n\
";
// Lost Space Warning
char *LostSpaceWarning="\n\
WARNING : Lost space detection may take a while. Are you sure you want this (y/n)?";
// Starting address of the in-memory maped hive image
PUCHAR Base;
// LostCells list used for lost space detection
UNKNOWN_LIST LostCells[FRAGMENTATION];
// OutputFile : future changes may use it to write the results to a file rather than to stdout
FILE *OutputFile;
#define NAME_BUFFERSIZE 2000
UNICODE_STRING KeyName;
WCHAR NameBuffer[NAME_BUFFERSIZE];
// Miscelaneous variables used fo data statistics
ULONG TotalKeyNode=0;
ULONG TotalKeyValue=0;
ULONG TotalKeyIndex=0;
ULONG TotalKeySecurity=0;
ULONG TotalValueIndex=0;
ULONG TotalUnknown=0;
ULONG CountKeyNode=0;
ULONG CountKeyValue=0;
ULONG CountKeyIndex=0;
ULONG CountKeySecurity=0;
ULONG CountValueIndex=0;
ULONG CountUnknown=0;
ULONG CountKeyNodeCompacted=0;
ULONG TotalFree=0;
ULONG FreeCount=0;
ULONG TotalUsed=0;
PHBIN FirstBin;
PHBIN MaxBin;
ULONG HiveLength;
#define OPTION_MODE 0
#define FILE_MODE 1
#define LEVEL_MODE 2
#define BIN_MODE 3
VOID
ChkDumpLogFile( PHBASE_BLOCK BaseBlock,ULONG Length );
VOID
ParseArgs (
int argc,
char *argv[]
)
{
char *p;
int i;
// specified what should we expect from the command line
int iMode = OPTION_MODE;
for(i=0;i<argc;i++) {
p = argv[i];
if ( *p == '/' || *p == '-' ) {
// option mode
p++;
iMode = OPTION_MODE;
while ((*p != '\0') && (*p != ' ')) {
switch (*p) {
case 'h':
case 'H':
case '?':
fprintf(stderr, "%s\n", Usage);
ExitProcess(1);
break;
case 'f':
case 'F':
iMode = FILE_MODE;
break;
case 'd':
case 'D':
iMode = LEVEL_MODE;
// when not specified, dump at least 100 levels
MaxLevel = 100;
CheckHive = FALSE;
break;
case 's':
case 'S':
SpaceUsage = TRUE;
iMode = BIN_MODE;
break;
case 'c':
case 'C':
p++;
CompactHive = TRUE;
break;
case 'l':
case 'L':
p++;
LostSpace = TRUE;
break;
case 'r':
case 'R':
p++;
FixHive = TRUE;
break;
default:
break;
}
if( iMode != OPTION_MODE ) {
// break the loop; ignore the rest of the current argv
break;
}
} // while
} else {
switch(iMode) {
case FILE_MODE:
Hive = argv[i];
break;
case LEVEL_MODE:
MaxLevel = (ULONG) atol(argv[i]);
break;
case BIN_MODE:
BinIndex = (LONG) atol(argv[i]);
break;
default:
break;
}
}
}
}
__cdecl
main(
int argc,
char *argv[]
)
{
ULONG FileIndex;
HANDLE myFileHandle, myMMFHandle;
LPBYTE myMMFViewHandle;
BYTE lowChar, hiChar, modVal;
DWORD dwFileSize;
ULONG Index,Index2;
PHBASE_BLOCK PHBaseBlock;
PHBIN NewBins;
ULONG Offset;
ULONG CellCount;
ULONG SizeCount;
REG_USAGE TotalUsage;
DWORD dwHiveFileAccess = GENERIC_READ;
DWORD flHiveViewProtect = PAGE_READONLY;
DWORD dwHiveViewAccess = FILE_MAP_READ;
ParseArgs( argc, argv );
if (!Hive) {
fprintf(stderr, "\nMust provide a hive name !!!\n\n");
fprintf(stderr, "%s\n", Usage);
ExitProcess(-1);
}
if(LostSpace) {
// are you sure you want lost cells detection? It may take a while!
int chLost;
fprintf(stdout, "%s",LostSpaceWarning);
fflush(stdin);
chLost = getchar();
if( (chLost != 'y') && (chLost != 'Y') ) {
// he changed his mind
LostSpace = FALSE;
}
fprintf(stderr, "\n");
}
if( FixHive ) {
dwHiveFileAccess |= GENERIC_WRITE;
flHiveViewProtect = PAGE_READWRITE;
dwHiveViewAccess = FILE_MAP_WRITE;
}
/* Create temporary file for mapping. */
if ((myFileHandle = CreateFile (Hive, dwHiveFileAccess,
0 , NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL))
== (HANDLE) INVALID_HANDLE_VALUE) /* Bad handle */ {
fprintf(stderr,"Could not create file %s\n", Hive);
exit(-1);
}
// Get the size of the file. I am assuming here that the
// file is smaller than 4 GB.
dwFileSize = GetFileSize(myFileHandle, NULL);
/* If we get here, we managed to name and create a temp file. Now we need
to create a mapping */
myMMFHandle = CreateFileMapping (myFileHandle, NULL, flHiveViewProtect,
0, dwFileSize, NULL);
if (myMMFHandle == (HANDLE) INVALID_HANDLE_VALUE) {
fprintf(stderr,"Could not map file %s\n", Hive);
exit(-1);
}
/* So we've mapped the file. Now try to map a view */
myMMFViewHandle = (LPBYTE) MapViewOfFile (myMMFHandle, dwHiveViewAccess, 0, 0, dwFileSize);
if (!myMMFViewHandle) {
fprintf(stderr,"Could not map view of file %s error = %lx\n", Hive,(ULONG)GetLastError());
exit(-1);
}
/* Now we have a view. Read through it */
PHBaseBlock = (PHBASE_BLOCK) myMMFViewHandle;
if( strstr(Hive,".LOG") != NULL ) {
// dumping log file
ChkDumpLogFile(PHBaseBlock,MaxLevel);
} else {
/*
if (PHBaseBlock->Minor < 4) {
fprintf(stderr,"Hive version %d is too old, must be 3 or later\n", PHBaseBlock->Minor);
ExitProcess(-1);
}
*/
// Initialization stuff
for(Index =0;Index<FRAGMENTATION;Index++) {
LostCells[Index].Count = 0;
for(Index2 = 0;Index2<SUBLISTS;Index2++) {
LostCells[Index].List[Index2] = NULL;
}
}
RootCell = PHBaseBlock->RootCell;
OutputFile = stdout;
Base = (PUCHAR)(PHBaseBlock) + HBLOCK_SIZE;
Offset=HBLOCK_SIZE;
HiveLength = PHBaseBlock->Length;
MaxBin= (PHBIN) (Base + HiveLength);
FirstBin = (PHBIN) (Base);
KeyName.Buffer = NameBuffer;
KeyName.MaximumLength = NAME_BUFFERSIZE;
ChkBaseBlock(PHBaseBlock,dwFileSize);
ChkSecurityDescriptors();
ChkPhysicalHive();
if (MaxLevel) {
fprintf(stdout,"%6s,%6s,%7s,%10s, %s\n",
"Keys",
"Values",
"Cells",
"Size",
"SubKeys");
}
DumpChkRegistry(0, 0, PHBaseBlock->RootCell,HCELL_NIL,&TotalUsage);
if(LostSpace) {
// clear the dirt on the screen
fprintf(OutputFile,"\r \n");
}
DumpUnknownList();
FreeUnknownList();
fprintf(OutputFile,"\nSUMMARY: \n");
fprintf(OutputFile,"%15s,%15s, %s\n",
"Cells",
"Size",
"Category");
fprintf(OutputFile,"%15lu,%15lu, Keys\n",
CountKeyNode,
TotalKeyNode
);
fprintf(OutputFile,"%15lu,%15lu, Values\n",
CountKeyValue,
TotalKeyValue
);
fprintf(OutputFile,"%15lu,%15lu, Key Index\n",
CountKeyIndex,
TotalKeyIndex
);
fprintf(OutputFile,"%15lu,%15lu, Value Index\n",
CountValueIndex,
TotalValueIndex
);
fprintf(OutputFile,"%15lu,%15lu, Security\n",
CountKeySecurity,
TotalKeySecurity
);
fprintf(OutputFile,"%15lu,%15lu, Data\n",
CountUnknown - CountValueIndex,
TotalUnknown - TotalValueIndex
);
fprintf(OutputFile,"%15lu,%15lu, Free\n",
FreeCount,
TotalFree
);
CellCount = CountKeyNode +
CountKeyValue +
CountKeyIndex +
CountKeySecurity +
CountUnknown +
FreeCount;
SizeCount = TotalKeyNode +
TotalKeyValue +
TotalKeyIndex +
TotalKeySecurity +
TotalUnknown +
TotalFree;
fprintf(OutputFile,"%15lu,%15lu, %s\n",
CellCount,
SizeCount,
"Total Hive");
fprintf(OutputFile,"\n%15lu compacted keys (all related cells in the same view)\n",CountKeyNodeCompacted);
}
UnmapViewOfFile(myMMFViewHandle);
CloseHandle(myMMFHandle);
CloseHandle(myFileHandle);
if(CompactHive) {
DoCompactHive();
}
return(0);
}