Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2169 lines
61 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. cmsubs.c
  5. Abstract:
  6. This module various support routines for the configuration manager.
  7. The routines in this module are not independent enough to be linked
  8. into any other program. The routines in cmsubs2.c are.
  9. Author:
  10. Bryan M. Willman (bryanwi) 12-Sep-1991
  11. Revision History:
  12. --*/
  13. #include "cmp.h"
  14. FAST_MUTEX CmpPostLock;
  15. #ifdef ALLOC_DATA_PRAGMA
  16. #pragma data_seg("PAGEDATA")
  17. #endif
  18. extern ULONG CmpDelayedCloseSize;
  19. extern BOOLEAN CmpHoldLazyFlush;
  20. PCM_KEY_HASH *CmpCacheTable = NULL;
  21. ULONG CmpHashTableSize = 2048;
  22. PCM_NAME_HASH *CmpNameCacheTable = NULL;
  23. #ifdef CMP_STATS
  24. extern struct {
  25. ULONG CmpMaxKcbNo;
  26. ULONG CmpKcbNo;
  27. ULONG CmpStatNo;
  28. ULONG CmpNtCreateKeyNo;
  29. ULONG CmpNtDeleteKeyNo;
  30. ULONG CmpNtDeleteValueKeyNo;
  31. ULONG CmpNtEnumerateKeyNo;
  32. ULONG CmpNtEnumerateValueKeyNo;
  33. ULONG CmpNtFlushKeyNo;
  34. ULONG CmpNtNotifyChangeMultipleKeysNo;
  35. ULONG CmpNtOpenKeyNo;
  36. ULONG CmpNtQueryKeyNo;
  37. ULONG CmpNtQueryValueKeyNo;
  38. ULONG CmpNtQueryMultipleValueKeyNo;
  39. ULONG CmpNtRestoreKeyNo;
  40. ULONG CmpNtSaveKeyNo;
  41. ULONG CmpNtSaveMergedKeysNo;
  42. ULONG CmpNtSetValueKeyNo;
  43. ULONG CmpNtLoadKeyNo;
  44. ULONG CmpNtUnloadKeyNo;
  45. ULONG CmpNtSetInformationKeyNo;
  46. ULONG CmpNtReplaceKeyNo;
  47. ULONG CmpNtQueryOpenSubKeysNo;
  48. } CmpStatsDebug;
  49. #endif
  50. VOID
  51. CmpRemoveKeyHash(
  52. IN PCM_KEY_HASH KeyHash
  53. );
  54. PCM_KEY_CONTROL_BLOCK
  55. CmpInsertKeyHash(
  56. IN PCM_KEY_HASH KeyHash,
  57. IN BOOLEAN FakeKey
  58. );
  59. //
  60. // private prototype for recursive worker
  61. //
  62. VOID
  63. CmpDereferenceNameControlBlockWithLock(
  64. PCM_NAME_CONTROL_BLOCK Ncb
  65. );
  66. VOID
  67. CmpDumpKeyBodyList(
  68. IN PCM_KEY_CONTROL_BLOCK kcb,
  69. IN PULONG Count,
  70. IN PVOID Context
  71. );
  72. #ifdef NT_RENAME_KEY
  73. ULONG
  74. CmpComputeKcbConvKey(
  75. PCM_KEY_CONTROL_BLOCK KeyControlBlock
  76. );
  77. BOOLEAN
  78. CmpRehashKcbSubtree(
  79. PCM_KEY_CONTROL_BLOCK Start,
  80. PCM_KEY_CONTROL_BLOCK End
  81. );
  82. #endif //NT_RENAME_KEY
  83. VOID
  84. CmpRebuildKcbCache(
  85. PCM_KEY_CONTROL_BLOCK KeyControlBlock
  86. );
  87. #ifdef ALLOC_PRAGMA
  88. #pragma alloc_text(PAGE,CmpCleanUpKCBCacheTable)
  89. #pragma alloc_text(PAGE,CmpSearchForOpenSubKeys)
  90. #pragma alloc_text(PAGE,CmpReferenceKeyControlBlock)
  91. #pragma alloc_text(PAGE,CmpGetNameControlBlock)
  92. #pragma alloc_text(PAGE,CmpDereferenceNameControlBlockWithLock)
  93. #pragma alloc_text(PAGE,CmpCleanUpSubKeyInfo)
  94. #pragma alloc_text(PAGE,CmpCleanUpKcbValueCache)
  95. #pragma alloc_text(PAGE,CmpCleanUpKcbCacheWithLock)
  96. #pragma alloc_text(PAGE,CmpConstructName)
  97. #pragma alloc_text(PAGE,CmpCreateKeyControlBlock)
  98. #pragma alloc_text(PAGE,CmpSearchKeyControlBlockTree)
  99. #pragma alloc_text(PAGE,CmpDereferenceKeyControlBlock)
  100. #pragma alloc_text(PAGE,CmpDereferenceKeyControlBlockWithLock)
  101. #pragma alloc_text(PAGE,CmpRemoveKeyControlBlock)
  102. #pragma alloc_text(PAGE,CmpFreeKeyBody)
  103. #pragma alloc_text(PAGE,CmpInsertKeyHash)
  104. #pragma alloc_text(PAGE,CmpRemoveKeyHash)
  105. #pragma alloc_text(PAGE,CmpInitializeCache)
  106. #pragma alloc_text(PAGE,CmpDumpKeyBodyList)
  107. #pragma alloc_text(PAGE,CmpFlushNotifiesOnKeyBodyList)
  108. #pragma alloc_text(PAGE,CmpRebuildKcbCache)
  109. #ifdef NT_RENAME_KEY
  110. #pragma alloc_text(PAGE,CmpComputeKcbConvKey)
  111. #pragma alloc_text(PAGE,CmpRehashKcbSubtree)
  112. #endif //NT_RENAME_KEY
  113. #ifdef CM_CHECK_FOR_ORPHANED_KCBS
  114. #pragma alloc_text(PAGE,CmpCheckForOrphanedKcbs)
  115. #endif //CM_CHECK_FOR_ORPHANED_KCBS
  116. #endif
  117. VOID
  118. CmpDumpKeyBodyList(
  119. IN PCM_KEY_CONTROL_BLOCK kcb,
  120. IN PULONG Count,
  121. IN PVOID Context
  122. )
  123. {
  124. PCM_KEY_BODY KeyBody;
  125. PUNICODE_STRING Name;
  126. if( IsListEmpty(&(kcb->KeyBodyListHead)) == TRUE ) {
  127. //
  128. // Nobody has this subkey open, but for sure some subkey must be
  129. // open. nicely return.
  130. //
  131. return;
  132. }
  133. Name = CmpConstructName(kcb);
  134. if( !Name ){
  135. // oops, we're low on resources
  136. if( Context != NULL ) {
  137. ((PQUERY_OPEN_SUBKEYS_CONTEXT)Context)->StatusCode = STATUS_INSUFFICIENT_RESOURCES;
  138. }
  139. return;
  140. }
  141. //
  142. // now iterate through the list of KEY_BODYs referencing this kcb
  143. //
  144. KeyBody = (PCM_KEY_BODY)kcb->KeyBodyListHead.Flink;
  145. while( KeyBody != (PCM_KEY_BODY)(&(kcb->KeyBodyListHead)) ) {
  146. KeyBody = CONTAINING_RECORD(KeyBody,
  147. CM_KEY_BODY,
  148. KeyBodyList);
  149. //
  150. // sanity check: this should be a KEY_BODY
  151. //
  152. ASSERT_KEY_OBJECT(KeyBody);
  153. if( !Context ) {
  154. //
  155. // NtQueryOpenSubKeys : dump it's name and owning process
  156. //
  157. #ifndef _CM_LDR_
  158. {
  159. PEPROCESS Process;
  160. PUCHAR ImageName = NULL;
  161. if( NT_SUCCESS(PsLookupProcessByProcessId(KeyBody->ProcessID,&Process))) {
  162. ImageName = PsGetProcessImageFileName(Process);
  163. } else {
  164. Process = NULL;
  165. }
  166. if( !ImageName ) {
  167. ImageName = (PUCHAR)"Unknown";
  168. }
  169. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"Process %p (PID = %lx ImageFileName = %s) (KCB = %p) :: Key %wZ \n",
  170. Process,KeyBody->ProcessID,ImageName,kcb,Name);
  171. if( Process ) {
  172. ObDereferenceObject (Process);
  173. }
  174. #ifdef CM_LEAK_STACK_TRACES
  175. if( KeyBody->Callers != 0 ) {
  176. ULONG i;
  177. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"Callers Stack Trace : \n");
  178. for( i=0;i<KeyBody->Callers;i++) {
  179. DbgPrintEx(DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"\t CallerAddress[%lu] = %p \n",i,KeyBody->CallerAddress[i]);
  180. }
  181. }
  182. #endif //CM_LEAK_STACK_TRACES
  183. }
  184. #endif //_CM_LDR_
  185. } else {
  186. //
  187. // NtQueryOpenSubKeysEx: build up the return buffer; make sure we only touch it
  188. // inside a try except as it's user-mode buffer
  189. //
  190. PQUERY_OPEN_SUBKEYS_CONTEXT QueryContext = (PQUERY_OPEN_SUBKEYS_CONTEXT)Context;
  191. PKEY_OPEN_SUBKEYS_INFORMATION SubkeysInfo = (PKEY_OPEN_SUBKEYS_INFORMATION)(QueryContext->Buffer);
  192. ULONG SizeNeeded;
  193. //
  194. // we need to ignore the one created by us inside NtQueryOpenSubKeysEx
  195. //
  196. if( QueryContext->KeyBodyToIgnore != KeyBody ) {
  197. //
  198. // update RequiredSize; we do this regardless if we have room or not in the buffer
  199. // reserve for one entry in the array and the unicode name buffer
  200. //
  201. SizeNeeded = (sizeof(KEY_PID_ARRAY) + (ULONG)(Name->Length));
  202. QueryContext->RequiredSize += SizeNeeded;
  203. //
  204. // if we have encountered an error (overflow, or else) at some previous iteration, no point going on
  205. //
  206. if( NT_SUCCESS(QueryContext->StatusCode) ) {
  207. //
  208. // see if we have enough room for current entry.
  209. //
  210. if( (QueryContext->UsedLength + SizeNeeded) > QueryContext->BufferLength ) {
  211. //
  212. // buffer not big enough;
  213. //
  214. QueryContext->StatusCode = STATUS_BUFFER_OVERFLOW;
  215. } else {
  216. //
  217. // we have established we have enough room; create/add a new entry to the key array
  218. // and build up unicode name buffer. copy key name to it.
  219. // array elements are at the beggining of the user buffer, while name buffers start at
  220. // the end and continue bacwards, as long as there is enough room.
  221. //
  222. try {
  223. //
  224. // protect user mode memory
  225. //
  226. SubkeysInfo->KeyArray[SubkeysInfo->Count].PID = KeyBody->ProcessID;
  227. SubkeysInfo->KeyArray[SubkeysInfo->Count].KeyName.Length = Name->Length;
  228. SubkeysInfo->KeyArray[SubkeysInfo->Count].KeyName.MaximumLength = Name->Length;
  229. SubkeysInfo->KeyArray[SubkeysInfo->Count].KeyName.Buffer = (PWSTR)((PUCHAR)QueryContext->CurrentNameBuffer - Name->Length);
  230. RtlCopyMemory( SubkeysInfo->KeyArray[SubkeysInfo->Count].KeyName.Buffer,
  231. Name->Buffer,
  232. Name->Length);
  233. //
  234. // update array count and work vars inside the querycontext
  235. //
  236. SubkeysInfo->Count++;
  237. QueryContext->CurrentNameBuffer = (PUCHAR)QueryContext->CurrentNameBuffer - Name->Length;
  238. QueryContext->UsedLength += SizeNeeded;
  239. } except (EXCEPTION_EXECUTE_HANDLER) {
  240. QueryContext->StatusCode = GetExceptionCode();
  241. }
  242. }
  243. }
  244. }
  245. }
  246. // count it
  247. (*Count)++;
  248. KeyBody = (PCM_KEY_BODY)KeyBody->KeyBodyList.Flink;
  249. }
  250. ExFreePoolWithTag(Name, CM_NAME_TAG | PROTECTED_POOL);
  251. }
  252. VOID
  253. CmpFlushNotifiesOnKeyBodyList(
  254. IN PCM_KEY_CONTROL_BLOCK kcb
  255. )
  256. {
  257. PCM_KEY_BODY KeyBody;
  258. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  259. Again:
  260. if( IsListEmpty(&(kcb->KeyBodyListHead)) == FALSE ) {
  261. //
  262. // now iterate through the list of KEY_BODYs referencing this kcb
  263. //
  264. KeyBody = (PCM_KEY_BODY)kcb->KeyBodyListHead.Flink;
  265. while( KeyBody != (PCM_KEY_BODY)(&(kcb->KeyBodyListHead)) ) {
  266. KeyBody = CONTAINING_RECORD(KeyBody,
  267. CM_KEY_BODY,
  268. KeyBodyList);
  269. //
  270. // sanity check: this should be a KEY_BODY
  271. //
  272. ASSERT_KEY_OBJECT(KeyBody);
  273. //
  274. // flush any notifies that might be set on it
  275. //
  276. if( KeyBody->NotifyBlock ) {
  277. //
  278. // add an extra reference on the key body so it won't go away.
  279. //
  280. //ObReferenceObject(KeyBody);
  281. if(ObReferenceObjectSafe(KeyBody)) {
  282. CmpFlushNotify(KeyBody,TRUE);
  283. ASSERT( KeyBody->NotifyBlock == NULL );
  284. ObDereferenceObject(KeyBody);
  285. goto Again;
  286. }
  287. }
  288. KeyBody = (PCM_KEY_BODY)KeyBody->KeyBodyList.Flink;
  289. }
  290. }
  291. }
  292. VOID CmpCleanUpKCBCacheTable()
  293. /*++
  294. Routine Description:
  295. Kicks out of cache all kcbs with RefCount == 0
  296. Arguments:
  297. Return Value:
  298. --*/
  299. {
  300. ULONG i;
  301. PCM_KEY_HASH *Current;
  302. PCM_KEY_CONTROL_BLOCK kcb;
  303. PAGED_CODE();
  304. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  305. for (i=0; i<CmpHashTableSize; i++) {
  306. Current = &CmpCacheTable[i];
  307. while (*Current) {
  308. kcb = CONTAINING_RECORD(*Current, CM_KEY_CONTROL_BLOCK, KeyHash);
  309. if (kcb->RefCount == 0) {
  310. //
  311. // This kcb is in DelayClose case, remove it.
  312. //
  313. CmpRemoveFromDelayedClose(kcb);
  314. CmpCleanUpKcbCacheWithLock(kcb);
  315. //
  316. // The HashTable is changed, start over in this index again.
  317. //
  318. Current = &CmpCacheTable[i];
  319. continue;
  320. }
  321. Current = &kcb->NextHash;
  322. }
  323. }
  324. }
  325. PERFINFO_REG_DUMP_CACHE()
  326. ULONG
  327. CmpSearchForOpenSubKeys(
  328. PCM_KEY_CONTROL_BLOCK KeyControlBlock,
  329. SUBKEY_SEARCH_TYPE SearchType,
  330. PVOID SearchContext
  331. )
  332. /*++
  333. Routine Description:
  334. This routine searches the KCB tree for any open handles to keys that
  335. are subkeys of the given key.
  336. It is used by CmRestoreKey to verify that the tree being restored to
  337. has no open handles.
  338. Arguments:
  339. KeyControlBlock - Supplies the key control block for the key for which
  340. open subkeys are to be found.
  341. SearchType - the type of the search
  342. SearchIfExist - exits at the first open subkey found ==> returns 1 if any subkey is open
  343. SearchAndDeref - Forces the keys underneath the Key referenced KeyControlBlock to
  344. be marked as not referenced (see the REG_FORCE_RESTORE flag in CmRestoreKey)
  345. returns 1 if at least one deref was made
  346. SearchAndCount - Counts all open subkeys - returns the number of them
  347. Return Value:
  348. TRUE - open handles to subkeys of the given key exist
  349. FALSE - open handles to subkeys of the given key do not exist.
  350. --*/
  351. {
  352. ULONG i;
  353. PCM_KEY_HASH *Current;
  354. PCM_KEY_CONTROL_BLOCK kcb;
  355. PCM_KEY_CONTROL_BLOCK Parent;
  356. ULONG LevelDiff, l;
  357. ULONG Count = 0;
  358. //
  359. // Registry lock should be held exclusively, so no need to KCB lock
  360. //
  361. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  362. //
  363. // First, clean up all subkeys in the cache
  364. //
  365. CmpCleanUpKCBCacheTable();
  366. if (KeyControlBlock->RefCount == 1) {
  367. //
  368. // There is only one open handle, so there must be no open subkeys.
  369. //
  370. Count = 0;
  371. } else {
  372. //
  373. // Now search for an open subkey handle.
  374. //
  375. Count = 0;
  376. //
  377. // dump the root first if we were asked to do so.
  378. //
  379. if(SearchType == SearchAndCount) {
  380. CmpDumpKeyBodyList(KeyControlBlock,&Count,SearchContext);
  381. }
  382. for (i=0; i<CmpHashTableSize; i++) {
  383. StartDeref:
  384. Current = &CmpCacheTable[i];
  385. while (*Current) {
  386. kcb = CONTAINING_RECORD(*Current, CM_KEY_CONTROL_BLOCK, KeyHash);
  387. if (kcb->TotalLevels > KeyControlBlock->TotalLevels) {
  388. LevelDiff = kcb->TotalLevels - KeyControlBlock->TotalLevels;
  389. Parent = kcb;
  390. for (l=0; l<LevelDiff; l++) {
  391. Parent = Parent->ParentKcb;
  392. }
  393. if (Parent == KeyControlBlock) {
  394. //
  395. // Found a match;
  396. //
  397. if( SearchType == SearchIfExist ) {
  398. Count = 1;
  399. break;
  400. } else if(SearchType == SearchAndTagNoDelayClose) {
  401. kcb->ExtFlags |= CM_KCB_NO_DELAY_CLOSE;
  402. } else if(SearchType == SearchAndDeref) {
  403. //
  404. // Mark the key as deleted, remove it from cache, but don't add it
  405. // to the Delay Close table (we want the key to be visible only to
  406. // the one(s) that have open handles on it.
  407. //
  408. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  409. Count++;
  410. //
  411. // don't mess with read only kcbs; this prevents a potential hack when
  412. // trying to FORCE_RESTORE over WPA keys.
  413. //
  414. if( !CmIsKcbReadOnly(kcb) ) {
  415. //
  416. // flush any pending notifies as the kcb won't be around any longer
  417. //
  418. CmpFlushNotifiesOnKeyBodyList(kcb);
  419. CmpCleanUpSubKeyInfo(kcb->ParentKcb);
  420. kcb->Delete = TRUE;
  421. CmpRemoveKeyControlBlock(kcb);
  422. kcb->KeyCell = HCELL_NIL;
  423. //
  424. // Restart the search
  425. //
  426. goto StartDeref;
  427. }
  428. } else if(SearchType == SearchAndCount) {
  429. //
  430. // here do the dumping and count incrementing stuff
  431. //
  432. CmpDumpKeyBodyList(kcb,&Count,SearchContext);
  433. #ifdef NT_RENAME_KEY
  434. } else if( SearchType == SearchAndRehash ) {
  435. //
  436. // every kcb which has the one passed as a parameter
  437. // as an ancestor needs to be moved to the right location
  438. // in the kcb hash table.
  439. //
  440. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  441. if( CmpRehashKcbSubtree(KeyControlBlock,kcb) == TRUE ) {
  442. //
  443. // at least one kcb has been moved, we need to reiterate this bucket
  444. //
  445. goto StartDeref;
  446. }
  447. #endif //NT_RENAME_KEY
  448. }
  449. }
  450. }
  451. Current = &kcb->NextHash;
  452. }
  453. }
  454. }
  455. return Count;
  456. }
  457. #ifdef NT_RENAME_KEY
  458. ULONG
  459. CmpComputeKcbConvKey(
  460. PCM_KEY_CONTROL_BLOCK KeyControlBlock
  461. )
  462. /*++
  463. Routine Description:
  464. Computes the convkey for this kcb based on the NCB and its parent ConvKey
  465. Arguments:
  466. KeyControlBlock - Supplies the key control block for the key for which
  467. the ConvKey is to be calculated
  468. Return Value:
  469. The new ConvKey
  470. Notes:
  471. This is to be used by the rename key api, which needs to rehash kcbs
  472. --*/
  473. {
  474. ULONG ConvKey = 0;
  475. ULONG Cnt;
  476. WCHAR Cp;
  477. PUCHAR u;
  478. PWCHAR w;
  479. PAGED_CODE();
  480. if( KeyControlBlock->ParentKcb != NULL ) {
  481. ConvKey = KeyControlBlock->ParentKcb->ConvKey;
  482. }
  483. //
  484. // Manually compute the hash to use.
  485. //
  486. ASSERT(KeyControlBlock->NameBlock->NameLength > 0);
  487. u = (PUCHAR)(&(KeyControlBlock->NameBlock->Name[0]));
  488. w = (PWCHAR)u;
  489. for( Cnt = 0; Cnt < KeyControlBlock->NameBlock->NameLength;) {
  490. if( KeyControlBlock->NameBlock->Compressed ) {
  491. Cp = (WCHAR)(*u);
  492. u++;
  493. Cnt += sizeof(UCHAR);
  494. } else {
  495. Cp = *w;
  496. w++;
  497. Cnt += sizeof(WCHAR);
  498. }
  499. ASSERT( Cp != OBJ_NAME_PATH_SEPARATOR );
  500. ConvKey = 37 * ConvKey + (ULONG)CmUpcaseUnicodeChar(Cp);
  501. }
  502. return ConvKey;
  503. }
  504. BOOLEAN
  505. CmpRehashKcbSubtree(
  506. PCM_KEY_CONTROL_BLOCK Start,
  507. PCM_KEY_CONTROL_BLOCK End
  508. )
  509. /*++
  510. Routine Description:
  511. Walks the path between End and Start and rehashed all kcbs that need
  512. rehashing;
  513. Assumptions: It is apriori taken that Start is an ancestor of End;
  514. Works in two steps:
  515. 1. walks the path backwards from End to Start, reverting the back-link
  516. (we use the ParentKcb member in the kcb structure for that). I.e. we build a
  517. forward path from Start to End
  518. 2.Walks the forward path built at 1, rehashes kcbs whos need rehashing and restores
  519. the parent relationship.
  520. Arguments:
  521. KeyControlBlock - where we start
  522. kcb - where we stop
  523. Return Value:
  524. TRUE if at least one kcb has been rehashed
  525. --*/
  526. {
  527. PCM_KEY_CONTROL_BLOCK Parent;
  528. PCM_KEY_CONTROL_BLOCK Current;
  529. PCM_KEY_CONTROL_BLOCK TmpKcb;
  530. ULONG ConvKey;
  531. BOOLEAN Result;
  532. PAGED_CODE();
  533. #if DBG
  534. //
  535. // make sure Start is an ancestor of End;
  536. //
  537. {
  538. ULONG LevelDiff = End->TotalLevels - Start->TotalLevels;
  539. ASSERT( (LONG)LevelDiff >= 0 );
  540. TmpKcb = End;
  541. for(;LevelDiff; LevelDiff--) {
  542. TmpKcb = TmpKcb->ParentKcb;
  543. }
  544. ASSERT( TmpKcb == Start );
  545. }
  546. #endif
  547. //
  548. // Step 1: walk the path backwards (using the parentkcb link) and
  549. // revert it, until we reach Start. It is assumed that Start is an
  550. // ancestor of End (the caller must not call this function otherwise !!!)
  551. //
  552. Current = NULL;
  553. Parent = End;
  554. while( Current != Start ) {
  555. //
  556. // revert the link
  557. //
  558. TmpKcb = Parent->ParentKcb;
  559. Parent->ParentKcb = Current;
  560. Current = Parent;
  561. Parent = TmpKcb;
  562. ASSERT( Current->TotalLevels >= Start->TotalLevels );
  563. }
  564. ASSERT( Current == Start );
  565. //
  566. // Step 2: Walk the forward path built at 1 and rehash the kcbs that need
  567. // caching; At the same time, restore the links (parent relationships)
  568. //
  569. Result = FALSE;
  570. while( Current != NULL ) {
  571. //
  572. // see if we need to rehash this kcb;
  573. //
  574. //
  575. // restore the parent relationship; need to do this first so
  576. // CmpComputeKcbConvKey works OK
  577. //
  578. TmpKcb = Current->ParentKcb;
  579. Current->ParentKcb = Parent;
  580. ConvKey = CmpComputeKcbConvKey(Current);
  581. if( ConvKey != Current->ConvKey ) {
  582. //
  583. // rehash the kcb by removing it from hash, and then inserting it
  584. // again with th new ConvKey
  585. //
  586. CmpRemoveKeyHash(&(Current->KeyHash));
  587. Current->ConvKey = ConvKey;
  588. CmpInsertKeyHash(&(Current->KeyHash),FALSE);
  589. Result = TRUE;
  590. }
  591. //
  592. // advance forward
  593. //
  594. Parent = Current;
  595. Current = TmpKcb;
  596. }
  597. ASSERT( Parent == End );
  598. return Result;
  599. }
  600. #endif //NT_RENAME_KEY
  601. BOOLEAN
  602. CmpReferenceKeyControlBlock(
  603. PCM_KEY_CONTROL_BLOCK KeyControlBlock
  604. )
  605. {
  606. // Note: this is called only under KCB lock
  607. LONG RefCount;
  608. RefCount = (InterlockedIncrement( (PLONG)&KeyControlBlock->RefCount )) & 0xffff;
  609. if (RefCount == 1) {
  610. //
  611. // need to get the lock exclusive as we are changing the cache table
  612. //
  613. if (CmpKcbOwner != KeGetCurrentThread()) {
  614. CmpUnlockKCBTree();
  615. CmpLockKCBTreeExclusive();
  616. }
  617. CmpRemoveFromDelayedClose(KeyControlBlock);
  618. } else if (RefCount == 0) {
  619. //
  620. // We have maxed out the ref count on this key. Probably
  621. // some bogus app has opened the same key 64K times without
  622. // ever closing it. Just fail the call
  623. //
  624. InterlockedDecrement( (PLONG)&KeyControlBlock->RefCount);
  625. return FALSE;
  626. }
  627. return TRUE;
  628. }
  629. PCM_NAME_CONTROL_BLOCK
  630. CmpGetNameControlBlock(
  631. PUNICODE_STRING NodeName
  632. )
  633. {
  634. PCM_NAME_CONTROL_BLOCK Ncb = NULL;
  635. ULONG Cnt;
  636. WCHAR *Cp;
  637. WCHAR *Cp2;
  638. ULONG Index;
  639. ULONG i;
  640. ULONG Size;
  641. PCM_NAME_HASH CurrentName;
  642. BOOLEAN NameFound = FALSE;
  643. USHORT NameSize;
  644. BOOLEAN NameCompressed;
  645. ULONG NameConvKey=0;
  646. //
  647. // Calculate the ConvKey for this NodeName;
  648. //
  649. Cp = NodeName->Buffer;
  650. for (Cnt=0; Cnt<NodeName->Length; Cnt += sizeof(WCHAR)) {
  651. if (*Cp != OBJ_NAME_PATH_SEPARATOR) {
  652. NameConvKey = 37 * NameConvKey + (ULONG) CmUpcaseUnicodeChar(*Cp);
  653. }
  654. ++Cp;
  655. }
  656. //
  657. // Find the Name Size;
  658. //
  659. NameCompressed = TRUE;
  660. NameSize = NodeName->Length / sizeof(WCHAR);
  661. for (i=0;i<NodeName->Length/sizeof(WCHAR);i++) {
  662. if ((USHORT)NodeName->Buffer[i] > (UCHAR)-1) {
  663. NameSize = NodeName->Length;
  664. NameCompressed = FALSE;
  665. }
  666. }
  667. Index = GET_HASH_INDEX(NameConvKey);
  668. CurrentName = CmpNameCacheTable[Index];
  669. while (CurrentName) {
  670. Ncb = CONTAINING_RECORD(CurrentName, CM_NAME_CONTROL_BLOCK, NameHash);
  671. if ((NameConvKey == CurrentName->ConvKey) &&
  672. (NameSize == Ncb->NameLength)) {
  673. //
  674. // Hash value matches, compare the names.
  675. //
  676. NameFound = TRUE;
  677. if (Ncb->Compressed) {
  678. // we already know the name is uppercase
  679. if (CmpCompareCompressedName(NodeName, Ncb->Name, NameSize, CMP_DEST_UP)) {
  680. NameFound = FALSE;
  681. }
  682. } else {
  683. Cp = (WCHAR *) NodeName->Buffer;
  684. Cp2 = (WCHAR *) Ncb->Name;
  685. for (i=0 ;i<Ncb->NameLength; i+= sizeof(WCHAR)) {
  686. //
  687. // Cp2 is always uppercase; see below
  688. //
  689. if (CmUpcaseUnicodeChar(*Cp) != (*Cp2) ) {
  690. NameFound = FALSE;
  691. break;
  692. }
  693. ++Cp;
  694. ++Cp2;
  695. }
  696. }
  697. if (NameFound) {
  698. //
  699. // Found it, increase the refcount.
  700. //
  701. if ((USHORT) (Ncb->RefCount + 1) == 0) {
  702. //
  703. // We have maxed out the ref count.
  704. // fail the call.
  705. //
  706. Ncb = NULL;
  707. } else {
  708. ++Ncb->RefCount;
  709. }
  710. break;
  711. }
  712. }
  713. CurrentName = CurrentName->NextHash;
  714. }
  715. if (NameFound == FALSE) {
  716. //
  717. // Now need to create one Name block for this string.
  718. //
  719. Size = FIELD_OFFSET(CM_NAME_CONTROL_BLOCK, Name) + NameSize;
  720. Ncb = ExAllocatePoolWithTag(PagedPool,
  721. Size,
  722. CM_NAME_TAG | PROTECTED_POOL);
  723. if (Ncb == NULL) {
  724. return(NULL);
  725. }
  726. RtlZeroMemory(Ncb, Size);
  727. //
  728. // Update all the info for this newly created Name block.
  729. // Starting with whistler, the name is always upercase in kcb name block
  730. //
  731. if (NameCompressed) {
  732. Ncb->Compressed = TRUE;
  733. for (i=0;i<NameSize;i++) {
  734. ((PUCHAR)Ncb->Name)[i] = (UCHAR)CmUpcaseUnicodeChar(NodeName->Buffer[i]);
  735. }
  736. } else {
  737. Ncb->Compressed = FALSE;
  738. for (i=0;i<NameSize/sizeof(WCHAR);i++) {
  739. Ncb->Name[i] = CmUpcaseUnicodeChar(NodeName->Buffer[i]);
  740. }
  741. }
  742. Ncb->ConvKey = NameConvKey;
  743. Ncb->RefCount = 1;
  744. Ncb->NameLength = NameSize;
  745. CurrentName = &(Ncb->NameHash);
  746. //
  747. // Insert into Name Hash table.
  748. //
  749. CurrentName->NextHash = CmpNameCacheTable[Index];
  750. CmpNameCacheTable[Index] = CurrentName;
  751. }
  752. return(Ncb);
  753. }
  754. VOID
  755. CmpDereferenceNameControlBlockWithLock(
  756. PCM_NAME_CONTROL_BLOCK Ncb
  757. )
  758. {
  759. PCM_NAME_HASH *Prev;
  760. PCM_NAME_HASH Current;
  761. if (--Ncb->RefCount == 0) {
  762. //
  763. // Remove it from the the Hash Table
  764. //
  765. Prev = &(GET_HASH_ENTRY(CmpNameCacheTable, Ncb->ConvKey));
  766. while (TRUE) {
  767. Current = *Prev;
  768. ASSERT(Current != NULL);
  769. if (Current == &(Ncb->NameHash)) {
  770. *Prev = Current->NextHash;
  771. break;
  772. }
  773. Prev = &Current->NextHash;
  774. }
  775. //
  776. // Free storage
  777. //
  778. ExFreePoolWithTag(Ncb, CM_NAME_TAG | PROTECTED_POOL);
  779. }
  780. return;
  781. }
  782. VOID
  783. CmpRebuildKcbCache(
  784. PCM_KEY_CONTROL_BLOCK KeyControlBlock
  785. )
  786. /*++
  787. Routine Description:
  788. rebuilds all the kcb cache values from knode; this routine is intended to be called
  789. after a tree sync/copy
  790. Arguments:
  791. KeyControlBlock - pointer to a key control block.
  792. Return Value:
  793. NONE.
  794. --*/
  795. {
  796. PCM_KEY_NODE Node;
  797. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  798. ASSERT( !(KeyControlBlock->ExtFlags & CM_KCB_SYM_LINK_FOUND) );
  799. Node = (PCM_KEY_NODE)HvGetCell(KeyControlBlock->KeyHive,KeyControlBlock->KeyCell);
  800. if( Node == NULL ) {
  801. //
  802. // this shouldn't happen as we should have the knode arround
  803. //
  804. ASSERT( FALSE );
  805. return;
  806. }
  807. HvReleaseCell(KeyControlBlock->KeyHive,KeyControlBlock->KeyCell);
  808. // subkey info;
  809. CmpCleanUpSubKeyInfo(KeyControlBlock);
  810. // value cache
  811. CmpCleanUpKcbValueCache(KeyControlBlock);
  812. CmpSetUpKcbValueCache(KeyControlBlock,Node->ValueList.Count,Node->ValueList.List);
  813. // the rest of the cache
  814. KeyControlBlock->KcbLastWriteTime = Node->LastWriteTime;
  815. KeyControlBlock->KcbMaxNameLen = (USHORT)Node->MaxNameLen;
  816. KeyControlBlock->KcbMaxValueNameLen = (USHORT)Node->MaxValueNameLen;
  817. KeyControlBlock->KcbMaxValueDataLen = Node->MaxValueDataLen;
  818. }
  819. VOID
  820. CmpCleanUpSubKeyInfo(
  821. PCM_KEY_CONTROL_BLOCK KeyControlBlock
  822. )
  823. /*++
  824. Routine Description:
  825. Clean up the subkey information cache due to create or delete keys.
  826. Registry is locked exclusively and no need to lock the KCB.
  827. Arguments:
  828. KeyControlBlock - pointer to a key control block.
  829. Return Value:
  830. NONE.
  831. --*/
  832. {
  833. PCM_KEY_NODE Node;
  834. ASSERT_CM_LOCK_OWNED_EXCLUSIVE();
  835. if (KeyControlBlock->ExtFlags & (CM_KCB_NO_SUBKEY | CM_KCB_SUBKEY_ONE | CM_KCB_SUBKEY_HINT)) {
  836. if (KeyControlBlock->ExtFlags & (CM_KCB_SUBKEY_HINT)) {
  837. ExFreePoolWithTag(KeyControlBlock->IndexHint, CM_CACHE_INDEX_TAG | PROTECTED_POOL);
  838. }
  839. KeyControlBlock->ExtFlags &= ~((CM_KCB_NO_SUBKEY | CM_KCB_SUBKEY_ONE | CM_KCB_SUBKEY_HINT));
  840. }
  841. //
  842. // Update the cached SubKeyCount in stored the kcb
  843. //
  844. if( KeyControlBlock->KeyCell == HCELL_NIL ) {
  845. //
  846. // prior call of ZwRestoreKey(REG_FORCE_RESTORE) invalidated this kcb
  847. //
  848. ASSERT( KeyControlBlock->Delete );
  849. Node = NULL;
  850. } else {
  851. Node = (PCM_KEY_NODE)HvGetCell(KeyControlBlock->KeyHive,KeyControlBlock->KeyCell);
  852. }
  853. if( Node == NULL ) {
  854. //
  855. // insufficient resources; mark subkeycount as invalid
  856. //
  857. KeyControlBlock->ExtFlags |= CM_KCB_INVALID_CACHED_INFO;
  858. } else {
  859. KeyControlBlock->ExtFlags &= ~CM_KCB_INVALID_CACHED_INFO;
  860. KeyControlBlock->SubKeyCount = Node->SubKeyCounts[Stable] + Node->SubKeyCounts[Volatile];
  861. HvReleaseCell(KeyControlBlock->KeyHive,KeyControlBlock->KeyCell);
  862. }
  863. }
  864. VOID
  865. CmpCleanUpKcbValueCache(
  866. PCM_KEY_CONTROL_BLOCK KeyControlBlock
  867. )
  868. /*++
  869. Routine Description:
  870. Clean up cached value/data that are associated to this key.
  871. Arguments:
  872. KeyControlBlock - pointer to a key control block.
  873. Return Value:
  874. NONE.
  875. --*/
  876. {
  877. ULONG i;
  878. PULONG_PTR CachedList;
  879. if (CMP_IS_CELL_CACHED(KeyControlBlock->ValueCache.ValueList)) {
  880. CachedList = (PULONG_PTR) CMP_GET_CACHED_CELLDATA(KeyControlBlock->ValueCache.ValueList);
  881. for (i = 0; i < KeyControlBlock->ValueCache.Count; i++) {
  882. if (CMP_IS_CELL_CACHED(CachedList[i])) {
  883. // Trying to catch the BAD guy who writes over our pool.
  884. CmpMakeSpecialPoolReadWrite( CMP_GET_CACHED_ADDRESS(CachedList[i]) );
  885. ExFreePool((PVOID) CMP_GET_CACHED_ADDRESS(CachedList[i]));
  886. }
  887. }
  888. // Trying to catch the BAD guy who writes over our pool.
  889. CmpMakeSpecialPoolReadWrite( CMP_GET_CACHED_ADDRESS(KeyControlBlock->ValueCache.ValueList) );
  890. ExFreePool((PVOID) CMP_GET_CACHED_ADDRESS(KeyControlBlock->ValueCache.ValueList));
  891. // Mark the ValueList as NULL
  892. KeyControlBlock->ValueCache.ValueList = HCELL_NIL;
  893. } else if (KeyControlBlock->ExtFlags & CM_KCB_SYM_LINK_FOUND) {
  894. //
  895. // This is a symbolic link key with symbolic name resolved.
  896. // Dereference to its real kcb and clear the bit.
  897. //
  898. if ((KeyControlBlock->ValueCache.RealKcb->RefCount == 1) && !(KeyControlBlock->ValueCache.RealKcb->Delete)) {
  899. KeyControlBlock->ValueCache.RealKcb->ExtFlags |= CM_KCB_NO_DELAY_CLOSE;
  900. }
  901. CmpDereferenceKeyControlBlockWithLock(KeyControlBlock->ValueCache.RealKcb);
  902. KeyControlBlock->ExtFlags &= ~CM_KCB_SYM_LINK_FOUND;
  903. }
  904. }
  905. VOID
  906. CmpCleanUpKcbCacheWithLock(
  907. PCM_KEY_CONTROL_BLOCK KeyControlBlock
  908. )
  909. /*++
  910. Routine Description:
  911. Clean up all cached allocations that are associated to this key.
  912. If the parent is still open just because of this one, Remove the parent as well.
  913. Arguments:
  914. KeyControlBlock - pointer to a key control block.
  915. Return Value:
  916. NONE.
  917. --*/
  918. {
  919. PCM_KEY_CONTROL_BLOCK Kcb;
  920. PCM_KEY_CONTROL_BLOCK ParentKcb;
  921. Kcb = KeyControlBlock;
  922. ASSERT(KeyControlBlock->RefCount == 0);
  923. while (Kcb && Kcb->RefCount == 0) {
  924. //
  925. // First, free allocations for Value/data.
  926. //
  927. CmpCleanUpKcbValueCache(Kcb);
  928. //
  929. // Free the kcb and dereference parentkcb and nameblock.
  930. //
  931. CmpDereferenceNameControlBlockWithLock(Kcb->NameBlock);
  932. if (Kcb->ExtFlags & CM_KCB_SUBKEY_HINT) {
  933. //
  934. // Now free the HintIndex allocation
  935. //
  936. ExFreePoolWithTag(Kcb->IndexHint, CM_CACHE_INDEX_TAG | PROTECTED_POOL);
  937. }
  938. //
  939. // Save the ParentKcb before we free the Kcb
  940. //
  941. ParentKcb = Kcb->ParentKcb;
  942. //
  943. // We cannot call CmpDereferenceKeyControlBlockWithLock so we can avoid recurrsion.
  944. //
  945. if (!Kcb->Delete) {
  946. CmpRemoveKeyControlBlock(Kcb);
  947. }
  948. SET_KCB_SIGNATURE(Kcb, '4FmC');
  949. #ifdef CMP_STATS
  950. CmpStatsDebug.CmpKcbNo--;
  951. ASSERT( CmpStatsDebug.CmpKcbNo >= 0 );
  952. #endif
  953. CmpFreeKeyControlBlock( Kcb );
  954. Kcb = ParentKcb;
  955. if (Kcb) {
  956. InterlockedDecrement( (PLONG)&Kcb->RefCount );
  957. }
  958. }
  959. }
  960. PUNICODE_STRING
  961. CmpConstructName(
  962. PCM_KEY_CONTROL_BLOCK kcb
  963. )
  964. /*++
  965. Routine Description:
  966. Construct the name given a kcb.
  967. Arguments:
  968. kcb - Kcb for the key
  969. Return Value:
  970. Pointer to the unicode string constructed.
  971. Caller is responsible to free this storage space.
  972. --*/
  973. {
  974. PUNICODE_STRING FullName;
  975. PCM_KEY_CONTROL_BLOCK TmpKcb;
  976. PCM_KEY_NODE KeyNode;
  977. SIZE_T Length;
  978. SIZE_T size;
  979. USHORT i;
  980. SIZE_T BeginPosition;
  981. WCHAR *w1, *w2;
  982. UCHAR *u2;
  983. //
  984. // Calculate the total string length.
  985. //
  986. Length = 0;
  987. TmpKcb = kcb;
  988. while (TmpKcb) {
  989. if (TmpKcb->NameBlock->Compressed) {
  990. Length += TmpKcb->NameBlock->NameLength * sizeof(WCHAR);
  991. } else {
  992. Length += TmpKcb->NameBlock->NameLength;
  993. }
  994. //
  995. // Add the space for OBJ_NAME_PATH_SEPARATOR;
  996. //
  997. Length += sizeof(WCHAR);
  998. TmpKcb = TmpKcb->ParentKcb;
  999. }
  1000. if (Length > MAXUSHORT) {
  1001. return NULL;
  1002. }
  1003. //
  1004. // Allocate the pool for the unicode string
  1005. //
  1006. size = sizeof(UNICODE_STRING) + Length;
  1007. FullName = (PUNICODE_STRING) ExAllocatePoolWithTag(PagedPool,
  1008. size,
  1009. CM_NAME_TAG | PROTECTED_POOL);
  1010. if (FullName) {
  1011. FullName->Buffer = (USHORT *) ((ULONG_PTR) FullName + sizeof(UNICODE_STRING));
  1012. FullName->Length = (USHORT) Length;
  1013. FullName->MaximumLength = (USHORT) Length;
  1014. //
  1015. // Now fill the name into the buffer.
  1016. //
  1017. TmpKcb = kcb;
  1018. BeginPosition = Length;
  1019. while (TmpKcb) {
  1020. if( (TmpKcb->KeyHive == NULL) || (TmpKcb->KeyCell == HCELL_NIL) || (TmpKcb->ExtFlags & CM_KCB_KEY_NON_EXIST) ) {
  1021. ExFreePoolWithTag(FullName, CM_NAME_TAG | PROTECTED_POOL);
  1022. FullName = NULL;
  1023. break;
  1024. }
  1025. KeyNode = (PCM_KEY_NODE)HvGetCell(TmpKcb->KeyHive,TmpKcb->KeyCell);
  1026. if( KeyNode == NULL ) {
  1027. //
  1028. // could not allocate view
  1029. //
  1030. ExFreePoolWithTag(FullName, CM_NAME_TAG | PROTECTED_POOL);
  1031. FullName = NULL;
  1032. break;
  1033. }
  1034. //
  1035. // sanity
  1036. //
  1037. #if DBG
  1038. if( ! (TmpKcb->Flags & (KEY_HIVE_ENTRY | KEY_HIVE_EXIT)) ) {
  1039. ASSERT( KeyNode->NameLength == TmpKcb->NameBlock->NameLength );
  1040. ASSERT( ((KeyNode->Flags&KEY_COMP_NAME) && (TmpKcb->NameBlock->Compressed)) ||
  1041. ((!(KeyNode->Flags&KEY_COMP_NAME)) && (!(TmpKcb->NameBlock->Compressed))) );
  1042. }
  1043. #endif //DBG
  1044. //
  1045. // Calculate the begin position of each subkey. Then fill in the char.
  1046. //
  1047. //
  1048. if (TmpKcb->NameBlock->Compressed) {
  1049. BeginPosition -= (TmpKcb->NameBlock->NameLength + 1) * sizeof(WCHAR);
  1050. w1 = &(FullName->Buffer[BeginPosition/sizeof(WCHAR)]);
  1051. *w1 = OBJ_NAME_PATH_SEPARATOR;
  1052. w1++;
  1053. if( ! (TmpKcb->Flags & (KEY_HIVE_ENTRY | KEY_HIVE_EXIT)) ) {
  1054. //
  1055. // Get the name from the knode; to preserve case
  1056. //
  1057. u2 = (UCHAR *) &(KeyNode->Name[0]);
  1058. } else {
  1059. //
  1060. // get it from the kcb, as in the keynode we don't hold the right name (see PROTO.HIV nodes)
  1061. //
  1062. u2 = (UCHAR *) &(TmpKcb->NameBlock->Name[0]);
  1063. }
  1064. for (i=0; i<TmpKcb->NameBlock->NameLength; i++) {
  1065. *w1 = (WCHAR)(*u2);
  1066. w1++;
  1067. u2++;
  1068. }
  1069. } else {
  1070. BeginPosition -= (TmpKcb->NameBlock->NameLength + sizeof(WCHAR));
  1071. w1 = &(FullName->Buffer[BeginPosition/sizeof(WCHAR)]);
  1072. *w1 = OBJ_NAME_PATH_SEPARATOR;
  1073. w1++;
  1074. if( ! (TmpKcb->Flags & (KEY_HIVE_ENTRY | KEY_HIVE_EXIT)) ) {
  1075. //
  1076. // Get the name from the knode; to preserve case
  1077. //
  1078. w2 = KeyNode->Name;
  1079. } else {
  1080. //
  1081. // get it from the kcb, as in the keynode we don't hold the right name (see PROTO.HIV nodes)
  1082. //
  1083. w2 = TmpKcb->NameBlock->Name;
  1084. }
  1085. for (i=0; i<TmpKcb->NameBlock->NameLength; i=i+sizeof(WCHAR)) {
  1086. *w1 = *w2;
  1087. w1++;
  1088. w2++;
  1089. }
  1090. }
  1091. HvReleaseCell(TmpKcb->KeyHive,TmpKcb->KeyCell);
  1092. TmpKcb = TmpKcb->ParentKcb;
  1093. }
  1094. }
  1095. return (FullName);
  1096. }
  1097. PCM_KEY_CONTROL_BLOCK
  1098. CmpCreateKeyControlBlock(
  1099. PHHIVE Hive,
  1100. HCELL_INDEX Cell,
  1101. PCM_KEY_NODE Node,
  1102. PCM_KEY_CONTROL_BLOCK ParentKcb,
  1103. BOOLEAN FakeKey,
  1104. PUNICODE_STRING KeyName
  1105. )
  1106. /*++
  1107. Routine Description:
  1108. Allocate and initialize a key control block, insert it into
  1109. the kcb tree.
  1110. Full path will be BaseName + '\' + KeyName, unless BaseName
  1111. NULL, in which case the full path is simply KeyName.
  1112. RefCount of returned KCB WILL have been incremented to reflect
  1113. callers ref.
  1114. Arguments:
  1115. Hive - Supplies Hive that holds the key we are creating a KCB for.
  1116. Cell - Supplies Cell that contains the key we are creating a KCB for.
  1117. Node - Supplies pointer to key node.
  1118. ParentKcb - Parent kcb of the kcb to be created
  1119. FakeKey - Whether the kcb to be create is a fake one or not
  1120. KeyName - the subkey name to of the KCB to be created.
  1121. NOTE: We need the parameter instead of just using the name in the KEY_NODE
  1122. because there is no name in the root cell of a hive.
  1123. Return Value:
  1124. NULL - failure (insufficient memory)
  1125. else a pointer to the new kcb.
  1126. --*/
  1127. {
  1128. PCM_KEY_CONTROL_BLOCK kcb;
  1129. PCM_KEY_CONTROL_BLOCK kcbmatch=NULL;
  1130. UNICODE_STRING NodeName;
  1131. ULONG ConvKey = 0;
  1132. ULONG Cnt;
  1133. WCHAR *Cp;
  1134. //
  1135. // ParentKCb has the base hash value.
  1136. //
  1137. if (ParentKcb) {
  1138. ConvKey = ParentKcb->ConvKey;
  1139. }
  1140. NodeName = *KeyName;
  1141. while ((NodeName.Length > 0) && (NodeName.Buffer[0] == OBJ_NAME_PATH_SEPARATOR)) {
  1142. //
  1143. // This must be the \REGISTRY.
  1144. // Strip off the leading OBJ_NAME_PATH_SEPARATOR
  1145. //
  1146. NodeName.Buffer++;
  1147. NodeName.Length -= sizeof(WCHAR);
  1148. }
  1149. //
  1150. // Manually compute the hash to use.
  1151. //
  1152. ASSERT(NodeName.Length > 0);
  1153. if (NodeName.Length) {
  1154. Cp = NodeName.Buffer;
  1155. for (Cnt=0; Cnt<NodeName.Length; Cnt += sizeof(WCHAR)) {
  1156. //
  1157. // UNICODE_NULL is a valid char !!!
  1158. //
  1159. if (*Cp != OBJ_NAME_PATH_SEPARATOR) {
  1160. //(*Cp != UNICODE_NULL)) {
  1161. ConvKey = 37 * ConvKey + (ULONG)CmUpcaseUnicodeChar(*Cp);
  1162. }
  1163. ++Cp;
  1164. }
  1165. }
  1166. //
  1167. // Create a new kcb, which we will free if one already exists
  1168. // for this key.
  1169. // Now it is a fixed size structure.
  1170. //
  1171. kcb = CmpAllocateKeyControlBlock( );
  1172. if (kcb == NULL) {
  1173. return(NULL);
  1174. } else {
  1175. SET_KCB_SIGNATURE(kcb, KCB_SIGNATURE);
  1176. INIT_KCB_KEYBODY_LIST(kcb);
  1177. kcb->Delete = FALSE;
  1178. kcb->RefCount = 1;
  1179. kcb->KeyHive = Hive;
  1180. kcb->KeyCell = Cell;
  1181. kcb->ConvKey = ConvKey;
  1182. // Initialize as not on delayed close (0=1st delayed close slot)
  1183. kcb->DelayedCloseIndex = CmpDelayedCloseSize;
  1184. #ifdef CMP_STATS
  1185. // colect stats
  1186. CmpStatsDebug.CmpKcbNo++;
  1187. if( CmpStatsDebug.CmpKcbNo > CmpStatsDebug.CmpMaxKcbNo ) {
  1188. CmpStatsDebug.CmpMaxKcbNo = CmpStatsDebug.CmpKcbNo;
  1189. }
  1190. #endif
  1191. }
  1192. ASSERT_KCB(kcb);
  1193. //
  1194. // Find location to insert kcb in kcb tree.
  1195. //
  1196. BEGIN_KCB_LOCK_GUARD;
  1197. CmpLockKCBTreeExclusive();
  1198. //
  1199. // Add the KCB to the hash table
  1200. //
  1201. kcbmatch = CmpInsertKeyHash(&kcb->KeyHash, FakeKey);
  1202. if (kcbmatch != NULL) {
  1203. //
  1204. // A match was found.
  1205. //
  1206. ASSERT(!kcbmatch->Delete);
  1207. SET_KCB_SIGNATURE(kcb, '1FmC');
  1208. #ifdef CMP_STATS
  1209. CmpStatsDebug.CmpKcbNo--;
  1210. ASSERT( CmpStatsDebug.CmpKcbNo >= 0 );
  1211. #endif
  1212. CmpFreeKeyControlBlock(kcb);
  1213. ASSERT_KCB(kcbmatch);
  1214. kcb = kcbmatch;
  1215. if( !CmpReferenceKeyControlBlock(kcb) ) {
  1216. //
  1217. // We have maxed out the ref count on this key. Probably
  1218. // some bogus app has opened the same key 64K times without
  1219. // ever closing it. Just fail the open, they've got enough
  1220. // handles already.
  1221. //
  1222. ASSERT(kcb->RefCount + 1 != 0);
  1223. kcb = NULL;
  1224. } else {
  1225. //
  1226. // update the keycell and hive, in case this is a fake kcb
  1227. //
  1228. if( (kcb->ExtFlags & CM_KCB_KEY_NON_EXIST) && (!FakeKey) ) {
  1229. kcb->ExtFlags = CM_KCB_INVALID_CACHED_INFO;
  1230. kcb->KeyHive = Hive;
  1231. kcb->KeyCell = Cell;
  1232. }
  1233. //
  1234. // Update the cached information stored in the kcb, since we have the key_node handy
  1235. //
  1236. if (!(kcb->ExtFlags & (CM_KCB_NO_SUBKEY | CM_KCB_SUBKEY_ONE | CM_KCB_SUBKEY_HINT)) ) {
  1237. // SubKeyCount
  1238. kcb->SubKeyCount = Node->SubKeyCounts[Stable] + Node->SubKeyCounts[Volatile];
  1239. // clean up the invalid flag (if any)
  1240. kcb->ExtFlags &= ~CM_KCB_INVALID_CACHED_INFO;
  1241. }
  1242. kcb->KcbLastWriteTime = Node->LastWriteTime;
  1243. kcb->KcbMaxNameLen = (USHORT)Node->MaxNameLen;
  1244. kcb->KcbMaxValueNameLen = (USHORT)Node->MaxValueNameLen;
  1245. kcb->KcbMaxValueDataLen = Node->MaxValueDataLen;
  1246. }
  1247. } else {
  1248. //
  1249. // No kcb created previously, fill in all the data.
  1250. //
  1251. //
  1252. // Now try to reference the parentkcb
  1253. //
  1254. if (ParentKcb) {
  1255. if ( ((ParentKcb->TotalLevels + 1) < CMP_MAX_REGISTRY_DEPTH) && (CmpReferenceKeyControlBlock(ParentKcb)) ) {
  1256. kcb->ParentKcb = ParentKcb;
  1257. kcb->TotalLevels = ParentKcb->TotalLevels + 1;
  1258. } else {
  1259. //
  1260. // We have maxed out the ref count on the parent.
  1261. // Since it has been cached in the cachetable,
  1262. // remove it first before we free the allocation.
  1263. //
  1264. CmpRemoveKeyControlBlock(kcb);
  1265. SET_KCB_SIGNATURE(kcb, '2FmC');
  1266. #ifdef CMP_STATS
  1267. CmpStatsDebug.CmpKcbNo--;
  1268. ASSERT( CmpStatsDebug.CmpKcbNo >= 0 );
  1269. #endif
  1270. CmpFreeKeyControlBlock(kcb);
  1271. kcb = NULL;
  1272. }
  1273. } else {
  1274. //
  1275. // It is the \REGISTRY node.
  1276. //
  1277. kcb->ParentKcb = NULL;
  1278. kcb->TotalLevels = 1;
  1279. }
  1280. if (kcb) {
  1281. //
  1282. // Cache the security cells in the kcb
  1283. //
  1284. CmpAssignSecurityToKcb(kcb,Node->Security);
  1285. //
  1286. // Now try to find the Name Control block that has the name for this node.
  1287. //
  1288. kcb->NameBlock = CmpGetNameControlBlock (&NodeName);
  1289. if (kcb->NameBlock) {
  1290. //
  1291. // Now fill in all the data needed for the cache.
  1292. //
  1293. kcb->ValueCache.Count = Node->ValueList.Count;
  1294. kcb->ValueCache.ValueList = (ULONG_PTR)(Node->ValueList.List);
  1295. kcb->Flags = Node->Flags;
  1296. kcb->ExtFlags = 0;
  1297. kcb->DelayedCloseIndex = CmpDelayedCloseSize;
  1298. if (FakeKey) {
  1299. //
  1300. // The KCb to be created is a fake one;
  1301. //
  1302. kcb->ExtFlags |= CM_KCB_KEY_NON_EXIST;
  1303. }
  1304. CmpTraceKcbCreate(kcb);
  1305. PERFINFO_REG_KCB_CREATE(kcb);
  1306. //
  1307. // Update the cached information stored in the kcb, since we have the key_node handy
  1308. //
  1309. // SubKeyCount
  1310. kcb->SubKeyCount = Node->SubKeyCounts[Stable] + Node->SubKeyCounts[Volatile];
  1311. kcb->KcbLastWriteTime = Node->LastWriteTime;
  1312. kcb->KcbMaxNameLen = (USHORT)Node->MaxNameLen;
  1313. kcb->KcbMaxValueNameLen = (USHORT)Node->MaxValueNameLen;
  1314. kcb->KcbMaxValueDataLen = Node->MaxValueDataLen;
  1315. } else {
  1316. //
  1317. // We have maxed out the ref count on the Name.
  1318. //
  1319. //
  1320. // First dereference the parent KCB.
  1321. //
  1322. CmpDereferenceKeyControlBlockWithLock(ParentKcb);
  1323. CmpRemoveKeyControlBlock(kcb);
  1324. SET_KCB_SIGNATURE(kcb, '3FmC');
  1325. #ifdef CMP_STATS
  1326. CmpStatsDebug.CmpKcbNo--;
  1327. ASSERT( CmpStatsDebug.CmpKcbNo >= 0 );
  1328. #endif
  1329. CmpFreeKeyControlBlock(kcb);
  1330. kcb = NULL;
  1331. }
  1332. }
  1333. }
  1334. #ifdef NT_UNLOAD_KEY_EX
  1335. if( kcb && IsHiveFrozen(Hive) && (!(kcb->Flags & KEY_SYM_LINK)) ) {
  1336. //
  1337. // kcbs created inside a frozen hive should not be added to delayclose table.
  1338. //
  1339. kcb->ExtFlags |= CM_KCB_NO_DELAY_CLOSE;
  1340. }
  1341. #endif //NT_UNLOAD_KEY_EX
  1342. CmpUnlockKCBTree();
  1343. END_KCB_LOCK_GUARD;
  1344. return kcb;
  1345. }
  1346. BOOLEAN
  1347. CmpSearchKeyControlBlockTree(
  1348. PKCB_WORKER_ROUTINE WorkerRoutine,
  1349. PVOID Context1,
  1350. PVOID Context2
  1351. )
  1352. /*++
  1353. Routine Description:
  1354. Traverse the kcb tree. We will visit all nodes unless WorkerRoutine
  1355. tells us to stop part way through.
  1356. For each node, call WorkerRoutine(..., Context1, Contex2). If it returns
  1357. KCB_WORKER_DONE, we are done, simply return. If it returns
  1358. KCB_WORKER_CONTINUE, just continue the search. If it returns KCB_WORKER_DELETE,
  1359. the specified KCB is marked as deleted.
  1360. If it returns KCB_WORKER_ERROR we bail out and signal the error to the caller.
  1361. This routine has the side-effect of removing all delayed-close KCBs.
  1362. Arguments:
  1363. WorkerRoutine - applied to nodes witch Match.
  1364. Context1 - data we pass through
  1365. Context2 - data we pass through
  1366. Return Value:
  1367. NONE.
  1368. --*/
  1369. {
  1370. PCM_KEY_CONTROL_BLOCK Current;
  1371. PCM_KEY_HASH *Prev;
  1372. ULONG WorkerResult;
  1373. ULONG i;
  1374. //
  1375. // Walk the hash table
  1376. //
  1377. for (i=0; i<CmpHashTableSize; i++) {
  1378. Prev = &CmpCacheTable[i];
  1379. while (*Prev) {
  1380. Current = CONTAINING_RECORD(*Prev,
  1381. CM_KEY_CONTROL_BLOCK,
  1382. KeyHash);
  1383. ASSERT_KCB(Current);
  1384. ASSERT(!Current->Delete);
  1385. if (Current->RefCount == 0) {
  1386. //
  1387. // This kcb is in DelayClose case, remove it.
  1388. //
  1389. CmpRemoveFromDelayedClose(Current);
  1390. CmpCleanUpKcbCacheWithLock(Current);
  1391. //
  1392. // The HashTable is changed, start over in this index again.
  1393. //
  1394. Prev = &CmpCacheTable[i];
  1395. continue;
  1396. }
  1397. WorkerResult = (WorkerRoutine)(Current, Context1, Context2);
  1398. if (WorkerResult == KCB_WORKER_DONE) {
  1399. return TRUE;
  1400. } else if (WorkerResult == KCB_WORKER_ERROR) {
  1401. return FALSE;
  1402. } else if (WorkerResult == KCB_WORKER_DELETE) {
  1403. ASSERT(Current->Delete);
  1404. *Prev = Current->NextHash;
  1405. continue;
  1406. } else {
  1407. ASSERT(WorkerResult == KCB_WORKER_CONTINUE);
  1408. Prev = &Current->NextHash;
  1409. }
  1410. }
  1411. }
  1412. return TRUE;
  1413. }
  1414. VOID
  1415. CmpDereferenceKeyControlBlock(
  1416. PCM_KEY_CONTROL_BLOCK KeyControlBlock
  1417. )
  1418. /*++
  1419. Routine Description:
  1420. Decrements the reference count on a key control block, and frees it if it
  1421. becomes zero.
  1422. It is expected that no notify control blocks remain if the reference count
  1423. becomes zero.
  1424. Arguments:
  1425. KeyControlBlock - pointer to a key control block.
  1426. Return Value:
  1427. NONE.
  1428. --*/
  1429. {
  1430. LONG OldRefCount;
  1431. LONG NewRefCount;
  1432. OldRefCount = *(PLONG)&KeyControlBlock->RefCount; //get entire dword
  1433. NewRefCount = OldRefCount - 1;
  1434. if( (NewRefCount & 0xffff) > 0 &&
  1435. InterlockedCompareExchange((PLONG)&KeyControlBlock->RefCount,NewRefCount,OldRefCount)
  1436. == OldRefCount ) {
  1437. return;
  1438. }
  1439. BEGIN_KCB_LOCK_GUARD;
  1440. CmpLockKCBTreeExclusive();
  1441. CmpDereferenceKeyControlBlockWithLock(KeyControlBlock) ;
  1442. CmpUnlockKCBTree();
  1443. END_KCB_LOCK_GUARD;
  1444. return;
  1445. }
  1446. VOID
  1447. CmpDereferenceKeyControlBlockWithLock(
  1448. PCM_KEY_CONTROL_BLOCK KeyControlBlock
  1449. )
  1450. {
  1451. ASSERT_KCB(KeyControlBlock);
  1452. ASSERT_KCB_LOCK_OWNED_EXCLUSIVE();
  1453. if( (InterlockedDecrement( (PLONG)&KeyControlBlock->RefCount ) & 0xffff) == 0) {
  1454. //
  1455. // Remove kcb from the tree
  1456. //
  1457. // delay close disabled during boot; up to the point CCS is saved.
  1458. // for symbolic links, we still need to keep the symbolic link kcb around.
  1459. //
  1460. if((CmpHoldLazyFlush && (!(KeyControlBlock->ExtFlags & CM_KCB_SYM_LINK_FOUND)) && (!(KeyControlBlock->Flags & KEY_SYM_LINK))) ||
  1461. (KeyControlBlock->ExtFlags & CM_KCB_NO_DELAY_CLOSE) ) {
  1462. //
  1463. // Free storage directly so we can clean up junk quickly.
  1464. //
  1465. //
  1466. // Need to free all cached Index List, Index Leaf, Value, etc.
  1467. //
  1468. CmpCleanUpKcbCacheWithLock(KeyControlBlock);
  1469. } else if (!KeyControlBlock->Delete) {
  1470. //
  1471. // Put this kcb on our delayed close list.
  1472. //
  1473. CmpAddToDelayedClose(KeyControlBlock);
  1474. } else {
  1475. //
  1476. // Free storage directly as there is no point in putting this on
  1477. // our delayed close list.
  1478. //
  1479. //
  1480. // Need to free all cached Index List, Index Leaf, Value, etc.
  1481. //
  1482. CmpCleanUpKcbCacheWithLock(KeyControlBlock);
  1483. }
  1484. }
  1485. return;
  1486. }
  1487. VOID
  1488. CmpRemoveKeyControlBlock(
  1489. PCM_KEY_CONTROL_BLOCK KeyControlBlock
  1490. )
  1491. /*++
  1492. Routine Description:
  1493. Remove a key control block from the KCB tree.
  1494. It is expected that no notify control blocks remain.
  1495. The kcb will NOT be freed, call DereferenceKeyControlBlock for that.
  1496. This call assumes the KCB tree is already locked or registry is locked exclusively.
  1497. Arguments:
  1498. KeyControlBlock - pointer to a key control block.
  1499. Return Value:
  1500. NONE.
  1501. --*/
  1502. {
  1503. ASSERT_KCB(KeyControlBlock);
  1504. //
  1505. // Remove the KCB from the hash table
  1506. //
  1507. CmpRemoveKeyHash(&KeyControlBlock->KeyHash);
  1508. return;
  1509. }
  1510. BOOLEAN
  1511. CmpFreeKeyBody(
  1512. PHHIVE Hive,
  1513. HCELL_INDEX Cell
  1514. )
  1515. /*++
  1516. Routine Description:
  1517. Free storage for the key entry Hive.Cell refers to, including
  1518. its class and security data. Will NOT free child list or value list.
  1519. Arguments:
  1520. Hive - supplies a pointer to the hive control structure for the hive
  1521. Cell - supplies index of key to free
  1522. Return Value:
  1523. TRUE - success
  1524. FALSE - error; couldn't map cell
  1525. --*/
  1526. {
  1527. PCELL_DATA key;
  1528. //
  1529. // map in the cell
  1530. //
  1531. key = HvGetCell(Hive, Cell);
  1532. if( key == NULL ) {
  1533. //
  1534. // we couldn't map the bin containing this cell
  1535. // Sorry, we cannot free the keybody
  1536. // this shouldn't happen as the cell must've been
  1537. // marked dirty (i.e. pinned in memory) by now
  1538. //
  1539. ASSERT( FALSE );
  1540. return FALSE;
  1541. }
  1542. if (!(key->u.KeyNode.Flags & KEY_HIVE_EXIT)) {
  1543. if (key->u.KeyNode.Security != HCELL_NIL) {
  1544. HvFreeCell(Hive, key->u.KeyNode.Security);
  1545. }
  1546. if (key->u.KeyNode.ClassLength > 0) {
  1547. HvFreeCell(Hive, key->u.KeyNode.Class);
  1548. }
  1549. }
  1550. HvReleaseCell(Hive,Cell);
  1551. //
  1552. // unmap the cell itself and free it
  1553. //
  1554. HvFreeCell(Hive, Cell);
  1555. return TRUE;
  1556. }
  1557. PCM_KEY_CONTROL_BLOCK
  1558. CmpInsertKeyHash(
  1559. IN PCM_KEY_HASH KeyHash,
  1560. IN BOOLEAN FakeKey
  1561. )
  1562. /*++
  1563. Routine Description:
  1564. Adds a key hash structure to the hash table. The hash table
  1565. will be checked to see if a duplicate entry already exists. If
  1566. a duplicate is found, its kcb will be returned. If a duplicate is not
  1567. found, NULL will be returned.
  1568. Arguments:
  1569. KeyHash - Supplies the key hash structure to be added.
  1570. Return Value:
  1571. NULL - if the supplied key has was added
  1572. PCM_KEY_HASH - The duplicate hash entry, if one was found
  1573. --*/
  1574. {
  1575. ULONG Index;
  1576. PCM_KEY_HASH Current;
  1577. ASSERT_KEY_HASH(KeyHash);
  1578. Index = GET_HASH_INDEX(KeyHash->ConvKey);
  1579. //
  1580. // If this is a fake key, we will use the cell and hive from its
  1581. // parent for uniqeness. To deal with the case when the fake
  1582. // has the same ConvKey as its parent (in which case we cannot distingish
  1583. // between the two), we set the lowest bit of the fake key's cell.
  1584. //
  1585. // It's possible (unlikely) that we cannot distingish two fake keys
  1586. // (when their Convkey's are the same) under the same key. It is not breaking
  1587. // anything, we just cannot find the other one in cache lookup.
  1588. //
  1589. //
  1590. if (FakeKey) {
  1591. KeyHash->KeyCell++;
  1592. }
  1593. //
  1594. // First look for duplicates.
  1595. //
  1596. Current = CmpCacheTable[Index];
  1597. while (Current) {
  1598. ASSERT_KEY_HASH(Current);
  1599. //
  1600. // We must check ConvKey since we can create a fake kcb
  1601. // for keys that does not exist.
  1602. // We will use the Hive and Cell from the parent.
  1603. //
  1604. if ((KeyHash->ConvKey == Current->ConvKey) &&
  1605. (KeyHash->KeyCell == Current->KeyCell) &&
  1606. (KeyHash->KeyHive == Current->KeyHive)) {
  1607. //
  1608. // Found a match
  1609. //
  1610. return(CONTAINING_RECORD(Current,
  1611. CM_KEY_CONTROL_BLOCK,
  1612. KeyHash));
  1613. }
  1614. Current = Current->NextHash;
  1615. }
  1616. #if DBG
  1617. //
  1618. // Make sure this key is not somehow cached in the wrong spot.
  1619. //
  1620. {
  1621. ULONG DbgIndex;
  1622. PCM_KEY_CONTROL_BLOCK kcb;
  1623. for (DbgIndex = 0; DbgIndex < CmpHashTableSize; DbgIndex++) {
  1624. Current = CmpCacheTable[DbgIndex];
  1625. while (Current) {
  1626. kcb = CONTAINING_RECORD(Current,
  1627. CM_KEY_CONTROL_BLOCK,
  1628. KeyHash);
  1629. ASSERT_KEY_HASH(Current);
  1630. ASSERT((KeyHash->KeyHive != Current->KeyHive) ||
  1631. FakeKey ||
  1632. (kcb->ExtFlags & CM_KCB_KEY_NON_EXIST) ||
  1633. (KeyHash->KeyCell != Current->KeyCell));
  1634. Current = Current->NextHash;
  1635. }
  1636. }
  1637. }
  1638. #endif
  1639. //
  1640. // No duplicate was found, add this entry at the head of the list
  1641. //
  1642. KeyHash->NextHash = CmpCacheTable[Index];
  1643. CmpCacheTable[Index] = KeyHash;
  1644. return(NULL);
  1645. }
  1646. VOID
  1647. CmpRemoveKeyHash(
  1648. IN PCM_KEY_HASH KeyHash
  1649. )
  1650. /*++
  1651. Routine Description:
  1652. Removes a key hash structure from the hash table.
  1653. Arguments:
  1654. KeyHash - Supplies the key hash structure to be deleted.
  1655. Return Value:
  1656. None
  1657. --*/
  1658. {
  1659. ULONG Index;
  1660. PCM_KEY_HASH *Prev;
  1661. PCM_KEY_HASH Current;
  1662. ASSERT_KEY_HASH(KeyHash);
  1663. Index = GET_HASH_INDEX(KeyHash->ConvKey);
  1664. //
  1665. // Find this entry.
  1666. //
  1667. Prev = &CmpCacheTable[Index];
  1668. while (TRUE) {
  1669. Current = *Prev;
  1670. ASSERT(Current != NULL);
  1671. ASSERT_KEY_HASH(Current);
  1672. if (Current == KeyHash) {
  1673. *Prev = Current->NextHash;
  1674. #if DBG
  1675. if (*Prev) {
  1676. ASSERT_KEY_HASH(*Prev);
  1677. }
  1678. #endif
  1679. break;
  1680. }
  1681. Prev = &Current->NextHash;
  1682. }
  1683. }
  1684. VOID
  1685. CmpInitializeCache()
  1686. {
  1687. ULONG TotalCmCacheSize;
  1688. TotalCmCacheSize = CmpHashTableSize * sizeof(PCM_KEY_HASH);
  1689. CmpCacheTable = ExAllocatePoolWithTag(PagedPool,
  1690. TotalCmCacheSize,
  1691. 'aCMC');
  1692. if (CmpCacheTable == NULL) {
  1693. CM_BUGCHECK(CONFIG_INITIALIZATION_FAILED,INIT_CACHE_TABLE,1,0,0);
  1694. return;
  1695. }
  1696. RtlZeroMemory(CmpCacheTable, TotalCmCacheSize);
  1697. TotalCmCacheSize = CmpHashTableSize * sizeof(PCM_NAME_HASH);
  1698. CmpNameCacheTable = ExAllocatePoolWithTag(PagedPool,
  1699. TotalCmCacheSize,
  1700. 'aCMC');
  1701. if (CmpNameCacheTable == NULL) {
  1702. CM_BUGCHECK(CONFIG_INITIALIZATION_FAILED,INIT_CACHE_TABLE,1,0,0);
  1703. return;
  1704. }
  1705. RtlZeroMemory(CmpNameCacheTable, TotalCmCacheSize);
  1706. CmpInitializeDelayedCloseTable();
  1707. }
  1708. #ifdef CM_CHECK_FOR_ORPHANED_KCBS
  1709. VOID
  1710. CmpCheckForOrphanedKcbs(
  1711. PHHIVE Hive
  1712. )
  1713. /*++
  1714. Routine Description:
  1715. Parses the entire kcb cache in search of kcbs that still reffer to the specified hive
  1716. breakpoint when a match is found.
  1717. Arguments:
  1718. Hive - Supplies Hive.
  1719. Return Value:
  1720. none
  1721. --*/
  1722. {
  1723. PCM_KEY_CONTROL_BLOCK KeyControlBlock;
  1724. PCM_KEY_HASH Current;
  1725. ULONG i;
  1726. //
  1727. // Walk the hash table
  1728. //
  1729. for (i=0; i<CmpHashTableSize; i++) {
  1730. Current = CmpCacheTable[i];
  1731. while (Current) {
  1732. KeyControlBlock = CONTAINING_RECORD(Current, CM_KEY_CONTROL_BLOCK, KeyHash);
  1733. ASSERT_KCB(KeyControlBlock);
  1734. if( KeyControlBlock->KeyHive == Hive ) {
  1735. //
  1736. // found it ! Break to investigate !!!
  1737. //
  1738. DbgPrint("\n Orphaned KCB (%p) found for hive (%p)\n\n",KeyControlBlock,Hive);
  1739. DbgBreakPoint();
  1740. }
  1741. Current = Current->NextHash;
  1742. }
  1743. }
  1744. }
  1745. #endif //CM_CHECK_FOR_ORPHANED_KCBS
  1746. #ifdef ALLOC_DATA_PRAGMA
  1747. #pragma data_seg()
  1748. #endif