553 lines
14 KiB
C
553 lines
14 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1992 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
cmtredel.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This file contains code for CmpDeleteTree, and support.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Bryan M. Willman (bryanwi) 24-Jan-92
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "cmp.h"
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text(PAGE,CmpDeleteTree)
|
|||
|
#pragma alloc_text(PAGE,CmpFreeKeyByCell)
|
|||
|
#pragma alloc_text(PAGE,CmpMarkKeyDirty)
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Routine to actually call to do a tree delete
|
|||
|
//
|
|||
|
|
|||
|
VOID
|
|||
|
CmpDeleteTree(
|
|||
|
PHHIVE Hive,
|
|||
|
HCELL_INDEX Cell
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Delete all child subkeys, recursively, of Hive.Cell. Delete all
|
|||
|
value entries of Hive.Cell. Do NOT delete Hive.Cell itself.
|
|||
|
|
|||
|
NOTE: If this call fails part way through, it will NOT undo
|
|||
|
any successfully completed deletes.
|
|||
|
|
|||
|
NOTE: This algorithm can deal with a hive of any depth, at the
|
|||
|
cost of some "redundent" scaning and mapping.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Hive - pointer to hive control structure for hive to delete from
|
|||
|
|
|||
|
Cell - index of cell at root of tree to delete
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
BOOLEAN - Result code from call, among the following:
|
|||
|
TRUE - it worked
|
|||
|
FALSE - the tree delete was not completed (though more than 0
|
|||
|
keys may have been deleted)
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
ULONG count;
|
|||
|
HCELL_INDEX ptr1;
|
|||
|
HCELL_INDEX ptr2;
|
|||
|
HCELL_INDEX parent;
|
|||
|
PCM_KEY_NODE Node;
|
|||
|
|
|||
|
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SAVRES,"CmpDeleteTree:\n"));
|
|||
|
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_SAVRES,"\tHive=%p Cell=%08lx\n",Hive,Cell));
|
|||
|
|
|||
|
//
|
|||
|
// we have the lock exclusive or nobody is operating inside this hive
|
|||
|
//
|
|||
|
//ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
|
|||
|
ASSERT_CM_EXCLUSIVE_HIVE_ACCESS(Hive);
|
|||
|
|
|||
|
ptr1 = Cell;
|
|||
|
|
|||
|
while(TRUE) {
|
|||
|
|
|||
|
Node = (PCM_KEY_NODE)HvGetCell(Hive, ptr1);
|
|||
|
if( Node == NULL ) {
|
|||
|
//
|
|||
|
// we couldn't map the bin containing this cell
|
|||
|
// bad luck! we cannot delete this tree
|
|||
|
//
|
|||
|
return;
|
|||
|
}
|
|||
|
count = Node->SubKeyCounts[Stable] +
|
|||
|
Node->SubKeyCounts[Volatile];
|
|||
|
parent = Node->Parent;
|
|||
|
|
|||
|
if (count > 0) { // ptr1->count > 0?
|
|||
|
|
|||
|
//
|
|||
|
// subkeys exist, find and delete them
|
|||
|
//
|
|||
|
ptr2 = CmpFindSubKeyByNumber(Hive, Node, 0);
|
|||
|
|
|||
|
//
|
|||
|
// release the cell here as we are overriding node
|
|||
|
//
|
|||
|
HvReleaseCell(Hive, ptr1);
|
|||
|
|
|||
|
if( ptr2 == HCELL_NIL ) {
|
|||
|
//
|
|||
|
// we couldn't map view inside
|
|||
|
// bad luck! we cannot delete this tree
|
|||
|
//
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
Node = (PCM_KEY_NODE)HvGetCell(Hive, ptr2);
|
|||
|
if( Node == NULL ) {
|
|||
|
//
|
|||
|
// we couldn't map the bin containing this cell
|
|||
|
// bad luck! we cannot delete this tree
|
|||
|
//
|
|||
|
return;
|
|||
|
}
|
|||
|
count = Node->SubKeyCounts[Stable] +
|
|||
|
Node->SubKeyCounts[Volatile];
|
|||
|
|
|||
|
//
|
|||
|
// release the cell here as we don't need it anymore
|
|||
|
//
|
|||
|
HvReleaseCell(Hive, ptr2);
|
|||
|
if (count > 0) { // ptr2->count > 0?
|
|||
|
|
|||
|
//
|
|||
|
// subkey has subkeys, descend to next level
|
|||
|
//
|
|||
|
ptr1 = ptr2;
|
|||
|
continue;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// have found leaf, delete it
|
|||
|
//
|
|||
|
CmpFreeKeyByCell(Hive, ptr2, TRUE);
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
//
|
|||
|
// release the cell here as we don't need it anymore
|
|||
|
//
|
|||
|
HvReleaseCell(Hive, ptr1);
|
|||
|
|
|||
|
//
|
|||
|
// no more subkeys at this level, we are now a leaf.
|
|||
|
//
|
|||
|
if (ptr1 != Cell) {
|
|||
|
|
|||
|
//
|
|||
|
// we are not at the root cell, so ascend to parent
|
|||
|
//
|
|||
|
ptr1 = parent; // ptr1 = ptr1->parent
|
|||
|
continue;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// we are at the root cell, we are done
|
|||
|
//
|
|||
|
return;
|
|||
|
}
|
|||
|
} // outer if
|
|||
|
} // while
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
CmpFreeKeyByCell(
|
|||
|
PHHIVE Hive,
|
|||
|
HCELL_INDEX Cell,
|
|||
|
BOOLEAN Unlink
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Actually free the storage for the specified cell. We will first
|
|||
|
remove it from its parent's child key list, then free all of its
|
|||
|
values, then the key body itself.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Hive - pointer to hive control structure for hive of interest
|
|||
|
|
|||
|
Cell - index for cell to free storage for (the target)
|
|||
|
|
|||
|
Unlink - if TRUE, target cell will be removed from parent cell's
|
|||
|
subkeylist, if FALSE, it will NOT be.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NONE.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PCELL_DATA ptarget;
|
|||
|
PCELL_DATA pparent;
|
|||
|
PCELL_DATA plist;
|
|||
|
ULONG i;
|
|||
|
|
|||
|
//
|
|||
|
// we have the lock exclusive or nobody is operating inside this hive
|
|||
|
//
|
|||
|
//ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
|
|||
|
ASSERT_CM_EXCLUSIVE_HIVE_ACCESS(Hive);
|
|||
|
|
|||
|
//
|
|||
|
// Mark dirty everything that we might touch
|
|||
|
//
|
|||
|
if (! CmpMarkKeyDirty(Hive, Cell
|
|||
|
#if DBG
|
|||
|
,TRUE
|
|||
|
#endif //DBG
|
|||
|
)) {
|
|||
|
return STATUS_NO_LOG_SPACE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Map in the target
|
|||
|
//
|
|||
|
ptarget = HvGetCell(Hive, Cell);
|
|||
|
if( ptarget == NULL ) {
|
|||
|
//
|
|||
|
// we couldn't map the bin containing this cell
|
|||
|
// we shouldn't hit this as we just marked the cell dirty
|
|||
|
//
|
|||
|
ASSERT( FALSE );
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
//
|
|||
|
// release the cell here as it is dirty(pinned); it cannot go anywhere
|
|||
|
//
|
|||
|
HvReleaseCell(Hive, Cell);
|
|||
|
|
|||
|
ASSERT((ptarget->u.KeyNode.SubKeyCounts[Stable] +
|
|||
|
ptarget->u.KeyNode.SubKeyCounts[Volatile]) == 0);
|
|||
|
|
|||
|
|
|||
|
if (Unlink == TRUE) {
|
|||
|
BOOLEAN Success;
|
|||
|
|
|||
|
Success = CmpRemoveSubKey(Hive, ptarget->u.KeyNode.Parent, Cell);
|
|||
|
if (!Success) {
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
pparent = HvGetCell(Hive, ptarget->u.KeyNode.Parent);
|
|||
|
if( pparent == NULL ) {
|
|||
|
//
|
|||
|
// we couldn't map the bin containing this cell
|
|||
|
// we shouldn't hit this as we just marked the cell dirty
|
|||
|
//
|
|||
|
ASSERT( FALSE );
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// release the cell here as it is dirty(pinned); it cannot go anywhere
|
|||
|
//
|
|||
|
HvReleaseCell(Hive, ptarget->u.KeyNode.Parent);
|
|||
|
|
|||
|
if ( (pparent->u.KeyNode.SubKeyCounts[Stable] +
|
|||
|
pparent->u.KeyNode.SubKeyCounts[Volatile]) == 0)
|
|||
|
{
|
|||
|
pparent->u.KeyNode.MaxNameLen = 0;
|
|||
|
pparent->u.KeyNode.MaxClassLen = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Target is now an unreferenced key, free it's actual storage
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Free misc stuff
|
|||
|
//
|
|||
|
if (!(ptarget->u.KeyNode.Flags & KEY_HIVE_EXIT) &&
|
|||
|
!(ptarget->u.KeyNode.Flags & KEY_PREDEF_HANDLE) ) {
|
|||
|
|
|||
|
//
|
|||
|
// First, free the value entries
|
|||
|
//
|
|||
|
if (ptarget->u.KeyNode.ValueList.Count > 0) {
|
|||
|
|
|||
|
// target list
|
|||
|
plist = HvGetCell(Hive, ptarget->u.KeyNode.ValueList.List);
|
|||
|
if( plist == NULL ) {
|
|||
|
//
|
|||
|
// we couldn't map the bin containing this cell
|
|||
|
// we shouldn't hit this as we just marked the cell dirty
|
|||
|
//
|
|||
|
ASSERT( FALSE );
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
//
|
|||
|
// release the cell here as it is dirty(pinned); it cannot go anywhere
|
|||
|
//
|
|||
|
HvReleaseCell(Hive, ptarget->u.KeyNode.ValueList.List);
|
|||
|
|
|||
|
for (i = 0; i < ptarget->u.KeyNode.ValueList.Count; i++) {
|
|||
|
//
|
|||
|
// even if we cannot free the value here, we ignore it.
|
|||
|
// nothing bad happens (just some leaks)
|
|||
|
//
|
|||
|
if( CmpFreeValue(Hive, plist->u.KeyList[i]) == FALSE ) {
|
|||
|
//
|
|||
|
// we couldn't map view inside call above
|
|||
|
// this shouldn't happen as we just marked the values dirty
|
|||
|
// (i.e. they should be PINNED into memory by now)
|
|||
|
//
|
|||
|
ASSERT( FALSE );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
HvFreeCell(Hive, ptarget->u.KeyNode.ValueList.List);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free the security descriptor
|
|||
|
//
|
|||
|
CmpFreeSecurityDescriptor(Hive, Cell);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free the key body itself, and Class data.
|
|||
|
//
|
|||
|
if( CmpFreeKeyBody(Hive, Cell) == FALSE ) {
|
|||
|
//
|
|||
|
// couldn't map view inside
|
|||
|
//
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
CmpMarkKeyDirty(
|
|||
|
PHHIVE Hive,
|
|||
|
HCELL_INDEX Cell
|
|||
|
#if DBG
|
|||
|
,
|
|||
|
BOOLEAN CheckNoSubkeys
|
|||
|
#endif
|
|||
|
)
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Mark all of the cells related to a key being deleted dirty.
|
|||
|
Includes the parent, the parent's child list, the key body,
|
|||
|
class, security, all value entry bodies, and all of their data cells.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Hive - pointer to hive control structure for hive of interest
|
|||
|
|
|||
|
Cell - index for cell holding keybody to make dirty
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
TRUE - it worked
|
|||
|
|
|||
|
FALSE - some error, most likely cannot get log space
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PCELL_DATA ptarget;
|
|||
|
PCELL_DATA plist;
|
|||
|
PCELL_DATA security;
|
|||
|
PCELL_DATA pvalue;
|
|||
|
ULONG i;
|
|||
|
ULONG realsize;
|
|||
|
|
|||
|
//
|
|||
|
// we have the lock exclusive or nobody is operating inside this hive
|
|||
|
//
|
|||
|
//ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
|
|||
|
ASSERT_CM_EXCLUSIVE_HIVE_ACCESS(Hive);
|
|||
|
|
|||
|
//
|
|||
|
// Map in the target
|
|||
|
//
|
|||
|
ptarget = HvGetCell(Hive, Cell);
|
|||
|
if( ptarget == NULL ) {
|
|||
|
//
|
|||
|
// we couldn't map the bin containing this cell
|
|||
|
//
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
#if DBG
|
|||
|
if(CheckNoSubkeys == TRUE) {
|
|||
|
ASSERT(ptarget->u.KeyNode.SubKeyCounts[Stable] == 0);
|
|||
|
ASSERT(ptarget->u.KeyNode.SubKeyCounts[Volatile] == 0);
|
|||
|
}
|
|||
|
#endif //DBG
|
|||
|
|
|||
|
if (ptarget->u.KeyNode.Flags & KEY_HIVE_EXIT) {
|
|||
|
|
|||
|
//
|
|||
|
// If this is a link node, we are done. Link nodes never have
|
|||
|
// classes, values, subkeys, or security descriptors. Since
|
|||
|
// they always reside in the master hive, they're always volatile.
|
|||
|
//
|
|||
|
HvReleaseCell(Hive, Cell);
|
|||
|
return(TRUE);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// mark cell itself
|
|||
|
//
|
|||
|
if (! HvMarkCellDirty(Hive, Cell)) {
|
|||
|
HvReleaseCell(Hive, Cell);
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
//
|
|||
|
// we can safely release it here, as it is now dirty/pinned
|
|||
|
//
|
|||
|
HvReleaseCell(Hive, Cell);
|
|||
|
|
|||
|
//
|
|||
|
// Mark the class
|
|||
|
//
|
|||
|
if (ptarget->u.KeyNode.Class != HCELL_NIL) {
|
|||
|
if (! HvMarkCellDirty(Hive, ptarget->u.KeyNode.Class)) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Mark security
|
|||
|
//
|
|||
|
if (ptarget->u.KeyNode.Security != HCELL_NIL) {
|
|||
|
if (! HvMarkCellDirty(Hive, ptarget->u.KeyNode.Security)) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
security = HvGetCell(Hive, ptarget->u.KeyNode.Security);
|
|||
|
if( security == NULL ) {
|
|||
|
//
|
|||
|
// we couldn't map the bin containing this cell
|
|||
|
// we shouldn't hit this as we just marked the cell dirty
|
|||
|
// (i.e. dirty == PINNED in memory)
|
|||
|
//
|
|||
|
ASSERT( FALSE );
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// we can safely release it here, as it is now dirty/pinned
|
|||
|
//
|
|||
|
HvReleaseCell(Hive, ptarget->u.KeyNode.Security);
|
|||
|
|
|||
|
if (! (HvMarkCellDirty(Hive, security->u.KeySecurity.Flink) &&
|
|||
|
HvMarkCellDirty(Hive, security->u.KeySecurity.Blink)))
|
|||
|
{
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Mark the value entries and their data
|
|||
|
//
|
|||
|
if ( !(ptarget->u.KeyNode.Flags & KEY_PREDEF_HANDLE) &&
|
|||
|
(ptarget->u.KeyNode.ValueList.Count > 0)
|
|||
|
) {
|
|||
|
|
|||
|
// target list
|
|||
|
if (! HvMarkCellDirty(Hive, ptarget->u.KeyNode.ValueList.List)) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
plist = HvGetCell(Hive, ptarget->u.KeyNode.ValueList.List);
|
|||
|
if( plist == NULL ) {
|
|||
|
//
|
|||
|
// we couldn't map the bin containing this cell
|
|||
|
// we shouldn't hit this as we just marked the cell dirty
|
|||
|
// (i.e. dirty == PINNED in memory)
|
|||
|
//
|
|||
|
ASSERT( FALSE );
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// we can safely release it here, as it is now dirty/pinned
|
|||
|
//
|
|||
|
HvReleaseCell(Hive, ptarget->u.KeyNode.ValueList.List);
|
|||
|
|
|||
|
for (i = 0; i < ptarget->u.KeyNode.ValueList.Count; i++) {
|
|||
|
if (! HvMarkCellDirty(Hive, plist->u.KeyList[i])) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
pvalue = HvGetCell(Hive, plist->u.KeyList[i]);
|
|||
|
if( pvalue == NULL ) {
|
|||
|
//
|
|||
|
// we couldn't map the bin containing this cell
|
|||
|
// we shouldn't hit this as we just marked the cell dirty
|
|||
|
// (i.e. dirty == PINNED in memory)
|
|||
|
//
|
|||
|
ASSERT( FALSE );
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// we can safely release it here, as it is now dirty/pinned
|
|||
|
//
|
|||
|
HvReleaseCell(Hive,plist->u.KeyList[i]);
|
|||
|
|
|||
|
if( !CmpMarkValueDataDirty(Hive,&(pvalue->u.KeyValue)) ) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (ptarget->u.KeyNode.Flags & KEY_HIVE_ENTRY) {
|
|||
|
|
|||
|
//
|
|||
|
// if this is an entry node, we are done. our parent will
|
|||
|
// be in the master hive (and thus volatile)
|
|||
|
//
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Mark the parent's Subkey list
|
|||
|
//
|
|||
|
if (! CmpMarkIndexDirty(Hive, ptarget->u.KeyNode.Parent, Cell)) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Mark the parent
|
|||
|
//
|
|||
|
if (! HvMarkCellDirty(Hive, ptarget->u.KeyNode.Parent)) {
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|