00001 /*++ 00002 00003 Copyright (c) 1991 Microsoft Corporation 00004 00005 Module Name: 00006 00007 cmapi2.c 00008 00009 Abstract: 00010 00011 This module contains CM level entry points for the registry, 00012 particularly those which we don't want to link into tools, 00013 setup, the boot loader, etc. 00014 00015 Author: 00016 00017 Bryan M. Willman (bryanwi) 26-Jan-1993 00018 00019 Revision History: 00020 00021 --*/ 00022 00023 #include "cmp.h" 00024 00025 #ifdef ALLOC_PRAGMA 00026 #pragma alloc_text(PAGE,CmDeleteKey) 00027 #endif 00028 00029 00030 NTSTATUS 00031 CmDeleteKey( 00032 IN PCM_KEY_BODY KeyBody 00033 ) 00034 /*++ 00035 00036 Routine Description: 00037 00038 Delete a registry key, clean up Notify block. 00039 00040 Arguments: 00041 00042 KeyBody - pointer to key handle object 00043 00044 Return Value: 00045 00046 NTSTATUS 00047 00048 --*/ 00049 { 00050 NTSTATUS status; 00051 PCM_KEY_NODE ptarget; 00052 PHHIVE Hive; 00053 HCELL_INDEX Cell; 00054 PCM_KEY_CONTROL_BLOCK KeyControlBlock; 00055 00056 CMLOG(CML_WORKER, CMS_CM) KdPrint(("CmDeleteKey\n")); 00057 00058 CmpLockRegistryExclusive(); 00059 00060 // 00061 // If already marked for deletion, storage is gone, so 00062 // do nothing and return success. 00063 // 00064 KeyControlBlock = KeyBody->KeyControlBlock; 00065 00066 if (KeyControlBlock->Delete == TRUE) { 00067 status = STATUS_SUCCESS; 00068 goto Exit; 00069 } 00070 00071 // Mark the hive as read only 00072 CmpMarkAllBinsReadOnly(KeyControlBlock->KeyHive); 00073 00074 ptarget = KeyControlBlock->KeyNode; 00075 00076 if ( ((ptarget->SubKeyCounts[Stable] + 00077 ptarget->SubKeyCounts[Volatile]) == 0) && 00078 ((ptarget->Flags & KEY_NO_DELETE) == 0)) 00079 { 00080 // 00081 // Cell is NOT marked NO_DELETE and does NOT have children 00082 // Send Notification while key still present, if delete fails, 00083 // we'll have sent a spurious notify, that doesn't matter 00084 // Delete the actual storage 00085 // 00086 Hive = KeyControlBlock->KeyHive; 00087 Cell = KeyControlBlock->KeyCell; 00088 00089 CmpReportNotify( 00090 KeyControlBlock, 00091 Hive, 00092 Cell, 00093 REG_NOTIFY_CHANGE_NAME 00094 ); 00095 00096 status = CmpFreeKeyByCell(Hive, Cell, TRUE); 00097 00098 if (NT_SUCCESS(status)) { 00099 // 00100 // post any waiting notifies 00101 // 00102 #ifdef KCB_TO_KEYBODY_LINK 00103 CmpFlushNotifiesOnKeyBodyList(KeyControlBlock); 00104 #else 00105 CmpFlushNotify(KeyBody); 00106 #endif 00107 00108 // 00109 // Remove kcb out of cache, but do NOT 00110 // free its storage, CmDelete will do that when 00111 // the RefCount becomes zero. 00112 // 00113 // There are two things that can hold the RefCount non-zero. 00114 // 00115 // 1. open handles for this key 00116 // 2. Fake subKeys that are still in DelayClose. 00117 // 00118 // At this point, we have no way of deleting the fake subkeys from cache 00119 // unless we do a search for the whole cache, which is too expensive. 00120 // Thus, we decide to either let the fake keys age out of cache or when 00121 // someone is doing the lookup for the fake key, then we delete it at that point. 00122 // See routine CmpCacheLookup in cmparse.c for more details. 00123 // 00124 // If the parent has the subkey info or hint cached, free it. 00125 // Again, registry is locked exclusively, no need to lock KCB. 00126 // 00127 ASSERT_CM_LOCK_OWNED_EXCLUSIVE(); 00128 CmpCleanUpSubKeyInfo(KeyControlBlock->ParentKcb); 00129 KeyControlBlock->Delete = TRUE; 00130 CmpRemoveKeyControlBlock(KeyControlBlock); 00131 KeyControlBlock->KeyCell = HCELL_NIL; 00132 KeyControlBlock->KeyNode = NULL; 00133 } 00134 00135 } else { 00136 00137 status = STATUS_CANNOT_DELETE; 00138 00139 } 00140 00141 Exit: 00142 CmpUnlockRegistry(); 00143 00144 // Mark the hive as read only 00145 CmpMarkAllBinsReadOnly(KeyControlBlock->KeyHive); 00146 00147 return status; 00148 }