WindowsXP/Source/XPSP1/NT/base/ntos/config/cmapi2.c

190 lines
5.2 KiB
C
Raw Normal View History

2024-08-03 16:30:48 +02:00
/*++
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;
}