VOID NTAPI CmpCleanUpKcbValueCache(IN PCM_KEY_CONTROL_BLOCK Kcb) { PULONG_PTR CachedList; ULONG i; /* Sanity check */ ASSERT((CmpIsKcbLockedExclusive(Kcb) == TRUE) || (CmpTestRegistryLockExclusive() == TRUE)); /* Check if the value list is cached */ if (CMP_IS_CELL_CACHED(Kcb->ValueCache.ValueList)) { /* Get the cache list */ CachedList = (PULONG_PTR)CMP_GET_CACHED_DATA(Kcb->ValueCache.ValueList); for (i = 0; i < Kcb->ValueCache.Count; i++) { /* Check if this cell is cached */ if (CMP_IS_CELL_CACHED(CachedList[i])) { /* Free it */ CmpFree((PVOID)CMP_GET_CACHED_CELL(CachedList[i]), 0); } } /* Now free the list */ CmpFree((PVOID)CMP_GET_CACHED_CELL(Kcb->ValueCache.ValueList), 0); Kcb->ValueCache.ValueList = HCELL_NIL; } else if (Kcb->ExtFlags & CM_KCB_SYM_LINK_FOUND) { /* This is a sym link, check if there's only one reference left */ if ((Kcb->ValueCache.RealKcb->RefCount == 1) && !(Kcb->ValueCache.RealKcb->Delete)) { /* Disable delay close for the KCB */ Kcb->ValueCache.RealKcb->ExtFlags |= CM_KCB_NO_DELAY_CLOSE; } /* Dereference the KCB */ CmpDelayDerefKeyControlBlock(Kcb->ValueCache.RealKcb); Kcb->ExtFlags &= ~CM_KCB_SYM_LINK_FOUND; } }
VOID NTAPI CmpCleanUpKcbCacheWithLock(IN PCM_KEY_CONTROL_BLOCK Kcb, IN BOOLEAN LockHeldExclusively) { PCM_KEY_CONTROL_BLOCK Parent; PAGED_CODE(); /* Sanity checks */ ASSERT((CmpIsKcbLockedExclusive(Kcb) == TRUE) || (CmpTestRegistryLockExclusive() == TRUE)); ASSERT(Kcb->RefCount == 0); /* Cleanup the value cache */ CmpCleanUpKcbValueCache(Kcb); /* Dereference the NCB */ CmpDereferenceNameControlBlockWithLock(Kcb->NameBlock); /* Check if we have an index hint block and free it */ if (Kcb->ExtFlags & CM_KCB_SUBKEY_HINT) CmpFree(Kcb->IndexHint, 0); /* Check if we were already deleted */ Parent = Kcb->ParentKcb; if (!Kcb->Delete) CmpRemoveKeyControlBlock(Kcb); /* Set invalid KCB signature */ Kcb->Signature = CM_KCB_INVALID_SIGNATURE; /* Free the KCB as well */ CmpFreeKeyControlBlock(Kcb); /* Check if we have a parent */ if (Parent) { /* Dereference the parent */ LockHeldExclusively ? CmpDereferenceKeyControlBlockWithLock(Parent,LockHeldExclusively) : CmpDelayDerefKeyControlBlock(Parent); } }
VOID CmpDeleteKeyObject( IN PVOID Object ) /*++ Routine Description: This routine interfaces to the NT Object Manager. It is invoked when the last reference to a particular Key object (or Key Root object) is destroyed. If the Key object going away holds the last reference to the extension it is associated with, that extension is destroyed. Arguments: Object - supplies a pointer to a KeyRoot or Key, thus -> KEY_BODY. Return Value: NONE. --*/ { PCM_KEY_CONTROL_BLOCK KeyControlBlock; PCM_KEY_BODY KeyBody; PCMHIVE CmHive = NULL; BOOLEAN DoUnloadCheck = FALSE; CM_PAGED_CODE(); CmKdPrintEx((DPFLTR_CONFIG_ID,CML_FLOW,"CmpDeleteKeyObject: Object = %p\n", Object)); // // HandleClose callback // if ( CmAreCallbacksRegistered() ) { REG_KEY_HANDLE_CLOSE_INFORMATION KeyHandleCloseInfo; KeyHandleCloseInfo.Object = Object; CmpCallCallBacks(RegNtPreKeyHandleClose,&KeyHandleCloseInfo,TRUE,RegNtPostKeyHandleClose,Object); } KeyBody = (PCM_KEY_BODY)Object; BEGIN_LOCK_CHECKPOINT; CmpLockRegistry(); if (KeyBody->Type==KEY_BODY_TYPE) { KeyControlBlock = KeyBody->KeyControlBlock; // // the keybody should be initialized; when kcb is null, something went wrong // between the creation and the dereferenciation of the object // if( KeyControlBlock != NULL ) { // // Clean up any outstanding notifies attached to the KeyBody // CmpFlushNotify(KeyBody,FALSE); // // Remove our reference to the KeyControlBlock, clean it up, perform any // pend-till-final-close operations. // // NOTE: Delete notification is seen at the parent of the deleted key, // not the deleted key itself. If any notify was outstanding on // this key, it was cleared away above us. Only parent/ancestor // keys will see the report. // // // The dereference will free the KeyControlBlock. If the key was deleted, it // has already been removed from the hash table, and relevant notifications // posted then as well. All we are doing is freeing the tombstone. // // If it was not deleted, we're both cutting the kcb out of // the kcb list/tree, AND freeing its storage. // // // Replace this with the definition so we avoid dropping and reacquiring the lock DelistKeyBodyFromKCB(KeyBody,FALSE); // // take additional precaution in the case the hive has been unloaded and this is the root // if( !KeyControlBlock->Delete ) { CmHive = (PCMHIVE)CONTAINING_RECORD(KeyControlBlock->KeyHive, CMHIVE, Hive); if( IsHiveFrozen(CmHive) ) { // // unload is pending for this hive; // DoUnloadCheck = TRUE; } } CmpDelayDerefKeyControlBlock(KeyControlBlock); } } else { // // This must be a predefined handle // some sanity asserts // KeyControlBlock = KeyBody->KeyControlBlock; ASSERT( KeyBody->Type®_PREDEF_HANDLE_MASK); ASSERT( KeyControlBlock->Flags&KEY_PREDEF_HANDLE ); if( KeyControlBlock != NULL ) { CmHive = (PCMHIVE)CONTAINING_RECORD(KeyControlBlock->KeyHive, CMHIVE, Hive); if( IsHiveFrozen(CmHive) ) { // // unload is pending for this hive; we shouldn't put the kcb in the delay // close table // DoUnloadCheck = TRUE; } CmpDereferenceKeyControlBlock(KeyControlBlock); } } // // if a handle inside a frozen hive has been closed, we may need to unload the hive // if( DoUnloadCheck == TRUE ) { CmpDoQueueLateUnloadWorker(CmHive); } CmpUnlockRegistry(); END_LOCK_CHECKPOINT; // // just a notification; disregard the return status // CmPostCallbackNotification(RegNtPostKeyHandleClose,NULL,STATUS_SUCCESS); return; }