mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
899 lines
20 KiB
899 lines
20 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
cmsubs.c
|
|
|
|
Abstract:
|
|
|
|
This module various support routines for the configuration manager.
|
|
|
|
The routines in this module are not independent enough to be linked
|
|
into any other program. The routines in cmsubs2.c are.
|
|
|
|
Author:
|
|
|
|
Bryan M. Willman (bryanwi) 12-Sep-1991
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "cmp.h"
|
|
|
|
extern PCM_KEY_CONTROL_BLOCK CmpKeyControlBlockRoot;
|
|
FAST_MUTEX CmpKcbLock;
|
|
|
|
#define LOCK_KCB_TREE() ExAcquireFastMutex(&CmpKcbLock)
|
|
#define UNLOCK_KCB_TREE() ExReleaseFastMutex(&CmpKcbLock)
|
|
|
|
//
|
|
// private prototype for recursive worker
|
|
//
|
|
|
|
|
|
ULONG
|
|
CmpSearchOpenWorker(
|
|
PCM_KEY_CONTROL_BLOCK Current,
|
|
PVOID Context1,
|
|
PVOID Context2
|
|
);
|
|
|
|
VOID
|
|
CmpRemoveKeyControlBlockWithLock(
|
|
PCM_KEY_CONTROL_BLOCK KeyControlBlock
|
|
);
|
|
|
|
LONG
|
|
CmpFindKeyControlBlockWithLock(
|
|
IN PCM_KEY_CONTROL_BLOCK Root,
|
|
IN PHHIVE MatchHive,
|
|
IN HCELL_INDEX MatchCell,
|
|
OUT PCM_KEY_CONTROL_BLOCK *FoundName
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE,CmpCreateKeyControlBlock)
|
|
#pragma alloc_text(PAGE,CmpSearchForOpenSubKeys)
|
|
#pragma alloc_text(PAGE,CmpFindKeyControlBlock)
|
|
#pragma alloc_text(PAGE,CmpFindKeyControlBlockWithLock)
|
|
#pragma alloc_text(PAGE,CmpDereferenceKeyControlBlock)
|
|
#pragma alloc_text(PAGE,CmpRemoveKeyControlBlock)
|
|
#pragma alloc_text(PAGE,CmpRemoveKeyControlBlockWithLock)
|
|
#pragma alloc_text(PAGE,CmpFreeKeyBody)
|
|
#pragma alloc_text(PAGE,CmpSearchKeyControlBlockTree)
|
|
#pragma alloc_text(PAGE,CmpSearchOpenWorker)
|
|
#pragma alloc_text(PAGE,CmpReinsertKeyControlBlock)
|
|
#endif
|
|
|
|
PCM_KEY_CONTROL_BLOCK
|
|
CmpCreateKeyControlBlock(
|
|
PHHIVE Hive,
|
|
HCELL_INDEX Cell,
|
|
PCM_KEY_NODE Node,
|
|
PUNICODE_STRING BaseName,
|
|
PUNICODE_STRING KeyName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allocate and initialize a key control block, insert it into
|
|
the kcb tree.
|
|
|
|
Full path will be BaseName + '\' + KeyName, unless BaseName
|
|
NULL, in which case the full path is simply KeyName.
|
|
|
|
RefCount of returned KCB WILL have been incremented to reflect
|
|
callers ref.
|
|
|
|
Arguments:
|
|
|
|
Hive - Supplies Hive that holds the key we are creating a KCB for.
|
|
|
|
Cell - Supplies Cell that contains the key we are creating a KCB for.
|
|
|
|
Node - Supplies pointer to key node.
|
|
|
|
BaseName - path of cell relative to which kcb is created
|
|
|
|
KeyName - path relative to basename
|
|
|
|
Return Value:
|
|
|
|
NULL - failure (insufficient memory)
|
|
else a pointer to the new kcb.
|
|
|
|
--*/
|
|
{
|
|
PCM_KEY_CONTROL_BLOCK kcb;
|
|
PCM_KEY_CONTROL_BLOCK kcbmatch;
|
|
PCMHIVE CmHive;
|
|
ULONG namelength;
|
|
PUNICODE_STRING fullname;
|
|
ULONG Size;
|
|
|
|
|
|
LOCK_KCB_TREE();
|
|
//
|
|
// Create a new kcb, which we will free if one already exists
|
|
// for this key.
|
|
//
|
|
|
|
namelength = BaseName->Length + KeyName->Length;
|
|
if (KeyName->Length != 0 && KeyName->Buffer[0] != OBJ_NAME_PATH_SEPARATOR) {
|
|
namelength += sizeof(WCHAR);
|
|
}
|
|
|
|
Size = FIELD_OFFSET(CM_KEY_CONTROL_BLOCK, NameBuffer) + namelength;
|
|
|
|
kcb = ExAllocatePoolWithTag(PagedPool,
|
|
Size,
|
|
CM_KCB_TAG);
|
|
|
|
if (kcb == NULL) {
|
|
UNLOCK_KCB_TREE();
|
|
return(NULL);
|
|
} else {
|
|
kcb->Delete = FALSE;
|
|
kcb->RefCount = 0;
|
|
kcb->KeyHive = Hive;
|
|
kcb->KeyCell = Cell;
|
|
kcb->KeyNode = Node;
|
|
|
|
kcb->Parent = NULL;
|
|
kcb->Left = NULL;
|
|
kcb->Right = NULL;
|
|
|
|
fullname = &(kcb->FullName);
|
|
fullname->Length = 0;
|
|
fullname->MaximumLength = (USHORT)namelength;
|
|
fullname->Buffer = &(kcb->NameBuffer[0]);
|
|
|
|
|
|
if (BaseName->Length > 0) {
|
|
RtlAppendStringToString(
|
|
(PSTRING)fullname,
|
|
(PSTRING)BaseName
|
|
);
|
|
}
|
|
if (KeyName->Length != 0 && KeyName->Buffer[0] != OBJ_NAME_PATH_SEPARATOR) {
|
|
fullname->Buffer[(fullname->Length)/sizeof(WCHAR)] =
|
|
OBJ_NAME_PATH_SEPARATOR;
|
|
fullname->Length += sizeof(WCHAR);
|
|
}
|
|
RtlAppendStringToString(
|
|
(PSTRING)fullname,
|
|
(PSTRING)KeyName
|
|
);
|
|
}
|
|
|
|
//
|
|
// Find location to insert kcb in kcb tree.
|
|
//
|
|
|
|
CmHive = CONTAINING_RECORD(Hive, CMHIVE, Hive);
|
|
|
|
if (CmpKeyControlBlockRoot != NULL) {
|
|
switch (CmpFindKeyControlBlockWithLock(CmpKeyControlBlockRoot,
|
|
Hive,
|
|
Cell,
|
|
&kcbmatch)) {
|
|
case 0:
|
|
// match
|
|
ExFreePool(kcb);
|
|
kcb = kcbmatch;
|
|
break;
|
|
|
|
case -1:
|
|
// no match, left child
|
|
kcbmatch->Left = kcb;
|
|
kcb->Parent = kcbmatch;
|
|
CmHive->KcbCount++;
|
|
break;
|
|
|
|
case 1:
|
|
// no match, right child
|
|
kcbmatch->Right = kcb;
|
|
kcb->Parent = kcbmatch;
|
|
CmHive->KcbCount++;
|
|
break;
|
|
|
|
default:
|
|
KeBugCheckEx(REGISTRY_ERROR,4,1,0,0);
|
|
break;
|
|
}
|
|
} else {
|
|
CmHive->KcbCount++;
|
|
CmpKeyControlBlockRoot = kcb;
|
|
}
|
|
|
|
++kcb->RefCount;
|
|
|
|
UNLOCK_KCB_TREE();
|
|
|
|
return kcb;
|
|
}
|
|
|
|
|
|
ULONG
|
|
CmpSearchOpenWorker(
|
|
PCM_KEY_CONTROL_BLOCK Current,
|
|
PVOID Context1,
|
|
PVOID Context2
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Helper used by CmpSearchForOpenSubKeys when calling
|
|
CmpSearchKeyControlBlockTree. Stops on first match.
|
|
Finding whether at least one match exists is goal.
|
|
|
|
Arguments:
|
|
|
|
Current - the kcb to examine
|
|
|
|
Context1 - the name to match
|
|
|
|
Context2 - pointer to boolean to hold result
|
|
|
|
Return Value:
|
|
|
|
0 - not done - keep going
|
|
|
|
1 - done - stop - returned on first match
|
|
|
|
2 - restart - won't happen
|
|
|
|
--*/
|
|
{
|
|
PBOOLEAN result;
|
|
|
|
result = (PBOOLEAN)Context2;
|
|
if ( RtlPrefixUnicodeString(
|
|
(PUNICODE_STRING)Context1,
|
|
&(Current->FullName),
|
|
TRUE
|
|
)
|
|
)
|
|
{
|
|
//
|
|
// we have a match
|
|
// set return data to TRUE (found) and function return TRUE (done)
|
|
//
|
|
*result = TRUE;
|
|
return KCB_WORKER_DONE;
|
|
}
|
|
return KCB_WORKER_CONTINUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
CmpSearchForOpenSubKeys(
|
|
IN PCM_KEY_CONTROL_BLOCK SearchKey
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine searches the KCB tree for any open handles to keys that
|
|
are subkeys of the given key.
|
|
|
|
It is used by CmRestoreKey to verify that the tree being restored to
|
|
has no open handles.
|
|
|
|
Arguments:
|
|
|
|
SearchKey - Supplies the key control block for the key for which
|
|
open subkeys are to be found.
|
|
|
|
Return Value:
|
|
|
|
TRUE - open handles to subkeys of the given key exist
|
|
|
|
FALSE - open handles to subkeys of the given key do not exist.
|
|
|
|
--*/
|
|
|
|
{
|
|
UNICODE_STRING PrefixName;
|
|
BOOLEAN Found;
|
|
|
|
ASSERT_CM_LOCK_OWNED();
|
|
|
|
if (CmpKeyControlBlockRoot == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Build up a name to be used as the prefix for searching the kcb
|
|
// tree. This is just the canonical path of the key (stored in the
|
|
// kcb) with a trailing '\' appended. Any subkeys of the key will
|
|
// have this name as a prefix of their canonical path.
|
|
//
|
|
|
|
PrefixName.Length = 0;
|
|
PrefixName.MaximumLength = SearchKey->FullName.Length +
|
|
sizeof(OBJ_NAME_PATH_SEPARATOR);
|
|
PrefixName.Buffer = ExAllocatePool(PagedPool, PrefixName.MaximumLength);
|
|
if (PrefixName.Buffer == NULL) {
|
|
return(TRUE);
|
|
}
|
|
|
|
RtlCopyUnicodeString(&PrefixName, &SearchKey->FullName);
|
|
PrefixName.Buffer[PrefixName.Length/sizeof(WCHAR)] = OBJ_NAME_PATH_SEPARATOR;
|
|
PrefixName.Length += sizeof(WCHAR);
|
|
|
|
Found = FALSE;
|
|
|
|
LOCK_KCB_TREE();
|
|
CmpSearchKeyControlBlockTree(
|
|
CmpSearchOpenWorker,
|
|
(PVOID)&PrefixName,
|
|
&Found
|
|
);
|
|
UNLOCK_KCB_TREE();
|
|
|
|
ExFreePool(PrefixName.Buffer);
|
|
|
|
return(Found);
|
|
}
|
|
|
|
|
|
VOID
|
|
CmpSearchKeyControlBlockTree(
|
|
PKCB_WORKER_ROUTINE WorkerRoutine,
|
|
PVOID Context1,
|
|
PVOID Context2
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Traverse the kcb tree. We will visit all nodes unless WorkerRoutine
|
|
tells us to stop part way through.
|
|
|
|
For each node, call WorkerRoutine(..., Context1, Contex2). If it returns
|
|
KCB_WORKER_DONE, we are done, simply return. If it returns
|
|
KCB_WORKER_CONTINUE, just continue the search.
|
|
|
|
If the worker returns KCB_WORKER_RESTART, restart the search from
|
|
the beginning.
|
|
|
|
WARNING: If worker routine modified KCB tree in any way, it
|
|
MUST return KCB_WORKER_RESTART.
|
|
|
|
Arguments:
|
|
|
|
WorkerRoutine - applied to nodes witch Match.
|
|
|
|
Context1 - data we pass through
|
|
|
|
Context2 - data we pass through
|
|
|
|
|
|
Return Value:
|
|
|
|
NONE.
|
|
|
|
--*/
|
|
{
|
|
PCM_KEY_CONTROL_BLOCK Current;
|
|
PCM_KEY_CONTROL_BLOCK Last;
|
|
ULONG WorkerResult;
|
|
|
|
restart:
|
|
Current = CmpKeyControlBlockRoot;
|
|
Last = (PCM_KEY_CONTROL_BLOCK)-1; // NOT NULL!
|
|
|
|
while (TRUE) {
|
|
|
|
ASSERT(Current != Last);
|
|
|
|
//
|
|
// Check left subtree, if right tree is Last, we were Last before it.
|
|
//
|
|
if (Current->Left != NULL) {
|
|
if ( (Current->Left != Last) &&
|
|
(Current->Right != Last))
|
|
{
|
|
Current = Current->Left;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check right subtree. if left is Last, means we're next (not Last)
|
|
//
|
|
if (Current->Right != NULL) {
|
|
if (Current->Right != Last) {
|
|
Current = Current->Right;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check self
|
|
//
|
|
WorkerResult = (WorkerRoutine)(Current, Context1, Context2);
|
|
|
|
if (WorkerResult == KCB_WORKER_RESTART) {
|
|
goto restart;
|
|
}
|
|
|
|
if (WorkerResult == KCB_WORKER_DONE) {
|
|
return;
|
|
}
|
|
|
|
ASSERT(WorkerResult == KCB_WORKER_CONTINUE);
|
|
|
|
if (Current == CmpKeyControlBlockRoot) {
|
|
return;
|
|
}
|
|
|
|
Last = Current;
|
|
Current = Current->Parent;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
|
|
LONG
|
|
CmpFindKeyControlBlock(
|
|
IN PCM_KEY_CONTROL_BLOCK Root,
|
|
IN PHHIVE MatchHive,
|
|
IN HCELL_INDEX MatchCell,
|
|
OUT PCM_KEY_CONTROL_BLOCK *FoundName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Root - Supplies pointer to root of kcb tree or subtree to search
|
|
|
|
MatchHive - Supplies Hive of key to look for
|
|
|
|
MatchCell - Supplies Cell of key to look for
|
|
|
|
FoundName - Returnspointer to the matched entry in the tree, OR, pointer
|
|
to entry in tree that will be parent of MatchName if it is
|
|
added.
|
|
|
|
Return Value:
|
|
|
|
0 - match, FoundName points to matching kcb entry
|
|
-1 - no match, MatchName would be the left child of FoundName
|
|
+1 - no match, MatchName would be the right child of FoundName
|
|
|
|
--*/
|
|
{
|
|
LONG result;
|
|
|
|
ASSERT(Root != NULL);
|
|
|
|
LOCK_KCB_TREE();
|
|
|
|
result = CmpFindKeyControlBlockWithLock(Root,
|
|
MatchHive,
|
|
MatchCell,
|
|
FoundName);
|
|
|
|
UNLOCK_KCB_TREE();
|
|
return result;
|
|
}
|
|
|
|
LONG
|
|
CmpFindKeyControlBlockWithLock(
|
|
IN PCM_KEY_CONTROL_BLOCK Root,
|
|
IN PHHIVE MatchHive,
|
|
IN HCELL_INDEX MatchCell,
|
|
OUT PCM_KEY_CONTROL_BLOCK *FoundName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Finds a key control block. The KCB lock is assumed to be held.
|
|
|
|
Arguments:
|
|
|
|
Root - Supplies pointer to root of kcb tree or subtree to search
|
|
|
|
MatchHive - Supplies Hive of key to look for
|
|
|
|
MatchCell - Supplies Cell of key to look for
|
|
|
|
FoundName - Returnspointer to the matched entry in the tree, OR, pointer
|
|
to entry in tree that will be parent of MatchName if it is
|
|
added.
|
|
|
|
Return Value:
|
|
|
|
0 - match, FoundName points to matching kcb entry
|
|
-1 - no match, MatchName would be the left child of FoundName
|
|
+1 - no match, MatchName would be the right child of FoundName
|
|
|
|
--*/
|
|
{
|
|
PCM_KEY_CONTROL_BLOCK p;
|
|
LONG cr;
|
|
LONG result;
|
|
|
|
ASSERT(Root != NULL);
|
|
|
|
p = Root;
|
|
|
|
while (TRUE) {
|
|
|
|
cr = (MatchHive - p->KeyHive);
|
|
if (cr==0) {
|
|
//
|
|
// Hives match, so compare the Cells
|
|
//
|
|
cr = ((ULONG)MatchCell - (ULONG)(p->KeyCell));
|
|
}
|
|
|
|
if (cr == 0) {
|
|
|
|
// match
|
|
result = 0;
|
|
break;
|
|
|
|
} else if (cr < 0) {
|
|
|
|
// kcb < p
|
|
if (p->Left == NULL) {
|
|
result = -1;
|
|
break;
|
|
}
|
|
p = p->Left;
|
|
|
|
} else {
|
|
|
|
// (cr > 0) -> kcb > p
|
|
if (p->Right == NULL) {
|
|
result = +1;
|
|
break;
|
|
}
|
|
p = p->Right;
|
|
}
|
|
}
|
|
|
|
*FoundName = p;
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
VOID
|
|
CmpDereferenceKeyControlBlock(
|
|
PCM_KEY_CONTROL_BLOCK KeyControlBlock
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Decrements the reference count on a key control block, and frees it if it
|
|
becomes zero.
|
|
|
|
It is expected that no notify control blocks remain if the reference count
|
|
becomes zero.
|
|
|
|
Arguments:
|
|
|
|
KeyControlBlock - pointer to a key control block.
|
|
|
|
Return Value:
|
|
|
|
NONE.
|
|
|
|
--*/
|
|
{
|
|
|
|
LOCK_KCB_TREE();
|
|
if (--KeyControlBlock->RefCount == 0) {
|
|
|
|
|
|
//
|
|
// Remove kcb from the tree, if it's in the tree
|
|
//
|
|
if (KeyControlBlock->Parent != NULL) {
|
|
CmpRemoveKeyControlBlockWithLock(KeyControlBlock);
|
|
}
|
|
|
|
//
|
|
// Free storage
|
|
//
|
|
ExFreePool(KeyControlBlock);
|
|
|
|
}
|
|
UNLOCK_KCB_TREE();
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
CmpRemoveKeyControlBlock(
|
|
PCM_KEY_CONTROL_BLOCK KeyControlBlock
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Remove a key control block from the KCB tree.
|
|
|
|
It is expected that no notify control blocks remain. Child
|
|
and parent pointers will be nulled out.
|
|
|
|
The kcb will NOT be freed, call DereferenceKeyControlBlock for that.
|
|
|
|
Arguments:
|
|
|
|
KeyControlBlock - pointer to a key control block.
|
|
|
|
Return Value:
|
|
|
|
NONE.
|
|
|
|
--*/
|
|
{
|
|
|
|
LOCK_KCB_TREE();
|
|
|
|
CmpRemoveKeyControlBlockWithLock(KeyControlBlock);
|
|
|
|
UNLOCK_KCB_TREE();
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
CmpRemoveKeyControlBlockWithLock(
|
|
PCM_KEY_CONTROL_BLOCK KeyControlBlock
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Remove a key control block from the KCB tree.
|
|
|
|
It is expected that no notify control blocks remain. Child
|
|
and parent pointers will be nulled out.
|
|
|
|
The kcb will NOT be freed, call DereferenceKeyControlBlock for that.
|
|
|
|
This call assumes the KCB tree is already locked.
|
|
|
|
Arguments:
|
|
|
|
KeyControlBlock - pointer to a key control block.
|
|
|
|
Return Value:
|
|
|
|
NONE.
|
|
|
|
--*/
|
|
{
|
|
PCM_KEY_CONTROL_BLOCK Left;
|
|
PCM_KEY_CONTROL_BLOCK Right;
|
|
PCM_KEY_CONTROL_BLOCK Parent;
|
|
PCM_KEY_CONTROL_BLOCK newparent;
|
|
PCMHIVE CmHive;
|
|
|
|
ASSERT(KeyControlBlock != CmpKeyControlBlockRoot);
|
|
|
|
//
|
|
// Capture Left, Right, and Parent pointers
|
|
//
|
|
Left = KeyControlBlock->Left;
|
|
Right = KeyControlBlock->Right;
|
|
Parent = KeyControlBlock->Parent;
|
|
|
|
ASSERT((Parent->Left == KeyControlBlock) ||
|
|
(Parent->Right == KeyControlBlock));
|
|
|
|
//
|
|
// Snip out of parent, reinsert children
|
|
//
|
|
if (Parent->Left == KeyControlBlock) {
|
|
Parent->Left = Left;
|
|
if (Left != NULL) {
|
|
Left->Parent = Parent;
|
|
}
|
|
if (Right != NULL) {
|
|
switch (CmpFindKeyControlBlockWithLock(Parent,
|
|
Right->KeyHive,
|
|
Right->KeyCell,
|
|
&newparent)) {
|
|
case -1:
|
|
newparent->Left = Right;
|
|
break;
|
|
|
|
case +1:
|
|
newparent->Right = Right;
|
|
break;
|
|
|
|
default:
|
|
KeBugCheckEx(REGISTRY_ERROR,4,2,0,0);
|
|
break;
|
|
}
|
|
Right->Parent = newparent;
|
|
}
|
|
} else {
|
|
Parent->Right = Right;
|
|
if (Right != NULL) {
|
|
Right->Parent = Parent;
|
|
}
|
|
if (Left != NULL) {
|
|
switch (CmpFindKeyControlBlockWithLock(Parent,
|
|
Left->KeyHive,
|
|
Left->KeyCell,
|
|
&newparent)) {
|
|
case -1:
|
|
newparent->Left = Left;
|
|
break;
|
|
|
|
case +1:
|
|
newparent->Right = Left;
|
|
break;
|
|
|
|
default:
|
|
KeBugCheckEx(REGISTRY_ERROR,4,3,0,0);
|
|
break;
|
|
}
|
|
Left->Parent = newparent;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Decrement hive's reference count.
|
|
//
|
|
CmHive = CONTAINING_RECORD(KeyControlBlock->KeyHive, CMHIVE, Hive);
|
|
CmHive->KcbCount -= 1;
|
|
|
|
//
|
|
// Sanitize the record
|
|
//
|
|
KeyControlBlock->Left = NULL;
|
|
KeyControlBlock->Right = NULL;
|
|
KeyControlBlock->Parent = NULL;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
CmpReinsertKeyControlBlock(
|
|
PCM_KEY_CONTROL_BLOCK KeyControlBlock
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Removes a key control block from the KCB tree and reinserts it.
|
|
|
|
This is intended to be used when the HCELL_INDEX of a key changes
|
|
(RestoreKey) to move the KCB to its new place in the tree.
|
|
|
|
Arguments:
|
|
|
|
KeyControlBlock - pointer to a key control block.
|
|
|
|
Return Value:
|
|
|
|
NONE.
|
|
|
|
--*/
|
|
{
|
|
PCM_KEY_CONTROL_BLOCK newparent;
|
|
PCMHIVE CmHive;
|
|
|
|
LOCK_KCB_TREE();
|
|
|
|
ASSERT(KeyControlBlock != CmpKeyControlBlockRoot);
|
|
CmHive = CONTAINING_RECORD(KeyControlBlock->KeyHive, CMHIVE, Hive);
|
|
|
|
//
|
|
// First remove the KCB from the tree.
|
|
//
|
|
CmpRemoveKeyControlBlockWithLock(KeyControlBlock);
|
|
|
|
//
|
|
// Now reinsert the KCB in the tree.
|
|
//
|
|
switch (CmpFindKeyControlBlockWithLock(CmpKeyControlBlockRoot,
|
|
KeyControlBlock->KeyHive,
|
|
KeyControlBlock->KeyCell,
|
|
&newparent)) {
|
|
case -1:
|
|
//
|
|
// left child
|
|
//
|
|
newparent->Left = KeyControlBlock;
|
|
KeyControlBlock->Parent = newparent;
|
|
break;
|
|
|
|
case 1:
|
|
//
|
|
// right child
|
|
//
|
|
newparent->Right = KeyControlBlock;
|
|
KeyControlBlock->Parent = newparent;
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// we should never find this, since we just removed it!
|
|
//
|
|
KeBugCheckEx(REGISTRY_ERROR,
|
|
4, 4,
|
|
(ULONG)KeyControlBlock,
|
|
(ULONG)newparent);
|
|
|
|
}
|
|
|
|
CmHive->KcbCount++; // CmpRemoveKeyControlBlock dereferenced this
|
|
UNLOCK_KCB_TREE();
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
CmpFreeKeyBody(
|
|
PHHIVE Hive,
|
|
HCELL_INDEX Cell
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free storage for the key entry Hive.Cell refers to, including
|
|
its class and security data. Will NOT free child list or value list.
|
|
|
|
Arguments:
|
|
|
|
Hive - supplies a pointer to the hive control structure for the hive
|
|
|
|
Cell - supplies index of key to free
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Result code from call, among the following:
|
|
|
|
<TBS>
|
|
|
|
--*/
|
|
{
|
|
PCELL_DATA key;
|
|
|
|
//
|
|
// map in the cell
|
|
//
|
|
key = HvGetCell(Hive, Cell);
|
|
|
|
if (!(key->u.KeyNode.Flags & KEY_HIVE_EXIT)) {
|
|
if (key->u.KeyNode.u1.s1.Security != HCELL_NIL) {
|
|
HvFreeCell(Hive, key->u.KeyNode.u1.s1.Security);
|
|
}
|
|
|
|
if (key->u.KeyNode.ClassLength > 0) {
|
|
HvFreeCell(Hive, key->u.KeyNode.u1.s1.Class);
|
|
}
|
|
}
|
|
|
|
//
|
|
// unmap the cell itself and free it
|
|
//
|
|
HvFreeCell(Hive, Cell);
|
|
|
|
return;
|
|
}
|