190 lines
5.2 KiB
C
190 lines
5.2 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
cmapi2.c
|
||
|
||
Abstract:
|
||
|
||
This module contains CM level entry points for the registry,
|
||
particularly those which we don't want to link into tools,
|
||
setup, the boot loader, etc.
|
||
|
||
Author:
|
||
|
||
Bryan M. Willman (bryanwi) 26-Jan-1993
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "cmp.h"
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE,CmDeleteKey)
|
||
#endif
|
||
|
||
|
||
NTSTATUS
|
||
CmDeleteKey(
|
||
IN PCM_KEY_BODY KeyBody
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Delete a registry key, clean up Notify block.
|
||
|
||
Arguments:
|
||
|
||
KeyBody - pointer to key handle object
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
PCM_KEY_NODE ptarget;
|
||
PHHIVE Hive;
|
||
HCELL_INDEX Cell;
|
||
HCELL_INDEX Parent;
|
||
PCM_KEY_CONTROL_BLOCK KeyControlBlock;
|
||
LARGE_INTEGER TimeStamp;
|
||
|
||
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_CM,"CmDeleteKey\n"));
|
||
|
||
CmpLockRegistryExclusive();
|
||
|
||
#ifdef CHECK_REGISTRY_USECOUNT
|
||
CmpCheckRegistryUseCount();
|
||
#endif //CHECK_REGISTRY_USECOUNT
|
||
|
||
//
|
||
// If already marked for deletion, storage is gone, so
|
||
// do nothing and return success.
|
||
//
|
||
KeyControlBlock = KeyBody->KeyControlBlock;
|
||
|
||
PERFINFO_REG_DELETE_KEY(KeyControlBlock);
|
||
|
||
if (KeyControlBlock->Delete == TRUE) {
|
||
status = STATUS_SUCCESS;
|
||
goto Exit;
|
||
}
|
||
|
||
// Mark the hive as read only
|
||
CmpMarkAllBinsReadOnly(KeyControlBlock->KeyHive);
|
||
|
||
ptarget = (PCM_KEY_NODE)HvGetCell(KeyControlBlock->KeyHive, KeyControlBlock->KeyCell);
|
||
if( ptarget == NULL ) {
|
||
//
|
||
// we couldn't map a view for the bin containing this cell
|
||
//
|
||
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto Exit;
|
||
}
|
||
|
||
// release the cell right here, as the registry is locked exclusively, so we don't care
|
||
HvReleaseCell(KeyControlBlock->KeyHive, KeyControlBlock->KeyCell);
|
||
|
||
ASSERT( ptarget->Flags == KeyControlBlock->Flags );
|
||
|
||
if ( ((ptarget->SubKeyCounts[Stable] + ptarget->SubKeyCounts[Volatile]) == 0) &&
|
||
((ptarget->Flags & KEY_NO_DELETE) == 0))
|
||
{
|
||
//
|
||
// Cell is NOT marked NO_DELETE and does NOT have children
|
||
// Send Notification while key still present, if delete fails,
|
||
// we'll have sent a spurious notify, that doesn't matter
|
||
// Delete the actual storage
|
||
//
|
||
Hive = KeyControlBlock->KeyHive;
|
||
Cell = KeyControlBlock->KeyCell;
|
||
Parent = ptarget->Parent;
|
||
|
||
CmpReportNotify(
|
||
KeyControlBlock,
|
||
Hive,
|
||
Cell,
|
||
REG_NOTIFY_CHANGE_NAME
|
||
);
|
||
|
||
status = CmpFreeKeyByCell(Hive, Cell, TRUE);
|
||
|
||
if (NT_SUCCESS(status)) {
|
||
//
|
||
// post any waiting notifies
|
||
//
|
||
CmpFlushNotifiesOnKeyBodyList(KeyControlBlock);
|
||
|
||
//
|
||
// Remove kcb out of cache, but do NOT
|
||
// free its storage, CmDelete will do that when
|
||
// the RefCount becomes zero.
|
||
//
|
||
// There are two things that can hold the RefCount non-zero.
|
||
//
|
||
// 1. open handles for this key
|
||
// 2. Fake subKeys that are still in DelayClose.
|
||
//
|
||
// At this point, we have no way of deleting the fake subkeys from cache
|
||
// unless we do a search for the whole cache, which is too expensive.
|
||
// Thus, we decide to either let the fake keys age out of cache or when
|
||
// someone is doing the lookup for the fake key, then we delete it at that point.
|
||
// See routine CmpCacheLookup in cmparse.c for more details.
|
||
//
|
||
// If the parent has the subkey info or hint cached, free it.
|
||
// Again, registry is locked exclusively, no need to lock KCB.
|
||
//
|
||
ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
|
||
CmpCleanUpSubKeyInfo(KeyControlBlock->ParentKcb);
|
||
ptarget = (PCM_KEY_NODE)HvGetCell(Hive, Parent);
|
||
if( ptarget != NULL ) {
|
||
// release the cell right here, as the registry is locked exclusively, so we don't care
|
||
HvReleaseCell(Hive, Parent);
|
||
|
||
//
|
||
// this should always be true as CmpFreeKeyByCell always marks the parent dirty on success
|
||
//
|
||
KeyControlBlock->ParentKcb->KcbMaxNameLen = (USHORT)ptarget->MaxNameLen;
|
||
// sanity
|
||
ASSERT_CELL_DIRTY(Hive,Parent);
|
||
//
|
||
// update the LastWriteTime on parent and kcb too
|
||
//
|
||
KeQuerySystemTime(&TimeStamp);
|
||
ptarget->LastWriteTime = TimeStamp;
|
||
KeyBody->KeyControlBlock->ParentKcb->KcbLastWriteTime = TimeStamp;
|
||
|
||
}
|
||
|
||
KeyControlBlock->Delete = TRUE;
|
||
CmpRemoveKeyControlBlock(KeyControlBlock);
|
||
KeyControlBlock->KeyCell = HCELL_NIL;
|
||
}
|
||
|
||
} else {
|
||
|
||
status = STATUS_CANNOT_DELETE;
|
||
|
||
}
|
||
|
||
Exit:
|
||
|
||
#ifdef CHECK_REGISTRY_USECOUNT
|
||
CmpCheckRegistryUseCount();
|
||
#endif //CHECK_REGISTRY_USECOUNT
|
||
|
||
CmpUnlockRegistry();
|
||
|
||
// Mark the hive as read only
|
||
CmpMarkAllBinsReadOnly(KeyControlBlock->KeyHive);
|
||
|
||
return status;
|
||
}
|