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

1158 lines
36 KiB
C

/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
regdmp.c
Abstract:
This module contains routines to check/dump the logical structure of the hive.
Author:
Dragos C. Sambotin (dragoss) 30-Dec-1998
Revision History:
--*/
#include "chkreg.h"
extern ULONG MaxLevel;
extern UNICODE_STRING KeyName;
extern WCHAR NameBuffer[];
extern FILE *OutputFile;
extern BOOLEAN FixHive;
extern BOOLEAN CompactHive;
extern ULONG CountKeyNodeCompacted;
extern HCELL_INDEX RootCell;
#define REG_MAX_PLAUSIBLE_KEY_SIZE \
((FIELD_OFFSET(CM_KEY_NODE, Name)) + \
(sizeof(WCHAR) * REG_MAX_KEY_NAME_LENGTH) + 16)
BOOLEAN ChkSecurityCellInList(HCELL_INDEX Security);
BOOLEAN
ChkAreCellsInSameVicinity(HCELL_INDEX Cell1,HCELL_INDEX Cell2)
{
ULONG Start = Cell1&(~HCELL_TYPE_MASK);
ULONG End = Cell2&(~HCELL_TYPE_MASK);
Start += HBLOCK_SIZE;
End += HBLOCK_SIZE;
//
// truncate to the CM_VIEW_SIZE segment
//
Start &= (~(CM_VIEW_SIZE - 1));
End &= (~(CM_VIEW_SIZE - 1));
if( Start != End ){
return FALSE;
}
return TRUE;
}
BOOLEAN
ChkAllocatedCell(HCELL_INDEX Cell)
/*
Routine Description:
Checks if the cell is allocated (i.e. the size is negative).
Arguments:
Cell - supplies the cell index of the cell of interest.
Return Value:
TRUE if Cell is allocated. FALSE otherwise.
*/
{
BOOLEAN bRez = TRUE;
if( Cell == HCELL_NIL ) {
fprintf(stderr, "Warning : HCELL_NIL referrenced !\n");
return bRez;
}
if( !IsCellAllocated( Cell ) ) {
bRez = FALSE;
fprintf(stderr, "Used free cell 0x%lx ",Cell);
if(FixHive) {
//
// REPAIR: mark the cell as allocated
//
AllocateCell(Cell);
fprintf(stderr, " ... fixed");
bRez = TRUE;
} else {
if(CompactHive) {
// any attempt to compact a corrupted hive will fail
CompactHive = FALSE;
fprintf(stderr, "\nRun chkreg /R to fix.");
}
}
fprintf(stderr, "\n");
}
return bRez;
}
static CHAR FixKeyNameCount = 0;
BOOLEAN
ChkKeyNodeCell(HCELL_INDEX KeyNodeCell,
HCELL_INDEX ParentCell
)
/*
Routine Description:
Checks if the cell is is a consistent keynode. Make fixes when neccessary/required.
The following tests are performed against the keynode cell:
1. the size should be smaller than the REG_MAX_PLAUSIBLE_KEY_SIZE ==> fatal error
2. the Name should not exceed the size of the cell
3. the signature should match CM_KEY_NODE_SIGNATURE
4. the parent cell in keynode should match the actual parent cell
Arguments:
KeyNodeCell - supplies the cell index of the key node of interest.
ParentCell - the actual parent of the current key node
Return Value:
TRUE if KeyNodeCell is reffering a consistent key node, or it was successfully recovered.
FALSE otherwise.
*/
{
PCM_KEY_NODE KeyNode = (PCM_KEY_NODE) GetCell(KeyNodeCell);
ULONG size;
BOOLEAN bRez = TRUE;
ULONG usedlen;
PUCHAR pName;
// this cell should not be considered as lost
RemoveCellFromUnknownList(KeyNodeCell);
ChkAllocatedCell(KeyNodeCell);
// Validate the size of the
size = GetCellSize(KeyNodeCell);
if (size > REG_MAX_PLAUSIBLE_KEY_SIZE) {
bRez = FALSE;
fprintf(stderr, "Implausible Key size %lx in cell 0x%lx ",size,KeyNodeCell);
if(FixHive) {
//
// REPAIR: unable to fix
//
fprintf(stderr, " ... deleting key\n");
return bRez;
}
}
usedlen = FIELD_OFFSET(CM_KEY_NODE, Name) + KeyNode->NameLength;
if (usedlen > size) {
bRez = FALSE;
fprintf(stderr, "Key (size = %lu) is bigger than containing cell 0x%lx (size = %lu) ",usedlen,KeyNodeCell,size);
if(FixHive) {
//
// REPAIR: set NameLength to fit the cell size (i.e. set it to size - FIELD_OFFSET(CM_KEY_NODE, Name) )
//
//
// WARNING: the name might be truncated!!!
//
bRez = TRUE;
KeyNode->NameLength = (USHORT)(size - FIELD_OFFSET(CM_KEY_NODE, Name));
fprintf(stderr, " ... fixed");
} else {
if(CompactHive) {
// any attempt to compact a corrupted hive will fail
CompactHive = FALSE;
fprintf(stderr, "\nRun chkreg /R to fix.");
}
}
fprintf(stderr, "\n");
}
if( KeyNode->Flags & KEY_COMP_NAME ) {
pName = (PUCHAR)KeyNode->Name;
for( usedlen = 0; usedlen < KeyNode->NameLength;usedlen++) {
if( pName[usedlen] == '\\' ) {
bRez = FALSE;
fprintf(stderr, "Invalid key Name for Key (0x%lx) == %s ",KeyNodeCell,pName);
if(FixHive) {
//
// REPAIR: unable to fix
//
fprintf(stderr, " ... deleting key\n");
return bRez;
} else {
if(CompactHive) {
// any attempt to compact a corrupted hive will fail
CompactHive = FALSE;
fprintf(stderr, "\nRun chkreg /R to fix.");
}
}
fprintf(stderr, "\n");
}
}
}
if (ParentCell != HCELL_NIL) {
if (KeyNode->Parent != ParentCell) {
bRez = FALSE;
fprintf(stderr, "Parent of Key (0x%lx) does not match with its ParentCell (0x%lx) ",ParentCell,KeyNode->Parent);
if(FixHive) {
//
// REPAIR: reset the parent
//
bRez = TRUE;
KeyNode->Parent = ParentCell;
fprintf(stderr, " ... fixed");
} else {
if(CompactHive) {
// any attempt to compact a corrupted hive will fail
CompactHive = FALSE;
fprintf(stderr, "\nRun chkreg /R to fix.");
}
}
fprintf(stderr, "\n");
}
}
if (KeyNode->Signature != CM_KEY_NODE_SIGNATURE) {
bRez = FALSE;
fprintf(stderr, "Invalid signature (0x%lx) in Key cell 0x%lx ",KeyNode->Signature,KeyNodeCell);
if(FixHive) {
//
// REPAIR:
// FATAL: Mismatched signature cannot be fixed. The key should be deleted!
//
fprintf(stderr, " ... deleting key");
} else {
if(CompactHive) {
// any attempt to compact a corrupted hive will fail
CompactHive = FALSE;
fprintf(stderr, "\nRun chkreg /R to fix.");
}
}
fprintf(stderr, "\n");
}
return bRez;
}
BOOLEAN
ChkClassCell(HCELL_INDEX Class)
/*
Routine Description:
Checks if the cell is a consistent class cell.
There is not much to be checked here.
Arguments:
Class - supplies the cell index of the cell of interest.
Return Value:
TRUE if Class is a valid cell.
FALSE otherwise.
*/
{
// this cell should not be considered as lost
RemoveCellFromUnknownList(Class);
return ChkAllocatedCell(Class);
}
BOOLEAN
ChkSecurityCell(HCELL_INDEX Security)
/*
Routine Description:
Checks if the cell is a consistent security cell.
A security cell must be allocated and must have a valid signature.
Arguments:
Security - supplies the cell index of the cell of interest.
Return Value:
TRUE if Security is a valid cell.
FALSE otherwise.
*/
{
PCM_KEY_SECURITY KeySecurity = (PCM_KEY_SECURITY) GetCell(Security);
BOOLEAN bRez = TRUE;
// this cell should not be considered as lost
RemoveCellFromUnknownList(Security);
if( !IsCellAllocated( Security ) ) {
// unalocated security cells are invalid.
// they are marked as free in the validate security descriptors check!
if(FixHive) {
//
// REPAIR:
// FATAL: Invalid security cells could not be fixed. Containg keys will be deleted.
//
} else {
if(CompactHive) {
// any attempt to compact a corrupted hive will fail
CompactHive = FALSE;
}
}
return FALSE;
}
if (KeySecurity->Signature != CM_KEY_SECURITY_SIGNATURE) {
fprintf(stderr, "Invalid signature (0x%lx) in Security Key cell 0x%lx ",KeySecurity->Signature,Security);
if(FixHive) {
//
// REPAIR:
// FATAL: Mismatched signature cannot be fixed. The key should be deleted!
//
fprintf(stderr, " ... deleting refering key");
} else {
bRez = FALSE;
if(CompactHive) {
// any attempt to compact a corrupted hive will fail
CompactHive = FALSE;
fprintf(stderr, "\nRun chkreg /R to fix.");
}
}
fprintf(stderr, "\n");
}
// check if this security cell is present in the security list.
if(!ChkSecurityCellInList(Security) ) {
bRez = FALSE;
}
return bRez;
}
BOOLEAN
ChkKeyValue(HCELL_INDEX KeyValue,
PREG_USAGE OwnUsage,
BOOLEAN *KeyCompacted
)
/*
Routine Description:
Checks if the cell is a consistent keyvalue cell.
The following tests are performed:
1. the cell must be allocated
2. the cell is tested against HCELL_NIL ==> fatal error
3. the signature should match CM_KEY_VALUE_SIGNATURE
4. the name should not exceed the size of the cell
5. the data cell should be allocated and its size should match DataLength
Arguments:
KeyValue - supplies the cell index of the cell of interest.
OwnUsage - used to collect data statistics
Return Value:
TRUE if KeyCell is a valid cell or it was successfully fixed.
FALSE otherwise.
*/
{
PCM_KEY_VALUE ValueNode;
ULONG realsize;
ULONG usedlen;
ULONG DataLength;
HCELL_INDEX Data;
ULONG size;
BOOLEAN bRez = TRUE;
if( KeyValue == HCELL_NIL ) {
bRez = FALSE;
fprintf(stderr, "NIL Key value encountered; Fatal error!");
if(FixHive) {
//
// REPAIR: fatal error, the value should be removed from the value list
//
fprintf(stderr, " ... deleting empty entry\n");
return bRez;
}
}
ChkAllocatedCell(KeyValue);
//
// Value size
//
size = GetCellSize(KeyValue);
OwnUsage->Size += size;
// this cell should not be considered as lost
RemoveCellFromUnknownList(KeyValue);
ValueNode = (PCM_KEY_VALUE) GetCell(KeyValue);
//
// Check out the value entry itself
//
usedlen = FIELD_OFFSET(CM_KEY_VALUE, Name) + ValueNode->NameLength;
if (usedlen > size) {
bRez = FALSE;
fprintf(stderr, "Key Value (size = %lu) is bigger than containing cell 0x%lx (size = %lu) ",usedlen,KeyValue,size);
if(FixHive) {
//
// REPAIR: set the actual size to HiveLength-FileOffset
//
//
// WARNING: the name might be truncated!!!
//
bRez = TRUE;
ValueNode->NameLength = (USHORT)(size - FIELD_OFFSET(CM_KEY_VALUE, Name));
fprintf(stderr, " ... fixed");
} else {
if(CompactHive) {
// any attempt to compact a corrupted hive will fail
CompactHive = FALSE;
fprintf(stderr, "\nRun chkreg /R to fix.");
}
}
fprintf(stderr, "\n");
}
//
// Check out value entry's data
//
DataLength = ValueNode->DataLength;
if (DataLength < CM_KEY_VALUE_SPECIAL_SIZE) {
Data = ValueNode->Data;
if ((DataLength == 0) && (Data != HCELL_NIL)) {
bRez = FALSE;
fprintf(stderr, "Data not null in Key Value (0x%lx) ",KeyValue);
if(FixHive) {
//
// REPAIR: set the actual size to HiveLength-FileOffset
//
//
// WARNING: a cell might get lost here!
//
bRez = TRUE;
ValueNode->Data = HCELL_NIL;
fprintf(stderr, " ... fixed");
} else {
if(CompactHive) {
// any attempt to compact a corrupted hive will fail
CompactHive = FALSE;
fprintf(stderr, "\nRun chkreg /R to fix.");
}
}
fprintf(stderr, "\n");
}
}
if (!CmpIsHKeyValueSmall(realsize, ValueNode->DataLength)) {
//
// Data Size
//
OwnUsage->Size += GetCellSize(ValueNode->Data);
OwnUsage->DataCount++;
OwnUsage->DataSize += GetCellSize(ValueNode->Data);
// this cell should not be considered as lost
RemoveCellFromUnknownList(ValueNode->Data);
ChkAllocatedCell(ValueNode->Data);
(*KeyCompacted) = ((*KeyCompacted) && ChkAreCellsInSameVicinity(KeyValue,ValueNode->Data));
}
//
// Now the signature
//
if (ValueNode->Signature != CM_KEY_VALUE_SIGNATURE) {
bRez = FALSE;
fprintf(stderr, "Invalid signature (0x%lx) in Key Value cell 0x%lx ",ValueNode->Signature,KeyValue);
if(FixHive) {
//
// REPAIR:
// FATAL: Mismatched signature cannot be fixed. The key should be deleted!
//
fprintf(stderr, " ... deleting value.");
} else {
if(CompactHive) {
// any attempt to compact a corrupted hive will fail
CompactHive = FALSE;
fprintf(stderr, "\nRun chkreg /R to fix.");
}
}
fprintf(stderr, "\n");
}
return bRez;
}
ULONG
DeleteNilCells( ULONG Count,
HCELL_INDEX List[]
)
/*
Routine Description:
steps through a list of HCELL_INDEXes and removes the HCELL_NIL ones
Arguments:
Count - the number of cells in list
List - the list to be checked
Return Value:
The new Count value for the list
*/
{
ULONG i;
BOOLEAN bFound = TRUE;
while(bFound) {
// assume we are done after this iteration
bFound = FALSE;
for( i=0;i<Count;i++) {
if( List[i] == HCELL_NIL ) {
for(;i<(Count-1);i++) {
List[i] = List[i+1];
}
bFound = TRUE;
Count--;
break;
}
}
}
return Count;
}
BOOLEAN
ChkValueList( HCELL_INDEX ValueList,
ULONG *ValueCount,
PREG_USAGE OwnUsage,
BOOLEAN *KeyCompacted)
/*
Routine Description:
Checks the consistency of a ValueList.
Each value is checked.
Bogus values are freed and removed.
Arguments:
ValueList - the list to be checked
ValueCount - count of the list
OwnUsage - used to collect data statistics
Return Value:
TRUE if KeyCell is a valid cell or it was successfully fixed.
FALSE otherwise.
*/
{
ULONG i;
PCELL_DATA List;
BOOLEAN bRez = TRUE;
//
// Value Index size
//
OwnUsage->Size += GetCellSize(ValueList);
OwnUsage->ValueIndexCount = 1;
// this cell should not be considered as lost
RemoveCellFromUnknownList(ValueList);
ChkAllocatedCell(ValueList);
List = (PCELL_DATA)GetCell(ValueList);
for (i=0; i<(*ValueCount); i++) {
if( !ChkKeyValue(List->u.KeyList[i],OwnUsage,KeyCompacted) ) {
// we should remove this value
bRez = FALSE;
// Warning: this my create generate lost cells
if(FixHive) {
if( List->u.KeyList[i] != HCELL_NIL ) {
//FreeCell(List->u.KeyList[i]);
List->u.KeyList[i] = HCELL_NIL;
}
}
}
(*KeyCompacted) = ((*KeyCompacted) && ChkAreCellsInSameVicinity(ValueList,List->u.KeyList[i]));
}
if( FixHive && !bRez) {
(*ValueCount) = DeleteNilCells( *ValueCount,List->u.KeyList);
bRez = TRUE;
}
// for now
return bRez;
}
BOOLEAN
DumpChkRegistry(
ULONG Level,
USHORT ParentLength,
HCELL_INDEX Cell,
HCELL_INDEX ParentCell,
PREG_USAGE PUsage
)
/*
Routine Description:
Recursively walks through the hive. Performs logical vallidation
checks on all cells along the path and fix errors when possible.
Arguments:
Level - the current depth level within the hive key tree
ParentLength - the length of the parent name (dump purposes only)
Cell - current key to be checked
ParentCell - parent cell, used for parent-son relationship checkings
OwnUsage - used to collect data statistics
Return Value:
TRUE if Cell is a consistent key, or it was fixed OK.
FALSE otherwise.
*/
{
PCM_KEY_FAST_INDEX FastIndex;
HCELL_INDEX LeafCell;
PCM_KEY_INDEX Leaf;
PCM_KEY_INDEX Index;
PCM_KEY_NODE KeyNode;
REG_USAGE ChildUsage, TotalChildUsage, OwnUsage;
ULONG i, j;
USHORT k;
WCHAR *w1;
UCHAR *u1;
USHORT CurrentLength;
ULONG CellCount;
BOOLEAN bRez = TRUE;
BOOLEAN KeyCompacted = TRUE;
ULONG ClassLength;
HCELL_INDEX Class;
ULONG ValueCount;
HCELL_INDEX ValueList;
HCELL_INDEX Security;
if( Cell == HCELL_NIL ) {
// TODO
// we should return an error code so the caller could deleted this child from the structure
fprintf(stderr, "HCELL_NIL referrenced as a child key of 0x%lx \n",ParentCell);
bRez = FALSE;
return bRez;
}
KeyNode = (PCM_KEY_NODE) GetCell(Cell);
// Verify KeyNode consistency
if(!ChkKeyNodeCell(Cell,ParentCell)) {
//
// Bad karma ==> this key should be deleted
//
QuitToParentWithError:
if(ParentCell == HCELL_NIL) {
//
// Root cell not consistent ==> unable to fix the hive
//
fprintf(stderr, "Fatal : Inconsistent Root Key 0x%lx",Cell);
if(FixHive) {
//
// FATAL: nothing to do
//
fprintf(stderr, " ... unable to fix");
} else {
if(CompactHive) {
// any attempt to compact a corrupted hive will fail
CompactHive = FALSE;
}
}
fprintf(stderr, "\n");
}
bRez = FALSE;
return bRez;
}
ClassLength = KeyNode->ClassLength;
Class = KeyNode->Class;
ValueCount = KeyNode->ValueList.Count;
ValueList = KeyNode->ValueList.List;
Security = KeyNode->Security;
if (ClassLength > 0) {
if( Class != HCELL_NIL ) {
ChkClassCell(Class);
KeyCompacted = (KeyCompacted && ChkAreCellsInSameVicinity(Cell,Class));
} else {
bRez = FALSE;
fprintf(stderr,"ClassLength (=%u) doesn't match NIL values in Class for Key 0x%lx",ClassLength,Cell);
if(FixHive) {
//
// REPAIR: reset the ClassLength
//
bRez = TRUE;
KeyNode->ClassLength = 0;
fprintf(stderr, " ... fixed");
} else {
if(CompactHive) {
// any attempt to compact a corrupted hive will fail
CompactHive = FALSE;
fprintf(stderr, "\nRun chkreg /R to fix.");
}
}
fprintf(stderr, "\n");
}
}
if (Security != HCELL_NIL) {
if( !ChkSecurityCell(Security) ) {
//
// Fatal : We don't mess up with security cells. We can't recover from invalid security cells.
//
//
// QUESTION : Is it acceptable to drop a security cell?
//
bRez = FALSE;
}
} else {
//
// Fatal: security cell is not allowed to be NIL
//
bRez = FALSE;
fprintf(stderr,"Security cell is NIL for Key 0x%lx",Cell);
if(FixHive) {
//
// REPAIR: reset the security to the root security
//
PCM_KEY_NODE RootNode;
PCM_KEY_SECURITY SecurityNode;
bRez = TRUE;
RootNode = (PCM_KEY_NODE) GetCell(RootCell);
KeyNode->Security = RootNode->Security;
SecurityNode = (PCM_KEY_SECURITY)GetCell(RootNode->Security);
SecurityNode->ReferenceCount++;
fprintf(stderr, " ... fixed");
}
}
//
// Construct the full path name of the key
//
if (Level > 0) {
KeyName.Length = ParentLength;
if (KeyNode->Flags & KEY_COMP_NAME) {
u1 = (UCHAR*) &(KeyNode->Name[0]);
w1 = &(NameBuffer[KeyName.Length/sizeof(WCHAR)]);
for (k=0;k<KeyNode->NameLength;k++) {
// NameBuffer[k] = (UCHAR)(KeyNode->Name[k]);
// NameBuffer[k] = (WCHAR)(u1[k]);
*w1 = (WCHAR) *u1;
w1++;
u1++;
}
KeyName.Length += KeyNode->NameLength*sizeof(WCHAR);
} else {
RtlCopyMemory((PVOID)&(NameBuffer[KeyName.Length]), (PVOID)(KeyNode->Name), KeyNode->NameLength);
KeyName.Length += KeyNode->NameLength;
}
NameBuffer[KeyName.Length/sizeof(WCHAR)] = OBJ_NAME_PATH_SEPARATOR;
KeyName.Length += sizeof(WCHAR);
}
CurrentLength = KeyName.Length;
//
// Calculate the count of this key and value
//
OwnUsage.KeyNodeCount = 1;
OwnUsage.KeyValueCount = KeyNode->ValueList.Count;
OwnUsage.ValueIndexCount = 0;
OwnUsage.DataCount = 0;
OwnUsage.DataSize = 0;
//
// Calculate the count (including overhead and value) of this key
//
// Key node size
//
OwnUsage.Size = GetCellSize(Cell);
if( ValueCount ) {
if( ValueList == HCELL_NIL ) {
bRez = FALSE;
fprintf(stderr,"ValueCount is %lu, but ValueList is NIL for key 0x%lx",ValueCount,Cell);
if(FixHive) {
//
// REPAIR: adjust the ValueList count
//
bRez = TRUE;
KeyNode->ValueList.Count = 0;
fprintf(stderr, " ... fixed");
} else {
if(CompactHive) {
// any attempt to compact a corrupted hive will fail
CompactHive = FALSE;
fprintf(stderr, "\nRun chkreg /R to fix.");
}
}
fprintf(stderr, "\n");
} else {
if(!ChkValueList(ValueList,&(KeyNode->ValueList.Count),&OwnUsage,&KeyCompacted) ) {
// the ValueList is not consistent or cannot be fixed
bRez = FALSE;
if(FixHive) {
//
// REPAIR: empty the ValueList
//
bRez = TRUE;
KeyNode->ValueList.Count = 0;
//FreeCell(ValueList);
KeyNode->ValueList.List = HCELL_NIL;
fprintf(stderr,"ValueList 0x%lx for key 0x%lx dropped!",ValueCount,Cell);
} else {
if(CompactHive) {
// any attempt to compact a corrupted hive will fail
CompactHive = FALSE;
fprintf(stderr, "\nRun chkreg /R to fix.");
}
}
fprintf(stderr, "\n");
}
KeyCompacted = (KeyCompacted && ChkAreCellsInSameVicinity(Cell,ValueList));
}
}
//
// Calculate the size of the children
//
TotalChildUsage.KeyNodeCount = 0;
TotalChildUsage.KeyValueCount = 0;
TotalChildUsage.ValueIndexCount = 0;
TotalChildUsage.KeyIndexCount = 0;
TotalChildUsage.DataCount = 0;
TotalChildUsage.DataSize = 0;
TotalChildUsage.Size = 0;
if (KeyNode->SubKeyCounts[0]) {
//
// Size for index cell
//
if( KeyNode->SubKeyLists[0] == HCELL_NIL ) {
//
// We got a problem here: the count says there should be some keys, but the list is NIL
//
bRez = FALSE;
fprintf(stderr,"SubKeyCounts is %lu, but the SubKeyLists is NIL for key 0x%lx",KeyNode->SubKeyCounts[0],Cell);
if(FixHive) {
//
// REPAIR: adjust the subkeys count
//
bRez = TRUE;
KeyNode->SubKeyCounts[0] = 0;
fprintf(stderr, " ... fixed");
} else {
if(CompactHive) {
// any attempt to compact a corrupted hive will fail
CompactHive = FALSE;
fprintf(stderr, "\nRun chkreg /R to fix.");
}
}
fprintf(stderr, "\n");
return bRez;
}
KeyCompacted = (KeyCompacted && ChkAreCellsInSameVicinity(Cell,KeyNode->SubKeyLists[0]));
TotalChildUsage.Size += GetCellSize(KeyNode->SubKeyLists[0]);
TotalChildUsage.KeyIndexCount++;
Index = (PCM_KEY_INDEX)GetCell(KeyNode->SubKeyLists[0]);
// this cell should not be considered as lost
RemoveCellFromUnknownList(KeyNode->SubKeyLists[0]);
ChkAllocatedCell(KeyNode->SubKeyLists[0]);
if (Index->Signature == CM_KEY_INDEX_ROOT) {
for (i = 0; i < Index->Count; i++) {
//
// Size of Index Leaf
//
LeafCell = Index->List[i];
TotalChildUsage.Size += GetCellSize(Index->List[i]);
TotalChildUsage.KeyIndexCount++;
// this cell should not be considered as lost
RemoveCellFromUnknownList(LeafCell);
ChkAllocatedCell(LeafCell);
Leaf = (PCM_KEY_INDEX)GetCell(LeafCell);
if ( (Leaf->Signature == CM_KEY_FAST_LEAF) ||
(Leaf->Signature == CM_KEY_HASH_LEAF) ) {
FastIndex = (PCM_KEY_FAST_INDEX)Leaf;
againFastLeaf1:
for (j = 0; j < FastIndex->Count; j++) {
if(!DumpChkRegistry(Level+1, CurrentLength, FastIndex->List[j].Cell,Cell,&ChildUsage)) {
// this child is not consistent or cannot be fixed. Remove it!!!
if(FixHive) {
//
// REPAIR: drop this child
//
fprintf(stderr,"Subkey 0x%lx of 0x%lx deleted!\n",FastIndex->List[j].Cell,Cell);
for( ;j<(ULONG)(FastIndex->Count-1);j++) {
FastIndex->List[j] = FastIndex->List[j+1];
}
FastIndex->Count--;
KeyNode->SubKeyCounts[0]--;
goto againFastLeaf1;
} else {
bRez = FALSE;
if(CompactHive) {
// any attempt to compact a corrupted hive will fail
CompactHive = FALSE;
fprintf(stderr, "\nRun chkreg /R to fix.");
}
}
fprintf(stderr, "\n");
}
//
// Add to total count
//
TotalChildUsage.KeyNodeCount += ChildUsage.KeyNodeCount;
TotalChildUsage.KeyValueCount += ChildUsage.KeyValueCount;
TotalChildUsage.ValueIndexCount += ChildUsage.ValueIndexCount;
TotalChildUsage.KeyIndexCount += ChildUsage.KeyIndexCount;
TotalChildUsage.DataCount += ChildUsage.DataCount;
TotalChildUsage.DataSize += ChildUsage.DataSize;
TotalChildUsage.Size += ChildUsage.Size;
}
} else if(Leaf->Signature == CM_KEY_INDEX_LEAF) {
againFastLeaf2:
for (j = 0; j < Leaf->Count; j++) {
if(!DumpChkRegistry(Level+1, CurrentLength, Leaf->List[j],Cell,&ChildUsage)) {
// this child is not consistent or cannot be fixed. Remove it!!!
if(FixHive) {
//
// REPAIR: drop this child
//
fprintf(stderr,"Subkey 0x%lx of 0x%lx deleted!\n",Leaf->List[j],Cell);
for( ;j<(ULONG)(Leaf->Count-1);j++) {
Leaf->List[j] = Leaf->List[j+1];
}
Leaf->Count--;
KeyNode->SubKeyCounts[0]--;
goto againFastLeaf2;
} else {
bRez = FALSE;
if(CompactHive) {
// any attempt to compact a corrupted hive will fail
CompactHive = FALSE;
fprintf(stderr, "\nRun chkreg /R to fix.");
}
}
fprintf(stderr, "\n");
}
//
// Add to total count
//
TotalChildUsage.KeyNodeCount += ChildUsage.KeyNodeCount;
TotalChildUsage.KeyValueCount += ChildUsage.KeyValueCount;
TotalChildUsage.ValueIndexCount += ChildUsage.ValueIndexCount;
TotalChildUsage.KeyIndexCount += ChildUsage.KeyIndexCount;
TotalChildUsage.DataCount += ChildUsage.DataCount;
TotalChildUsage.DataSize += ChildUsage.DataSize;
TotalChildUsage.Size += ChildUsage.Size;
}
} else {
// invalid index signature: only way to fix it is by dropping the entire key
fprintf(stderr,"Invalid Index signature 0x%lx in key 0x%lx",(ULONG)Leaf->Signature,Cell);
if(FixHive) {
//
// REPAIR:
// FATAL: Mismatched signature cannot be fixed. The key should be deleted!
//
fprintf(stderr, " ... deleting containing key");
}
fprintf(stderr,"\n");
goto QuitToParentWithError;
}
}
} else if( (Index->Signature == CM_KEY_FAST_LEAF) ||
(Index->Signature == CM_KEY_HASH_LEAF) ) {
FastIndex = (PCM_KEY_FAST_INDEX)Index;
againFastLeaf3:
for (i = 0; i < FastIndex->Count; i++) {
if(!DumpChkRegistry(Level+1, CurrentLength, FastIndex->List[i].Cell,Cell,&ChildUsage)) {
// this child is not consistent or cannot be fixed. Remove it!!!
if(FixHive) {
//
// REPAIR: drop this child
//
fprintf(stderr,"Subkey 0x%lx of 0x%lx deleted!\n",FastIndex->List[i].Cell,Cell);
for( ;i<(ULONG)(FastIndex->Count-1);i++) {
FastIndex->List[i] = FastIndex->List[i+1];
}
FastIndex->Count--;
KeyNode->SubKeyCounts[0]--;
goto againFastLeaf3;
} else {
bRez = FALSE;
if(CompactHive) {
// any attempt to compact a corrupted hive will fail
CompactHive = FALSE;
fprintf(stderr, "\nRun chkreg /R to fix.");
}
}
fprintf(stderr, "\n");
}
//
// Add to total count
//
TotalChildUsage.KeyNodeCount += ChildUsage.KeyNodeCount;
TotalChildUsage.KeyValueCount += ChildUsage.KeyValueCount;
TotalChildUsage.ValueIndexCount += ChildUsage.ValueIndexCount;
TotalChildUsage.KeyIndexCount += ChildUsage.KeyIndexCount;
TotalChildUsage.DataCount += ChildUsage.DataCount;
TotalChildUsage.DataSize += ChildUsage.DataSize;
TotalChildUsage.Size += ChildUsage.Size;
}
} else if(Index->Signature == CM_KEY_INDEX_LEAF) {
for (i = 0; i < Index->Count; i++) {
againFastLeaf4:
if(!DumpChkRegistry(Level+1, CurrentLength, Index->List[i],Cell, &ChildUsage)) {
// this child is not consistent or cannot be fixed. Remove it!!!
if(FixHive) {
//
// REPAIR: drop this child
//
fprintf(stderr,"Subkey 0x%lx of 0x%lx deleted!\n",Index->List[i],Cell);
for( ;i<(ULONG)(Index->Count-1);i++) {
Index->List[i] = Index->List[i+1];
}
Index->Count--;
KeyNode->SubKeyCounts[0]--;
goto againFastLeaf4;
} else {
bRez = FALSE;
if(CompactHive) {
// any attempt to compact a corrupted hive will fail
CompactHive = FALSE;
fprintf(stderr, "\nRun chkreg /R to fix.");
}
}
fprintf(stderr, "\n");
}
//
// Add to total count
//
TotalChildUsage.KeyNodeCount += ChildUsage.KeyNodeCount;
TotalChildUsage.KeyValueCount += ChildUsage.KeyValueCount;
TotalChildUsage.ValueIndexCount += ChildUsage.ValueIndexCount;
TotalChildUsage.KeyIndexCount += ChildUsage.KeyIndexCount;
TotalChildUsage.DataCount += ChildUsage.DataCount;
TotalChildUsage.DataSize += ChildUsage.DataSize;
TotalChildUsage.Size += ChildUsage.Size;
}
} else {
// invalid index signature: only way to fix it is by dropping the entire key
fprintf(stderr,"Invalid Index signature 0x%lx in key 0x%lx",(ULONG)Index->Signature,Cell);
if(FixHive) {
//
// REPAIR:
// FATAL: Mismatched signature cannot be fixed. The key should be deleted!
//
fprintf(stderr, " ... deleting containing key");
}
fprintf(stderr,"\n");
goto QuitToParentWithError;
}
KeyName.Length = CurrentLength;
}
PUsage->KeyNodeCount = OwnUsage.KeyNodeCount + TotalChildUsage.KeyNodeCount;
PUsage->KeyValueCount = OwnUsage.KeyValueCount + TotalChildUsage.KeyValueCount;
PUsage->ValueIndexCount = OwnUsage.ValueIndexCount + TotalChildUsage.ValueIndexCount;
PUsage->KeyIndexCount = TotalChildUsage.KeyIndexCount;
PUsage->DataCount = OwnUsage.DataCount + TotalChildUsage.DataCount;
PUsage->DataSize = OwnUsage.DataSize + TotalChildUsage.DataSize;
PUsage->Size = OwnUsage.Size + TotalChildUsage.Size;
if(KeyCompacted) {
CountKeyNodeCompacted++;
}
if ((Level <= MaxLevel) && (Level > 0)) {
CellCount = PUsage->KeyNodeCount +
PUsage->KeyValueCount +
PUsage->ValueIndexCount +
PUsage->KeyIndexCount +
PUsage->DataCount;
fprintf(OutputFile,"%6d,%6d,%7d,%10d, %wZ\n",
PUsage->KeyNodeCount,
PUsage->KeyValueCount,
CellCount,
PUsage->Size,
&KeyName);
}
return bRez;
}