Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

cmsubs.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1991 Microsoft Corporation 00004 00005 Module Name: 00006 00007 cmsubs.c 00008 00009 Abstract: 00010 00011 This module various support routines for the configuration manager. 00012 00013 The routines in this module are not independent enough to be linked 00014 into any other program. The routines in cmsubs2.c are. 00015 00016 Author: 00017 00018 Bryan M. Willman (bryanwi) 12-Sep-1991 00019 00020 Revision History: 00021 00022 --*/ 00023 00024 #include "cmp.h" 00025 00026 FAST_MUTEX CmpKcbLock; 00027 FAST_MUTEX CmpPostLock; 00028 00029 PCM_KEY_HASH *CmpCacheTable; 00030 ULONG CmpHashTableSize = 2048; 00031 ULONG CmpDelayedCloseSize = 512; 00032 PCM_KEY_CONTROL_BLOCK *CmpDelayedCloseTable; 00033 PCM_KEY_CONTROL_BLOCK *CmpDelayedCloseCurrent; 00034 ULONG_PTR CmpDelayedFreeIndex=0; 00035 PCM_NAME_HASH *CmpNameCacheTable; 00036 00037 VOID 00038 CmpRemoveKeyHash( 00039 IN PCM_KEY_HASH KeyHash 00040 ); 00041 00042 PCM_KEY_CONTROL_BLOCK 00043 CmpInsertKeyHash( 00044 IN PCM_KEY_HASH KeyHash, 00045 IN BOOLEAN FakeKey 00046 ); 00047 00048 // 00049 // private prototype for recursive worker 00050 // 00051 00052 00053 VOID 00054 CmpDereferenceNameControlBlockWithLock( 00055 PCM_NAME_CONTROL_BLOCK Ncb 00056 ); 00057 00058 #ifdef KCB_TO_KEYBODY_LINK 00059 VOID 00060 CmpDumpKeyBodyList( 00061 IN PCM_KEY_CONTROL_BLOCK kcb, 00062 IN PULONG Count 00063 ); 00064 #endif 00065 00066 #ifdef ALLOC_PRAGMA 00067 #pragma alloc_text(PAGE,CmpSearchForOpenSubKeys) 00068 #pragma alloc_text(PAGE,CmpReferenceKeyControlBlock) 00069 #pragma alloc_text(PAGE,CmpGetNameControlBlock) 00070 #pragma alloc_text(PAGE,CmpDereferenceNameControlBlockWithLock) 00071 #pragma alloc_text(PAGE,CmpCleanUpSubKeyInfo) 00072 #pragma alloc_text(PAGE,CmpCleanUpKcbValueCache) 00073 #pragma alloc_text(PAGE,CmpCleanUpKcbCacheWithLock) 00074 #pragma alloc_text(PAGE,CmpConstructName) 00075 #pragma alloc_text(PAGE,CmpRemoveFromDelayedClose) 00076 #pragma alloc_text(PAGE,CmpCreateKeyControlBlock) 00077 #pragma alloc_text(PAGE,CmpSearchKeyControlBlockTree) 00078 #pragma alloc_text(PAGE,CmpDereferenceKeyControlBlock) 00079 #pragma alloc_text(PAGE,CmpDereferenceKeyControlBlockWithLock) 00080 #pragma alloc_text(PAGE,CmpRemoveKeyControlBlock) 00081 #pragma alloc_text(PAGE,CmpFreeKeyBody) 00082 #pragma alloc_text(PAGE,CmpInsertKeyHash) 00083 #pragma alloc_text(PAGE,CmpRemoveKeyHash) 00084 #pragma alloc_text(PAGE,CmpInitializeCache) 00085 00086 #ifdef KCB_TO_KEYBODY_LINK 00087 #pragma alloc_text(PAGE,CmpDumpKeyBodyList) 00088 #pragma alloc_text(PAGE,CmpFlushNotifiesOnKeyBodyList) 00089 #endif 00090 00091 #endif 00092 00093 #ifdef KCB_TO_KEYBODY_LINK 00094 VOID 00095 CmpDumpKeyBodyList( 00096 IN PCM_KEY_CONTROL_BLOCK kcb, 00097 IN PULONG Count 00098 ) 00099 { 00100 00101 PCM_KEY_BODY KeyBody; 00102 PUNICODE_STRING Name; 00103 00104 if( IsListEmpty(&(kcb->KeyBodyListHead)) == TRUE ) { 00105 // 00106 // Nobody has this subkey open, but for sure some subkey must be 00107 // open. nicely return. 00108 // 00109 return; 00110 } 00111 00112 00113 Name = CmpConstructName(kcb); 00114 if( !Name ){ 00115 // oops, we're low on resources 00116 return; 00117 } 00118 00119 // 00120 // now iterate through the list of KEY_BODYs referencing this kcb 00121 // 00122 KeyBody = (PCM_KEY_BODY)kcb->KeyBodyListHead.Flink; 00123 while( KeyBody != (PCM_KEY_BODY)(&(kcb->KeyBodyListHead)) ) { 00124 KeyBody = CONTAINING_RECORD(KeyBody, 00125 CM_KEY_BODY, 00126 KeyBodyList); 00127 // 00128 // sanity check: this should be a KEY_BODY 00129 // 00130 ASSERT_KEY_OBJECT(KeyBody); 00131 00132 // 00133 // dump it's name and owning process 00134 // 00135 DbgPrint("Process %lx :: Key %wZ \n",KeyBody->Process,Name); 00136 00137 // count it 00138 (*Count)++; 00139 00140 KeyBody = (PCM_KEY_BODY)KeyBody->KeyBodyList.Flink; 00141 } 00142 00143 ExFreePoolWithTag(Name, CM_NAME_TAG | PROTECTED_POOL); 00144 00145 } 00146 00147 VOID 00148 CmpFlushNotifiesOnKeyBodyList( 00149 IN PCM_KEY_CONTROL_BLOCK kcb 00150 ) 00151 { 00152 PCM_KEY_BODY KeyBody; 00153 00154 if( IsListEmpty(&(kcb->KeyBodyListHead)) == FALSE ) { 00155 // 00156 // now iterate through the list of KEY_BODYs referencing this kcb 00157 // 00158 KeyBody = (PCM_KEY_BODY)kcb->KeyBodyListHead.Flink; 00159 while( KeyBody != (PCM_KEY_BODY)(&(kcb->KeyBodyListHead)) ) { 00160 KeyBody = CONTAINING_RECORD(KeyBody, 00161 CM_KEY_BODY, 00162 KeyBodyList); 00163 // 00164 // sanity check: this should be a KEY_BODY 00165 // 00166 ASSERT_KEY_OBJECT(KeyBody); 00167 00168 // 00169 // flush any notifies that might be set on it 00170 // 00171 CmpFlushNotify(KeyBody); 00172 00173 KeyBody = (PCM_KEY_BODY)KeyBody->KeyBodyList.Flink; 00174 } 00175 } 00176 } 00177 #endif 00178 00179 ULONG 00180 CmpSearchForOpenSubKeys( 00181 PCM_KEY_CONTROL_BLOCK KeyControlBlock, 00182 SUBKEY_SEARCH_TYPE SearchType 00183 ) 00184 /*++ 00185 Routine Description: 00186 00187 This routine searches the KCB tree for any open handles to keys that 00188 are subkeys of the given key. 00189 00190 It is used by CmRestoreKey to verify that the tree being restored to 00191 has no open handles. 00192 00193 Arguments: 00194 00195 KeyControlBlock - Supplies the key control block for the key for which 00196 open subkeys are to be found. 00197 00198 SearchType - the type of the search 00199 SearchIfExist - exits at the first open subkey found ==> returns 1 if any subkey is open 00200 00201 SearchAndDeref - Forces the keys underneath the Key referenced KeyControlBlock to 00202 be marked as not referenced (see the REG_FORCE_RESTORE flag in CmRestoreKey) 00203 returns 1 if at least one deref was made 00204 00205 SearchAndCount - Counts all open subkeys - returns the number of them 00206 00207 Return Value: 00208 00209 TRUE - open handles to subkeys of the given key exist 00210 00211 FALSE - open handles to subkeys of the given key do not exist. 00212 --*/ 00213 { 00214 ULONG i; 00215 PCM_KEY_HASH *Current; 00216 PCM_KEY_CONTROL_BLOCK kcb; 00217 PCM_KEY_CONTROL_BLOCK Realkcb; 00218 PCM_KEY_CONTROL_BLOCK Parent; 00219 USHORT LevelDiff, l; 00220 ULONG Count = 0; 00221 00222 // 00223 // Registry lock should be held exclusively, so no need to KCB lock 00224 // 00225 ASSERT_CM_LOCK_OWNED_EXCLUSIVE(); 00226 00227 00228 // 00229 // First, clean up all subkeys in the cache 00230 // 00231 for (i=0; i<CmpHashTableSize; i++) { 00232 Current = &CmpCacheTable[i]; 00233 while (*Current) { 00234 kcb = CONTAINING_RECORD(*Current, CM_KEY_CONTROL_BLOCK, KeyHash); 00235 if (kcb->RefCount == 0) { 00236 // 00237 // This kcb is in DelayClose case, remove it. 00238 // 00239 CmpRemoveFromDelayedClose(kcb); 00240 CmpCleanUpKcbCacheWithLock(kcb); 00241 00242 // 00243 // The HashTable is changed, start over in this index again. 00244 // 00245 Current = &CmpCacheTable[i]; 00246 continue; 00247 } 00248 Current = &kcb->NextHash; 00249 } 00250 } 00251 00252 if (KeyControlBlock->RefCount == 1) { 00253 // 00254 // There is only one open handle, so there must be no open subkeys. 00255 // 00256 Count = 0; 00257 } else { 00258 // 00259 // Now search for an open subkey handle. 00260 // 00261 Count = 0; 00262 00263 00264 #ifdef KCB_TO_KEYBODY_LINK 00265 // 00266 // dump the root first if we were asked to do so. 00267 // 00268 if(SearchType == SearchAndCount) { 00269 CmpDumpKeyBodyList(KeyControlBlock,&Count); 00270 } 00271 #endif 00272 for (i=0; i<CmpHashTableSize; i++) { 00273 00274 StartDeref: 00275 Current = &CmpCacheTable[i]; 00276 while (*Current) { 00277 kcb = CONTAINING_RECORD(*Current, CM_KEY_CONTROL_BLOCK, KeyHash); 00278 if (kcb->TotalLevels > KeyControlBlock->TotalLevels) { 00279 LevelDiff = kcb->TotalLevels - KeyControlBlock->TotalLevels; 00280 00281 Parent = kcb; 00282 for (l=0; l<LevelDiff; l++) { 00283 Parent = Parent->ParentKcb; 00284 } 00285 00286 if (Parent == KeyControlBlock) { 00287 // 00288 // Found a match; 00289 // 00290 if( SearchType == SearchIfExist ) { 00291 Count = 1; 00292 break; 00293 } else if(SearchType == SearchAndDeref) { 00294 // 00295 // Mark the key as deleted, remove it from cache, but don't add it 00296 // to the Delay Close table (we want the key to be visible only to 00297 // the one(s) that have open handles on it. 00298 // 00299 00300 ASSERT_CM_LOCK_OWNED_EXCLUSIVE(); 00301 00302 // 00303 // flush any pending notifies as the kcb won't be around any longer 00304 // 00305 #ifdef KCB_TO_KEYBODY_LINK 00306 CmpFlushNotifiesOnKeyBodyList(kcb); 00307 #endif 00308 00309 CmpCleanUpSubKeyInfo(kcb->ParentKcb); 00310 kcb->Delete = TRUE; 00311 CmpRemoveKeyControlBlock(kcb); 00312 kcb->KeyCell = HCELL_NIL; 00313 kcb->KeyNode = NULL; 00314 Count++; 00315 00316 // 00317 // Restart the search 00318 // 00319 goto StartDeref; 00320 00321 } else if(SearchType == SearchAndCount) { 00322 // 00323 // here do the dumping and count incrementing stuff 00324 // 00325 #ifdef KCB_TO_KEYBODY_LINK 00326 CmpDumpKeyBodyList(kcb,&Count); 00327 #else 00328 Count++; 00329 #endif 00330 } 00331 } 00332 00333 } 00334 Current = &kcb->NextHash; 00335 } 00336 } 00337 } 00338 00339 00340 return Count; 00341 } 00342 00343 00344 BOOLEAN 00345 CmpReferenceKeyControlBlock( 00346 PCM_KEY_CONTROL_BLOCK KeyControlBlock 00347 ) 00348 { 00349 if (KeyControlBlock->RefCount == 0) { 00350 CmpRemoveFromDelayedClose(KeyControlBlock); 00351 } 00352 00353 if ((USHORT)(KeyControlBlock->RefCount + 1) == 0) { 00354 // 00355 // We have maxed out the ref count on this key. Probably 00356 // some bogus app has opened the same key 64K times without 00357 // ever closing it. Just fail the call 00358 // 00359 return (FALSE); 00360 } else { 00361 ++(KeyControlBlock->RefCount); 00362 return (TRUE); 00363 } 00364 } 00365 00366 00367 PCM_NAME_CONTROL_BLOCK 00368 CmpGetNameControlBlock( 00369 PUNICODE_STRING NodeName 00370 ) 00371 { 00372 PCM_NAME_CONTROL_BLOCK Ncb; 00373 ULONG Cnt; 00374 WCHAR *Cp; 00375 WCHAR *Cp2; 00376 ULONG Index; 00377 ULONG i; 00378 ULONG Size; 00379 PCM_NAME_HASH CurrentName; 00380 ULONG rc; 00381 BOOLEAN NameFound = FALSE; 00382 USHORT NameSize; 00383 BOOLEAN NameCompressed; 00384 ULONG NameConvKey=0; 00385 LONG Result; 00386 00387 // 00388 // Calculate the ConvKey for this NadeName; 00389 // 00390 00391 Cp = NodeName->Buffer; 00392 for (Cnt=0; Cnt<NodeName->Length; Cnt += sizeof(WCHAR)) { 00393 if (*Cp != OBJ_NAME_PATH_SEPARATOR) { 00394 NameConvKey = 37 * NameConvKey + (ULONG) RtlUpcaseUnicodeChar(*Cp); 00395 } 00396 ++Cp; 00397 } 00398 00399 // 00400 // Find the Name Size; 00401 // 00402 NameCompressed = TRUE; 00403 NameSize = NodeName->Length / sizeof(WCHAR); 00404 for (i=0;i<NodeName->Length/sizeof(WCHAR);i++) { 00405 if ((USHORT)NodeName->Buffer[i] > (UCHAR)-1) { 00406 NameSize = NodeName->Length; 00407 NameCompressed = FALSE; 00408 } 00409 } 00410 00411 Index = GET_HASH_INDEX(NameConvKey); 00412 CurrentName = CmpNameCacheTable[Index]; 00413 00414 while (CurrentName) { 00415 Ncb = CONTAINING_RECORD(CurrentName, CM_NAME_CONTROL_BLOCK, NameHash); 00416 00417 if ((NameConvKey == CurrentName->ConvKey) && 00418 (NameSize == Ncb->NameLength)) { 00419 // 00420 // Hash value matches, compare the names. 00421 // 00422 NameFound = TRUE; 00423 if (Ncb->Compressed) { 00424 if (CmpCompareCompressedName(NodeName, Ncb->Name, NameSize)) { 00425 NameFound = FALSE; 00426 } 00427 } else { 00428 Cp = (WCHAR *) NodeName->Buffer; 00429 Cp2 = (WCHAR *) Ncb->Name; 00430 for (i=0 ;i<Ncb->NameLength; i+= sizeof(WCHAR)) { 00431 if (RtlUpcaseUnicodeChar(*Cp) != RtlUpcaseUnicodeChar(*Cp2)) { 00432 NameFound = FALSE; 00433 break; 00434 } 00435 ++Cp; 00436 ++Cp2; 00437 } 00438 } 00439 if (NameFound) { 00440 // 00441 // Found it, increase the refcount. 00442 // 00443 if ((USHORT) (Ncb->RefCount + 1) == 0) { 00444 // 00445 // We have maxed out the ref count. 00446 // fail the call. 00447 // 00448 Ncb = NULL; 00449 } else { 00450 ++Ncb->RefCount; 00451 } 00452 break; 00453 } 00454 } 00455 CurrentName = CurrentName->NextHash; 00456 } 00457 00458 if (NameFound == FALSE) { 00459 // 00460 // Now need to create one Name block for this string. 00461 // 00462 Size = FIELD_OFFSET(CM_NAME_CONTROL_BLOCK, Name) + NameSize; 00463 00464 Ncb = ExAllocatePoolWithTag(PagedPool, 00465 Size, 00466 CM_NAME_TAG | PROTECTED_POOL); 00467 00468 if (Ncb == NULL) { 00469 return(NULL); 00470 } 00471 RtlZeroMemory(Ncb, Size); 00472 00473 // 00474 // Update all the info for this newly created Name block. 00475 // 00476 if (NameCompressed) { 00477 Ncb->Compressed = TRUE; 00478 for (i=0;i<NameSize;i++) { 00479 ((PUCHAR)Ncb->Name)[i] = (UCHAR)(NodeName->Buffer[i]); 00480 } 00481 } else { 00482 Ncb->Compressed = FALSE; 00483 RtlCopyMemory((PVOID)(Ncb->Name), (PVOID)(NodeName->Buffer), NameSize); 00484 } 00485 00486 Ncb->ConvKey = NameConvKey; 00487 Ncb->RefCount = 1; 00488 Ncb->NameLength = NameSize; 00489 00490 CurrentName = &(Ncb->NameHash); 00491 // 00492 // Insert into Name Hash table. 00493 // 00494 CurrentName->NextHash = CmpNameCacheTable[Index]; 00495 CmpNameCacheTable[Index] = CurrentName; 00496 } 00497 00498 return(Ncb); 00499 } 00500 00501 00502 VOID 00503 CmpDereferenceNameControlBlockWithLock( 00504 PCM_NAME_CONTROL_BLOCK Ncb 00505 ) 00506 { 00507 PCM_NAME_HASH *Prev; 00508 PCM_NAME_HASH Current; 00509 00510 if (--Ncb->RefCount == 0) { 00511 00512 // 00513 // Remove it from the the Hash Table 00514 // 00515 Prev = &(GET_HASH_ENTRY(CmpNameCacheTable, Ncb->ConvKey)); 00516 00517 while (TRUE) { 00518 Current = *Prev; 00519 ASSERT(Current != NULL); 00520 if (Current == &(Ncb->NameHash)) { 00521 *Prev = Current->NextHash; 00522 break; 00523 } 00524 Prev = &Current->NextHash; 00525 } 00526 00527 // 00528 // Free storage 00529 // 00530 ExFreePoolWithTag(Ncb, CM_NAME_TAG | PROTECTED_POOL); 00531 } 00532 return; 00533 } 00534 00535 00536 VOID 00537 CmpCleanUpSubKeyInfo( 00538 PCM_KEY_CONTROL_BLOCK KeyControlBlock 00539 ) 00540 /*++ 00541 Routine Description: 00542 00543 Clean up the subkey information cache due to create or delete keys. 00544 Registry is locked exclusively and no need to lock the KCB. 00545 00546 Arguments: 00547 00548 KeyControlBlock - pointer to a key control block. 00549 00550 Return Value: 00551 00552 NONE. 00553 00554 --*/ 00555 { 00556 ASSERT_CM_LOCK_OWNED_EXCLUSIVE(); 00557 00558 if (KeyControlBlock->ExtFlags & (CM_KCB_NO_SUBKEY | CM_KCB_SUBKEY_ONE | CM_KCB_SUBKEY_HINT)) { 00559 if (KeyControlBlock->ExtFlags & (CM_KCB_SUBKEY_HINT)) { 00560 ExFreePoolWithTag(KeyControlBlock->IndexHint, CM_CACHE_INDEX_TAG | PROTECTED_POOL); 00561 } 00562 KeyControlBlock->ExtFlags &= ~((CM_KCB_NO_SUBKEY | CM_KCB_SUBKEY_ONE | CM_KCB_SUBKEY_HINT)); 00563 } 00564 } 00565 00566 00567 VOID 00568 CmpCleanUpKcbValueCache( 00569 PCM_KEY_CONTROL_BLOCK KeyControlBlock 00570 ) 00571 /*++ 00572 00573 Routine Description: 00574 00575 Clean up cached value/data that are associated to this key. 00576 00577 Arguments: 00578 00579 KeyControlBlock - pointer to a key control block. 00580 00581 Return Value: 00582 00583 NONE. 00584 00585 --*/ 00586 { 00587 ULONG i; 00588 PULONG_PTR CachedList; 00589 PCELL_DATA pcell; 00590 ULONG realsize; 00591 BOOLEAN small; 00592 00593 if (CMP_IS_CELL_CACHED(KeyControlBlock->ValueCache.ValueList)) { 00594 CachedList = (PULONG_PTR) CMP_GET_CACHED_CELLDATA(KeyControlBlock->ValueCache.ValueList); 00595 for (i = 0; i < KeyControlBlock->ValueCache.Count; i++) { 00596 if (CMP_IS_CELL_CACHED(CachedList[i])) { 00597 00598 // Trying to catch the BAD guy who writes over our pool. 00599 CmpMakeSpecialPoolReadWrite( CMP_GET_CACHED_ADDRESS(CachedList[i]) ); 00600 00601 ExFreePool((PVOID) CMP_GET_CACHED_ADDRESS(CachedList[i])); 00602 00603 } 00604 } 00605 00606 // Trying to catch the BAD guy who writes over our pool. 00607 CmpMakeSpecialPoolReadWrite( CMP_GET_CACHED_ADDRESS(KeyControlBlock->ValueCache.ValueList) ); 00608 00609 ExFreePool((PVOID) CMP_GET_CACHED_ADDRESS(KeyControlBlock->ValueCache.ValueList)); 00610 00611 // Mark the ValueList as NULL 00612 KeyControlBlock->ValueCache.ValueList = HCELL_NIL; 00613 00614 } else if (KeyControlBlock->ExtFlags & CM_KCB_SYM_LINK_FOUND) { 00615 // 00616 // This is a symbolic link key with symbolic name resolved. 00617 // Dereference to its real kcb and clear the bit. 00618 // 00619 if ((KeyControlBlock->ValueCache.RealKcb->RefCount == 1) && !(KeyControlBlock->ValueCache.RealKcb->Delete)) { 00620 KeyControlBlock->ValueCache.RealKcb->ExtFlags |= CM_KCB_NO_DELAY_CLOSE; 00621 } 00622 CmpDereferenceKeyControlBlockWithLock(KeyControlBlock->ValueCache.RealKcb); 00623 KeyControlBlock->ExtFlags &= ~CM_KCB_SYM_LINK_FOUND; 00624 } 00625 } 00626 00627 00628 VOID 00629 CmpCleanUpKcbCacheWithLock( 00630 PCM_KEY_CONTROL_BLOCK KeyControlBlock 00631 ) 00632 /*++ 00633 00634 Routine Description: 00635 00636 Clean up all cached allocations that are associated to this key. 00637 If the parent is still open just because of this one, Remove the parent as well. 00638 00639 Arguments: 00640 00641 KeyControlBlock - pointer to a key control block. 00642 00643 Return Value: 00644 00645 NONE. 00646 00647 --*/ 00648 { 00649 PCM_KEY_CONTROL_BLOCK Kcb; 00650 PCM_KEY_CONTROL_BLOCK ParentKcb; 00651 00652 Kcb = KeyControlBlock; 00653 00654 ASSERT(KeyControlBlock->RefCount == 0); 00655 00656 while (Kcb->RefCount == 0) { 00657 // 00658 // First, free allocations for Value/data. 00659 // 00660 00661 CmpCleanUpKcbValueCache(Kcb); 00662 00663 // 00664 // Free the kcb and dereference parentkcb and nameblock. 00665 // 00666 00667 CmpDereferenceNameControlBlockWithLock(Kcb->NameBlock); 00668 00669 if (Kcb->ExtFlags & CM_KCB_SUBKEY_HINT) { 00670 // 00671 // Now free the HintIndex allocation 00672 // 00673 ExFreePoolWithTag(Kcb->IndexHint, CM_CACHE_INDEX_TAG | PROTECTED_POOL); 00674 } 00675 00676 // 00677 // Save the ParentKcb before we free the Kcb 00678 // 00679 ParentKcb = Kcb->ParentKcb; 00680 00681 // 00682 // We cannot call CmpDereferenceKeyControlBlockWithLock so we can avoid recurrsion. 00683 // 00684 00685 if (!Kcb->Delete) { 00686 CmpRemoveKeyControlBlock(Kcb); 00687 } 00688 SET_KCB_SIGNATURE(Kcb, '4FmC'); 00689 ASSERT_KEYBODY_LIST_EMPTY(Kcb); 00690 ExFreePoolWithTag(Kcb, CM_KCB_TAG | PROTECTED_POOL); 00691 00692 Kcb = ParentKcb; 00693 Kcb->RefCount--; 00694 } 00695 } 00696 00697 00698 PUNICODE_STRING 00699 CmpConstructName( 00700 PCM_KEY_CONTROL_BLOCK kcb 00701 ) 00702 /*++ 00703 00704 Routine Description: 00705 00706 Construct the name given a kcb. 00707 00708 Arguments: 00709 00710 kcb - Kcb for the key 00711 00712 Return Value: 00713 00714 Pointer to the unicode string constructed. 00715 Caller is responsible to free this storage space. 00716 00717 --*/ 00718 { 00719 PUNICODE_STRING FullName; 00720 PCM_KEY_CONTROL_BLOCK TmpKcb; 00721 USHORT Length; 00722 USHORT size; 00723 USHORT i; 00724 USHORT BeginPosition; 00725 WCHAR *w1, *w2; 00726 UCHAR *u2; 00727 00728 // 00729 // Calculate the total string length. 00730 // 00731 Length = 0; 00732 TmpKcb = kcb; 00733 while (TmpKcb) { 00734 if (TmpKcb->NameBlock->Compressed) { 00735 Length += TmpKcb->NameBlock->NameLength * sizeof(WCHAR); 00736 } else { 00737 Length += TmpKcb->NameBlock->NameLength; 00738 } 00739 // 00740 // Add the sapce for OBJ_NAME_PATH_SEPARATOR; 00741 // 00742 Length += sizeof(WCHAR); 00743 00744 TmpKcb = TmpKcb->ParentKcb; 00745 } 00746 00747 // 00748 // Allocate the pool for the unicode string 00749 // 00750 size = sizeof(UNICODE_STRING) + Length; 00751 00752 FullName = (PUNICODE_STRING) ExAllocatePoolWithTag(PagedPool, 00753 size, 00754 CM_NAME_TAG | PROTECTED_POOL); 00755 00756 if (FullName) { 00757 FullName->Buffer = (USHORT *) ((ULONG_PTR) FullName + sizeof(UNICODE_STRING)); 00758 FullName->Length = Length; 00759 FullName->MaximumLength = Length; 00760 00761 // 00762 // Now fill the name into the buffer. 00763 // 00764 TmpKcb = kcb; 00765 BeginPosition = Length; 00766 00767 while (TmpKcb) { 00768 // 00769 // Calculate the begin position of each subkey. Then fill in the char. 00770 // 00771 // 00772 if (TmpKcb->NameBlock->Compressed) { 00773 BeginPosition -= (TmpKcb->NameBlock->NameLength + 1) * sizeof(WCHAR); 00774 w1 = &(FullName->Buffer[BeginPosition/sizeof(WCHAR)]); 00775 *w1 = OBJ_NAME_PATH_SEPARATOR; 00776 w1++; 00777 00778 u2 = (UCHAR *) &(TmpKcb->NameBlock->Name[0]); 00779 00780 for (i=0; i<TmpKcb->NameBlock->NameLength; i++) { 00781 *w1 = (WCHAR)(*u2); 00782 w1++; 00783 u2++; 00784 } 00785 } else { 00786 BeginPosition -= (TmpKcb->NameBlock->NameLength + sizeof(WCHAR)); 00787 w1 = &(FullName->Buffer[BeginPosition/sizeof(WCHAR)]); 00788 *w1 = OBJ_NAME_PATH_SEPARATOR; 00789 w1++; 00790 00791 w2 = TmpKcb->NameBlock->Name; 00792 00793 for (i=0; i<TmpKcb->NameBlock->NameLength; i=i+sizeof(WCHAR)) { 00794 *w1 = *w2; 00795 w1++; 00796 w2++; 00797 } 00798 } 00799 TmpKcb = TmpKcb->ParentKcb; 00800 } 00801 } 00802 return (FullName); 00803 } 00804 00805 00806 VOID 00807 CmpRemoveFromDelayedClose( 00808 IN PCM_KEY_CONTROL_BLOCK kcb 00809 ) 00810 { 00811 ULONG i; 00812 i = kcb->DelayedCloseIndex; 00813 00814 ASSERT (CmpDelayedCloseTable[i] == kcb); 00815 ASSERT(i != CmpDelayedCloseSize); 00816 00817 CmpDelayedCloseTable[i] = (PCM_KEY_CONTROL_BLOCK)CmpDelayedFreeIndex; 00818 CmpDelayedFreeIndex = i; 00819 kcb->DelayedCloseIndex = 0; 00820 } 00821 00822 00823 PCM_KEY_CONTROL_BLOCK 00824 CmpCreateKeyControlBlock( 00825 PHHIVE Hive, 00826 HCELL_INDEX Cell, 00827 PCM_KEY_NODE Node, 00828 PCM_KEY_CONTROL_BLOCK ParentKcb, 00829 BOOLEAN FakeKey, 00830 PUNICODE_STRING KeyName 00831 ) 00832 /*++ 00833 00834 Routine Description: 00835 00836 Allocate and initialize a key control block, insert it into 00837 the kcb tree. 00838 00839 Full path will be BaseName + '\' + KeyName, unless BaseName 00840 NULL, in which case the full path is simply KeyName. 00841 00842 RefCount of returned KCB WILL have been incremented to reflect 00843 callers ref. 00844 00845 Arguments: 00846 00847 Hive - Supplies Hive that holds the key we are creating a KCB for. 00848 00849 Cell - Supplies Cell that contains the key we are creating a KCB for. 00850 00851 Node - Supplies pointer to key node. 00852 00853 ParentKcb - Parent kcb of the kcb to be created 00854 00855 FakeKey - Whether the kcb to be create is a fake one or not 00856 00857 KeyName - the subkey name to of the KCB to be created. 00858 00859 NOTE: We need the parameter instead of just using the name in the KEY_NODE 00860 because there is no name in the root cell of a hive. 00861 00862 Return Value: 00863 00864 NULL - failure (insufficient memory) 00865 else a pointer to the new kcb. 00866 00867 --*/ 00868 { 00869 PCM_KEY_CONTROL_BLOCK kcb; 00870 PCM_KEY_CONTROL_BLOCK kcbmatch=NULL; 00871 PCMHIVE CmHive; 00872 ULONG namelength; 00873 PUNICODE_STRING fullname; 00874 ULONG Size; 00875 ULONG i; 00876 00877 UNICODE_STRING NodeName; 00878 ULONG ConvKey=0; 00879 ULONG Cnt; 00880 WCHAR *Cp; 00881 00882 // 00883 // ParentKCb has the base hash value. 00884 // 00885 if (ParentKcb) { 00886 ConvKey = ParentKcb->ConvKey; 00887 } 00888 00889 NodeName = *KeyName; 00890 00891 while ((NodeName.Length > 0) && (NodeName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR)) { 00892 // 00893 // This must be the \REGISTRY. 00894 // Strip off the leading OBJ_NAME_PATH_SEPARATOR 00895 // 00896 NodeName.Buffer++; 00897 NodeName.Length -= sizeof(WCHAR); 00898 } 00899 00900 // 00901 // Manually compute the hash to use. 00902 // 00903 ASSERT(NodeName.Length > 0); 00904 00905 if (NodeName.Length) { 00906 Cp = NodeName.Buffer; 00907 for (Cnt=0; Cnt<NodeName.Length; Cnt += sizeof(WCHAR)) { 00908 if ((*Cp != OBJ_NAME_PATH_SEPARATOR) && 00909 (*Cp != UNICODE_NULL)) { 00910 ConvKey = 37 * ConvKey + (ULONG)RtlUpcaseUnicodeChar(*Cp); 00911 } 00912 ++Cp; 00913 } 00914 } 00915 00916 // 00917 // Create a new kcb, which we will free if one already exists 00918 // for this key. 00919 // Now it is a fixed size structure. 00920 // 00921 kcb = ExAllocatePoolWithTag(PagedPool, 00922 sizeof(CM_KEY_CONTROL_BLOCK), 00923 CM_KCB_TAG | PROTECTED_POOL); 00924 00925 00926 if (kcb == NULL) { 00927 return(NULL); 00928 } else { 00929 SET_KCB_SIGNATURE(kcb, KCB_SIGNATURE); 00930 INIT_KCB_KEYBODY_LIST(kcb); 00931 kcb->Delete = FALSE; 00932 kcb->RefCount = 1; 00933 kcb->KeyHive = Hive; 00934 kcb->KeyCell = Cell; 00935 kcb->KeyNode = Node; 00936 kcb->ConvKey = ConvKey; 00937 00938 } 00939 00940 ASSERT_KCB(kcb); 00941 // 00942 // Find location to insert kcb in kcb tree. 00943 // 00944 00945 00946 LOCK_KCB_TREE(); 00947 00948 // 00949 // Add the KCB to the hash table 00950 // 00951 kcbmatch = CmpInsertKeyHash(&kcb->KeyHash, FakeKey); 00952 if (kcbmatch != NULL) { 00953 // 00954 // A match was found. 00955 // 00956 ASSERT(!kcbmatch->Delete); 00957 SET_KCB_SIGNATURE(kcb, '1FmC'); 00958 ASSERT_KEYBODY_LIST_EMPTY(kcb); 00959 ExFreePoolWithTag(kcb, CM_KCB_TAG | PROTECTED_POOL); 00960 ASSERT_KCB(kcbmatch); 00961 kcb = kcbmatch; 00962 if (kcb->RefCount == 0) { 00963 // 00964 // This kcb is on the delayed close list. Remove it from that 00965 // list. 00966 // 00967 CmpRemoveFromDelayedClose(kcb); 00968 } 00969 if ((USHORT)(kcb->RefCount + 1) == 0) { 00970 // 00971 // We have maxed out the ref count on this key. Probably 00972 // some bogus app has opened the same key 64K times without 00973 // ever closing it. Just fail the open, they've got enough 00974 // handles already. 00975 // 00976 ASSERT(kcb->RefCount + 1 != 0); 00977 kcb = NULL; 00978 } else { 00979 ++kcb->RefCount; 00980 } 00981 } 00982 else { 00983 // 00984 // No kcb created previously, fill in all the data. 00985 // 00986 00987 // 00988 // Now try to reference the parentkcb 00989 // 00990 00991 if (ParentKcb) { 00992 if (CmpReferenceKeyControlBlock(ParentKcb)) { 00993 kcb->ParentKcb = ParentKcb; 00994 kcb->TotalLevels = ParentKcb->TotalLevels + 1; 00995 } else { 00996 // 00997 // We have maxed out the ref count on the parent. 00998 // Since it has been cached in the cachetable, 00999 // remove it first before we free the allocation. 01000 // 01001 CmpRemoveKeyControlBlock(kcb); 01002 SET_KCB_SIGNATURE(kcb, '2FmC'); 01003 ASSERT_KEYBODY_LIST_EMPTY(kcb); 01004 ExFreePoolWithTag(kcb, CM_KCB_TAG | PROTECTED_POOL); 01005 kcb = NULL; 01006 } 01007 } else { 01008 // 01009 // It is the \REGISTRY node. 01010 // 01011 kcb->ParentKcb = NULL; 01012 kcb->TotalLevels = 1; 01013 } 01014 01015 if (kcb) { 01016 // 01017 // Now try to find the Name Control block that has the name for this node. 01018 // 01019 01020 kcb->NameBlock = CmpGetNameControlBlock (&NodeName); 01021 01022 if (kcb->NameBlock) { 01023 // 01024 // Now fill in all the data needed for the cache. 01025 // 01026 kcb->ValueCache.Count = Node->ValueList.Count; 01027 kcb->ValueCache.ValueList = (ULONG_PTR) Node->ValueList.List; 01028 01029 kcb->Flags = Node->Flags; 01030 kcb->ExtFlags = 0; 01031 kcb->DelayedCloseIndex = 0; 01032 01033 // 01034 // Cache the security cells in the kcb 01035 // 01036 kcb->Security = Node->Security; 01037 01038 if (FakeKey) { 01039 // 01040 // The KCb to be created is a fake one 01041 // 01042 kcb->ExtFlags |= CM_KCB_KEY_NON_EXIST; 01043 } 01044 } else { 01045 // 01046 // We have maxed out the ref count on the Name. 01047 // 01048 01049 // 01050 // First dereference the parent KCB. 01051 // 01052 CmpDereferenceKeyControlBlockWithLock(ParentKcb); 01053 01054 CmpRemoveKeyControlBlock(kcb); 01055 SET_KCB_SIGNATURE(kcb, '3FmC'); 01056 ASSERT_KEYBODY_LIST_EMPTY(kcb); 01057 ExFreePoolWithTag(kcb, CM_KCB_TAG | PROTECTED_POOL); 01058 kcb = NULL; 01059 } 01060 } 01061 } 01062 01063 01064 UNLOCK_KCB_TREE(); 01065 return kcb; 01066 } 01067 01068 01069 01070 VOID 01071 CmpSearchKeyControlBlockTree( 01072 PKCB_WORKER_ROUTINE WorkerRoutine, 01073 PVOID Context1, 01074 PVOID Context2 01075 ) 01076 /*++ 01077 01078 Routine Description: 01079 01080 Traverse the kcb tree. We will visit all nodes unless WorkerRoutine 01081 tells us to stop part way through. 01082 01083 For each node, call WorkerRoutine(..., Context1, Contex2). If it returns 01084 KCB_WORKER_DONE, we are done, simply return. If it returns 01085 KCB_WORKER_CONTINUE, just continue the search. If it returns KCB_WORKER_DELETE, 01086 the specified KCB is marked as deleted. 01087 01088 This routine has the side-effect of removing all delayed-close KCBs. 01089 01090 Arguments: 01091 01092 WorkerRoutine - applied to nodes witch Match. 01093 01094 Context1 - data we pass through 01095 01096 Context2 - data we pass through 01097 01098 01099 Return Value: 01100 01101 NONE. 01102 01103 --*/ 01104 { 01105 PCM_KEY_CONTROL_BLOCK Current; 01106 PCM_KEY_CONTROL_BLOCK Next; 01107 PCM_KEY_HASH *Prev; 01108 ULONG WorkerResult; 01109 ULONG i; 01110 01111 // 01112 // Walk the hash table 01113 // 01114 for (i=0; i<CmpHashTableSize; i++) { 01115 Prev = &CmpCacheTable[i]; 01116 while (*Prev) { 01117 Current = CONTAINING_RECORD(*Prev, 01118 CM_KEY_CONTROL_BLOCK, 01119 KeyHash); 01120 ASSERT_KCB(Current); 01121 ASSERT(!Current->Delete); 01122 if (Current->RefCount == 0) { 01123 // 01124 // This kcb is in DelayClose case, remove it. 01125 // 01126 CmpRemoveFromDelayedClose(Current); 01127 CmpCleanUpKcbCacheWithLock(Current); 01128 01129 // 01130 // The HashTable is changed, start over in this index again. 01131 // 01132 Prev = &CmpCacheTable[i]; 01133 continue; 01134 } 01135 01136 WorkerResult = (WorkerRoutine)(Current, Context1, Context2); 01137 if (WorkerResult == KCB_WORKER_DONE) { 01138 return; 01139 } else if (WorkerResult == KCB_WORKER_DELETE) { 01140 ASSERT(Current->Delete); 01141 *Prev = Current->NextHash; 01142 continue; 01143 } else { 01144 ASSERT(WorkerResult == KCB_WORKER_CONTINUE); 01145 Prev = &Current->NextHash; 01146 } 01147 } 01148 } 01149 } 01150 01151 01152 VOID 01153 CmpDereferenceKeyControlBlock( 01154 PCM_KEY_CONTROL_BLOCK KeyControlBlock 01155 ) 01156 /*++ 01157 01158 Routine Description: 01159 01160 Decrements the reference count on a key control block, and frees it if it 01161 becomes zero. 01162 01163 It is expected that no notify control blocks remain if the reference count 01164 becomes zero. 01165 01166 Arguments: 01167 01168 KeyControlBlock - pointer to a key control block. 01169 01170 Return Value: 01171 01172 NONE. 01173 01174 --*/ 01175 { 01176 LOCK_KCB_TREE(); 01177 CmpDereferenceKeyControlBlockWithLock(KeyControlBlock) ; 01178 UNLOCK_KCB_TREE(); 01179 return; 01180 } 01181 01182 01183 VOID 01184 CmpDereferenceKeyControlBlockWithLock( 01185 PCM_KEY_CONTROL_BLOCK KeyControlBlock 01186 ) 01187 { 01188 ULONG_PTR FreeIndex; 01189 PCM_KEY_CONTROL_BLOCK KcbToFree; 01190 01191 01192 01193 ASSERT_KCB(KeyControlBlock); 01194 01195 if (--KeyControlBlock->RefCount == 0) { 01196 // 01197 // Remove kcb from the tree 01198 // 01199 if (KeyControlBlock->ExtFlags & CM_KCB_NO_DELAY_CLOSE) { 01200 // 01201 // Free storage directly so we can clean up junk quickly. 01202 // 01203 // 01204 // Need to free all cached Index List, Index Leaf, Value, etc. 01205 // 01206 CmpCleanUpKcbCacheWithLock(KeyControlBlock); 01207 } else if (!KeyControlBlock->Delete) { 01208 01209 // 01210 // Put this kcb on our delayed close list. 01211 // 01212 // First check the free list for a free slot. 01213 // 01214 FreeIndex = CmpDelayedFreeIndex; 01215 if (FreeIndex != -1) { 01216 ASSERT(FreeIndex < CmpDelayedCloseSize); 01217 CmpDelayedFreeIndex = (ULONG_PTR)CmpDelayedCloseTable[FreeIndex]; 01218 KeyControlBlock->DelayedCloseIndex = (USHORT) FreeIndex; 01219 ASSERT((CmpDelayedFreeIndex == -1) || 01220 (CmpDelayedFreeIndex < CmpDelayedCloseSize)); 01221 CmpDelayedCloseTable[FreeIndex] = KeyControlBlock; 01222 } else { 01223 01224 // 01225 // Nothing is free, we have to get rid of something. 01226 // 01227 ASSERT(*CmpDelayedCloseCurrent != NULL); 01228 ASSERT(!(*CmpDelayedCloseCurrent)->Delete); 01229 // 01230 // Need to free all cached Index List, Index Leaf, Value, etc. 01231 // Change the code sequence for the recurrsive call to dereference the parent. 01232 // 01233 KcbToFree = *CmpDelayedCloseCurrent; 01234 *CmpDelayedCloseCurrent = KeyControlBlock; 01235 KeyControlBlock->DelayedCloseIndex = (USHORT)(CmpDelayedCloseCurrent - CmpDelayedCloseTable); 01236 ++CmpDelayedCloseCurrent; 01237 if ((ULONG)(CmpDelayedCloseCurrent - CmpDelayedCloseTable) == CmpDelayedCloseSize) { 01238 CmpDelayedCloseCurrent = CmpDelayedCloseTable; 01239 } 01240 01241 CmpCleanUpKcbCacheWithLock(KcbToFree); 01242 } 01243 } else { 01244 // 01245 // Free storage directly as there is no point in putting this on 01246 // our delayed close list. 01247 // 01248 // 01249 // Need to free all cached Index List, Index Leaf, Value, etc. 01250 // 01251 CmpCleanUpKcbCacheWithLock(KeyControlBlock); 01252 } 01253 } 01254 01255 return; 01256 } 01257 01258 01259 VOID 01260 CmpRemoveKeyControlBlock( 01261 PCM_KEY_CONTROL_BLOCK KeyControlBlock 01262 ) 01263 /*++ 01264 01265 Routine Description: 01266 01267 Remove a key control block from the KCB tree. 01268 01269 It is expected that no notify control blocks remain. 01270 01271 The kcb will NOT be freed, call DereferenceKeyControlBlock for that. 01272 01273 This call assumes the KCB tree is already locked or registry is locked exclusively. 01274 01275 Arguments: 01276 01277 KeyControlBlock - pointer to a key control block. 01278 01279 Return Value: 01280 01281 NONE. 01282 01283 --*/ 01284 { 01285 ASSERT_KCB(KeyControlBlock); 01286 01287 // 01288 // Remove the KCB from the hash table 01289 // 01290 CmpRemoveKeyHash(&KeyControlBlock->KeyHash); 01291 01292 return; 01293 } 01294 01295 01296 VOID 01297 CmpFreeKeyBody( 01298 PHHIVE Hive, 01299 HCELL_INDEX Cell 01300 ) 01301 /*++ 01302 01303 Routine Description: 01304 01305 Free storage for the key entry Hive.Cell refers to, including 01306 its class and security data. Will NOT free child list or value list. 01307 01308 Arguments: 01309 01310 Hive - supplies a pointer to the hive control structure for the hive 01311 01312 Cell - supplies index of key to free 01313 01314 Return Value: 01315 01316 NTSTATUS - Result code from call, among the following: 01317 01318 <TBS> 01319 01320 --*/ 01321 { 01322 PCELL_DATA key; 01323 01324 // 01325 // map in the cell 01326 // 01327 key = HvGetCell(Hive, Cell); 01328 01329 if (!(key->u.KeyNode.Flags & KEY_HIVE_EXIT)) { 01330 if (key->u.KeyNode.Security != HCELL_NIL) { 01331 HvFreeCell(Hive, key->u.KeyNode.Security); 01332 } 01333 01334 if (key->u.KeyNode.ClassLength > 0) { 01335 HvFreeCell(Hive, key->u.KeyNode.Class); 01336 } 01337 } 01338 01339 // 01340 // unmap the cell itself and free it 01341 // 01342 HvFreeCell(Hive, Cell); 01343 01344 return; 01345 } 01346 01347 01348 01349 PCM_KEY_CONTROL_BLOCK 01350 CmpInsertKeyHash( 01351 IN PCM_KEY_HASH KeyHash, 01352 IN BOOLEAN FakeKey 01353 ) 01354 /*++ 01355 01356 Routine Description: 01357 01358 Adds a key hash structure to the hash table. The hash table 01359 will be checked to see if a duplicate entry already exists. If 01360 a duplicate is found, its kcb will be returned. If a duplicate is not 01361 found, NULL will be returned. 01362 01363 Arguments: 01364 01365 KeyHash - Supplies the key hash structure to be added. 01366 01367 Return Value: 01368 01369 NULL - if the supplied key has was added 01370 PCM_KEY_HASH - The duplicate hash entry, if one was found 01371 01372 --*/ 01373 01374 { 01375 HASH_VALUE Hash; 01376 ULONG Index; 01377 PCM_KEY_HASH Current; 01378 01379 ASSERT_KEY_HASH(KeyHash); 01380 Index = GET_HASH_INDEX(KeyHash->ConvKey); 01381 01382 // 01383 // If this is a fake key, we will use the cell and hive from its 01384 // parent for uniqeness. To deal with the case when the fake 01385 // has the same ConvKey as its parent (in which case we cannot distingish 01386 // between the two), we set the lowest bit of the fake key's cell. 01387 // 01388 // It's possible (unlikely) that we cannot distingish two fake keys 01389 // (when their Convkey's are the same) under the same key. It is not breaking 01390 // anything, we just cannot find the other one in cache lookup. 01391 // 01392 // 01393 if (FakeKey) { 01394 KeyHash->KeyCell++; 01395 } 01396 01397 // 01398 // First look for duplicates. 01399 // 01400 Current = CmpCacheTable[Index]; 01401 while (Current) { 01402 ASSERT_KEY_HASH(Current); 01403 // 01404 // We must check ConvKey since we can create a fake kcb 01405 // for keys that does not exist. 01406 // We will use the Hive and Cell from the parent. 01407 // 01408 01409 if ((KeyHash->ConvKey == Current->ConvKey) && 01410 (KeyHash->KeyCell == Current->KeyCell) && 01411 (KeyHash->KeyHive == Current->KeyHive)) { 01412 // 01413 // Found a match 01414 // 01415 return(CONTAINING_RECORD(Current, 01416 CM_KEY_CONTROL_BLOCK, 01417 KeyHash)); 01418 } 01419 Current = Current->NextHash; 01420 } 01421 01422 #if DBG 01423 // 01424 // Make sure this key is not somehow cached in the wrong spot. 01425 // 01426 { 01427 ULONG DbgIndex; 01428 PCM_KEY_CONTROL_BLOCK kcb; 01429 01430 for (DbgIndex = 0; DbgIndex < CmpHashTableSize; DbgIndex++) { 01431 Current = CmpCacheTable[DbgIndex]; 01432 while (Current) { 01433 kcb = CONTAINING_RECORD(Current, 01434 CM_KEY_CONTROL_BLOCK, 01435 KeyHash); 01436 01437 ASSERT_KEY_HASH(Current); 01438 ASSERT((KeyHash->KeyHive != Current->KeyHive) || 01439 FakeKey || 01440 (kcb->ExtFlags & CM_KCB_KEY_NON_EXIST) || 01441 (KeyHash->KeyCell != Current->KeyCell)); 01442 Current = Current->NextHash; 01443 } 01444 } 01445 } 01446 01447 #endif 01448 01449 // 01450 // No duplicate was found, add this entry at the head of the list 01451 // 01452 KeyHash->NextHash = CmpCacheTable[Index]; 01453 CmpCacheTable[Index] = KeyHash; 01454 return(NULL); 01455 } 01456 01457 01458 VOID 01459 CmpRemoveKeyHash( 01460 IN PCM_KEY_HASH KeyHash 01461 ) 01462 /*++ 01463 01464 Routine Description: 01465 01466 Removes a key hash structure from the hash table. 01467 01468 Arguments: 01469 01470 KeyHash - Supplies the key hash structure to be deleted. 01471 01472 Return Value: 01473 01474 None 01475 01476 --*/ 01477 01478 { 01479 HASH_VALUE Hash; 01480 ULONG Index; 01481 PCM_KEY_HASH *Prev; 01482 PCM_KEY_HASH Current; 01483 01484 ASSERT_KEY_HASH(KeyHash); 01485 01486 Hash = HASH_KEY(KeyHash->ConvKey); 01487 Index = Hash % CmpHashTableSize; 01488 01489 // 01490 // Find this entry. 01491 // 01492 Prev = &CmpCacheTable[Index]; 01493 while (TRUE) { 01494 Current = *Prev; 01495 ASSERT(Current != NULL); 01496 ASSERT_KEY_HASH(Current); 01497 if (Current == KeyHash) { 01498 *Prev = Current->NextHash; 01499 #if DBG 01500 if (*Prev) { 01501 ASSERT_KEY_HASH(*Prev); 01502 } 01503 #endif 01504 break; 01505 } 01506 Prev = &Current->NextHash; 01507 } 01508 } 01509 01510 01511 VOID 01512 CmpInitializeCache() 01513 { 01514 ULONG TotalCmCacheSize; 01515 ULONG i; 01516 01517 TotalCmCacheSize = CmpHashTableSize * sizeof(PCM_KEY_HASH); 01518 01519 CmpCacheTable = ExAllocatePoolWithTag(PagedPool, 01520 TotalCmCacheSize, 01521 'aCMC'); 01522 if (CmpCacheTable == NULL) { 01523 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED,6,1,0,0); 01524 return; 01525 } 01526 RtlZeroMemory(CmpCacheTable, TotalCmCacheSize); 01527 01528 TotalCmCacheSize = CmpHashTableSize * sizeof(PCM_NAME_HASH); 01529 CmpNameCacheTable = ExAllocatePoolWithTag(PagedPool, 01530 TotalCmCacheSize, 01531 'aCMC'); 01532 if (CmpNameCacheTable == NULL) { 01533 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED,6,1,0,0); 01534 return; 01535 } 01536 RtlZeroMemory(CmpNameCacheTable, TotalCmCacheSize); 01537 01538 CmpDelayedCloseTable = ExAllocatePoolWithTag(PagedPool, 01539 CmpDelayedCloseSize * sizeof(PCM_KEY_CONTROL_BLOCK), 01540 'cDMC'); 01541 if (CmpDelayedCloseTable == NULL) { 01542 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED,6,2,0,0); 01543 return; 01544 } 01545 CmpDelayedFreeIndex = 0; 01546 for (i=0; i<CmpDelayedCloseSize-1; i++) { 01547 CmpDelayedCloseTable[i] = (PCM_KEY_CONTROL_BLOCK)ULongToPtr(i+1); 01548 } 01549 CmpDelayedCloseTable[CmpDelayedCloseSize-1] = (PCM_KEY_CONTROL_BLOCK)-1; 01550 CmpDelayedCloseCurrent = CmpDelayedCloseTable; 01551 }

Generated on Sat May 15 19:39:28 2004 for test by doxygen 1.3.7