mirror of
https://github.com/reactos/reactos.git
synced 2024-11-09 08:08:38 +00:00
c501d8112c
svn path=/branches/aicom-network-fixes/; revision=34994
1526 lines
45 KiB
C
1526 lines
45 KiB
C
/*
|
|
* PROJECT: ReactOS Kernel
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
* FILE: ntoskrnl/config/cmindex.c
|
|
* PURPOSE: Configuration Manager - Cell Indexes
|
|
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
|
*/
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
#include "ntoskrnl.h"
|
|
#define NDEBUG
|
|
#include "debug.h"
|
|
|
|
/* GLOBALS *******************************************************************/
|
|
|
|
ULONG CmpMaxFastIndexPerHblock =
|
|
(HBLOCK_SIZE - (sizeof(HBIN) +
|
|
sizeof(HCELL) +
|
|
FIELD_OFFSET(CM_KEY_FAST_INDEX, List))) / sizeof(CM_INDEX);
|
|
|
|
ULONG CmpMaxIndexPerHblock =
|
|
(HBLOCK_SIZE - (sizeof(HBIN) +
|
|
sizeof(HCELL) +
|
|
FIELD_OFFSET(CM_KEY_INDEX, List))) / sizeof(HCELL_INDEX) - 1;
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
LONG
|
|
NTAPI
|
|
CmpDoCompareKeyName(IN PHHIVE Hive,
|
|
IN PCUNICODE_STRING SearchName,
|
|
IN HCELL_INDEX Cell)
|
|
{
|
|
PCM_KEY_NODE Node;
|
|
UNICODE_STRING KeyName;
|
|
LONG Result;
|
|
|
|
/* Get the node */
|
|
Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell);
|
|
if (!Node) return 2;
|
|
|
|
/* Check if it's compressed */
|
|
if (Node->Flags & KEY_COMP_NAME)
|
|
{
|
|
/* Compare compressed names */
|
|
Result = CmpCompareCompressedName(SearchName,
|
|
Node->Name,
|
|
Node->NameLength);
|
|
}
|
|
else
|
|
{
|
|
/* Compare the Unicode name directly */
|
|
KeyName.Buffer = Node->Name;
|
|
KeyName.Length = Node->NameLength;
|
|
KeyName.MaximumLength = KeyName.Length;
|
|
Result = RtlCompareUnicodeString(SearchName, &KeyName, TRUE);
|
|
}
|
|
|
|
/* Release the cell and return the normalized result */
|
|
HvReleaseCell(Hive, Cell);
|
|
return (Result == 0) ? Result : ((Result > 0) ? 1 : -1);
|
|
}
|
|
|
|
LONG
|
|
NTAPI
|
|
CmpCompareInIndex(IN PHHIVE Hive,
|
|
IN PCUNICODE_STRING SearchName,
|
|
IN ULONG Count,
|
|
IN PCM_KEY_INDEX Index,
|
|
IN PHCELL_INDEX SubKey)
|
|
{
|
|
PCM_KEY_FAST_INDEX FastIndex;
|
|
PCM_INDEX FastEntry;
|
|
LONG Result;
|
|
ULONG i;
|
|
ULONG ActualNameLength = 4, CompareLength, NameLength;
|
|
WCHAR p, pp;
|
|
|
|
/* Assume failure */
|
|
*SubKey = HCELL_NIL;
|
|
|
|
/* Check if we are a fast or hashed leaf */
|
|
if ((Index->Signature == CM_KEY_FAST_LEAF) ||
|
|
(Index->Signature == CM_KEY_HASH_LEAF))
|
|
{
|
|
/* Get the Fast/Hash Index */
|
|
FastIndex = (PCM_KEY_FAST_INDEX)Index;
|
|
FastEntry = &FastIndex->List[Count];
|
|
|
|
/* Check if we are a hash leaf, in which case we skip all this */
|
|
if (Index->Signature == CM_KEY_FAST_LEAF)
|
|
{
|
|
/* Find out just how much of the name is there */
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
/* Check if this entry is empty */
|
|
if (!FastEntry->NameHint[i])
|
|
{
|
|
/* Only this much! */
|
|
ActualNameLength = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* How large is the name and how many characters to compare */
|
|
NameLength = SearchName->Length / sizeof(WCHAR);
|
|
CompareLength = min(NameLength, ActualNameLength);
|
|
|
|
/* Loop all the chars we'll test */
|
|
for (i = 0; i < CompareLength; i++)
|
|
{
|
|
/* Get one char from each buffer */
|
|
p = SearchName->Buffer[i];
|
|
pp = FastEntry->NameHint[i];
|
|
|
|
/* See if they match and return result if they don't */
|
|
Result = (LONG)RtlUpcaseUnicodeChar(p) -
|
|
(LONG)RtlUpcaseUnicodeChar(pp);
|
|
if (Result) return (Result > 0) ? 1 : -1;
|
|
}
|
|
}
|
|
|
|
/* If we got here then we have to do a full compare */
|
|
Result = CmpDoCompareKeyName(Hive, SearchName, FastEntry->Cell);
|
|
if (Result == 2) return Result;
|
|
if (!Result) *SubKey = FastEntry->Cell;
|
|
}
|
|
else
|
|
{
|
|
/* We aren't, so do a name compare and return the subkey found */
|
|
Result = CmpDoCompareKeyName(Hive, SearchName, Index->List[Count]);
|
|
if (Result == 2) return Result;
|
|
if (!Result) *SubKey = Index->List[Count];
|
|
}
|
|
|
|
/* Return the comparison result */
|
|
return Result;
|
|
}
|
|
|
|
ULONG
|
|
NTAPI
|
|
CmpFindSubKeyInRoot(IN PHHIVE Hive,
|
|
IN PCM_KEY_INDEX Index,
|
|
IN PCUNICODE_STRING SearchName,
|
|
IN PHCELL_INDEX SubKey)
|
|
{
|
|
ULONG High, Low = 0, i, ReturnIndex;
|
|
HCELL_INDEX LeafCell;
|
|
PCM_KEY_INDEX Leaf;
|
|
LONG Result;
|
|
|
|
/* Verify Index for validity */
|
|
ASSERTMSG("We don't do a linear search yet!\n", FALSE);
|
|
ASSERT(Index->Count != 0);
|
|
ASSERT(Index->Signature == CM_KEY_INDEX_ROOT);
|
|
|
|
/* Set high limit and loop */
|
|
High = Index->Count - 1;
|
|
while (TRUE)
|
|
{
|
|
/* Choose next entry */
|
|
i = ((High - Low) / 2) + Low;
|
|
|
|
/* Get the leaf cell and then the leaf itself */
|
|
LeafCell = Index->List[i];
|
|
Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell);
|
|
if (Leaf)
|
|
{
|
|
/* Make sure the leaf is valid */
|
|
ASSERT((Leaf->Signature == CM_KEY_INDEX_LEAF) ||
|
|
(Leaf->Signature == CM_KEY_FAST_LEAF) ||
|
|
(Leaf->Signature == CM_KEY_HASH_LEAF));
|
|
ASSERT(Leaf->Count != 0);
|
|
|
|
/* Do the compare */
|
|
Result = CmpCompareInIndex(Hive,
|
|
SearchName,
|
|
Leaf->Count - 1,
|
|
Leaf,
|
|
SubKey);
|
|
if (Result == 2) goto Big;
|
|
|
|
/* Check if we found the leaf */
|
|
if (!Result)
|
|
{
|
|
/* We found the leaf */
|
|
*SubKey = LeafCell;
|
|
ReturnIndex = i;
|
|
goto Return;
|
|
}
|
|
|
|
/* Check for negative result */
|
|
if (Result < 0)
|
|
{
|
|
/* If we got here, we should be at -1 */
|
|
ASSERT(Result == -1);
|
|
|
|
/* Do another lookup, since we might still be in the right leaf */
|
|
Result = CmpCompareInIndex(Hive,
|
|
SearchName,
|
|
0,
|
|
Leaf,
|
|
SubKey);
|
|
if (Result == 2) goto Big;
|
|
|
|
/* Check if it's not below */
|
|
if (Result >= 0)
|
|
{
|
|
/*
|
|
* If the name was first below, and now it is above,
|
|
* then this means that it is somewhere in this leaf.
|
|
* Make sure we didn't get some weird result
|
|
*/
|
|
ASSERT((Result == 1) || (Result == 0));
|
|
|
|
/* Return it */
|
|
*SubKey = LeafCell;
|
|
ReturnIndex = Low;
|
|
goto Return;
|
|
}
|
|
|
|
/* Update the limit to this index, since we know it's not higher. */
|
|
High = i;
|
|
}
|
|
else
|
|
{
|
|
/* Update the base to this index, since we know it's not lower. */
|
|
Low = i;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Big:
|
|
/* This was some sort of special key */
|
|
ReturnIndex = 0x80000000;
|
|
goto ReturnFailure;
|
|
}
|
|
|
|
/* Check if there is only one entry left */
|
|
if ((High - Low) <= 1) break;
|
|
|
|
/* Release the leaf cell */
|
|
HvReleaseCell(Hive, LeafCell);
|
|
}
|
|
|
|
/* Make sure we got here for the right reasons */
|
|
ASSERT((High - Low == 1) || (High == Low));
|
|
|
|
/* Get the leaf cell and the leaf */
|
|
LeafCell = Index->List[Low];
|
|
Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell);
|
|
if (!Leaf) goto Big;
|
|
|
|
/* Do the compare */
|
|
Result = CmpCompareInIndex(Hive,
|
|
SearchName,
|
|
Leaf->Count-1,
|
|
Leaf,
|
|
SubKey);
|
|
if (Result == 2) goto Big;
|
|
|
|
/* Check if we found it */
|
|
if (!Result)
|
|
{
|
|
/* We got lucky...return it */
|
|
*SubKey = LeafCell;
|
|
ReturnIndex = Low;
|
|
goto Return;
|
|
}
|
|
|
|
/* It's below, so could still be in this leaf */
|
|
if (Result < 0)
|
|
{
|
|
/* Make sure we're -1 */
|
|
ASSERT(Result == -1);
|
|
|
|
/* Do a search from the bottom */
|
|
Result = CmpCompareInIndex(Hive, SearchName, 0, Leaf, SubKey);
|
|
if (Result == 2) goto Big;
|
|
|
|
/*
|
|
* Check if it's above, which means that it's within the ranges of our
|
|
* leaf (since we were below before).
|
|
*/
|
|
if (Result >= 0)
|
|
{
|
|
/* Sanity check */
|
|
ASSERT((Result == 1) || (Result == 0));
|
|
|
|
/* Yep, so we're in the right leaf; return it. */
|
|
*SubKey = LeafCell;
|
|
ReturnIndex = Low;
|
|
goto Return;
|
|
}
|
|
|
|
/* It's still below us, so fail */
|
|
ReturnIndex = Low;
|
|
goto ReturnFailure;
|
|
}
|
|
|
|
/* Release the leaf cell */
|
|
HvReleaseCell(Hive, LeafCell);
|
|
|
|
/* Well the low didn't work too well, so try the high. */
|
|
LeafCell = Index->List[High];
|
|
Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell);
|
|
if (!Leaf) goto Big;
|
|
|
|
/* Do the compare */
|
|
Result = CmpCompareInIndex(Hive,
|
|
SearchName,
|
|
Leaf->Count - 1,
|
|
Leaf,
|
|
SubKey);
|
|
if (Result == 2) goto Big;
|
|
|
|
/* Check if we found it */
|
|
if (Result == 0)
|
|
{
|
|
/* We got lucky... return it */
|
|
*SubKey = LeafCell;
|
|
ReturnIndex = High;
|
|
goto Return;
|
|
}
|
|
|
|
/* Check if we are too high */
|
|
if (Result < 0)
|
|
{
|
|
/* Make sure we're -1 */
|
|
ASSERT(Result == -1);
|
|
|
|
/*
|
|
* Once again... since we were first too low and now too high, then
|
|
* this means we are within the range of this leaf... return it.
|
|
*/
|
|
*SubKey = LeafCell;
|
|
ReturnIndex = High;
|
|
goto Return;
|
|
}
|
|
|
|
/* If we got here, then we are too low, again. */
|
|
ReturnIndex = High;
|
|
|
|
/* Failure path */
|
|
ReturnFailure:
|
|
*SubKey = HCELL_NIL;
|
|
|
|
/* Return path...check if we have a leaf to free */
|
|
Return:
|
|
if (Leaf) HvReleaseCell(Hive, LeafCell);
|
|
|
|
/* Return the index */
|
|
return ReturnIndex;
|
|
}
|
|
|
|
ULONG
|
|
NTAPI
|
|
CmpFindSubKeyInLeaf(IN PHHIVE Hive,
|
|
IN PCM_KEY_INDEX Index,
|
|
IN PCUNICODE_STRING SearchName,
|
|
IN PHCELL_INDEX SubKey)
|
|
{
|
|
ULONG High, Low = 0, i;
|
|
LONG Result;
|
|
|
|
/* Verify Index for validity */
|
|
ASSERT((Index->Signature == CM_KEY_INDEX_LEAF) ||
|
|
(Index->Signature == CM_KEY_FAST_LEAF) ||
|
|
(Index->Signature == CM_KEY_HASH_LEAF));
|
|
|
|
/* Get the upper bound and middle entry */
|
|
High = Index->Count - 1;
|
|
#ifdef SOMEONE_WAS_NICE_ENOUGH_TO_MAKE_OUR_CELLS_LEXICALLY_SORTED
|
|
i = High / 2;
|
|
#else
|
|
i = 0;
|
|
#endif
|
|
|
|
/* Check if we don't actually have any entries */
|
|
if (!Index->Count)
|
|
{
|
|
/* Return failure */
|
|
*SubKey = HCELL_NIL;
|
|
return 0;
|
|
}
|
|
|
|
/* Start compare loop */
|
|
while (TRUE)
|
|
{
|
|
/* Do the actual comparison and check the result */
|
|
Result = CmpCompareInIndex(Hive, SearchName, i, Index, SubKey);
|
|
if (Result == 2)
|
|
{
|
|
/* Fail with special value */
|
|
*SubKey = HCELL_NIL;
|
|
return 0x80000000;
|
|
}
|
|
|
|
/* Check if we got lucky and found it */
|
|
if (!Result) return i;
|
|
|
|
#ifdef SOMEONE_WAS_NICE_ENOUGH_TO_MAKE_OUR_CELLS_LEXICALLY_SORTED
|
|
/* Check if the result is below us */
|
|
if (Result < 0)
|
|
{
|
|
/* Set the new bound; it can't be higher then where we are now. */
|
|
ASSERT(Result == -1);
|
|
High = i;
|
|
}
|
|
else
|
|
{
|
|
/* Set the new bound... it can't be lower then where we are now. */
|
|
ASSERT(Result == 1);
|
|
Low = i;
|
|
}
|
|
|
|
/* Check if this is the last entry, if so, break out and handle it */
|
|
if ((High - Low) <= 1) break;
|
|
|
|
/* Set the new index */
|
|
i = ((High - Low) / 2) + Low;
|
|
#else
|
|
if (++i > High)
|
|
{
|
|
/* Return failure */
|
|
*SubKey = HCELL_NIL;
|
|
return 0;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* If we get here, High - Low = 1 or High == Low
|
|
* Simply look first at Low, then at High
|
|
*/
|
|
Result = CmpCompareInIndex(Hive, SearchName, Low, Index, SubKey);
|
|
if (Result == 2)
|
|
{
|
|
/* Fail with special value */
|
|
*SubKey = HCELL_NIL;
|
|
return 0x80000000;
|
|
}
|
|
|
|
/* Check if we got lucky and found it */
|
|
if (!Result) return Low;
|
|
|
|
/* Check if the result is below us */
|
|
if (Result < 0)
|
|
{
|
|
/* Return the low entry */
|
|
ASSERT(Result == -1);
|
|
return Low;
|
|
}
|
|
|
|
/*
|
|
* If we got here, then just check the high and return it no matter what
|
|
* the result is (since we're a leaf, it has to be near there anyway).
|
|
*/
|
|
Result = CmpCompareInIndex(Hive, SearchName, High, Index, SubKey);
|
|
if (Result == 2)
|
|
{
|
|
/* Fail with special value */
|
|
*SubKey = HCELL_NIL;
|
|
return 0x80000000;
|
|
}
|
|
|
|
/* Return the high */
|
|
return High;
|
|
}
|
|
|
|
ULONG
|
|
NTAPI
|
|
CmpComputeHashKey(IN ULONG Hash,
|
|
IN PCUNICODE_STRING Name,
|
|
IN BOOLEAN AllowSeparators)
|
|
{
|
|
LPWSTR Cp;
|
|
ULONG Value, i;
|
|
|
|
/* Make some sanity checks on our parameters */
|
|
ASSERT((Name->Length == 0) ||
|
|
(AllowSeparators) ||
|
|
(Name->Buffer[0] != OBJ_NAME_PATH_SEPARATOR));
|
|
|
|
/* If the name is empty, there is nothing to hash! */
|
|
if (!Name->Length) return Hash;
|
|
|
|
/* Set the buffer and loop every character */
|
|
Cp = Name->Buffer;
|
|
for (i = 0; i < Name->Length; i += sizeof(WCHAR), Cp++)
|
|
{
|
|
/* Make sure we don't have a separator when we shouldn't */
|
|
ASSERT(AllowSeparators || (*Cp != OBJ_NAME_PATH_SEPARATOR));
|
|
|
|
/* Check what kind of char we have */
|
|
if (*Cp >= L'a')
|
|
{
|
|
/* In the lower case region... is it truly lower case? */
|
|
if (*Cp < L'z')
|
|
{
|
|
/* Yes! Calculate it ourselves! */
|
|
Value = *Cp - L'a' + L'A';
|
|
}
|
|
else
|
|
{
|
|
/* No, use the API */
|
|
Value = RtlUpcaseUnicodeChar(*Cp);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Reuse the char, it's already upcased */
|
|
Value = *Cp;
|
|
}
|
|
|
|
/* Multiply by a prime and add our value */
|
|
Hash *= 37;
|
|
Hash += Value;
|
|
}
|
|
|
|
/* Return the hash */
|
|
return Hash;
|
|
}
|
|
|
|
HCELL_INDEX
|
|
NTAPI
|
|
CmpDoFindSubKeyByNumber(IN PHHIVE Hive,
|
|
IN PCM_KEY_INDEX Index,
|
|
IN ULONG Number)
|
|
{
|
|
ULONG i;
|
|
HCELL_INDEX LeafCell = 0;
|
|
PCM_KEY_INDEX Leaf = NULL;
|
|
PCM_KEY_FAST_INDEX FastIndex;
|
|
HCELL_INDEX Result;
|
|
|
|
/* Check if this is a root */
|
|
if (Index->Signature == CM_KEY_INDEX_ROOT)
|
|
{
|
|
/* Loop the index */
|
|
for (i = 0; i < Index->Count; i++)
|
|
{
|
|
/* Check if this isn't the first iteration */
|
|
if (i)
|
|
{
|
|
/* Make sure we had something valid, and release it */
|
|
ASSERT(Leaf != NULL );
|
|
ASSERT(LeafCell == Index->List[i - 1]);
|
|
HvReleaseCell(Hive, LeafCell);
|
|
}
|
|
|
|
/* Get the leaf cell and the leaf for this index */
|
|
LeafCell = Index->List[i];
|
|
Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell);
|
|
if (!Leaf) return HCELL_NIL;
|
|
|
|
/* Check if the index may be inside it */
|
|
if (Number < Leaf->Count)
|
|
{
|
|
/* Check if this is a fast or hash leaf */
|
|
if ((Leaf->Signature == CM_KEY_FAST_LEAF) ||
|
|
(Leaf->Signature == CM_KEY_HASH_LEAF))
|
|
{
|
|
/* Get the fast index */
|
|
FastIndex = (PCM_KEY_FAST_INDEX)Leaf;
|
|
|
|
/* Look inside the list to get our actual cell */
|
|
Result = FastIndex->List[Number].Cell;
|
|
HvReleaseCell(Hive, LeafCell);
|
|
return Result;
|
|
}
|
|
else
|
|
{
|
|
/* Regular leaf, so just use the index directly */
|
|
Result = Leaf->List[Number];
|
|
|
|
/* Release and return it */
|
|
HvReleaseCell(Hive,LeafCell);
|
|
return Result;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Otherwise, skip this leaf */
|
|
Number = Number - Leaf->Count;
|
|
}
|
|
}
|
|
|
|
/* Should never get here */
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
/* If we got here, then the cell is in this index */
|
|
ASSERT(Number < Index->Count);
|
|
|
|
/* Check if we're a fast or hash leaf */
|
|
if ((Index->Signature == CM_KEY_FAST_LEAF) ||
|
|
(Index->Signature == CM_KEY_HASH_LEAF))
|
|
{
|
|
/* We are, get the fast index and get the cell from the list */
|
|
FastIndex = (PCM_KEY_FAST_INDEX)Index;
|
|
return FastIndex->List[Number].Cell;
|
|
}
|
|
else
|
|
{
|
|
/* We aren't, so use the index directly to grab the cell */
|
|
return Index->List[Number];
|
|
}
|
|
}
|
|
|
|
HCELL_INDEX
|
|
NTAPI
|
|
CmpFindSubKeyByNumber(IN PHHIVE Hive,
|
|
IN PCM_KEY_NODE Node,
|
|
IN ULONG Number)
|
|
{
|
|
PCM_KEY_INDEX Index;
|
|
HCELL_INDEX Result = HCELL_NIL;
|
|
|
|
/* Check if it's in the stable list */
|
|
if (Number < Node->SubKeyCounts[Stable])
|
|
{
|
|
/* Get the actual key index */
|
|
Index = (PCM_KEY_INDEX)HvGetCell(Hive, Node->SubKeyLists[Stable]);
|
|
if (!Index) return HCELL_NIL;
|
|
|
|
/* Do a search inside it */
|
|
Result = CmpDoFindSubKeyByNumber(Hive, Index, Number);
|
|
|
|
/* Release the cell and return the result */
|
|
HvReleaseCell(Hive, Node->SubKeyLists[Stable]);
|
|
return Result;
|
|
}
|
|
else if (Hive->StorageTypeCount > Volatile)
|
|
{
|
|
/* It's in the volatile list */
|
|
Number = Number - Node->SubKeyCounts[Stable];
|
|
if (Number < Node->SubKeyCounts[Volatile])
|
|
{
|
|
/* Get the actual key index */
|
|
Index = (PCM_KEY_INDEX)HvGetCell(Hive,
|
|
Node->SubKeyLists[Volatile]);
|
|
if (!Index) return HCELL_NIL;
|
|
|
|
/* Do a search inside it */
|
|
Result = CmpDoFindSubKeyByNumber(Hive, Index, Number);
|
|
|
|
/* Release the cell and return the result */
|
|
HvReleaseCell(Hive, Node->SubKeyLists[Volatile]);
|
|
return Result;
|
|
}
|
|
}
|
|
|
|
/* Nothing was found */
|
|
return HCELL_NIL;
|
|
}
|
|
|
|
static HCELL_INDEX
|
|
NTAPI
|
|
CmpFindSubKeyByHash(IN PHHIVE Hive,
|
|
IN PCM_KEY_FAST_INDEX FastIndex,
|
|
IN PCUNICODE_STRING SearchName)
|
|
{
|
|
ULONG HashKey, i;
|
|
PCM_INDEX FastEntry;
|
|
|
|
/* Make sure it's really a hash */
|
|
ASSERT(FastIndex->Signature == CM_KEY_HASH_LEAF);
|
|
|
|
/* Compute the hash key for the name */
|
|
HashKey = CmpComputeHashKey(0, SearchName, FALSE);
|
|
|
|
/* Loop all the entries */
|
|
for (i = 0; i < FastIndex->Count; i++)
|
|
{
|
|
/* Get the entry */
|
|
FastEntry = &FastIndex->List[i];
|
|
|
|
/* Compare the hash first */
|
|
if (FastEntry->HashKey == HashKey)
|
|
{
|
|
/* Go ahead for a full compare */
|
|
if (!(CmpDoCompareKeyName(Hive, SearchName, FastEntry->Cell)))
|
|
{
|
|
/* It matched, return the cell */
|
|
return FastEntry->Cell;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* If we got here then we failed */
|
|
return HCELL_NIL;
|
|
}
|
|
|
|
HCELL_INDEX
|
|
NTAPI
|
|
CmpFindSubKeyByName(IN PHHIVE Hive,
|
|
IN PCM_KEY_NODE Parent,
|
|
IN PCUNICODE_STRING SearchName)
|
|
{
|
|
ULONG i;
|
|
PCM_KEY_INDEX IndexRoot;
|
|
HCELL_INDEX SubKey, CellToRelease;
|
|
ULONG Found;
|
|
|
|
/* Loop each storage type */
|
|
for (i = 0; i < Hive->StorageTypeCount; i++)
|
|
{
|
|
/* Make sure the parent node has subkeys */
|
|
if (Parent->SubKeyCounts[i])
|
|
{
|
|
/* Get the Index */
|
|
IndexRoot = (PCM_KEY_INDEX)HvGetCell(Hive, Parent->SubKeyLists[i]);
|
|
if (!IndexRoot) return HCELL_NIL;
|
|
|
|
/* Get the cell we'll need to release */
|
|
CellToRelease = Parent->SubKeyLists[i];
|
|
|
|
/* Check if this is another index root */
|
|
if (IndexRoot->Signature == CM_KEY_INDEX_ROOT)
|
|
{
|
|
/* Lookup the name in the root */
|
|
Found = CmpFindSubKeyInRoot(Hive,
|
|
IndexRoot,
|
|
SearchName,
|
|
&SubKey);
|
|
|
|
/* Release the previous cell */
|
|
ASSERT(CellToRelease != HCELL_NIL);
|
|
HvReleaseCell(Hive, CellToRelease);
|
|
|
|
/* Make sure we found something valid */
|
|
if (Found & 0x80000000) break;
|
|
|
|
/* Get the new Index Root and set the new cell to be released */
|
|
if (SubKey == HCELL_NIL) continue;
|
|
CellToRelease = SubKey;
|
|
IndexRoot = (PCM_KEY_INDEX)HvGetCell(Hive, SubKey);
|
|
}
|
|
|
|
/* Make sure the signature is what we expect it to be */
|
|
ASSERT((IndexRoot->Signature == CM_KEY_INDEX_LEAF) ||
|
|
(IndexRoot->Signature == CM_KEY_FAST_LEAF) ||
|
|
(IndexRoot->Signature == CM_KEY_HASH_LEAF));
|
|
|
|
/* Check if this isn't a hashed leaf */
|
|
if (IndexRoot->Signature != CM_KEY_HASH_LEAF)
|
|
{
|
|
/* Find the subkey in the leaf */
|
|
Found = CmpFindSubKeyInLeaf(Hive,
|
|
IndexRoot,
|
|
SearchName,
|
|
&SubKey);
|
|
|
|
/* Release the previous cell */
|
|
ASSERT(CellToRelease != HCELL_NIL);
|
|
HvReleaseCell(Hive, CellToRelease);
|
|
|
|
/* Make sure we found a valid index */
|
|
if (Found & 0x80000000) break;
|
|
}
|
|
else
|
|
{
|
|
/* Find the subkey in the hash */
|
|
SubKey = CmpFindSubKeyByHash(Hive,
|
|
(PCM_KEY_FAST_INDEX)IndexRoot,
|
|
SearchName);
|
|
|
|
/* Release the previous cell */
|
|
ASSERT(CellToRelease != HCELL_NIL);
|
|
HvReleaseCell(Hive, CellToRelease);
|
|
}
|
|
|
|
/* Make sure we got a valid subkey and return it */
|
|
if (SubKey != HCELL_NIL) return SubKey;
|
|
}
|
|
}
|
|
|
|
/* If we got here, then we failed */
|
|
return HCELL_NIL;
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
CmpMarkIndexDirty(IN PHHIVE Hive,
|
|
IN HCELL_INDEX ParentKey,
|
|
IN HCELL_INDEX TargetKey)
|
|
{
|
|
PCM_KEY_NODE Node;
|
|
UNICODE_STRING SearchName;
|
|
BOOLEAN IsCompressed;
|
|
ULONG i, Result;
|
|
PCM_KEY_INDEX Index;
|
|
HCELL_INDEX IndexCell, Child = HCELL_NIL, CellToRelease = HCELL_NIL;
|
|
|
|
/* Get the target key node */
|
|
Node = (PCM_KEY_NODE)HvGetCell(Hive, TargetKey);
|
|
if (!Node) return FALSE;
|
|
|
|
/* Check if it's compressed */
|
|
if (Node->Flags & KEY_COMP_NAME)
|
|
{
|
|
/* Remember this for later */
|
|
IsCompressed = TRUE;
|
|
|
|
/* Build the search name */
|
|
SearchName.Length = CmpCompressedNameSize(Node->Name,
|
|
Node->NameLength);
|
|
SearchName.MaximumLength = SearchName.Length;
|
|
SearchName.Buffer = ExAllocatePoolWithTag(PagedPool,
|
|
SearchName.Length,
|
|
TAG_CM);
|
|
if (!SearchName.Buffer)
|
|
{
|
|
/* Fail */
|
|
HvReleaseCell(Hive, TargetKey);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Copy it */
|
|
CmpCopyCompressedName(SearchName.Buffer,
|
|
SearchName.MaximumLength,
|
|
Node->Name,
|
|
Node->NameLength);
|
|
}
|
|
else
|
|
{
|
|
/* Name isn't compressed, build it directly from the node */
|
|
IsCompressed = FALSE;
|
|
SearchName.Length = Node->NameLength;
|
|
SearchName.MaximumLength = Node->NameLength;
|
|
SearchName.Buffer = Node->Name;
|
|
}
|
|
|
|
/* We can release the target key now */
|
|
HvReleaseCell(Hive, TargetKey);
|
|
|
|
/* Now get the parent key node */
|
|
Node = (PCM_KEY_NODE)HvGetCell(Hive, ParentKey);
|
|
if (!Node) goto Quickie;
|
|
|
|
/* Loop all hive storage */
|
|
for (i = 0; i < Hive->StorageTypeCount; i++)
|
|
{
|
|
/* Check if any subkeys are in this index */
|
|
if (Node->SubKeyCounts[i])
|
|
{
|
|
/* Get the cell index */
|
|
//ASSERT(HvIsCellAllocated(Hive, Node->SubKeyLists[i]));
|
|
IndexCell = Node->SubKeyLists[i];
|
|
|
|
/* Check if we had anything to release from before */
|
|
if (CellToRelease != HCELL_NIL)
|
|
{
|
|
/* Release it now */
|
|
HvReleaseCell(Hive, CellToRelease);
|
|
CellToRelease = HCELL_NIL;
|
|
}
|
|
|
|
/* Get the key index for the cell */
|
|
Index = (PCM_KEY_INDEX)HvGetCell(Hive, IndexCell);
|
|
if (!Index) goto Quickie;
|
|
|
|
/* Release it at the next iteration or below */
|
|
CellToRelease = IndexCell;
|
|
|
|
/* Check if this is a root */
|
|
if (Index->Signature == CM_KEY_INDEX_ROOT)
|
|
{
|
|
/* Get the child inside the root */
|
|
Result = CmpFindSubKeyInRoot(Hive, Index, &SearchName, &Child);
|
|
if (Result & 0x80000000) goto Quickie;
|
|
if (Child == HCELL_NIL) continue;
|
|
|
|
/* We found it, mark the cell dirty */
|
|
HvMarkCellDirty(Hive, IndexCell, FALSE);
|
|
|
|
/* Check if we had anything to release from before */
|
|
if (CellToRelease != HCELL_NIL)
|
|
{
|
|
/* Release it now */
|
|
HvReleaseCell(Hive, CellToRelease);
|
|
CellToRelease = HCELL_NIL;
|
|
}
|
|
|
|
/* Now this child is the index, get the actual key index */
|
|
IndexCell = Child;
|
|
Index = (PCM_KEY_INDEX)HvGetCell(Hive, Child);
|
|
if (!Index) goto Quickie;
|
|
|
|
/* Release it later */
|
|
CellToRelease = Child;
|
|
}
|
|
|
|
/* Make sure this is a valid index */
|
|
ASSERT((Index->Signature == CM_KEY_INDEX_LEAF) ||
|
|
(Index->Signature == CM_KEY_FAST_LEAF) ||
|
|
(Index->Signature == CM_KEY_HASH_LEAF));
|
|
|
|
/* Find the child in the leaf */
|
|
Result = CmpFindSubKeyInLeaf(Hive, Index, &SearchName, &Child);
|
|
if (Result & 0x80000000) goto Quickie;
|
|
if (Child != HCELL_NIL)
|
|
{
|
|
/* We found it, free the name now */
|
|
if (IsCompressed) ExFreePool(SearchName.Buffer);
|
|
|
|
/* Release the parent key */
|
|
HvReleaseCell(Hive, ParentKey);
|
|
|
|
/* Check if we had a left over cell to release */
|
|
if (CellToRelease != HCELL_NIL)
|
|
{
|
|
/* Release it */
|
|
HvReleaseCell(Hive, CellToRelease);
|
|
}
|
|
|
|
/* And mark the index cell dirty */
|
|
HvMarkCellDirty(Hive, IndexCell, FALSE);
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
Quickie:
|
|
/* Release any cells that we still hold */
|
|
if (Node) HvReleaseCell(Hive, ParentKey);
|
|
if (CellToRelease != HCELL_NIL) HvReleaseCell(Hive, CellToRelease);
|
|
|
|
/* Free the search name and return failure */
|
|
if (IsCompressed) ExFreePool(SearchName.Buffer);
|
|
return FALSE;
|
|
}
|
|
|
|
HCELL_INDEX
|
|
NTAPI
|
|
CmpAddToLeaf(IN PHHIVE Hive,
|
|
IN HCELL_INDEX LeafCell,
|
|
IN HCELL_INDEX NewKey,
|
|
IN PUNICODE_STRING Name)
|
|
{
|
|
PCM_KEY_INDEX Leaf;
|
|
PCM_KEY_FAST_INDEX FastLeaf;
|
|
ULONG Size, OldSize, EntrySize, i, j;
|
|
HCELL_INDEX NewCell, Child;
|
|
LONG Result;
|
|
|
|
/* Mark the leaf dirty */
|
|
HvMarkCellDirty(Hive, LeafCell, FALSE);
|
|
|
|
/* Get the leaf cell */
|
|
Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell);
|
|
if (!Leaf)
|
|
{
|
|
/* Shouldn't happen */
|
|
ASSERT(FALSE);
|
|
return HCELL_NIL;
|
|
}
|
|
|
|
/* Release it */
|
|
HvReleaseCell(Hive, LeafCell);
|
|
|
|
/* Check if this is an index leaf */
|
|
if (Leaf->Signature == CM_KEY_INDEX_LEAF)
|
|
{
|
|
/* This is an old-style leaf */
|
|
FastLeaf = NULL;
|
|
EntrySize = sizeof(HCELL_INDEX);
|
|
}
|
|
else
|
|
{
|
|
/* Sanity check */
|
|
ASSERT((Leaf->Signature == CM_KEY_FAST_LEAF) ||
|
|
(Leaf->Signature == CM_KEY_HASH_LEAF));
|
|
|
|
/* This is a new-style optimized fast (or hash) leaf */
|
|
FastLeaf = (PCM_KEY_FAST_INDEX)Leaf;
|
|
EntrySize = sizeof(CM_INDEX);
|
|
}
|
|
|
|
/* Get the current size of the leaf */
|
|
OldSize = HvGetCellSize(Hive, Leaf);
|
|
|
|
/* Calculate the size of the free entries */
|
|
Size = OldSize;
|
|
Size -= EntrySize * Leaf->Count + FIELD_OFFSET(CM_KEY_INDEX, List);
|
|
|
|
/* Assume we'll re-use the same leaf */
|
|
NewCell = LeafCell;
|
|
|
|
/* Check if we're out of space */
|
|
if ((Size / EntrySize) < 1)
|
|
{
|
|
/* Grow the leaf by 1.5x, making sure we can at least fit this entry */
|
|
Size = OldSize + OldSize / 2;
|
|
if (Size < (OldSize + EntrySize)) Size = OldSize + EntrySize;
|
|
|
|
/* Re-allocate the leaf */
|
|
NewCell = HvReallocateCell(Hive, LeafCell, Size);
|
|
if (NewCell == HCELL_NIL) return HCELL_NIL;
|
|
|
|
/* Get the leaf cell */
|
|
Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, NewCell);
|
|
if (!Leaf)
|
|
{
|
|
/* This shouldn't happen */
|
|
ASSERT(FALSE);
|
|
return HCELL_NIL;
|
|
}
|
|
|
|
/* Release the cell */
|
|
HvReleaseCell(Hive, NewCell);
|
|
|
|
/* Update the fast leaf pointer if we had one */
|
|
if (FastLeaf) FastLeaf = (PCM_KEY_FAST_INDEX)Leaf;
|
|
}
|
|
|
|
/* Find the insertion point for our entry */
|
|
i = CmpFindSubKeyInLeaf(Hive, Leaf, Name, &Child);
|
|
if (i & 0x80000000) return HCELL_NIL;
|
|
ASSERT(Child == HCELL_NIL);
|
|
|
|
/* Check if we're not last */
|
|
if (i != Leaf->Count)
|
|
{
|
|
/* Find out where we should go */
|
|
Result = CmpCompareInIndex(Hive,
|
|
Name,
|
|
i,
|
|
Leaf,
|
|
&Child);
|
|
if (Result == 2) return HCELL_NIL;
|
|
ASSERT(Result != 0);
|
|
|
|
/* Check if we come after */
|
|
if (Result > 0)
|
|
{
|
|
/* We do, insert us after the key */
|
|
ASSERT(Result == 1);
|
|
i++;
|
|
}
|
|
|
|
/* Check if we're still not last */
|
|
if (i != Leaf->Count)
|
|
{
|
|
/* Check if we had a fast leaf or not */
|
|
if (FastLeaf)
|
|
{
|
|
/* Copy the fast indexes */
|
|
RtlMoveMemory(&FastLeaf->List[i + 1],
|
|
&FastLeaf->List[i],
|
|
(FastLeaf->Count - i) * sizeof(CM_INDEX));
|
|
}
|
|
else
|
|
{
|
|
/* Copy the indexes themselves */
|
|
RtlMoveMemory(&Leaf->List[i + 1],
|
|
&Leaf->List[i],
|
|
(Leaf->Count - i) * sizeof(HCELL_INDEX));
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Check if this is a new-style leaf */
|
|
if (FastLeaf)
|
|
{
|
|
/* Set our cell */
|
|
FastLeaf->List[i].Cell = NewKey;
|
|
|
|
/* Check if this is a hash leaf */
|
|
if( FastLeaf->Signature == CM_KEY_HASH_LEAF )
|
|
{
|
|
/* Set our hash key */
|
|
FastLeaf->List[i].HashKey = CmpComputeHashKey(0, Name, FALSE);
|
|
}
|
|
else
|
|
{
|
|
/* First, clear the name */
|
|
FastLeaf->List[i].NameHint[0] = 0;
|
|
FastLeaf->List[i].NameHint[1] = 0;
|
|
FastLeaf->List[i].NameHint[2] = 0;
|
|
FastLeaf->List[i].NameHint[3] = 0;
|
|
|
|
/* Now, figure out if we can fit */
|
|
if (Name->Length / sizeof(WCHAR) < 4)
|
|
{
|
|
/* We can fit, use our length */
|
|
j = Name->Length / sizeof(WCHAR);
|
|
}
|
|
else
|
|
{
|
|
/* We can't, use a maximum of 4 */
|
|
j = 4;
|
|
}
|
|
|
|
/* Now fill out the name hint */
|
|
do
|
|
{
|
|
/* Look for invalid characters and break out if we found one */
|
|
if ((USHORT)Name->Buffer[j - 1] > (UCHAR)-1) break;
|
|
|
|
/* Otherwise, copy the a character */
|
|
FastLeaf->List[i].NameHint[j - 1] = (UCHAR)Name->Buffer[j - 1];
|
|
} while (--j > 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* This is an old-style leaf, just set our index directly */
|
|
Leaf->List[i] = NewKey;
|
|
}
|
|
|
|
/* Update the leaf count and return the new cell */
|
|
Leaf->Count += 1;
|
|
return NewCell;
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
CmpAddSubKey(IN PHHIVE Hive,
|
|
IN HCELL_INDEX Parent,
|
|
IN HCELL_INDEX Child)
|
|
{
|
|
PCM_KEY_NODE KeyNode;
|
|
PCM_KEY_INDEX Index;
|
|
PCM_KEY_FAST_INDEX OldIndex;
|
|
UNICODE_STRING Name;
|
|
HCELL_INDEX IndexCell = HCELL_NIL, CellToRelease = HCELL_NIL, LeafCell;
|
|
PHCELL_INDEX RootPointer = NULL;
|
|
ULONG Type, i;
|
|
BOOLEAN IsCompressed;
|
|
PAGED_CODE();
|
|
|
|
/* Get the key node */
|
|
KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Child);
|
|
if (!KeyNode)
|
|
{
|
|
/* Shouldn't happen */
|
|
ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Check if the name is compressed */
|
|
if (KeyNode->Flags & KEY_COMP_NAME)
|
|
{
|
|
/* Remember for later */
|
|
IsCompressed = TRUE;
|
|
|
|
/* Create the compressed name and allocate it */
|
|
Name.Length = CmpCompressedNameSize(KeyNode->Name, KeyNode->NameLength);
|
|
Name.MaximumLength = Name.Length;
|
|
Name.Buffer = Hive->Allocate(Name.Length, TRUE, TAG_CM);
|
|
if (!Name.Buffer)
|
|
{
|
|
/* Release the cell and fail */
|
|
HvReleaseCell(Hive, Child);
|
|
ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Copy the compressed name */
|
|
CmpCopyCompressedName(Name.Buffer,
|
|
Name.MaximumLength,
|
|
KeyNode->Name,
|
|
KeyNode->NameLength);
|
|
}
|
|
else
|
|
{
|
|
/* Remember for later */
|
|
IsCompressed = FALSE;
|
|
|
|
/* Build the unicode string */
|
|
Name.Length = KeyNode->NameLength;
|
|
Name.MaximumLength = KeyNode->NameLength;
|
|
Name.Buffer = &KeyNode->Name[0];
|
|
}
|
|
|
|
/* Release the cell */
|
|
HvReleaseCell(Hive, Child);
|
|
|
|
/* Get the parent node */
|
|
KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Parent);
|
|
if (!KeyNode)
|
|
{
|
|
/* Not handled */
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
/* Find out the type of the cell, and check if this is the first subkey */
|
|
Type = HvGetCellType(Child);
|
|
if (!KeyNode->SubKeyCounts[Type])
|
|
{
|
|
/* Allocate a fast leaf */
|
|
IndexCell = HvAllocateCell(Hive, sizeof(CM_KEY_FAST_INDEX), Type, HCELL_NIL);
|
|
if (IndexCell == HCELL_NIL)
|
|
{
|
|
/* Not handled */
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
/* Get the leaf cell */
|
|
Index = (PCM_KEY_INDEX)HvGetCell(Hive, IndexCell);
|
|
if (!Index)
|
|
{
|
|
/* Shouldn't happen */
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
/* Now check what kind of hive we're dealing with */
|
|
if (Hive->Version >= 5)
|
|
{
|
|
/* XP Hive: Use hash leaf */
|
|
Index->Signature = CM_KEY_HASH_LEAF;
|
|
}
|
|
else if (Hive->Version >= 3)
|
|
{
|
|
/* Windows 2000 and ReactOS: Use fast leaf */
|
|
Index->Signature = CM_KEY_FAST_LEAF;
|
|
}
|
|
else
|
|
{
|
|
/* NT 4: Use index leaf */
|
|
Index->Signature = CM_KEY_INDEX_LEAF;
|
|
}
|
|
|
|
/* Setup the index list */
|
|
Index->Count = 0;
|
|
KeyNode->SubKeyLists[Type] = IndexCell;
|
|
}
|
|
else
|
|
{
|
|
/* We already have an index, get it */
|
|
Index = (PCM_KEY_INDEX)HvGetCell(Hive, KeyNode->SubKeyLists[Type]);
|
|
if (!Index)
|
|
{
|
|
/* Not handled */
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
/* Remember to release the cell later */
|
|
CellToRelease = KeyNode->SubKeyLists[Type];
|
|
|
|
/* Check if this is a fast leaf that's gotten too full */
|
|
if ((Index->Signature == CM_KEY_FAST_LEAF) &&
|
|
(Index->Count >= CmpMaxFastIndexPerHblock))
|
|
{
|
|
DPRINT("Doing Fast->Slow Leaf conversion\n");
|
|
|
|
/* Mark this cell as dirty */
|
|
HvMarkCellDirty(Hive, CellToRelease, FALSE);
|
|
|
|
/* Convert */
|
|
OldIndex = (PCM_KEY_FAST_INDEX)Index;
|
|
|
|
for (i=0; i < OldIndex->Count; i++)
|
|
{
|
|
Index->List[i] = OldIndex->List[i].Cell;
|
|
}
|
|
|
|
/* Set the new type value */
|
|
Index->Signature = CM_KEY_INDEX_LEAF;
|
|
}
|
|
else if (((Index->Signature == CM_KEY_INDEX_LEAF) ||
|
|
(Index->Signature == CM_KEY_HASH_LEAF)) &&
|
|
(Index->Count >= CmpMaxIndexPerHblock))
|
|
{
|
|
/* This is an old/hashed leaf that's gotten too large, root it */
|
|
IndexCell = HvAllocateCell(Hive,
|
|
sizeof(CM_KEY_INDEX) +
|
|
sizeof(HCELL_INDEX),
|
|
Type,
|
|
HCELL_NIL);
|
|
if (IndexCell == HCELL_NIL)
|
|
{
|
|
/* Not handled */
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
/* Get the index cell */
|
|
Index = (PCM_KEY_INDEX)HvGetCell(Hive, IndexCell);
|
|
if (!Index)
|
|
{
|
|
/* Shouldn't happen */
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
/* Mark the index as a root, and set the index cell */
|
|
Index->Signature = CM_KEY_INDEX_ROOT;
|
|
Index->Count = 1;
|
|
Index->List[0] = KeyNode->SubKeyLists[Type];
|
|
KeyNode->SubKeyLists[Type] = IndexCell;
|
|
}
|
|
}
|
|
|
|
/* Now we can choose the leaf cell */
|
|
LeafCell = KeyNode->SubKeyLists[Type];
|
|
|
|
/* Check if we turned the index into a root */
|
|
if (Index->Signature == CM_KEY_INDEX_ROOT)
|
|
{
|
|
/* Not handled yet */
|
|
DPRINT1("Leaf->Root Index Conversion not yet implemented!\n");
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
/* Add our leaf cell */
|
|
LeafCell = CmpAddToLeaf(Hive, LeafCell, Child, &Name);
|
|
if (LeafCell == HCELL_NIL)
|
|
{
|
|
/* Not handled */
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
/* Update the key counts */
|
|
KeyNode->SubKeyCounts[Type]++;
|
|
|
|
/* Check if caller wants us to return the leaf */
|
|
if (RootPointer)
|
|
{
|
|
/* Return it */
|
|
*RootPointer = LeafCell;
|
|
}
|
|
else
|
|
{
|
|
/* Otherwise, mark it as the list index for the cell */
|
|
KeyNode->SubKeyLists[Type] = LeafCell;
|
|
}
|
|
|
|
/* If the name was compressed, free our copy */
|
|
if (IsCompressed) Hive->Free(Name.Buffer, 0);
|
|
|
|
/* Release all our cells */
|
|
if (IndexCell != HCELL_NIL) HvReleaseCell(Hive, IndexCell);
|
|
if (CellToRelease != HCELL_NIL) HvReleaseCell(Hive, CellToRelease);
|
|
HvReleaseCell(Hive, Parent);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
CmpRemoveSubKey(IN PHHIVE Hive,
|
|
IN HCELL_INDEX ParentKey,
|
|
IN HCELL_INDEX TargetKey)
|
|
{
|
|
PCM_KEY_NODE Node;
|
|
UNICODE_STRING SearchName;
|
|
BOOLEAN IsCompressed;
|
|
WCHAR Buffer[50];
|
|
HCELL_INDEX RootCell = HCELL_NIL, LeafCell, ChildCell;
|
|
PCM_KEY_INDEX Root = NULL, Leaf;
|
|
PCM_KEY_FAST_INDEX Child;
|
|
ULONG Storage, RootIndex = 0x80000000, LeafIndex;
|
|
BOOLEAN Result = FALSE;
|
|
HCELL_INDEX CellToRelease1 = HCELL_NIL, CellToRelease2 = HCELL_NIL;
|
|
|
|
/* Get the target key node */
|
|
Node = (PCM_KEY_NODE)HvGetCell(Hive, TargetKey);
|
|
if (!Node) return FALSE;
|
|
|
|
/* Make sure it's dirty, then release it */
|
|
ASSERT(HvIsCellDirty(Hive, TargetKey));
|
|
HvReleaseCell(Hive, TargetKey);
|
|
|
|
/* Check if the name is compressed */
|
|
if (Node->Flags & KEY_COMP_NAME)
|
|
{
|
|
/* Remember for later */
|
|
IsCompressed = TRUE;
|
|
|
|
/* Build the search name */
|
|
SearchName.Length = CmpCompressedNameSize(Node->Name,
|
|
Node->NameLength);
|
|
SearchName.MaximumLength = SearchName.Length;
|
|
|
|
/* Do we need an extra bufer? */
|
|
if (SearchName.MaximumLength > sizeof(Buffer))
|
|
{
|
|
/* Allocate one */
|
|
SearchName.Buffer = ExAllocatePoolWithTag(PagedPool,
|
|
SearchName.Length,
|
|
TAG_CM);
|
|
if (!SearchName.Buffer) return FALSE;
|
|
}
|
|
else
|
|
{
|
|
/* Otherwise, use our local stack buffer */
|
|
SearchName.Buffer = Buffer;
|
|
}
|
|
|
|
/* Copy the compressed name */
|
|
CmpCopyCompressedName(SearchName.Buffer,
|
|
SearchName.MaximumLength,
|
|
Node->Name,
|
|
Node->NameLength);
|
|
}
|
|
else
|
|
{
|
|
/* It's not compressed, build the name directly from the node */
|
|
IsCompressed = FALSE;
|
|
SearchName.Length = Node->NameLength;
|
|
SearchName.MaximumLength = Node->NameLength;
|
|
SearchName.Buffer = Node->Name;
|
|
}
|
|
|
|
/* Now get the parent node */
|
|
Node = (PCM_KEY_NODE)HvGetCell(Hive, ParentKey);
|
|
if (!Node) goto Exit;
|
|
|
|
/* Make sure it's dirty, then release it */
|
|
ASSERT(HvIsCellDirty(Hive, ParentKey));
|
|
HvReleaseCell(Hive, ParentKey);
|
|
|
|
/* Get the storage type and make sure it's not empty */
|
|
Storage = HvGetCellType(TargetKey);
|
|
ASSERT(Node->SubKeyCounts[Storage] != 0);
|
|
//ASSERT(HvIsCellAllocated(Hive, Node->SubKeyLists[Storage]));
|
|
|
|
/* Get the leaf cell now */
|
|
LeafCell = Node->SubKeyLists[Storage];
|
|
Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell);
|
|
if (!Leaf) goto Exit;
|
|
|
|
/* Remember to release it later */
|
|
CellToRelease1 = LeafCell;
|
|
|
|
/* Check if the leaf is a root */
|
|
if (Leaf->Signature == CM_KEY_INDEX_ROOT)
|
|
{
|
|
/* Find the child inside the root */
|
|
RootIndex = CmpFindSubKeyInRoot(Hive, Leaf, &SearchName, &ChildCell);
|
|
if (RootIndex & 0x80000000) goto Exit;
|
|
ASSERT(ChildCell != FALSE);
|
|
|
|
/* The root cell is now this leaf */
|
|
Root = Leaf;
|
|
RootCell = LeafCell;
|
|
|
|
/* And the new leaf is now this child */
|
|
LeafCell = ChildCell;
|
|
Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell);
|
|
if (!Leaf) goto Exit;
|
|
|
|
/* Remember to release it later */
|
|
CellToRelease2 = LeafCell;
|
|
}
|
|
|
|
/* Make sure the leaf is valid */
|
|
ASSERT((Leaf->Signature == CM_KEY_INDEX_LEAF) ||
|
|
(Leaf->Signature == CM_KEY_FAST_LEAF) ||
|
|
(Leaf->Signature == CM_KEY_HASH_LEAF));
|
|
|
|
/* Now get the child in the leaf */
|
|
LeafIndex = CmpFindSubKeyInLeaf(Hive, Leaf, &SearchName, &ChildCell);
|
|
if (LeafIndex & 0x80000000) goto Exit;
|
|
ASSERT(ChildCell != HCELL_NIL);
|
|
|
|
/* Decrement key counts and check if this was the last leaf entry */
|
|
Node->SubKeyCounts[Storage]--;
|
|
if (!(--Leaf->Count))
|
|
{
|
|
/* Free the leaf */
|
|
HvFreeCell(Hive, LeafCell);
|
|
|
|
/* Check if we were inside a root */
|
|
if (Root)
|
|
{
|
|
/* Decrease the root count too, since the leaf is going away */
|
|
if (!(--Root->Count))
|
|
{
|
|
/* The root is gone too,n ow */
|
|
HvFreeCell(Hive, RootCell);
|
|
Node->SubKeyLists[Storage] = HCELL_NIL;
|
|
}
|
|
else if (RootIndex < Root->Count)
|
|
{
|
|
/* Bring everything up by one */
|
|
RtlMoveMemory(&Root->List[RootIndex],
|
|
&Root->List[RootIndex + 1],
|
|
(Root->Count - RootIndex) * sizeof(HCELL_INDEX));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Otherwise, just clear the cell */
|
|
Node->SubKeyLists[Storage] = HCELL_NIL;
|
|
}
|
|
}
|
|
else if (LeafIndex < Leaf->Count)
|
|
{
|
|
/* Was the leaf a normal index? */
|
|
if (Leaf->Signature == CM_KEY_INDEX_LEAF)
|
|
{
|
|
/* Bring everything up by one */
|
|
RtlMoveMemory(&Leaf->List[LeafIndex],
|
|
&Leaf->List[LeafIndex + 1],
|
|
(Leaf->Count - LeafIndex) * sizeof(HCELL_INDEX));
|
|
}
|
|
else
|
|
{
|
|
/* This is a fast index, bring everything up by one */
|
|
Child = (PCM_KEY_FAST_INDEX)Leaf;
|
|
RtlMoveMemory(&Child->List[LeafIndex],
|
|
&Child->List[LeafIndex+1],
|
|
(Child->Count - LeafIndex) * sizeof(CM_INDEX));
|
|
}
|
|
}
|
|
|
|
/* If we got here, now we're done */
|
|
Result = TRUE;
|
|
|
|
Exit:
|
|
/* Release any cells we may have been holding */
|
|
if (CellToRelease1 != HCELL_NIL) HvReleaseCell(Hive, CellToRelease1);
|
|
if (CellToRelease2 != HCELL_NIL) HvReleaseCell(Hive, CellToRelease2);
|
|
|
|
/* Check if the name was compressed and not inside our local buffer */
|
|
if ((IsCompressed) && (SearchName.MaximumLength > sizeof(Buffer)))
|
|
{
|
|
/* Free the buffer we allocated */
|
|
ExFreePool(SearchName.Buffer);
|
|
}
|
|
|
|
/* Return the result */
|
|
return Result;
|
|
}
|