windows-nt/Source/XPSP1/NT/base/ntos/config/cmindex.c

3240 lines
88 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
//depot/main/Base/ntos/config/cmindex.c#12 - integrate change 19035 (text)
/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
cmindex.c
Abstract:
This module contains cm routines that understand the structure
of child subkey indicies.
Author:
Bryan M. Willman (bryanwi) 21-Apr-92
Revision History:
--*/
/*
The Structure:
Use a 1 or 2 level tree. Leaf nodes are arrays of pointers to
cells, sorted. Binary search to find cell of interest. Directory
node (can be only one) is an array of pointers to leaf blocks.
Do compare on last entry of each leaf block.
One Level:
Key--->+----+
| |
| x----------><key whose name is "apple", string in key>
| |
+----+
| |
| x----------><as above, but key named "banana">
| |
+----+
| |
| |
| |
+----+
| |
| |
| |
+----+
| |
| x----------><as above, but key named "zumwat">
| |
+----+
Two Level:
Key--->+----+
| | +-----+
| x----->| |
| | | x----------------->"aaa"
+----+ | |
| | +-----+
| | | |
| | | |
+----+ | |
| | +-----+
| | | |
| | | x----------------->"abc"
+----+ | |
| | +-----+
| |
| |
+----+
| | +-----+
| x----->| |
| | | x----------------->"w"
+----+ | |
+-----+
| |
| |
| |
+-----+
| |
| x----------------->"z"
| |
+-----+
Never more than two levels.
Each block must fix in on HBLOCK_SIZE Cell. Allows about 1000
entries. Max of 1 million total, best case. Worst case something
like 1/4 of that.
*/
#include "cmp.h"
ULONG
CmpFindSubKeyInRoot(
PHHIVE Hive,
PCM_KEY_INDEX Index,
PUNICODE_STRING SearchName,
PHCELL_INDEX Child
);
ULONG
CmpFindSubKeyInLeaf(
PHHIVE Hive,
PCM_KEY_INDEX Index,
PUNICODE_STRING SearchName,
PHCELL_INDEX Child
);
LONG
CmpCompareInIndex(
PHHIVE Hive,
PUNICODE_STRING SearchName,
ULONG Count,
PCM_KEY_INDEX Index,
PHCELL_INDEX Child
);
LONG
CmpDoCompareKeyName(
PHHIVE Hive,
PUNICODE_STRING SearchName,
HCELL_INDEX Cell
);
HCELL_INDEX
CmpDoFindSubKeyByNumber(
PHHIVE Hive,
PCM_KEY_INDEX Index,
ULONG Number
);
HCELL_INDEX
CmpAddToLeaf(
PHHIVE Hive,
HCELL_INDEX LeafCell,
HCELL_INDEX NewKey,
PUNICODE_STRING NewName
);
HCELL_INDEX
CmpSelectLeaf(
PHHIVE Hive,
PCM_KEY_NODE ParentKey,
PUNICODE_STRING NewName,
HSTORAGE_TYPE Type,
PHCELL_INDEX *RootPointer
);
HCELL_INDEX
CmpSplitLeaf(
PHHIVE Hive,
HCELL_INDEX RootCell,
ULONG RootSelect,
HSTORAGE_TYPE Type
);
HCELL_INDEX
CmpFindSubKeyByHash(
PHHIVE Hive,
PCM_KEY_FAST_INDEX FastIndex,
PUNICODE_STRING SearchName
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,CmpFindSubKeyByName)
#pragma alloc_text(PAGE,CmpFindSubKeyInRoot)
#pragma alloc_text(PAGE,CmpFindSubKeyInLeaf)
#pragma alloc_text(PAGE,CmpDoCompareKeyName)
#pragma alloc_text(PAGE,CmpCompareInIndex)
#pragma alloc_text(PAGE,CmpFindSubKeyByNumber)
#pragma alloc_text(PAGE,CmpDoFindSubKeyByNumber)
#pragma alloc_text(PAGE,CmpAddSubKey)
#pragma alloc_text(PAGE,CmpAddToLeaf)
#pragma alloc_text(PAGE,CmpSelectLeaf)
#pragma alloc_text(PAGE,CmpSplitLeaf)
#pragma alloc_text(PAGE,CmpMarkIndexDirty)
#pragma alloc_text(PAGE,CmpRemoveSubKey)
#pragma alloc_text(PAGE,CmpComputeHashKey)
#pragma alloc_text(PAGE,CmpComputeHashKeyForCompressedName)
#pragma alloc_text(PAGE,CmpFindSubKeyByHash)
#ifdef NT_RENAME_KEY
#pragma alloc_text(PAGE,CmpDuplicateIndex)
#pragma alloc_text(PAGE,CmpUpdateParentForEachSon)
#endif //NT_RENAME_KEY
#pragma alloc_text(PAGE,CmpRemoveSubKeyCellNoCellRef)
#endif
HCELL_INDEX
CmpFindSubKeyByName(
PHHIVE Hive,
PCM_KEY_NODE Parent,
PUNICODE_STRING SearchName
)
/*++
Routine Description:
Find the child cell (either subkey or value) specified by name.
Arguments:
Hive - pointer to hive control structure for hive of interest
Parent - cell of key body which is parent of child of interest
SearchName - name of child of interest
Return Value:
Cell of matching child key, or HCELL_NIL if none.
--*/
{
PCM_KEY_INDEX IndexRoot;
HCELL_INDEX Child;
ULONG i;
ULONG FoundIndex;
HCELL_INDEX CellToRelease = HCELL_NIL;
#ifndef _CM_LDR_
PAGED_CODE();
#endif //_CM_LDR_
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_INDEX,"CmpFindSubKeyByName:\n\t"));
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_INDEX,"Hive=%p Parent=%p SearchName=%p\n", Hive, Parent, SearchName));
//
// Try first the Stable, then the Volatile store. Assumes that
// all Volatile refs in Stable space are zeroed out at boot.
//
for (i = 0; i < Hive->StorageTypeCount; i++) {
if (Parent->SubKeyCounts[i] != 0) {
IndexRoot = (PCM_KEY_INDEX)HvGetCell(Hive, Parent->SubKeyLists[i]);
ASSERT( (IndexRoot == NULL) || HvIsCellAllocated(Hive, Parent->SubKeyLists[i]) );
if( IndexRoot == NULL ) {
//
// we couldn't map a view for the bin containing this cell
//
return HCELL_NIL;
}
CellToRelease = Parent->SubKeyLists[i];
if (IndexRoot->Signature == CM_KEY_INDEX_ROOT) {
if( INVALID_INDEX & CmpFindSubKeyInRoot(Hive, IndexRoot, SearchName, &Child) ) {
//
// couldn't map view inside
//
ASSERT( CellToRelease != HCELL_NIL );
HvReleaseCell(Hive,CellToRelease);
return HCELL_NIL;
}
ASSERT( CellToRelease != HCELL_NIL );
HvReleaseCell(Hive,CellToRelease);
if (Child == HCELL_NIL) {
continue;
}
IndexRoot = (PCM_KEY_INDEX)HvGetCell(Hive, Child);
if( IndexRoot == NULL ) {
//
// we couldn't map a view for the bin containing this cell
//
return HCELL_NIL;
}
CellToRelease = Child;
}
ASSERT((IndexRoot->Signature == CM_KEY_INDEX_LEAF) ||
(IndexRoot->Signature == CM_KEY_FAST_LEAF) ||
(IndexRoot->Signature == CM_KEY_HASH_LEAF)
);
if( IndexRoot->Signature == CM_KEY_HASH_LEAF ) {
Child = CmpFindSubKeyByHash(Hive,(PCM_KEY_FAST_INDEX)IndexRoot,SearchName);
ASSERT( CellToRelease != HCELL_NIL );
HvReleaseCell(Hive,CellToRelease);
} else {
FoundIndex = CmpFindSubKeyInLeaf(Hive,
IndexRoot,
SearchName,
&Child);
ASSERT( CellToRelease != HCELL_NIL );
HvReleaseCell(Hive,CellToRelease);
if( INVALID_INDEX & FoundIndex ) {
//
// couldn't map view
//
return HCELL_NIL;
}
}
if (Child != HCELL_NIL) {
//
// success
//
return Child;
}
}
}
#if 0 //DBG
//
// Validation code. manually search for the key and break when found
//
if (Parent->SubKeyCounts[Stable] != 0) {
ULONG Cnt1,Cnt2;
LONG Result;
HCELL_INDEX Cell;
PCM_KEY_INDEX Leaf;
PCM_KEY_INDEX DbgIndexRoot = (PCM_KEY_INDEX)HvGetCell(Hive, Parent->SubKeyLists[Stable]);
if(DbgIndexRoot->Signature == CM_KEY_INDEX_ROOT ) {
for(Cnt1=0;Cnt1<DbgIndexRoot->Count;Cnt1++) {
Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, DbgIndexRoot->List[Cnt1]);
for( Cnt2=0;Cnt2<Leaf->Count;Cnt2++) {
Result = CmpCompareInIndex( Hive,
SearchName,
Cnt2,
Leaf,
&Cell);
if( Result == 0 ) {
//
// Found it !!! Error above !!!
//
DbgPrint("CmpFindSubKeyByName: Hive = %p, Parent = %p, SearchName = %p\n",Hive,Parent,SearchName);
DbgPrint(" : IndexRoot = %p, DbgIndexRoot = %p, Cnt1 = %lx, Cnt2 = %lx\n",IndexRoot,DbgIndexRoot,Cnt1,Cnt2);
DbgPrint(" : Leaf = %p\n",Leaf);
DbgBreakPoint();
}
}
HvReleaseCell(Hive,DbgIndexRoot->List[Cnt1]);
}
}
HvReleaseCell(Hive,Parent->SubKeyLists[Stable]);
}
#endif //0
return HCELL_NIL;
}
ULONG
CmpFindSubKeyInRoot(
PHHIVE Hive,
PCM_KEY_INDEX Index,
PUNICODE_STRING SearchName,
PHCELL_INDEX Child
)
/*++
Routine Description:
Find the leaf index that would contain a key, if there is one.
Arguments:
Hive - pointer to hive control structure for hive of interest
Index - pointer to root index block
SearchName - pointer to name of key of interest
Child - pointer to variable to receive hcell_index of found leaf index
block, HCELL_NIL if none. Non nil does not necessarily mean
the key is present, call FindSubKeyInLeaf to decide that.
Return Value:
Index in List of last Leaf Cell entry examined. If Child != HCELL_NIL,
Index is entry that matched, else, index is for last entry we looked
at. (Target Leaf will be this value plus or minus 1)
If an error appears while searching the subkey (i.e. a cell cannot be
mapped into memory) INVALID_INDEX is returned.
--*/
{
ULONG High;
ULONG Low;
ULONG CanCount;
HCELL_INDEX LeafCell;
PCM_KEY_INDEX Leaf;
LONG Result;
ULONG ReturnIndex = INVALID_INDEX;
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_INDEX,"CmpFindSubKeyInRoot:\n\t"));
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_INDEX,"Hive=%p Index=%p SearchName=%p\n",Hive,Index,SearchName));
ASSERT(Index->Count != 0);
ASSERT(Index->Signature == CM_KEY_INDEX_ROOT);
High = Index->Count - 1;
Low = 0;
while (TRUE) {
//
// Compute where to look next, get correct pointer, do compare
//
CanCount = ((High-Low)/2)+Low;
LeafCell = Index->List[CanCount];
Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell);
if( Leaf == NULL ) {
//
// we couldn't map the bin containing this cell
//
*Child = HCELL_NIL;
ReturnIndex = INVALID_INDEX;
goto JustReturn;
}
ASSERT((Leaf->Signature == CM_KEY_INDEX_LEAF) ||
(Leaf->Signature == CM_KEY_FAST_LEAF) ||
(Leaf->Signature == CM_KEY_HASH_LEAF)
);
ASSERT(Leaf->Count != 0);
Result = CmpCompareInIndex(Hive,
SearchName,
Leaf->Count-1,
Leaf,
Child);
if( Result == 2 ) {
//
// couldn't map view inside; bail out
//
*Child = HCELL_NIL;
ReturnIndex = INVALID_INDEX;
goto JustReturn;
}
if (Result == 0) {
//
// SearchName == KeyName of last key in leaf, so
// this is our leaf
//
*Child = LeafCell;
ReturnIndex = CanCount;
goto JustReturn;
}
if (Result < 0) {
ASSERT( Result == -1 );
//
// SearchName < KeyName, so this may still be our leaf
//
Result = CmpCompareInIndex(Hive,
SearchName,
0,
Leaf,
Child);
if( Result == 2 ) {
//
// couldn't map view inside; bail out
//
*Child = HCELL_NIL;
ReturnIndex = INVALID_INDEX;
goto JustReturn;
}
if (Result >= 0) {
ASSERT( (Result == 1) || (Result == 0) );
//
// we know from above that SearchName is less than
// last key in leaf.
// since it is also >= first key in leaf, it must
// reside in leaf somewhere, and we are done
//
*Child = LeafCell;
ReturnIndex = CanCount;
goto JustReturn;
}
High = CanCount;
} else {
//
// SearchName > KeyName
//
Low = CanCount;
}
if ((High - Low) <= 1) {
break;
}
HvReleaseCell(Hive, LeafCell);
}
HvReleaseCell(Hive, LeafCell);
//
// If we get here, High - Low = 1 or High == Low
//
ASSERT((High - Low == 1) || (High == Low));
LeafCell = Index->List[Low];
Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell);
if( Leaf == NULL ) {
//
// we couldn't map the bin containing this cell
//
*Child = HCELL_NIL;
ReturnIndex = INVALID_INDEX;
goto JustReturn;
}
Result = CmpCompareInIndex(Hive,
SearchName,
Leaf->Count-1,
Leaf,
Child);
if( Result == 2 ) {
//
// couldn't map view inside; bail out
//
*Child = HCELL_NIL;
ReturnIndex = INVALID_INDEX;
goto JustReturn;
}
if (Result == 0) {
//
// found it
//
*Child = LeafCell;
ReturnIndex = Low;
goto JustReturn;
}
if (Result < 0) {
ASSERT( Result == -1 );
//
// SearchName < KeyName, so this may still be our leaf
//
Result = CmpCompareInIndex(Hive,
SearchName,
0,
Leaf,
Child);
if( Result == 2 ) {
//
// couldn't map view inside; bail out
//
*Child = HCELL_NIL;
ReturnIndex = INVALID_INDEX;
goto JustReturn;
}
if (Result >= 0) {
ASSERT( (Result == 1) || (Result == 0) );
//
// we know from above that SearchName is less than
// last key in leaf.
// since it is also >= first key in leaf, it must
// reside in leaf somewhere, and we are done
//
*Child = LeafCell;
ReturnIndex = Low;
goto JustReturn;
}
//
// does not exist, but belongs in Low or Leaf below low
//
*Child = HCELL_NIL;
ReturnIndex = Low;
goto JustReturn;
}
HvReleaseCell(Hive, LeafCell);
//
// see if High matches
//
LeafCell = Index->List[High];
Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell);
if( Leaf == NULL ) {
//
// we couldn't map the bin containing this cell
//
*Child = HCELL_NIL;
ReturnIndex = INVALID_INDEX;
goto JustReturn;
}
Result = CmpCompareInIndex(Hive,
SearchName,
Leaf->Count - 1,
Leaf,
Child);
if( Result == 2 ) {
//
// couldn't map view inside; bail out
//
*Child = HCELL_NIL;
ReturnIndex = INVALID_INDEX;
goto JustReturn;
}
if (Result == 0) {
//
// found it
//
*Child = LeafCell;
ReturnIndex = High;
goto JustReturn;
} else if (Result < 0) {
ASSERT( Result == -1 );
//
// Clearly greater than low, or we wouldn't be here.
// So regardless of whether it's below the start
// of this leaf, it would be in this leaf if it were
// where, so report this leaf.
//
*Child = LeafCell;
ReturnIndex = High;
goto JustReturn;
}
//
// Off the high end
//
*Child = HCELL_NIL;
ReturnIndex = High;
JustReturn:
if(Leaf != NULL){
HvReleaseCell(Hive, LeafCell);
}
return ReturnIndex;
}
ULONG
CmpFindSubKeyInLeaf(
PHHIVE Hive,
PCM_KEY_INDEX Index,
PUNICODE_STRING SearchName,
PHCELL_INDEX Child
)
/*++
Routine Description:
Find a named key in a leaf index, if it exists. The supplied index
may be either a fast index or a slow one.
Arguments:
Hive - pointer to hive control structure for hive of interest
Index - pointer to leaf block
SearchName - pointer to name of key of interest
Child - pointer to variable to receive hcell_index of found key
HCELL_NIL if none found
Return Value:
Index in List of last cell. If Child != HCELL_NIL, is offset in
list at which Child was found. Else, is offset of last place
we looked.
INVALID_INDEX - resources problem; couldn't map view
--*/
{
ULONG High;
ULONG Low;
ULONG CanCount;
LONG Result;
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_INDEX,"CmpFindSubKeyInLeaf:\n\t"));
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_INDEX,"Hive=%p Index=%p SearchName=%p\n",Hive,Index,SearchName));
ASSERT((Index->Signature == CM_KEY_INDEX_LEAF) ||
(Index->Signature == CM_KEY_FAST_LEAF) ||
(Index->Signature == CM_KEY_HASH_LEAF)
);
High = Index->Count - 1;
Low = 0;
CanCount = High/2;
if (Index->Count == 0) {
*Child = HCELL_NIL;
return 0;
}
while (TRUE) {
//
// Compute where to look next, get correct pointer, do compare
//
Result = CmpCompareInIndex(Hive,
SearchName,
CanCount,
Index,
Child);
if( Result == 2 ) {
//
// couldn't map view inside; bail out
//
*Child = HCELL_NIL;
return INVALID_INDEX;
}
if (Result == 0) {
//
// SearchName == KeyName
//
return CanCount;
}
if (Result < 0) {
ASSERT( Result == -1 );
//
// SearchName < KeyName
//
High = CanCount;
} else {
ASSERT( Result == 1 );
//
// SearchName > KeyName
//
Low = CanCount;
}
if ((High - Low) <= 1) {
break;
}
CanCount = ((High-Low)/2)+Low;
}
//
// If we get here, High - Low = 1 or High == Low
// Simply look first at Low, then at High
//
Result = CmpCompareInIndex(Hive,
SearchName,
Low,
Index,
Child);
if( Result == 2 ) {
//
// couldn't map view inside; bail out
//
*Child = HCELL_NIL;
return INVALID_INDEX;
}
if (Result == 0) {
//
// found it
//
return Low;
}
if (Result < 0) {
ASSERT( Result == -1 );
//
// does not exist, under
//
return Low;
}
//
// see if High matches, we will return High as the
// closest key regardless.
//
Result = CmpCompareInIndex(Hive,
SearchName,
High,
Index,
Child);
if( Result == 2 ) {
//
// couldn't map view inside; bail out
//
*Child = HCELL_NIL;
return INVALID_INDEX;
}
return High;
}
LONG
CmpCompareInIndex(
PHHIVE Hive,
PUNICODE_STRING SearchName,
ULONG Count,
PCM_KEY_INDEX Index,
PHCELL_INDEX Child
)
/*++
Routine Description:
Do a compare of a name in an index. This routine handles both
fast leafs and slow ones.
Arguments:
Hive - pointer to hive control structure for hive of interest
SearchName - pointer to name of key we are searching for
Count - supplies index that we are searching at.
Index - Supplies pointer to either a CM_KEY_INDEX or
a CM_KEY_FAST_INDEX. This routine will determine which
type of index it is passed.
Child - pointer to variable to receive hcell_index of found key
HCELL_NIL if result != 0
Return Value:
0 = SearchName == KeyName (of Cell)
-1 = SearchName < KeyName
+1 = SearchName > KeyName
+2 = Error, insufficient resources
--*/
{
PCM_KEY_FAST_INDEX FastIndex;
LONG Result;
ULONG i;
WCHAR c1;
WCHAR c2;
ULONG HintLength;
ULONG ValidChars;
ULONG NameLength;
PCM_INDEX Hint;
*Child = HCELL_NIL;
if ( (Index->Signature == CM_KEY_FAST_LEAF) ||
(Index->Signature == CM_KEY_HASH_LEAF) ) {
FastIndex = (PCM_KEY_FAST_INDEX)Index;
Hint = &FastIndex->List[Count];
if(Index->Signature == CM_KEY_FAST_LEAF) {
//
// Compute the number of valid characters in the hint to compare.
//
HintLength = 4;
for (i=0;i<4;i++) {
if (Hint->NameHint[i] == 0) {
HintLength = i;
break;
}
}
NameLength = SearchName->Length / sizeof(WCHAR);
if (NameLength < HintLength) {
ValidChars = NameLength;
} else {
ValidChars = HintLength;
}
for (i=0; i<ValidChars; i++) {
c1 = SearchName->Buffer[i];
c2 = FastIndex->List[Count].NameHint[i];
Result = (LONG)RtlUpcaseUnicodeChar(c1) -
(LONG)RtlUpcaseUnicodeChar(c2);
if (Result != 0) {
//
// We have found a mismatched character in the hint,
// we can now tell which direction to go.
//
return (Result > 0) ? 1 : -1 ;
}
}
}
//
// We have compared all the available characters without a
// discrepancy. Go ahead and do the actual comparison now.
//
Result = CmpDoCompareKeyName(Hive,SearchName,FastIndex->List[Count].Cell);
if( Result == 2 ) {
//
// couldn't map view inside; signal it to the caller
//
return 2;
}
if (Result == 0) {
*Child = Hint->Cell;
}
} else {
//
// This is just a normal old slow index.
//
Result = CmpDoCompareKeyName(Hive,SearchName,Index->List[Count]);
if( Result == 2 ) {
//
// couldn't map view inside; signal it to the caller
//
return 2;
}
if (Result == 0) {
*Child = Index->List[Count];
}
}
return(Result);
}
LONG
CmpDoCompareKeyName(
PHHIVE Hive,
PUNICODE_STRING SearchName,
HCELL_INDEX Cell
)
/*++
Routine Description:
Do a compare of a name with a key.
Arguments:
Hive - pointer to hive control structure for hive of interest
SearchName - pointer to name of key we are searching for
Cell - cell of key we are to compare with
Return Value:
0 = SearchName == KeyName (of Cell)
-1 = SearchName < KeyName
+1 = SearchName > KeyName
+2 = Error (couldn't map bin)
--*/
{
PCM_KEY_NODE Pcan;
UNICODE_STRING KeyName;
LONG Result;
Pcan = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
if( Pcan == NULL ) {
//
// we couldn't map the bin containing this cell
// return error, so the caller could safely bail out
//
return 2;
}
if (Pcan->Flags & KEY_COMP_NAME) {
Result = CmpCompareCompressedName(SearchName,
Pcan->Name,
Pcan->NameLength,
0);
} else {
KeyName.Buffer = &(Pcan->Name[0]);
KeyName.Length = Pcan->NameLength;
KeyName.MaximumLength = KeyName.Length;
Result = RtlCompareUnicodeString(SearchName,
&KeyName,
TRUE);
}
HvReleaseCell(Hive, Cell);
if( Result == 0 ) {
//
// match
//
return 0;
}
return (Result < 0) ? -1 : 1;
}
HCELL_INDEX
CmpFindSubKeyByNumber(
PHHIVE Hive,
PCM_KEY_NODE Node,
ULONG Number
)
/*++
Routine Description:
Find the Number'th entry in the index, starting from 0.
Arguments:
Hive - pointer to hive control structure for hive of interest
Node - pointer to key body which is parent of child of interest
Number - ordinal of child key to return
Return Value:
Cell of matching child key, or HCELL_NIL if none or error.
--*/
{
PCM_KEY_INDEX Index;
HCELL_INDEX Result = HCELL_NIL;
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_INDEX,"CmpFindSubKeyByNumber:\n\t"));
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_INDEX,"Hive=%p Node=%p Number=%08lx\n",Hive,Node,Number));
if (Number < Node->SubKeyCounts[Stable]) {
//
// It's in the stable set
//
Index = (PCM_KEY_INDEX)HvGetCell(Hive, Node->SubKeyLists[Stable]);
if( Index == NULL ) {
//
// we couldn't map the bin containing this cell
//
return HCELL_NIL;
}
Result = CmpDoFindSubKeyByNumber(Hive, Index, Number);
HvReleaseCell(Hive, Node->SubKeyLists[Stable]);
return Result;
} else if (Hive->StorageTypeCount > Volatile) {
//
// It's in the volatile set
//
Number = Number - Node->SubKeyCounts[Stable];
if (Number < Node->SubKeyCounts[Volatile]) {
Index = (PCM_KEY_INDEX)HvGetCell(Hive, Node->SubKeyLists[Volatile]);
if( Index == NULL ) {
//
// we couldn't map the bin containing this cell
//
return HCELL_NIL;
}
Result = CmpDoFindSubKeyByNumber(Hive, Index, Number);
HvReleaseCell(Hive, Node->SubKeyLists[Volatile]);
return Result;
}
}
//
// It's nowhere
//
return HCELL_NIL;
}
HCELL_INDEX
CmpDoFindSubKeyByNumber(
PHHIVE Hive,
PCM_KEY_INDEX Index,
ULONG Number
)
/*++
Routine Description:
Helper for CmpFindSubKeyByNumber,
Find the Number'th entry in the index, starting from 0.
Arguments:
Hive - pointer to hive control structure for hive of interest
Index - root or leaf of the index
Number - ordinal of child key to return
Return Value:
Cell of requested entry. HCELL_NIL on resources problem
--*/
{
ULONG i;
HCELL_INDEX LeafCell;
PCM_KEY_INDEX Leaf;
PCM_KEY_FAST_INDEX FastIndex;
HCELL_INDEX Result;
if (Index->Signature == CM_KEY_INDEX_ROOT) {
//
// step through root, till we find the right leaf
//
for (i = 0; i < Index->Count; i++) {
if( i ) {
ASSERT( Leaf!= NULL );
ASSERT( LeafCell == Index->List[i-1] );
HvReleaseCell(Hive,LeafCell);
}
LeafCell = Index->List[i];
Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell);
if( Leaf == NULL ) {
//
// we couldn't map the bin containing this cell
//
return HCELL_NIL;
}
if (Number < Leaf->Count) {
if ( (Leaf->Signature == CM_KEY_FAST_LEAF) ||
(Leaf->Signature == CM_KEY_HASH_LEAF) ) {
FastIndex = (PCM_KEY_FAST_INDEX)Leaf;
Result = FastIndex->List[Number].Cell;
HvReleaseCell(Hive,LeafCell);
return Result;
} else {
Result = Leaf->List[Number];
HvReleaseCell(Hive,LeafCell);
return Result;
}
} else {
Number = Number - Leaf->Count;
}
}
ASSERT(FALSE);
}
ASSERT(Number < Index->Count);
if ( (Index->Signature == CM_KEY_FAST_LEAF) ||
(Index->Signature == CM_KEY_HASH_LEAF) ) {
FastIndex = (PCM_KEY_FAST_INDEX)Index;
return(FastIndex->List[Number].Cell);
} else {
return (Index->List[Number]);
}
}
BOOLEAN
CmpRemoveSubKeyCellNoCellRef(
PHHIVE Hive,
HCELL_INDEX Parent,
HCELL_INDEX Child
)
/*++
Routine Description:
Removes a subkey by cell index; Also marks relevant data dirty.
Intended for self healing process.
Arguments:
Hive - pointer to hive control structure for hive of interest
Parent - cell of key that will be parent of new key
Child - key to delete from Paren't sub key list
Return Value:
TRUE - it worked
FALSE - resource problem
--*/
{
PCM_KEY_NODE Node = NULL;
PCM_KEY_INDEX Index = NULL;
BOOLEAN Result = TRUE;
ULONG i,j;
HCELL_INDEX LeafCell = 0;
PCM_KEY_INDEX Leaf = NULL;
PCM_KEY_FAST_INDEX FastIndex;
#ifndef _CM_LDR_
PAGED_CODE();
#endif //_CM_LDR_
Node = (PCM_KEY_NODE)HvGetCell(Hive,Parent);
if( Node == NULL ) {
Result = FALSE;
goto Exit;
}
Index = (PCM_KEY_INDEX)HvGetCell(Hive, Node->SubKeyLists[Stable]);
if( Index == NULL ) {
Result = FALSE;
goto Exit;
}
if (Index->Signature == CM_KEY_INDEX_ROOT) {
//
// step through root, till we find the right leaf
//
for (i = 0; i < Index->Count; i++) {
if( i ) {
ASSERT( Leaf!= NULL );
ASSERT( LeafCell == Index->List[i-1] );
HvReleaseCell(Hive,LeafCell);
}
LeafCell = Index->List[i];
Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell);
if( Leaf == NULL ) {
Result = FALSE;
goto Exit;
}
for(j=0;j<Leaf->Count;j++) {
if ( (Leaf->Signature == CM_KEY_FAST_LEAF) ||
(Leaf->Signature == CM_KEY_HASH_LEAF) ) {
FastIndex = (PCM_KEY_FAST_INDEX)Leaf;
if( FastIndex->List[j].Cell == Child ) {
//
// found it!
//
HvReleaseCell(Hive,LeafCell);
HvMarkCellDirty(Hive,LeafCell);
FastIndex->Count--;
RtlMoveMemory((PVOID)&(FastIndex->List[j]),
(PVOID)&(FastIndex->List[j+1]),
(FastIndex->Count - j) * sizeof(CM_INDEX));
goto DirtyParentAndIndex;
}
} else {
if( Leaf->List[j] == Child ) {
//
// found it!
//
HvReleaseCell(Hive,LeafCell);
HvMarkCellDirty(Hive,LeafCell);
Leaf->Count--;
RtlMoveMemory((PVOID)&(Leaf->List[j]),
(PVOID)&(Leaf->List[j+1]),
(Leaf->Count - j) * sizeof(HCELL_INDEX));
goto DirtyParentAndIndex;
}
}
}
}
} else {
for(j=0;j<Index->Count;j++) {
if ( (Index->Signature == CM_KEY_FAST_LEAF) ||
(Index->Signature == CM_KEY_HASH_LEAF) ) {
FastIndex = (PCM_KEY_FAST_INDEX)Index;
if( FastIndex->List[j].Cell == Child ) {
//
// found it!
//
RtlMoveMemory((PVOID)&(FastIndex->List[j]),
(PVOID)&(FastIndex->List[j+1]),
(FastIndex->Count - j) * sizeof(CM_INDEX));
goto DirtyParentAndIndex;
}
} else {
if( Index->List[j] == Child ) {
//
// found it!
//
RtlMoveMemory((PVOID)&(Index->List[j]),
(PVOID)&(Index->List[j+1]),
(Index->Count - j) * sizeof(HCELL_INDEX));
goto DirtyParentAndIndex;
}
}
}
}
ASSERT( FALSE );
DirtyParentAndIndex:
//
// mark parent and index dirty and decrement index count.
//
HvMarkCellDirty(Hive,Node->SubKeyLists[Stable]);
HvMarkCellDirty(Hive,Parent);
Index->Count--;
Node->SubKeyCounts[Stable]--;
Exit:
if( Index ) {
ASSERT( Node );
HvReleaseCell(Hive,Node->SubKeyLists[Stable]);
}
if( Node ) {
HvReleaseCell(Hive,Parent);
}
return Result;
}
BOOLEAN
CmpAddSubKey(
PHHIVE Hive,
HCELL_INDEX Parent,
HCELL_INDEX Child
)
/*++
Routine Description:
Add a new child subkey to the subkey index for a cell. The
child MUST NOT already be present (bugcheck if so.)
NOTE: We expect Parent to already be marked dirty.
We will mark stuff in Index dirty
Arguments:
Hive - pointer to hive control structure for hive of interest
Parent - cell of key that will be parent of new key
Child - new key to put in Paren't sub key list
Return Value:
TRUE - it worked
FALSE - resource problem
--*/
{
PCM_KEY_NODE pcell;
HCELL_INDEX WorkCell;
PCM_KEY_INDEX Index;
PCM_KEY_FAST_INDEX FastIndex;
UNICODE_STRING NewName;
HCELL_INDEX LeafCell;
PHCELL_INDEX RootPointer = NULL;
ULONG cleanup = 0;
ULONG Type;
BOOLEAN IsCompressed;
ULONG i;
#ifndef _CM_LDR_
PAGED_CODE();
#endif //_CM_LDR_
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_INDEX,"CmpAddSubKey:\n\t"));
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_INDEX,"Hive=%p Parent=%08lx Child=%08lx\n",Hive,Parent,Child));
//
// we have the lock exclusive or nobody is operating inside this hive
//
//ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
ASSERT_CM_EXCLUSIVE_HIVE_ACCESS(Hive);
//
// build a name string
//
pcell = (PCM_KEY_NODE)HvGetCell(Hive, Child);
if( pcell == NULL ) {
//
// we couldn't map the bin containing this cell
//
return FALSE;
}
// release the cell here; as the registry is locked exclusive (i.e. we don't care)
HvReleaseCell(Hive, Child);
if (pcell->Flags & KEY_COMP_NAME) {
IsCompressed = TRUE;
NewName.Length = CmpCompressedNameSize(pcell->Name, pcell->NameLength);
NewName.MaximumLength = NewName.Length;
NewName.Buffer = (Hive->Allocate)(NewName.Length, FALSE,CM_FIND_LEAK_TAG8);
if (NewName.Buffer==NULL) {
return(FALSE);
}
CmpCopyCompressedName(NewName.Buffer,
NewName.MaximumLength,
pcell->Name,
pcell->NameLength);
} else {
IsCompressed = FALSE;
NewName.Length = pcell->NameLength;
NewName.MaximumLength = pcell->NameLength;
NewName.Buffer = &(pcell->Name[0]);
}
pcell = (PCM_KEY_NODE)HvGetCell(Hive, Parent);
if( pcell == NULL ) {
//
// we couldn't map the bin containing this cell
//
goto ErrorExit;
}
//ASSERT_CELL_DIRTY(Hive,Parent);
// release the cell here; as the registry is locked exclusive (i.e. we don't care)
HvReleaseCell(Hive, Parent);
Type = HvGetCellType(Child);
if (pcell->SubKeyCounts[Type] == 0) {
ULONG Signature;
//
// we must allocate a leaf
//
WorkCell = HvAllocateCell(Hive, sizeof(CM_KEY_FAST_INDEX), Type,(HvGetCellType(Parent)==Type)?Parent:HCELL_NIL);
if (WorkCell == HCELL_NIL) {
goto ErrorExit;
}
Index = (PCM_KEY_INDEX)HvGetCell(Hive, WorkCell);
if( Index == NULL ) {
//
// we couldn't map the bin containing this cell
// this shouldn't happen 'cause we just allocated this
// cell (i.e. bin is PINNED in memory ! )
//
ASSERT( FALSE );
goto ErrorExit;
}
// release the cell here; as the registry is locked exclusive (i.e. we don't care)
HvReleaseCell(Hive, WorkCell);
if( UseHashIndex(Hive) ) {
Index->Signature = CM_KEY_HASH_LEAF;
} else if( UseFastIndex(Hive) ) {
Index->Signature = CM_KEY_FAST_LEAF;
} else {
Index->Signature = CM_KEY_INDEX_LEAF;
}
Index->Count = 0;
pcell->SubKeyLists[Type] = WorkCell;
cleanup = 1;
} else {
Index = (PCM_KEY_INDEX)HvGetCell(Hive, pcell->SubKeyLists[Type]);
if( Index == NULL ) {
//
// we couldn't map the bin containing this cell
//
goto ErrorExit;
}
// release the cell here; as the registry is locked exclusive (i.e. we don't care)
HvReleaseCell(Hive, pcell->SubKeyLists[Type]);
if ( (Index->Signature == CM_KEY_FAST_LEAF) &&
(Index->Count >= (CM_MAX_FAST_INDEX)) ) {
//
// We must change fast index to a slow index to accomodate
// growth.
//
FastIndex = (PCM_KEY_FAST_INDEX)Index;
for (i=0; i<Index->Count; i++) {
Index->List[i] = FastIndex->List[i].Cell;
}
Index->Signature = CM_KEY_INDEX_LEAF;
} else if (((Index->Signature == CM_KEY_INDEX_LEAF) ||
(Index->Signature == CM_KEY_HASH_LEAF)) &&
(Index->Count >= (CM_MAX_INDEX - 1) )) {
//
// We must change flat entry to a root/leaf tree
//
WorkCell = HvAllocateCell(
Hive,
sizeof(CM_KEY_INDEX) + sizeof(HCELL_INDEX), // allow for 2
Type,
(HvGetCellType(Parent)==Type)?Parent:HCELL_NIL
);
if (WorkCell == HCELL_NIL) {
goto ErrorExit;
}
Index = (PCM_KEY_INDEX)HvGetCell(Hive, WorkCell);
if( Index == NULL ) {
//
// we couldn't map the bin containing this cell
// this shouldn't happen 'cause we just allocated this
// cell (i.e. bin is PINNED in memory
ASSERT( FALSE );
goto ErrorExit;
}
// release the cell here; as the registry is locked exclusive (i.e. we don't care)
HvReleaseCell(Hive, WorkCell);
Index->Signature = CM_KEY_INDEX_ROOT;
Index->Count = 1;
Index->List[0] = pcell->SubKeyLists[Type];
pcell->SubKeyLists[Type] = WorkCell;
cleanup = 2;
}
}
LeafCell = pcell->SubKeyLists[Type];
//
// LeafCell is target for add, or perhaps root
// Index is pointer to fast leaf, slow Leaf or Root, whichever applies
//
if (Index->Signature == CM_KEY_INDEX_ROOT) {
LeafCell = CmpSelectLeaf(Hive, pcell, &NewName, Type, &RootPointer);
if (LeafCell == HCELL_NIL) {
goto ErrorExit;
}
}
#if 0
//
// Validation code. manually search for the key and break when found
//
if(Index->Signature == CM_KEY_INDEX_ROOT) {
LONG Result;
PCM_KEY_INDEX Leaf;
HCELL_INDEX Cell;
ULONG iCnt;
PCM_KEY_INDEX PrevLeaf;
Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell);
HvReleaseCell(Hive, LeafCell);
if( Leaf->Count ) {
Result = CmpCompareInIndex( Hive,
&NewName,
0,
Leaf,
&Cell);
//
// must be bigger, or the first leaf
//
if( (Result < 0) && (RootPointer != &(Index->List[0])) ) {
for( iCnt=0;iCnt<Index->Count;iCnt++) {
if( Index->List[iCnt] == LeafCell ) {
break;
}
}
ASSERT( Index->List[iCnt] == LeafCell );
ASSERT( iCnt > 0 );
PrevLeaf = (PCM_KEY_INDEX)HvGetCell(Hive, Index->List[iCnt-1]);
HvReleaseCell(Hive, Index->List[iCnt-1]);
if( PrevLeaf->Count ) {
//
// must be bigger than last in prev leaf
//
Result = CmpCompareInIndex( Hive,
&NewName,
PrevLeaf->Count - 1,
PrevLeaf,
&Cell);
if( Result <= 0 ) {
//
// Error ==> Debug
//
DbgPrint("CmpAddSubKey: Wrong spot selected [1]!!!\n");
DbgPrint("Hive = %p Parent = %lx Child = %lx , Leaf = %p\n",Hive,Parent,Child,Leaf);
DbgPrint("RootPointer = %p Index = %p PrevLeaf = %p\n",RootPointer,Index,PrevLeaf);
DbgBreakPoint();
}
}
}
}
Result = CmpCompareInIndex( Hive,
&NewName,
Leaf->Count - 1,
Leaf,
&Cell);
if( Result > 0) {
//
// must be the last one
//
if( (ULONG)(Index->Count - 1) > (ULONG)(((PUCHAR)RootPointer - (PUCHAR)(&(Index->List[0])))/sizeof(HCELL_INDEX)) ) {
//
// Error ==> Debug
//
DbgPrint("CmpAddSubKey: Wrong spot selected [2]!!!\n");
DbgPrint("Hive = %p Parent = %lx Child = %lx , Leaf = %p\n",Hive,Parent,Child,Leaf);
DbgPrint("RootPointer = %p Index = %p\n",RootPointer,Index);
DbgBreakPoint();
}
}
}
#endif //0
//
// Add new cell to Leaf, update pointers
//
LeafCell = CmpAddToLeaf(Hive, LeafCell, Child, &NewName);
if (LeafCell == HCELL_NIL) {
goto ErrorExit;
}
pcell->SubKeyCounts[Type] += 1;
if (RootPointer != NULL) {
*RootPointer = LeafCell;
} else {
pcell->SubKeyLists[Type] = LeafCell;
}
if (IsCompressed) {
(Hive->Free)(NewName.Buffer, NewName.Length);
}
return TRUE;
ErrorExit:
if (IsCompressed) {
(Hive->Free)(NewName.Buffer, NewName.Length);
}
switch (cleanup) {
case 1:
HvFreeCell(Hive, pcell->SubKeyLists[Type]);
pcell->SubKeyLists[Type] = HCELL_NIL;
break;
case 2:
Index = (PCM_KEY_INDEX)HvGetCell(Hive, pcell->SubKeyLists[Type]);
if( Index == NULL ) {
//
// we couldn't map the bin containing this cell
// this shouldn't happen 'cause we just allocated this
// cell (i.e. bin is PINNED in memory).
// But ... better safe than sorry
//
ASSERT( FALSE );
return FALSE;
}
// release the cell here; as the registry is locked exclusive (i.e. we don't care)
HvReleaseCell(Hive, pcell->SubKeyLists[Type]);
WorkCell = Index->List[0];
HvFreeCell(Hive, pcell->SubKeyLists[Type]);
pcell->SubKeyLists[Type] = WorkCell;
break;
}
return FALSE;
}
HCELL_INDEX
CmpAddToLeaf(
PHHIVE Hive,
HCELL_INDEX LeafCell,
HCELL_INDEX NewKey,
PUNICODE_STRING NewName
)
/*++
Routine Description:
Insert a new subkey into a Leaf index. Supports both fast and slow
leaf indexes and will determine which sort of index the given leaf is.
NOTE: We expect Root to already be marked dirty by caller if non NULL.
We expect Leaf to always be marked dirty by caller.
Arguments:
Hive - pointer to hive control structure for hive of interest
LeafCell - cell of index leaf node we are to add entry too
NewKey - cell of KEY_NODE we are to add
NewName - pointer to unicode string with name to we are to add
Return Value:
HCELL_NIL - some resource problem
Else - cell of Leaf index when are done, caller is expected to
set this into Root index or Key body.
--*/
{
PCM_KEY_INDEX Leaf;
PCM_KEY_FAST_INDEX FastLeaf;
ULONG Size;
ULONG OldSize;
ULONG freecount;
HCELL_INDEX NewCell;
HCELL_INDEX Child;
ULONG Select;
LONG Result;
ULONG EntrySize;
ULONG i;
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_INDEX,"CmpAddToLeaf:\n\t"));
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_INDEX,"Hive=%p LeafCell=%08lx NewKey=%08lx\n",Hive,LeafCell,NewKey));
//
// we have the lock exclusive or nobody is operating inside this hive
//
//ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
ASSERT_CM_EXCLUSIVE_HIVE_ACCESS(Hive);
if (!HvMarkCellDirty(Hive, LeafCell)) {
return HCELL_NIL;
}
//
// compute number free slots left in the leaf
//
Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell);
if( Leaf == NULL ) {
//
// we couldn't map the bin containing this cell
// this shouldn't happen as marking dirty means
// PINNING the view into memory
//
ASSERT( FALSE );
return HCELL_NIL;
}
// release the cell here; as the registry is locked exclusive (i.e. we don't care)
HvReleaseCell(Hive, LeafCell);
if (Leaf->Signature == CM_KEY_INDEX_LEAF) {
FastLeaf = NULL;
EntrySize = sizeof(HCELL_INDEX);
} else {
ASSERT( (Leaf->Signature == CM_KEY_FAST_LEAF) ||
(Leaf->Signature == CM_KEY_HASH_LEAF)
);
FastLeaf = (PCM_KEY_FAST_INDEX)Leaf;
EntrySize = sizeof(CM_INDEX);
}
OldSize = HvGetCellSize(Hive, Leaf);
Size = OldSize - ((EntrySize * Leaf->Count) +
FIELD_OFFSET(CM_KEY_INDEX, List));
freecount = Size / EntrySize;
//
// grow the leaf if it isn't big enough
//
NewCell = LeafCell;
if (freecount < 1) {
Size = OldSize + OldSize / 2;
if (Size < (OldSize + EntrySize)) {
Size = OldSize + EntrySize;
}
NewCell = HvReallocateCell(Hive, LeafCell, Size);
if (NewCell == HCELL_NIL) {
return HCELL_NIL;
}
Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, NewCell);
if( Leaf == NULL ) {
//
// we couldn't map the bin containing this cell
// this shouldn't happen 'cause we just allocated this
// cell (i.e. bin is PINNED in memory)
//
ASSERT( FALSE );
return HCELL_NIL;
}
// release the cell here; as the registry is locked exclusive (i.e. we don't care)
HvReleaseCell(Hive, NewCell);
if (FastLeaf != NULL) {
FastLeaf = (PCM_KEY_FAST_INDEX)Leaf;
}
}
//
// Find where to put the new entry
//
Select = CmpFindSubKeyInLeaf(Hive, Leaf, NewName, &Child);
if( INVALID_INDEX & Select ) {
//
// couldn't map view
//
return HCELL_NIL;
}
ASSERT(Child == HCELL_NIL);
//
// Select is the index in List of the entry nearest where the
// new entry should go.
// Decide wether the new entry goes before or after Offset entry,
// and then ripple copy and set.
// If Select == Count, then the leaf is empty, so simply set our entry
//
if (Select != Leaf->Count) {
Result = CmpCompareInIndex(Hive,
NewName,
Select,
Leaf,
&Child);
if( Result == 2 ) {
//
// couldn't map view inside; bail out
//
return HCELL_NIL;
}
ASSERT(Result != 0);
//
// Result -1 - NewName/NewKey less than selected key, insert before
// +1 - NewName/NewKey greater than selected key, insert after
//
if (Result > 0) {
ASSERT( Result == 1 );
Select++;
}
if (Select != Leaf->Count) {
//
// ripple copy to make space and insert
//
if (FastLeaf != NULL) {
RtlMoveMemory((PVOID)&(FastLeaf->List[Select+1]),
(PVOID)&(FastLeaf->List[Select]),
sizeof(CM_INDEX)*(FastLeaf->Count - Select));
} else {
RtlMoveMemory((PVOID)&(Leaf->List[Select+1]),
(PVOID)&(Leaf->List[Select]),
sizeof(HCELL_INDEX)*(Leaf->Count - Select));
}
}
}
if (FastLeaf != NULL) {
FastLeaf->List[Select].Cell = NewKey;
if( FastLeaf->Signature == CM_KEY_HASH_LEAF ) {
//
// Hash leaf; store the HashKey
//
FastLeaf->List[Select].HashKey = CmpComputeHashKey(NewName);
} else {
FastLeaf->List[Select].NameHint[0] = 0;
FastLeaf->List[Select].NameHint[1] = 0;
FastLeaf->List[Select].NameHint[2] = 0;
FastLeaf->List[Select].NameHint[3] = 0;
if (NewName->Length/sizeof(WCHAR) < 4) {
i = NewName->Length/sizeof(WCHAR);
} else {
i = 4;
}
do {
if ((USHORT)NewName->Buffer[i-1] > (UCHAR)-1) {
//
// Can't compress this name. Leave NameHint[0]==0
// to force the name to be looked up in the key.
//
break;
}
FastLeaf->List[Select].NameHint[i-1] = (UCHAR)NewName->Buffer[i-1];
i--;
} while ( i>0 );
}
} else {
Leaf->List[Select] = NewKey;
}
Leaf->Count += 1;
return NewCell;
}
HCELL_INDEX
CmpSelectLeaf(
PHHIVE Hive,
PCM_KEY_NODE ParentKey,
PUNICODE_STRING NewName,
HSTORAGE_TYPE Type,
PHCELL_INDEX *RootPointer
)
/*++
Routine Description:
This routine is only called if the subkey index for a cell is NOT
simply a single Leaf index block.
It selects the Leaf index block to which a new entry is to be
added. It may create this block by splitting an existing Leaf
block.
Arguments:
Hive - pointer to hive control structure for hive of interest
ParentKey - mapped pointer to parent key
NewName - pointer to unicode string naming entry to add
Type - Stable or Volatile, describes Child's storage
RootPointer - pointer to variable to receive address of HCELL_INDEX
that points to Leaf block returned as function argument.
Used for updates.
Return Value:
HCELL_NIL - resource problem
Else, cell index of Leaf index block to add entry to
--*/
{
HCELL_INDEX LeafCell;
HCELL_INDEX WorkCell;
PCM_KEY_INDEX Index;
PCM_KEY_INDEX Leaf;
PCM_KEY_FAST_INDEX FastLeaf;
ULONG RootSelect;
LONG Result;
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_INDEX,"CmpSelectLeaf:\n\t"));
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_INDEX,"Hive=%p ParentKey=%p\n", Hive, ParentKey));
//
// we have the lock exclusive or nobody is operating inside this hive
//
//ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
ASSERT_CM_EXCLUSIVE_HIVE_ACCESS(Hive);
//
// Force root to always be dirty, since we'll either grow it or edit it,
// and it needs to be marked dirty for BOTH cases. (Edit may not
// occur until after we leave
//
if (! HvMarkCellDirty(Hive, ParentKey->SubKeyLists[Type])) {
return HCELL_NIL;
}
//
// must find the proper leaf
//
Index = (PCM_KEY_INDEX)HvGetCell(Hive, ParentKey->SubKeyLists[Type]);
if( Index == NULL ) {
//
// we couldn't map the bin containing this cell
// this shouldn't happen as marking dirty means
// PINNING the view into memory
//
ASSERT( FALSE );
return HCELL_NIL;
}
ASSERT(Index->Signature == CM_KEY_INDEX_ROOT);
// release the cell here; as the registry is locked exclusive (i.e. we don't care)
HvReleaseCell(Hive, ParentKey->SubKeyLists[Type]);
while (TRUE) {
RootSelect = CmpFindSubKeyInRoot(Hive, Index, NewName, &LeafCell);
if( INVALID_INDEX & RootSelect ) {
//
// couldn't map view inside; bail out
//
return HCELL_NIL;
}
if (LeafCell == HCELL_NIL) {
//
// Leaf of interest is somewhere near RootSelect
//
// . Always use lowest order leaf we can get away with
// . Never split a leaf if there's one with space we can use
// . When we split a leaf, we have to repeat search
//
// If (NewKey is below lowest key in selected)
// If there's a Leaf below selected with space
// use the leaf below
// else
// use the leaf (split it if not enough space)
// Else
// must be above highest key in selected, less than
// lowest key in Leaf to right of selected
// if space in selected
// use selected
// else if space in leaf above selected
// use leaf above
// else
// split selected
//
LeafCell = Index->List[RootSelect];
Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell);
if( Leaf == NULL ) {
//
// we couldn't map the bin containing this cell
//
return HCELL_NIL;
}
// release the cell here; as the registry is locked exclusive (i.e. we don't care)
HvReleaseCell(Hive, LeafCell);
if( (Leaf->Signature == CM_KEY_FAST_LEAF) ||
(Leaf->Signature == CM_KEY_HASH_LEAF) ) {
FastLeaf = (PCM_KEY_FAST_INDEX)Leaf;
WorkCell = FastLeaf->List[0].Cell;
} else {
ASSERT( Leaf->Signature == CM_KEY_INDEX_LEAF );
WorkCell = Leaf->List[0];
}
Result = CmpDoCompareKeyName(Hive, NewName, WorkCell);
if( Result == 2 ) {
//
// couldn't map view inside; bail out
//
return HCELL_NIL;
}
ASSERT(Result != 0);
if (Result < 0) {
//
// new is off the left end of Selected
//
if (RootSelect > 0) {
//
// there's a Leaf to the left, try to use it
//
LeafCell = Index->List[RootSelect-1];
Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell);
if( Leaf == NULL ) {
//
// we couldn't map the bin containing this cell
//
return HCELL_NIL;
}
// release the cell here; as the registry is locked exclusive (i.e. we don't care)
HvReleaseCell(Hive, LeafCell);
if (Leaf->Count < (CM_MAX_INDEX - 1)) {
RootSelect--;
*RootPointer = &(Index->List[RootSelect]);
break;
}
} else {
//
// new key is off the left end of the leftmost leaf.
// Use the leftmost leaf, if there's enough room
//
LeafCell = Index->List[0];
Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell);
if( Leaf == NULL ) {
//
// we couldn't map the bin containing this cell
//
return HCELL_NIL;
}
// release the cell here; as the registry is locked exclusive (i.e. we don't care)
HvReleaseCell(Hive, LeafCell);
if (Leaf->Count < (CM_MAX_INDEX - 1)) {
*RootPointer = &(Index->List[0]);
break;
}
}
//
// else fall to split case
//
} else {
//
// since new key is not in a Leaf, and is not off
// the left end of the ResultSelect Leaf, it must
// be off the right end.
//
LeafCell = Index->List[RootSelect];
Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell);
if( Leaf == NULL ) {
//
// we couldn't map the bin containing this cell
//
return HCELL_NIL;
}
// release the cell here; as the registry is locked exclusive (i.e. we don't care)
HvReleaseCell(Hive, LeafCell);
if (Leaf->Count < (CM_MAX_INDEX - 1)) {
*RootPointer = &(Index->List[RootSelect]);
break;
}
//
// No space, see if there's a leaf to the rigth
// and if it has space
//
if (RootSelect < (ULONG)(Index->Count - 1)) {
LeafCell = Index->List[RootSelect+1];
Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell);
if( Leaf == NULL ) {
//
// we couldn't map the bin containing this cell
//
return HCELL_NIL;
}
// release the cell here; as the registry is locked exclusive (i.e. we don't care)
HvReleaseCell(Hive, LeafCell);
if (Leaf->Count < (CM_MAX_INDEX - 1)) {
*RootPointer = &(Index->List[RootSelect+1]);
break;
}
}
//
// fall to split case
//
}
} else { // LeafCell != HCELL_NIL
//
// Since newkey cannot already be in tree, it must be
// greater than the bottom of Leaf and less than the top,
// therefore it must go in Leaf. If no space, split it.
//
Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell);
if( Leaf == NULL ) {
//
// we couldn't map the bin containing this cell
//
return HCELL_NIL;
}
// release the cell here; as the registry is locked exclusive (i.e. we don't care)
HvReleaseCell(Hive, LeafCell);
if (Leaf->Count < (CM_MAX_INDEX - 1)) {
*RootPointer = &(Index->List[RootSelect]);
break;
}
//
// fall to split case
//
}
//
// either no neigbor, or no space in neighbor, so split
//
WorkCell = CmpSplitLeaf(
Hive,
ParentKey->SubKeyLists[Type], // root cell
RootSelect,
Type
);
if (WorkCell == HCELL_NIL) {
return HCELL_NIL;
}
ParentKey->SubKeyLists[Type] = WorkCell;
Index = (PCM_KEY_INDEX)HvGetCell(Hive, WorkCell);
if( Index == NULL ) {
//
// we couldn't map the bin containing this cell
//
return HCELL_NIL;
}
// release the cell here; as the registry is locked exclusive (i.e. we don't care)
HvReleaseCell(Hive, WorkCell);
ASSERT(Index->Signature == CM_KEY_INDEX_ROOT);
} // while(true)
return LeafCell;
}
HCELL_INDEX
CmpSplitLeaf(
PHHIVE Hive,
HCELL_INDEX RootCell,
ULONG RootSelect,
HSTORAGE_TYPE Type
)
/*++
Routine Description:
Split the Leaf index block specified by RootSelect, causing both
of the split out Leaf blocks to appear in the Root index block
specified by RootCell.
Caller is expected to have marked old root cell dirty.
Arguments:
Hive - pointer to hive control structure for hive of interest
RootCell - cell of the Root index block of index being grown
RootSelect - indicates which child of Root to split
Type - Stable or Volatile
Return Value:
HCELL_NIL - some resource problem
Else - cell of new (e.g. reallocated) Root index block
--*/
{
PCM_KEY_INDEX Root;
HCELL_INDEX LeafCell;
PCM_KEY_INDEX Leaf;
HCELL_INDEX NewLeafCell;
PCM_KEY_INDEX NewLeaf;
PCM_KEY_FAST_INDEX FastLeaf;
ULONG Size;
ULONG freecount;
USHORT OldCount;
USHORT KeepCount;
USHORT NewCount;
USHORT ElemSize;
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_INDEX,"CmpSplitLeaf:\n\t"));
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_INDEX,"Hive=%p RootCell=%08lx RootSelect\n", Hive, RootCell, RootSelect));
//
// we have the lock exclusive or nobody is operating inside this hive
//
//ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
ASSERT_CM_EXCLUSIVE_HIVE_ACCESS(Hive);
//
// allocate new Leaf index block
//
Root = (PCM_KEY_INDEX)HvGetCell(Hive, RootCell);
if( Root == NULL ) {
//
// we couldn't map the bin containing this cell
//
return HCELL_NIL;
}
// release the cell here; as the registry is locked exclusive (i.e. we don't care)
HvReleaseCell(Hive, RootCell);
LeafCell = Root->List[RootSelect];
Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell);
if( Leaf == NULL ) {
//
// we couldn't map the bin containing this cell
//
return HCELL_NIL;
}
OldCount = Leaf->Count;
// release the cell here; as the registry is locked exclusive (i.e. we don't care)
HvReleaseCell(Hive, LeafCell);
KeepCount = (USHORT)(OldCount / 2); // # of entries to keep in org. Leaf
NewCount = (OldCount - KeepCount); // # of entries to move
if( UseHashIndex(Hive) ) {
ASSERT( Leaf->Signature == CM_KEY_HASH_LEAF );
ElemSize = sizeof(CM_INDEX);
} else {
ElemSize = sizeof(HCELL_INDEX);
ASSERT( Leaf->Signature == CM_KEY_INDEX_LEAF );
}
ASSERT( FIELD_OFFSET(CM_KEY_INDEX, List) == FIELD_OFFSET(CM_KEY_FAST_INDEX, List) );
Size = (ElemSize * NewCount) +
FIELD_OFFSET(CM_KEY_INDEX, List) + 1; // +1 to assure room for add
if (!HvMarkCellDirty(Hive, LeafCell)) {
return HCELL_NIL;
}
//
//
//
ASSERT( (HvGetCellType(LeafCell) == (ULONG)Type) );
NewLeafCell = HvAllocateCell(Hive, Size, Type,LeafCell);
if (NewLeafCell == HCELL_NIL) {
return HCELL_NIL;
}
NewLeaf = (PCM_KEY_INDEX)HvGetCell(Hive, NewLeafCell);
if( NewLeaf == NULL ) {
//
// we couldn't map the bin containing this cell
// this shouldn't happen as we just allocated this cell
// so it's bin should be PINNED into memory
//
ASSERT( FALSE );
HvFreeCell(Hive, NewLeafCell);
return HCELL_NIL;
}
if( UseHashIndex(Hive) ) {
NewLeaf->Signature = CM_KEY_HASH_LEAF;
} else {
NewLeaf->Signature = CM_KEY_INDEX_LEAF;
}
// release the cell here; as the registry is locked exclusive (i.e. we don't care)
HvReleaseCell(Hive, NewLeafCell);
//
// compute number of free slots left in the root
//
Size = HvGetCellSize(Hive, Root);
Size = Size - ((sizeof(HCELL_INDEX) * Root->Count) +
FIELD_OFFSET(CM_KEY_INDEX, List));
freecount = Size / sizeof(HCELL_INDEX);
//
// grow the root if it isn't big enough
//
if (freecount < 1) {
Size = HvGetCellSize(Hive, Root) + sizeof(HCELL_INDEX);
RootCell = HvReallocateCell(Hive, RootCell, Size);
if (RootCell == HCELL_NIL) {
HvFreeCell(Hive, NewLeafCell);
return HCELL_NIL;
}
Root = (PCM_KEY_INDEX)HvGetCell(Hive, RootCell);
if( Root == NULL ) {
//
// we couldn't map the bin containing this cell
// this shouldn't happen as we just allocated this cell
// so it's bin should be PINNED into memory
//
ASSERT( FALSE );
HvFreeCell(Hive, NewLeafCell);
return HCELL_NIL;
}
// release the cell here; as the registry is locked exclusive (i.e. we don't care)
HvReleaseCell(Hive, RootCell);
}
//
// copy data from one Leaf to the other
//
//
if( UseHashIndex(Hive) ) {
FastLeaf = (PCM_KEY_FAST_INDEX)Leaf;
#if 0 //DBG
{
HCELL_INDEX PrevCell = HCELL_NIL;
HCELL_INDEX CurCell;
ULONG i;
for( i=0;i<(ULONG)(Leaf->Count);i++) {
CurCell = FastLeaf->List[i].Cell;
if( (PrevCell != HCELL_NIL) && (PrevCell == CurCell) ) {
DbgPrint("CmpSplitLeaf(%p,%lx,%lx) \n",Hive,RootCell,RootSelect);
DbgPrint("\t Leaf = %p\n",Leaf);
DbgPrint("\t at index %lx we have duplicate cell - BEFORE\n",i);
DbgBreakPoint();
}
PrevCell = CurCell;
}
}
#endif //DBG
RtlMoveMemory(
(PVOID)&(NewLeaf->List[0]),
(PVOID)&(FastLeaf->List[KeepCount]),
ElemSize * NewCount
);
} else {
RtlMoveMemory(
(PVOID)&(NewLeaf->List[0]),
(PVOID)&(Leaf->List[KeepCount]),
ElemSize * NewCount
);
}
ASSERT(KeepCount != 0);
ASSERT(NewCount != 0);
Leaf->Count = KeepCount;
NewLeaf->Count = NewCount;
//
// make an open slot in the root
//
if (RootSelect < (ULONG)(Root->Count-1)) {
RtlMoveMemory(
(PVOID)&(Root->List[RootSelect+2]),
(PVOID)&(Root->List[RootSelect+1]),
(Root->Count - (RootSelect + 1)) * sizeof(HCELL_INDEX)
);
}
//
// update the root
//
Root->Count += 1;
Root->List[RootSelect+1] = NewLeafCell;
return RootCell;
}
BOOLEAN
CmpMarkIndexDirty(
PHHIVE Hive,
HCELL_INDEX ParentKey,
HCELL_INDEX TargetKey
)
/*++
Routine Description:
Mark as dirty relevent cells of a subkey index. The Leaf that
points to TargetKey, and the Root index block, if applicable,
will be marked dirty. This call assumes we are setting up
for a subkey delete.
Arguments:
Hive - pointer to hive control structure for hive of interest
ParentKey - key from whose subkey list delete is to be performed
TargetKey - key being deleted
Return Value:
TRUE - it worked, FALSE - it didn't, some resource problem
--*/
{
PCM_KEY_NODE pcell;
ULONG i;
HCELL_INDEX IndexCell;
PCM_KEY_INDEX Index;
HCELL_INDEX Child = HCELL_NIL;
UNICODE_STRING SearchName;
BOOLEAN IsCompressed;
HCELL_INDEX CellToRelease = HCELL_NIL;
pcell = (PCM_KEY_NODE)HvGetCell(Hive, TargetKey);
if( pcell == NULL ) {
//
// we couldn't map the bin containing this cell
//
return FALSE;
}
if (pcell->Flags & KEY_COMP_NAME) {
IsCompressed = TRUE;
SearchName.Length = CmpCompressedNameSize(pcell->Name, pcell->NameLength);
SearchName.MaximumLength = SearchName.Length;
#if defined(_CM_LDR_)
SearchName.Buffer = (Hive->Allocate)(SearchName.Length, FALSE,CM_FIND_LEAK_TAG9);
#else
SearchName.Buffer = ExAllocatePool(PagedPool, SearchName.Length);
#endif
if (SearchName.Buffer==NULL) {
HvReleaseCell(Hive, TargetKey);
return(FALSE);
}
CmpCopyCompressedName(SearchName.Buffer,
SearchName.MaximumLength,
pcell->Name,
pcell->NameLength);
} else {
IsCompressed = FALSE;
SearchName.Length = pcell->NameLength;
SearchName.MaximumLength = pcell->NameLength;
SearchName.Buffer = &(pcell->Name[0]);
}
HvReleaseCell(Hive, TargetKey);
pcell = (PCM_KEY_NODE)HvGetCell(Hive, ParentKey);
if( pcell == NULL ) {
//
// we couldn't map the bin containing this cell
//
goto ErrorExit;
}
for (i = 0; i < Hive->StorageTypeCount; i++) {
if (pcell->SubKeyCounts[i] != 0) {
ASSERT(HvIsCellAllocated(Hive, pcell->SubKeyLists[i]));
IndexCell = pcell->SubKeyLists[i];
if( CellToRelease != HCELL_NIL ) {
HvReleaseCell(Hive, CellToRelease);
CellToRelease = HCELL_NIL;
}
Index = (PCM_KEY_INDEX)HvGetCell(Hive, IndexCell);
if( Index == NULL ) {
//
// we couldn't map the bin containing this cell
//
goto ErrorExit;
}
CellToRelease = IndexCell;
if (Index->Signature == CM_KEY_INDEX_ROOT) {
//
// target even in index?
//
if( INVALID_INDEX & CmpFindSubKeyInRoot(Hive, Index, &SearchName, &Child) ) {
//
// couldn't map view inside; bail out
//
goto ErrorExit;
}
if (Child == HCELL_NIL) {
continue;
}
//
// mark root dirty
//
if (! HvMarkCellDirty(Hive, IndexCell)) {
goto ErrorExit;
}
if( CellToRelease != HCELL_NIL ) {
HvReleaseCell(Hive, CellToRelease);
CellToRelease = HCELL_NIL;
}
IndexCell = Child;
Index = (PCM_KEY_INDEX)HvGetCell(Hive, Child);
if( Index == NULL ) {
//
// we couldn't map the bin containing this cell
//
goto ErrorExit;
}
CellToRelease = Child;
}
ASSERT((Index->Signature == CM_KEY_INDEX_LEAF) ||
(Index->Signature == CM_KEY_FAST_LEAF) ||
(Index->Signature == CM_KEY_HASH_LEAF)
);
if( INVALID_INDEX & CmpFindSubKeyInLeaf(Hive, Index, &SearchName, &Child) ) {
//
// couldn't map view
//
goto ErrorExit;
}
if (Child != HCELL_NIL) {
if (IsCompressed) {
#if defined(_CM_LDR_)
(Hive->Free)(SearchName.Buffer, SearchName.Length);
#else
ExFreePool(SearchName.Buffer);
#endif
}
// cleanup
HvReleaseCell(Hive, ParentKey);
if( CellToRelease != HCELL_NIL ) {
HvReleaseCell(Hive, CellToRelease);
}
return(HvMarkCellDirty(Hive, IndexCell));
}
}
}
ErrorExit:
if( pcell!= NULL ) {
HvReleaseCell(Hive, ParentKey);
}
if( CellToRelease != HCELL_NIL ) {
HvReleaseCell(Hive, CellToRelease);
}
if (IsCompressed) {
#if defined(_CM_LDR_)
(Hive->Free)(SearchName.Buffer, SearchName.Length);
#else
ExFreePool(SearchName.Buffer);
#endif
}
return FALSE;
}
BOOLEAN
CmpRemoveSubKey(
PHHIVE Hive,
HCELL_INDEX ParentKey,
HCELL_INDEX TargetKey
)
/*++
Routine Description:
Remove the subkey TargetKey refers to from ParentKey's list.
NOTE: Assumes that caller has marked relevent cells dirty,
see CmpMarkIndexDirty.
Arguments:
Hive - pointer to hive control structure for hive of interest
ParentKey - key from whose subkey list delete is to be performed
TargetKey - key being deleted
Return Value:
TRUE - it worked, FALSE - it didn't, some resource problem
--*/
{
PCM_KEY_NODE pcell;
HCELL_INDEX LeafCell;
PCM_KEY_INDEX Leaf;
PCM_KEY_FAST_INDEX FastIndex;
HCELL_INDEX RootCell = HCELL_NIL;
PCM_KEY_INDEX Root = NULL;
HCELL_INDEX Child;
ULONG Type;
ULONG RootSelect;
ULONG LeafSelect;
UNICODE_STRING SearchName;
BOOLEAN IsCompressed;
WCHAR CompressedBuffer[50];
BOOLEAN Result;
HCELL_INDEX CellToRelease1 = HCELL_NIL,CellToRelease2 = HCELL_NIL;
pcell = (PCM_KEY_NODE)HvGetCell(Hive, TargetKey);
if( pcell == NULL ) {
//
// we couldn't map the bin containing this cell
//
return FALSE;
}
ASSERT_CELL_DIRTY(Hive,TargetKey);
//
// release the cell here; as key is dirty/pinned
//
HvReleaseCell(Hive, TargetKey);
if (pcell->Flags & KEY_COMP_NAME) {
IsCompressed = TRUE;
SearchName.Length = CmpCompressedNameSize(pcell->Name, pcell->NameLength);
SearchName.MaximumLength = SearchName.Length;
if (SearchName.MaximumLength > sizeof(CompressedBuffer)) {
#if defined(_CM_LDR_)
SearchName.Buffer = (Hive->Allocate)(SearchName.Length, FALSE,CM_FIND_LEAK_TAG40);
#else
SearchName.Buffer = ExAllocatePool(PagedPool, SearchName.Length);
#endif
if (SearchName.Buffer==NULL) {
return(FALSE);
}
} else {
SearchName.Buffer = CompressedBuffer;
}
CmpCopyCompressedName(SearchName.Buffer,
SearchName.MaximumLength,
pcell->Name,
pcell->NameLength);
} else {
IsCompressed = FALSE;
SearchName.Length = pcell->NameLength;
SearchName.MaximumLength = pcell->NameLength;
SearchName.Buffer = &(pcell->Name[0]);
}
pcell = (PCM_KEY_NODE)HvGetCell(Hive, ParentKey);
if( pcell == NULL ) {
//
// we couldn't map the bin containing this cell
//
Result = FALSE;
goto Exit;
}
ASSERT_CELL_DIRTY(Hive,ParentKey);
//
// release the cell here; as key is dirty/pinned
//
HvReleaseCell(Hive, ParentKey);
Type = HvGetCellType(TargetKey);
ASSERT(pcell->SubKeyCounts[Type] != 0);
ASSERT(HvIsCellAllocated(Hive, pcell->SubKeyLists[Type]));
LeafCell = pcell->SubKeyLists[Type];
Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell);
if( Leaf == NULL ) {
//
// we couldn't map the bin containing this cell
//
Result = FALSE;
goto Exit;
}
CellToRelease1 = LeafCell;
if (Leaf->Signature == CM_KEY_INDEX_ROOT) {
RootSelect = CmpFindSubKeyInRoot(Hive, Leaf, &SearchName, &Child);
if( INVALID_INDEX & RootSelect ) {
//
// couldn't map view inside; bail out
//
Result = FALSE;
goto Exit;
}
ASSERT(Child != FALSE);
Root = Leaf;
RootCell = LeafCell;
LeafCell = Child;
Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell);
if( Leaf == NULL ) {
//
// we couldn't map the bin containing this cell
//
Result = FALSE;
goto Exit;
}
CellToRelease2 = LeafCell;
}
ASSERT((Leaf->Signature == CM_KEY_INDEX_LEAF) ||
(Leaf->Signature == CM_KEY_FAST_LEAF) ||
(Leaf->Signature == CM_KEY_HASH_LEAF)
);
LeafSelect = CmpFindSubKeyInLeaf(Hive, Leaf, &SearchName, &Child);
if( INVALID_INDEX & LeafSelect ) {
//
// couldn't map view
//
Result = FALSE;
goto Exit;
}
ASSERT(Child != HCELL_NIL);
//
// Leaf points to Index Leaf block
// Child is Index Leaf block cell
// LeafSelect is Index for List[]
//
pcell->SubKeyCounts[Type] -= 1;
Leaf->Count -= 1;
if (Leaf->Count == 0) {
//
// Empty Leaf, drop it.
//
HvFreeCell(Hive, LeafCell);
if (Root != NULL) {
Root->Count -= 1;
if (Root->Count == 0) {
//
// Root is empty, free it too.
//
HvFreeCell(Hive, RootCell);
pcell->SubKeyLists[Type] = HCELL_NIL;
} else if (RootSelect < (ULONG)(Root->Count)) {
//
// Middle entry, squeeze root
//
RtlMoveMemory(
(PVOID)&(Root->List[RootSelect]),
(PVOID)&(Root->List[RootSelect+1]),
(Root->Count - RootSelect) * sizeof(HCELL_INDEX)
);
}
//
// Else RootSelect == last entry, so decrementing count
// was all we needed to do
//
} else {
pcell->SubKeyLists[Type] = HCELL_NIL;
}
} else if (LeafSelect < (ULONG)(Leaf->Count)) {
if (Leaf->Signature == CM_KEY_INDEX_LEAF) {
RtlMoveMemory((PVOID)&(Leaf->List[LeafSelect]),
(PVOID)&(Leaf->List[LeafSelect+1]),
(Leaf->Count - LeafSelect) * sizeof(HCELL_INDEX));
} else {
FastIndex = (PCM_KEY_FAST_INDEX)Leaf;
RtlMoveMemory((PVOID)&(FastIndex->List[LeafSelect]),
(PVOID)&(FastIndex->List[LeafSelect+1]),
(FastIndex->Count - LeafSelect) * sizeof(CM_INDEX));
}
}
//
// Else LeafSelect == last entry, so decrementing count was enough
//
// things went OK
Result = TRUE;
Exit:
if( CellToRelease1 != HCELL_NIL ) {
HvReleaseCell(Hive,CellToRelease1);
}
if( CellToRelease2 != HCELL_NIL ) {
HvReleaseCell(Hive,CellToRelease2);
}
if ((IsCompressed) &&
(SearchName.MaximumLength > sizeof(CompressedBuffer))) {
#if defined(_CM_LDR_)
(Hive->Free)(SearchName.Buffer, SearchName.Length);
#else
ExFreePool(SearchName.Buffer);
#endif
}
return Result;
}
#ifdef NT_RENAME_KEY
HCELL_INDEX
CmpDuplicateIndex(
PHHIVE Hive,
HCELL_INDEX IndexCell,
ULONG StorageType
)
/*++
Routine Description:
Duplicate an index, regardless of its type; Needed for NtRenameKey
Arguments:
Hive - pointer to hive control structure for hive of interest
IndexCell - the index to be duplicated
StorageType - storagetype (Stable or Volatile)
Return Value:
cellindex of a duplicate or HCELL_NIL
--*/
{
PCM_KEY_INDEX Index;
PCM_KEY_INDEX Leaf;
ULONG i;
PCM_KEY_INDEX NewIndex = NULL;
HCELL_INDEX NewIndexCell;
HCELL_INDEX LeafCell;
PAGED_CODE();
//
// we have the lock exclusive or nobody is operating inside this hive
//
//ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
ASSERT_CM_EXCLUSIVE_HIVE_ACCESS(Hive);
ASSERT( HvGetCellType(IndexCell) == StorageType );
Index = (PCM_KEY_INDEX)HvGetCell(Hive, IndexCell);
if( Index == NULL ) {
//
// we couldn't map a view for the bin containing this cell
//
return HCELL_NIL;
}
// release the cell here; as the registry is locked exclusive (i.e. we don't care)
HvReleaseCell(Hive, IndexCell);
if (Index->Signature == CM_KEY_INDEX_ROOT) {
//
// first duplicate IndexCell, zeroing out the new content
//
NewIndexCell = HvDuplicateCell(Hive,IndexCell,StorageType,FALSE);
if( NewIndexCell == HCELL_NIL ) {
return HCELL_NIL;
}
NewIndex = (PCM_KEY_INDEX)HvGetCell(Hive, NewIndexCell);
if( NewIndex == NULL ) {
//
// we couldn't map a view for the bin containing this cell
// this shouldn't happen as we just allocated this cell (i.e. is dirty/pinned into memory)
//
ASSERT( FALSE );
goto ErrorExit;
}
// release the cell here; as the registry is locked exclusive (i.e. we don't care)
HvReleaseCell(Hive, NewIndexCell);
//
// we have a root index;
//
NewIndex->Signature = CM_KEY_INDEX_ROOT;
NewIndex->Count = 0;
//
// copy first level.
//
for( i=0;i<Index->Count;i++) {
#if DBG
Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, Index->List[i]);
if( Leaf == NULL ) {
//
// we couldn't map the bin containing this cell
//
goto ErrorExit;
}
// release the cell here; as the registry is locked exclusive (i.e. we don't care)
HvReleaseCell(Hive, Index->List[i]);
ASSERT((Leaf->Signature == CM_KEY_INDEX_LEAF) ||
(Leaf->Signature == CM_KEY_FAST_LEAF) ||
(Leaf->Signature == CM_KEY_HASH_LEAF)
);
ASSERT(Leaf->Count != 0);
#endif
LeafCell = HvDuplicateCell(Hive,Index->List[i],StorageType,TRUE);
if( LeafCell == HCELL_NIL ) {
goto ErrorExit;
}
NewIndex->List[i] = LeafCell;
NewIndex->Count++;
}
ASSERT( NewIndex->Count == Index->Count );
} else {
//
// leaf index
//
ASSERT((Index->Signature == CM_KEY_INDEX_LEAF) ||
(Index->Signature == CM_KEY_FAST_LEAF) ||
(Index->Signature == CM_KEY_HASH_LEAF)
);
ASSERT(Index->Count != 0);
//
// first duplicate IndexCell, copying the old content
//
NewIndexCell = HvDuplicateCell(Hive,IndexCell,StorageType,TRUE);
}
return NewIndexCell;
ErrorExit:
if( NewIndex != NULL ){
// we can get here only if we are trying to duplicate an index_root
ASSERT( NewIndex->Signature == CM_KEY_INDEX_ROOT );
//
// free the space we already allocated
//
for(i=0;i<NewIndex->Count;i++) {
ASSERT(NewIndex->List[i] != 0 );
HvFreeCell(Hive, NewIndex->List[i]);
}
}
HvFreeCell(Hive, NewIndexCell);
return HCELL_NIL;
}
BOOLEAN
CmpUpdateParentForEachSon(
PHHIVE Hive,
HCELL_INDEX Parent
)
/*++
Routine Description:
Walks the child's list (both stable and volatile and marks updates
the parent link to Parent.
First step is to mark all children dirty, and then to update the link.
This way, if we fail part through, we leave everything in good order
Arguments:
Hive - pointer to hive control structure for hive of interest
Parent - cell index of the cell who's son's to be updated.
Return Value:
TRUE - successfully updated
--*/
{
PCM_KEY_NODE ParentNode;
PCM_KEY_NODE CurrentSon;
HCELL_INDEX Child;
ULONG Count;
ULONG i;
PAGED_CODE();
//
// we have the lock exclusive or nobody is operating inside this hive
//
//ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
ASSERT_CM_EXCLUSIVE_HIVE_ACCESS(Hive);
//
// grab the parent node; this was already marked as dirty, we shouldn't
// have any problem here;
//
ParentNode = (PCM_KEY_NODE)HvGetCell(Hive,Parent);
if( ParentNode == NULL ) {
//
// cannot map view; this shouldn't happen as we just allocated
// this cell (i.e. it should be dirty/pinned into memory)
//
ASSERT( FALSE );
return FALSE;
}
// release the cell here; as the registry is locked exclusive (i.e. we don't care)
HvReleaseCell(Hive, Parent);
//
// iterate through the child list (both stable and volatile), marking every
// child dirty; this will pin the cell into memory and we will have no problems
// changine the parent later on
//
Count = ParentNode->SubKeyCounts[Stable] + ParentNode->SubKeyCounts[Volatile];
for( i=0;i<Count;i++) {
Child = CmpFindSubKeyByNumber(Hive,ParentNode,i);
if( Child == HCELL_NIL ) {
return FALSE;
}
if(!HvMarkCellDirty(Hive,Child)) {
return FALSE;
}
}
//
// second iteration, change the parent for each and every son
//
for( i=0;i<Count;i++) {
Child = CmpFindSubKeyByNumber(Hive,ParentNode,i);
//
// sanity test: we marked this dirty few lines above!
//
ASSERT( Child != HCELL_NIL );
CurrentSon = (PCM_KEY_NODE)HvGetCell(Hive,Child);
// release the cell here; as the registry is locked exclusive (i.e. we don't care)
HvReleaseCell(Hive, Child);
//
// sanity test: this cell should be pinned in memory by now
//
ASSERT( CurrentSon != NULL );
//
// change the parent
//
CurrentSon->Parent = Parent;
}
return TRUE;
}
#endif //NT_RENAME_KEY
ULONG
CmpComputeHashKey(
PUNICODE_STRING Name
)
{
ULONG ConvKey = 0;
ULONG Cnt;
WCHAR *Cp;
ASSERT( (Name->Buffer[0] != OBJ_NAME_PATH_SEPARATOR) || (Name->Length == 0));
//
// Manually compute the hash to use.
//
Cp = Name->Buffer;
for (Cnt=0; Cnt<Name->Length; Cnt += sizeof(WCHAR)) {
ASSERT( *Cp != OBJ_NAME_PATH_SEPARATOR );
ConvKey = 37 * ConvKey + (ULONG)RtlUpcaseUnicodeChar(*Cp);
++Cp;
}
return ConvKey;
}
ULONG
CmpComputeHashKeyForCompressedName(
IN PWCHAR Source,
IN ULONG SourceLength
)
{
ULONG ConvKey = 0;
ULONG i;
for (i=0;i<SourceLength;i++) {
ConvKey = 37*ConvKey + (ULONG)RtlUpcaseUnicodeChar((WCHAR)(((PUCHAR)Source)[i]));
}
return ConvKey;
}
//
// HashIndex routines
//
HCELL_INDEX
CmpFindSubKeyByHash(
PHHIVE Hive,
PCM_KEY_FAST_INDEX FastIndex,
PUNICODE_STRING SearchName
)
/*++
Routine Description:
Find the child cell (either subkey or value) specified by name.
It searched in the index table ordered by the hash
Arguments:
Hive - pointer to hive control structure for hive of interest
Index -
SearchName - name of child of interest
Return Value:
Cell of matching child key, or HCELL_NIL if none.
--*/
{
USHORT Current;
ULONG HashKey;
LONG Result;
#ifndef _CM_LDR_
PAGED_CODE();
#endif //_CM_LDR_
ASSERT( FastIndex->Signature == CM_KEY_HASH_LEAF );
HashKey = CmpComputeHashKey(SearchName);
for(Current = 0; Current < FastIndex->Count; Current++ ) {
if( HashKey == FastIndex->List[Current].HashKey ) {
//
// HashKey matches; see if this is a real hit
//
Result = CmpDoCompareKeyName(Hive,SearchName,FastIndex->List[Current].Cell);
if (Result == 0) {
return FastIndex->List[Current].Cell;
}
}
}
return HCELL_NIL;
}