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;
|
|||
|
}
|