1158 lines
36 KiB
C
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;
|
||
|
}
|
||
|
|