Source code of Windows XP (NT5)
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.

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