2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/config/cmkcbncb.c
5 * PURPOSE: Routines for handling KCBs, NCBs, as well as key hashes.
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES ******************************************************************/
15 /* GLOBALS *******************************************************************/
17 ULONG CmpHashTableSize
= 2048;
18 PCM_KEY_HASH_TABLE_ENTRY CmpCacheTable
;
19 PCM_NAME_HASH_TABLE_ENTRY CmpNameCacheTable
;
21 BOOLEAN CmpHoldLazyFlush
;
23 /* FUNCTIONS *****************************************************************/
27 CmpInitializeCache(VOID
)
31 /* Calculate length for the table */
32 Length
= CmpHashTableSize
* sizeof(CM_KEY_HASH_TABLE_ENTRY
);
35 CmpCacheTable
= ExAllocatePoolWithTag(PagedPool
, Length
, TAG_CM
);
38 /* Take the system down */
39 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 3, 1, 0, 0);
42 /* Zero out the table */
43 RtlZeroMemory(CmpCacheTable
, Length
);
45 /* Initialize the locks */
46 for (i
= 0;i
< CmpHashTableSize
; i
++)
48 /* Setup the pushlock */
49 ExInitializePushLock((PULONG_PTR
)&CmpCacheTable
[i
].Lock
);
52 /* Calculate length for the name cache */
53 Length
= CmpHashTableSize
* sizeof(CM_NAME_HASH_TABLE_ENTRY
);
55 /* Now allocate the name cache table */
56 CmpNameCacheTable
= ExAllocatePoolWithTag(PagedPool
, Length
, TAG_CM
);
57 if (!CmpNameCacheTable
)
59 /* Take the system down */
60 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 3, 3, 0, 0);
63 /* Zero out the table */
64 RtlZeroMemory(CmpNameCacheTable
, Length
);
66 /* Initialize the locks */
67 for (i
= 0;i
< CmpHashTableSize
; i
++)
69 /* Setup the pushlock */
70 ExInitializePushLock((PULONG_PTR
)&CmpNameCacheTable
[i
].Lock
);
73 /* Setup the delayed close table */
74 CmpInitializeDelayedCloseTable();
79 CmpRemoveKeyHash(IN PCM_KEY_HASH KeyHash
)
83 ASSERT_VALID_HASH(KeyHash
);
85 /* Lookup all the keys in this index entry */
86 Prev
= &GET_HASH_ENTRY(CmpCacheTable
, KeyHash
->ConvKey
).Entry
;
89 /* Save the current one and make sure it's valid */
91 ASSERT(Current
!= NULL
);
92 ASSERT_VALID_HASH(Current
);
94 /* Check if it matches */
95 if (Current
== KeyHash
)
97 /* Then write the previous one */
98 *Prev
= Current
->NextHash
;
99 if (*Prev
) ASSERT_VALID_HASH(*Prev
);
103 /* Otherwise, keep going */
104 Prev
= &Current
->NextHash
;
108 PCM_KEY_CONTROL_BLOCK
110 CmpInsertKeyHash(IN PCM_KEY_HASH KeyHash
,
115 ASSERT_VALID_HASH(KeyHash
);
117 /* Get the hash index */
118 i
= GET_HASH_INDEX(KeyHash
->ConvKey
);
120 /* If this is a fake key, increase the key cell to use the parent data */
121 if (IsFake
) KeyHash
->KeyCell
++;
123 /* Loop the hash table */
124 Entry
= CmpCacheTable
[i
].Entry
;
127 /* Check if this matches */
128 ASSERT_VALID_HASH(Entry
);
129 if ((KeyHash
->ConvKey
== Entry
->ConvKey
) &&
130 (KeyHash
->KeyCell
== Entry
->KeyCell
) &&
131 (KeyHash
->KeyHive
== Entry
->KeyHive
))
134 return CONTAINING_RECORD(Entry
, CM_KEY_CONTROL_BLOCK
, KeyHash
);
138 Entry
= Entry
->NextHash
;
141 /* No entry found, add this one and return NULL since none existed */
142 KeyHash
->NextHash
= CmpCacheTable
[i
].Entry
;
143 CmpCacheTable
[i
].Entry
= KeyHash
;
147 PCM_NAME_CONTROL_BLOCK
149 CmpGetNameControlBlock(IN PUNICODE_STRING NodeName
)
151 PCM_NAME_CONTROL_BLOCK Ncb
= NULL
;
155 BOOLEAN IsCompressed
= TRUE
, Found
= FALSE
;
156 PCM_NAME_HASH HashEntry
;
157 ULONG Length
, NcbSize
;
160 p
= NodeName
->Buffer
;
161 for (i
= 0; i
< NodeName
->Length
; i
+= sizeof(WCHAR
))
163 /* Make sure it's not a slash */
164 if (*p
!= OBJ_NAME_PATH_SEPARATOR
)
166 /* Add it to the hash */
167 ConvKey
= 37 * ConvKey
+ RtlUpcaseUnicodeChar(*p
);
174 /* Set assumed lengh and loop to check */
175 Length
= NodeName
->Length
/ sizeof(WCHAR
);
176 for (i
= 0; i
< (NodeName
->Length
/ sizeof(WCHAR
)); i
++)
178 /* Check if this is a valid character */
179 if (*NodeName
->Buffer
> (UCHAR
)-1)
181 /* This is the actual size, and we know we're not compressed */
182 Length
= NodeName
->Length
;
183 IsCompressed
= FALSE
;
187 /* Lock the NCB entry */
188 CmpAcquireNcbLockExclusiveByKey(ConvKey
);
190 /* Get the hash entry */
191 HashEntry
= GET_HASH_ENTRY(CmpNameCacheTable
, ConvKey
).Entry
;
194 /* Get the current NCB */
195 Ncb
= CONTAINING_RECORD(HashEntry
, CM_NAME_CONTROL_BLOCK
, NameHash
);
197 /* Check if the hash matches */
198 if ((ConvKey
= HashEntry
->ConvKey
) && (Length
= Ncb
->NameLength
))
203 /* If the NCB is compressed, do a compressed name compare */
207 if (CmpCompareCompressedName(NodeName
, Ncb
->Name
, Length
))
215 /* Do a manual compare */
216 p
= NodeName
->Buffer
;
218 for (i
= 0; i
< Ncb
->NameLength
; i
+= sizeof(WCHAR
))
220 /* Compare the character */
221 if (RtlUpcaseUnicodeChar(*p
) != RtlUpcaseUnicodeChar(*pp
))
234 /* Check if we found a name */
242 /* Go to the next hash */
243 HashEntry
= HashEntry
->NextHash
;
246 /* Check if we didn't find it */
250 NcbSize
= FIELD_OFFSET(CM_NAME_CONTROL_BLOCK
, Name
) + Length
;
251 Ncb
= ExAllocatePoolWithTag(PagedPool
, NcbSize
, TAG_CM
);
254 /* Release the lock and fail */
255 CmpReleaseNcbLockByKey(ConvKey
);
260 RtlZeroMemory(Ncb
, NcbSize
);
262 /* Check if the name was compressed */
265 /* Copy the compressed name */
266 Ncb
->Compressed
= TRUE
;
267 for (i
= 0; i
< Length
; i
++)
269 /* Copy Unicode to ANSI */
270 ((PCHAR
)Ncb
->Name
)[i
] = (CHAR
)RtlUpcaseUnicodeChar(NodeName
->Buffer
[i
]);
275 /* Copy the name directly */
276 Ncb
->Compressed
= FALSE
;
277 for (i
= 0; i
< Length
; i
++)
279 /* Copy each unicode character */
280 Ncb
->Name
[i
] = RtlUpcaseUnicodeChar(NodeName
->Buffer
[i
]);
284 /* Setup the rest of the NCB */
285 Ncb
->ConvKey
= ConvKey
;
287 Ncb
->NameLength
= Length
;
289 /* Insert the name in the hash table */
290 HashEntry
= &Ncb
->NameHash
;
291 HashEntry
->NextHash
= GET_HASH_ENTRY(CmpNameCacheTable
, ConvKey
).Entry
;
292 GET_HASH_ENTRY(CmpNameCacheTable
, ConvKey
).Entry
= HashEntry
;
295 /* Release NCB lock */
296 CmpReleaseNcbLockByKey(ConvKey
);
298 /* Return the NCB found */
304 CmpRemoveKeyControlBlock(IN PCM_KEY_CONTROL_BLOCK Kcb
)
306 /* Make sure that the registry and KCB are utterly locked */
307 ASSERT((CmpIsKcbLockedExclusive(Kcb
) == TRUE
) ||
308 (CmpTestRegistryLockExclusive() == TRUE
));
310 /* Remove the key hash */
311 CmpRemoveKeyHash(&Kcb
->KeyHash
);
316 CmpDereferenceNameControlBlockWithLock(IN PCM_NAME_CONTROL_BLOCK Ncb
)
318 PCM_NAME_HASH Current
, *Next
;
319 ULONG ConvKey
= Ncb
->ConvKey
;
322 CmpAcquireNcbLockExclusiveByKey(ConvKey
);
324 /* Decrease the reference count */
325 if (!(--Ncb
->RefCount
))
327 /* Find the NCB in the table */
328 Next
= &GET_HASH_ENTRY(CmpNameCacheTable
, Ncb
->ConvKey
).Entry
;
331 /* Check the current entry */
333 ASSERT(Current
!= NULL
);
334 if (Current
== &Ncb
->NameHash
)
337 *Next
= Current
->NextHash
;
341 /* Get to the next one */
342 Next
= &Current
->NextHash
;
345 /* Found it, now free it */
349 /* Release the lock */
350 CmpReleaseNcbLockByKey(ConvKey
);
355 CmpReferenceKeyControlBlock(IN PCM_KEY_CONTROL_BLOCK Kcb
)
357 /* Check if this is the KCB's first reference */
358 if (Kcb
->RefCount
== 0)
360 /* Check if the KCB is locked in shared mode */
361 if (!CmpIsKcbLockedExclusive(Kcb
))
363 /* Convert it to exclusive */
364 if (!CmpTryToConvertKcbSharedToExclusive(Kcb
))
366 /* Set the delayed close index so that we can be ignored */
367 Kcb
->DelayedCloseIndex
= 1;
369 /* Increase the reference count while we release the lock */
370 InterlockedIncrement((PLONG
)&Kcb
->RefCount
);
372 /* Go from shared to exclusive */
373 CmpConvertKcbSharedToExclusive(Kcb
);
375 /* Decrement the reference count; the lock is now held again */
376 InterlockedDecrement((PLONG
)&Kcb
->RefCount
);
378 /* Check if we still control the index */
379 if (Kcb
->DelayedCloseIndex
== 1)
382 Kcb
->DelayedCloseIndex
= 0;
387 ASSERT((Kcb
->DelayedCloseIndex
== CmpDelayedCloseSize
) ||
388 (Kcb
->DelayedCloseIndex
== 0));
394 /* Increase the reference count */
395 if ((InterlockedIncrement((PLONG
)&Kcb
->RefCount
) & 0xFFFF) == 0)
397 /* We've overflown to 64K references, bail out */
398 InterlockedDecrement((PLONG
)&Kcb
->RefCount
);
402 /* Check if this was the last close index */
403 if (!Kcb
->DelayedCloseIndex
)
405 /* Check if the KCB is locked in shared mode */
406 if (!CmpIsKcbLockedExclusive(Kcb
))
408 /* Convert it to exclusive */
409 if (!CmpTryToConvertKcbSharedToExclusive(Kcb
))
411 /* Go from shared to exclusive */
412 CmpConvertKcbSharedToExclusive(Kcb
);
416 /* If we're still the last entry, remove us */
417 if (!Kcb
->DelayedCloseIndex
) CmpRemoveFromDelayedClose(Kcb
);
426 CmpCleanUpKcbValueCache(IN PCM_KEY_CONTROL_BLOCK Kcb
)
428 PULONG_PTR CachedList
;
432 ASSERT((CmpIsKcbLockedExclusive(Kcb
) == TRUE
) ||
433 (CmpTestRegistryLockExclusive() == TRUE
));
435 /* Check if the value list is cached */
436 if (CMP_IS_CELL_CACHED(Kcb
->ValueCache
.ValueList
))
438 /* Get the cache list */
439 CachedList
= (PULONG_PTR
)CMP_GET_CACHED_DATA(Kcb
->ValueCache
.ValueList
);
440 for (i
= 0; i
< Kcb
->ValueCache
.Count
; i
++)
442 /* Check if this cell is cached */
443 if (CMP_IS_CELL_CACHED(CachedList
[i
]))
446 ExFreePool((PVOID
)CMP_GET_CACHED_CELL(CachedList
[i
]));
450 /* Now free the list */
451 ExFreePool((PVOID
)CMP_GET_CACHED_CELL(Kcb
->ValueCache
.ValueList
));
452 Kcb
->ValueCache
.ValueList
= HCELL_NIL
;
454 else if (Kcb
->ExtFlags
& CM_KCB_SYM_LINK_FOUND
)
456 /* This is a sym link, check if there's only one reference left */
457 if ((Kcb
->ValueCache
.RealKcb
->RefCount
== 1) &&
458 !(Kcb
->ValueCache
.RealKcb
->Delete
))
460 /* Disable delay close for the KCB */
461 Kcb
->ValueCache
.RealKcb
->ExtFlags
|= CM_KCB_NO_DELAY_CLOSE
;
464 /* Dereference the KCB */
465 CmpDelayDerefKeyControlBlock(Kcb
->ValueCache
.RealKcb
);
466 Kcb
->ExtFlags
&= ~CM_KCB_SYM_LINK_FOUND
;
472 CmpCleanUpKcbCacheWithLock(IN PCM_KEY_CONTROL_BLOCK Kcb
,
473 IN BOOLEAN LockHeldExclusively
)
475 PCM_KEY_CONTROL_BLOCK Parent
;
479 ASSERT((CmpIsKcbLockedExclusive(Kcb
) == TRUE
) ||
480 (CmpTestRegistryLockExclusive() == TRUE
));
481 ASSERT(Kcb
->RefCount
== 0);
483 /* Cleanup the value cache */
484 CmpCleanUpKcbValueCache(Kcb
);
486 /* Reference the NCB */
487 CmpDereferenceNameControlBlockWithLock(Kcb
->NameBlock
);
489 /* Check if we have an index hint block and free it */
490 if (Kcb
->ExtFlags
& CM_KCB_SUBKEY_HINT
) ExFreePool(Kcb
->IndexHint
);
492 /* Check if we were already deleted */
493 Parent
= Kcb
->ParentKcb
;
494 if (!Kcb
->Delete
) CmpRemoveKeyControlBlock(Kcb
);
496 /* Set invalid KCB signature */
497 Kcb
->Signature
= CM_KCB_INVALID_SIGNATURE
;
499 /* Free the KCB as well */
500 CmpFreeKeyControlBlock(Kcb
);
502 /* Check if we have a parent */
505 /* Dereference the parent */
506 LockHeldExclusively
?
507 CmpDereferenceKeyControlBlockWithLock(Kcb
,LockHeldExclusively
) :
508 CmpDelayDerefKeyControlBlock(Kcb
);
514 CmpCleanUpSubKeyInfo(IN PCM_KEY_CONTROL_BLOCK Kcb
)
516 PCM_KEY_NODE KeyNode
;
519 ASSERT((CmpIsKcbLockedExclusive(Kcb
) == TRUE
) ||
520 (CmpTestRegistryLockExclusive() == TRUE
));
522 /* Check if there's any cached subkey */
523 if (Kcb
->ExtFlags
& (CM_KCB_NO_SUBKEY
| CM_KCB_SUBKEY_ONE
| CM_KCB_SUBKEY_HINT
))
525 /* Check if there's a hint */
526 if (Kcb
->ExtFlags
& (CM_KCB_SUBKEY_HINT
))
529 ExFreePool(Kcb
->IndexHint
);
532 /* Remove subkey flags */
533 Kcb
->ExtFlags
&= ~(CM_KCB_NO_SUBKEY
| CM_KCB_SUBKEY_ONE
| CM_KCB_SUBKEY_HINT
);
536 /* Check if there's no linked cell */
537 if (Kcb
->KeyCell
== HCELL_NIL
)
539 /* Make sure it's a delete */
545 /* Get the key node */
546 KeyNode
= (PCM_KEY_NODE
)HvGetCell(Kcb
->KeyHive
, Kcb
->KeyCell
);
549 /* Check if we got the node */
552 /* We didn't, mark the cached data invalid */
553 Kcb
->ExtFlags
|= CM_KCB_INVALID_CACHED_INFO
;
557 /* We have a keynode, update subkey counts */
558 Kcb
->ExtFlags
&= ~CM_KCB_INVALID_CACHED_INFO
;
559 Kcb
->SubKeyCount
= KeyNode
->SubKeyCounts
[Stable
] +
560 KeyNode
->SubKeyCounts
[Volatile
];
562 /* Release the cell */
563 HvReleaseCell(Kcb
->KeyHive
, Kcb
->KeyCell
);
569 CmpDereferenceKeyControlBlock(IN PCM_KEY_CONTROL_BLOCK Kcb
)
571 LONG OldRefCount
, NewRefCount
;
574 /* Get the ref count and update it */
575 OldRefCount
= *(PLONG
)&Kcb
->RefCount
;
576 NewRefCount
= OldRefCount
- 1;
578 /* Check if we still have references */
579 if( (NewRefCount
& 0xFFFF) > 0)
581 /* Do the dereference */
582 if (InterlockedCompareExchange((PLONG
)&Kcb
->RefCount
,
584 OldRefCount
) == OldRefCount
)
592 ConvKey
= Kcb
->ConvKey
;
594 /* Do the dereference inside the lock */
595 CmpAcquireKcbLockExclusive(Kcb
);
596 CmpDereferenceKeyControlBlockWithLock(Kcb
, FALSE
);
597 CmpReleaseKcbLockByKey(ConvKey
);
602 CmpDereferenceKeyControlBlockWithLock(IN PCM_KEY_CONTROL_BLOCK Kcb
,
603 IN BOOLEAN LockHeldExclusively
)
606 ASSERT_KCB_VALID(Kcb
);
608 /* Check if this is the last reference */
609 if ((InterlockedDecrement((PLONG
)&Kcb
->RefCount
) & 0xFFFF) == 0)
612 ASSERT((CmpIsKcbLockedExclusive(Kcb
) == TRUE
) ||
613 (CmpTestRegistryLockExclusive() == TRUE
));
615 /* Check if we should do a direct delete */
616 if (((CmpHoldLazyFlush
) &&
617 !(Kcb
->ExtFlags
& CM_KCB_SYM_LINK_FOUND
) &&
618 !(Kcb
->Flags
& KEY_SYM_LINK
)) ||
619 (Kcb
->ExtFlags
& CM_KCB_NO_DELAY_CLOSE
) ||
622 /* Clean up the KCB*/
623 CmpCleanUpKcbCacheWithLock(Kcb
, LockHeldExclusively
);
627 /* Otherwise, use delayed close */
628 CmpAddToDelayedClose(Kcb
, LockHeldExclusively
);
635 InitializeKCBKeyBodyList(IN PCM_KEY_CONTROL_BLOCK Kcb
)
637 /* Initialize the list */
638 InitializeListHead(&Kcb
->KeyBodyListHead
);
640 /* Clear the bodies */
641 Kcb
->KeyBodyArray
[0] =
642 Kcb
->KeyBodyArray
[1] =
643 Kcb
->KeyBodyArray
[2] =
644 Kcb
->KeyBodyArray
[3] = NULL
;
647 PCM_KEY_CONTROL_BLOCK
649 CmpCreateKeyControlBlock(IN PHHIVE Hive
,
650 IN HCELL_INDEX Index
,
651 IN PCM_KEY_NODE Node
,
652 IN PCM_KEY_CONTROL_BLOCK Parent
,
654 IN PUNICODE_STRING KeyName
)
656 PCM_KEY_CONTROL_BLOCK Kcb
, FoundKcb
= NULL
;
657 UNICODE_STRING NodeName
;
658 ULONG ConvKey
= 0, i
;
659 BOOLEAN IsFake
, HashLock
;
662 /* Make sure we own this hive in case it's being unloaded */
663 if ((Hive
->HiveFlags
& HIVE_IS_UNLOADING
) &&
664 (((PCMHIVE
)Hive
)->CreatorOwner
!= KeGetCurrentThread()))
670 /* Check if this is a fake KCB */
671 IsFake
= Flags
& CMP_CREATE_FAKE_KCB
? TRUE
: FALSE
;
673 /* If we have a parent, use its ConvKey */
674 if (Parent
) ConvKey
= Parent
->ConvKey
;
676 /* Make a copy of the name */
679 /* Remove leading slash */
680 while ((NodeName
.Length
) && (*NodeName
.Buffer
== OBJ_NAME_PATH_SEPARATOR
))
682 /* Move the buffer by one */
684 NodeName
.Length
-= sizeof(WCHAR
);
687 /* Make sure we didn't get just a slash or something */
688 ASSERT(NodeName
.Length
> 0);
690 /* Now setup the hash */
692 for (i
= 0; i
< NodeName
.Length
; i
+= sizeof(WCHAR
))
694 /* Make sure it's a valid character */
695 if (*p
!= OBJ_NAME_PATH_SEPARATOR
)
697 /* Add this key to the hash */
698 ConvKey
= 37 * ConvKey
+ RtlUpcaseUnicodeChar(*p
);
705 /* Allocate the KCB */
706 Kcb
= CmpAllocateKeyControlBlock();
707 if (!Kcb
) return NULL
;
709 /* Initailize the key list */
710 InitializeKCBKeyBodyList(Kcb
);
713 Kcb
->Signature
= CM_KCB_SIGNATURE
;
717 Kcb
->KeyCell
= Index
;
718 Kcb
->ConvKey
= ConvKey
;
719 Kcb
->DelayedCloseIndex
= CmpDelayedCloseSize
;
720 Kcb
->InDelayClose
= 0;
721 ASSERT_KCB_VALID(Kcb
);
723 /* Check if we have two hash entires */
724 HashLock
= Flags
& CMP_LOCK_HASHES_FOR_KCB
? TRUE
: FALSE
;
727 /* It's not locked, do we have a parent? */
730 /* Lock the parent KCB and ourselves */
731 CmpAcquireTwoKcbLocksExclusiveByKey(ConvKey
, Parent
->ConvKey
);
735 /* Lock only ourselves */
736 CmpAcquireKcbLockExclusive(Kcb
);
740 /* Check if we already have a KCB */
741 FoundKcb
= CmpInsertKeyHash(&Kcb
->KeyHash
, IsFake
);
745 ASSERT(!FoundKcb
->Delete
);
746 Kcb
->Signature
= CM_KCB_INVALID_SIGNATURE
;
748 /* Free the one we allocated and reference this one */
749 CmpFreeKeyControlBlock(Kcb
);
750 ASSERT_KCB_VALID(FoundKcb
);
752 if (!CmpReferenceKeyControlBlock(Kcb
))
754 /* We got too many handles */
755 ASSERT(Kcb
->RefCount
+ 1 != 0);
760 /* Check if we're not creating a fake one, but it used to be fake */
761 if ((Kcb
->ExtFlags
& CM_KCB_KEY_NON_EXIST
) && !(IsFake
))
763 /* Set the hive and cell */
765 Kcb
->KeyCell
= Index
;
767 /* This means that our current information is invalid */
768 Kcb
->ExtFlags
= CM_KCB_INVALID_CACHED_INFO
;
771 /* Check if we didn't have any valid data */
772 if (!(Kcb
->ExtFlags
& (CM_KCB_NO_SUBKEY
|
774 CM_KCB_SUBKEY_HINT
)))
776 /* Calculate the index hint */
777 Kcb
->SubKeyCount
= Node
->SubKeyCounts
[Stable
] +
778 Node
->SubKeyCounts
[Volatile
];
780 /* Cached information is now valid */
781 Kcb
->ExtFlags
&= ~CM_KCB_INVALID_CACHED_INFO
;
784 /* Setup the other data */
785 Kcb
->KcbLastWriteTime
= Node
->LastWriteTime
;
786 Kcb
->KcbMaxNameLen
= (USHORT
)Node
->MaxNameLen
;
787 Kcb
->KcbMaxValueNameLen
= (USHORT
)Node
->MaxValueNameLen
;
788 Kcb
->KcbMaxValueDataLen
= Node
->MaxValueDataLen
;
793 /* No KCB, do we have a parent? */
796 /* Reference the parent */
797 if (((Parent
->TotalLevels
+ 1) < 512) &&
798 (CmpReferenceKeyControlBlock(Parent
)))
801 Kcb
->ParentKcb
= Parent
;
802 Kcb
->TotalLevels
= Parent
->TotalLevels
+ 1;
806 /* Remove the KCB and free it */
807 CmpRemoveKeyControlBlock(Kcb
);
808 Kcb
->Signature
= CM_KCB_INVALID_SIGNATURE
;
809 CmpFreeKeyControlBlock(Kcb
);
815 /* No parent, this is the root node */
816 Kcb
->ParentKcb
= NULL
;
817 Kcb
->TotalLevels
= 1;
820 /* Check if we have a KCB */
824 Kcb
->NameBlock
= CmpGetNameControlBlock(&NodeName
);
828 Kcb
->ValueCache
.Count
= Node
->ValueList
.Count
;
829 Kcb
->ValueCache
.ValueList
= Node
->ValueList
.List
;
830 Kcb
->Flags
= Node
->Flags
;
832 Kcb
->DelayedCloseIndex
= CmpDelayedCloseSize
;
834 /* Remember if this is a fake key */
835 if (IsFake
) Kcb
->ExtFlags
|= CM_KCB_KEY_NON_EXIST
;
837 /* Setup the other data */
838 Kcb
->SubKeyCount
= Node
->SubKeyCounts
[Stable
] +
839 Node
->SubKeyCounts
[Volatile
];
840 Kcb
->KcbLastWriteTime
= Node
->LastWriteTime
;
841 Kcb
->KcbMaxNameLen
= (USHORT
)Node
->MaxNameLen
;
842 Kcb
->KcbMaxValueNameLen
= (USHORT
)Node
->MaxValueNameLen
;
843 Kcb
->KcbMaxValueDataLen
= (USHORT
)Node
->MaxValueDataLen
;
847 /* Dereference the KCB */
848 CmpDereferenceKeyControlBlockWithLock(Parent
, FALSE
);
850 /* Remove the KCB and free it */
851 CmpRemoveKeyControlBlock(Kcb
);
852 Kcb
->Signature
= CM_KCB_INVALID_SIGNATURE
;
853 CmpFreeKeyControlBlock(Kcb
);
859 /* Check if this is a KCB inside a frozen hive */
860 if ((Kcb
) && (((PCMHIVE
)Hive
)->Frozen
) && (!(Kcb
->Flags
& KEY_SYM_LINK
)))
862 /* Don't add these to the delay close */
863 Kcb
->ExtFlags
|= CM_KCB_NO_DELAY_CLOSE
;
867 ASSERT((!Kcb
) || (Kcb
->Delete
== FALSE
));
869 /* Check if we had locked the hashes */
872 /* We locked them manually, do we have a parent? */
875 /* Unlock the parent KCB and ourselves */
876 CmpReleaseTwoKcbLockByKey(ConvKey
, Parent
->ConvKey
);
880 /* Unlock only ourselves */
881 CmpReleaseKcbLockByKey(ConvKey
);
891 EnlistKeyBodyWithKCB(IN PCM_KEY_BODY KeyBody
,
897 ASSERT(KeyBody
->KeyControlBlock
!= NULL
);
899 /* Initialize the list entry */
900 InitializeListHead(&KeyBody
->KeyBodyList
);
902 /* Check if we can use the parent KCB array */
903 for (i
= 0; i
< 4; i
++)
905 /* Add it into the list */
906 if (!InterlockedCompareExchangePointer((PVOID
*)&KeyBody
->KeyControlBlock
->
916 /* Array full, check if we need to unlock the KCB */
917 if (Flags
& CMP_ENLIST_KCB_LOCKED_SHARED
)
919 /* It's shared, so release the KCB shared lock */
920 CmpReleaseKcbLock(KeyBody
->KeyControlBlock
);
921 ASSERT(!(Flags
& CMP_ENLIST_KCB_LOCKED_EXCLUSIVE
));
924 /* Check if we need to lock the KCB */
925 if (!(Flags
& CMP_ENLIST_KCB_LOCKED_EXCLUSIVE
))
927 /* Acquire the lock */
928 CmpAcquireKcbLockExclusive(KeyBody
->KeyControlBlock
);
931 /* Make sure we have the exclusive lock */
932 ASSERT((CmpIsKcbLockedExclusive(KeyBody
->KeyControlBlock
) == TRUE
) ||
933 (CmpTestRegistryLockExclusive() == TRUE
));
936 InsertTailList(&KeyBody
->KeyControlBlock
->KeyBodyListHead
,
937 &KeyBody
->KeyBodyList
);
939 /* Check if we did a manual lock */
940 if (!(Flags
& (CMP_ENLIST_KCB_LOCKED_SHARED
|
941 CMP_ENLIST_KCB_LOCKED_EXCLUSIVE
)))
943 /* Release the lock */
944 CmpReleaseKcbLock(KeyBody
->KeyControlBlock
);
950 DelistKeyBodyFromKCB(IN PCM_KEY_BODY KeyBody
,
956 ASSERT(KeyBody
->KeyControlBlock
!= NULL
);
958 /* Check if we can use the parent KCB array */
959 for (i
= 0; i
< 4; i
++)
961 /* Add it into the list */
962 if (InterlockedCompareExchangePointer((VOID
*)&KeyBody
->KeyControlBlock
->
973 ASSERT(IsListEmpty(&KeyBody
->KeyControlBlock
->KeyBodyListHead
) == FALSE
);
974 ASSERT(IsListEmpty(&KeyBody
->KeyBodyList
) == FALSE
);
977 if (!LockHeld
) CmpAcquireKcbLockExclusive(KeyBody
->KeyControlBlock
);
978 ASSERT((CmpIsKcbLockedExclusive(KeyBody
->KeyControlBlock
) == TRUE
) ||
979 (CmpTestRegistryLockExclusive() == TRUE
));
981 /* Remove the entry */
982 RemoveEntryList(&KeyBody
->KeyBodyList
);
984 /* Unlock it it if we did a manual lock */
985 if (!LockHeld
) CmpReleaseKcbLock(KeyBody
->KeyControlBlock
);