/*++ 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; }