2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/config/cmindex.c
5 * PURPOSE: Configuration Manager - Cell Indexes
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES ******************************************************************/
16 /* GLOBALS *******************************************************************/
18 /* FUNCTIONS *****************************************************************/
22 CmpDoCompareKeyName(IN PHHIVE Hive
,
23 IN PUNICODE_STRING SearchName
,
27 UNICODE_STRING KeyName
;
31 Node
= (PCM_KEY_NODE
)HvGetCell(Hive
, Cell
);
34 /* Check if it's compressed */
35 if (Node
->Flags
& KEY_COMP_NAME
)
37 /* Compare compressed names */
38 Result
= CmpCompareCompressedName(SearchName
,
44 /* Compare the Unicode name directly */
45 KeyName
.Buffer
= Node
->Name
;
46 KeyName
.Length
= Node
->NameLength
;
47 KeyName
.MaximumLength
= KeyName
.Length
;
48 Result
= RtlCompareUnicodeString(SearchName
, &KeyName
, TRUE
);
51 /* Release the cell and return the normalized result */
52 HvReleaseCell(Hive
, Cell
);
53 return (Result
== 0) ? Result
: ((Result
> 0) ? 1 : -1);
58 CmpCompareInIndex(IN PHHIVE Hive
,
59 IN PUNICODE_STRING SearchName
,
61 IN PCM_KEY_INDEX Index
,
62 IN PHCELL_INDEX SubKey
)
64 PCM_KEY_FAST_INDEX FastIndex
;
68 ULONG ActualNameLength
= 4, CompareLength
, NameLength
;
74 /* Check if we are a fast or hashed leaf */
75 if ((Index
->Signature
== CM_KEY_FAST_LEAF
) ||
76 (Index
->Signature
== CM_KEY_HASH_LEAF
))
78 /* Get the Fast/Hash Index */
79 FastIndex
= (PCM_KEY_FAST_INDEX
)Index
;
80 FastEntry
= &FastIndex
->List
[Count
];
82 /* Check if we are a hash leaf, in which case we skip all this */
83 if (Index
->Signature
== CM_KEY_FAST_LEAF
)
85 /* Find out just how much of the name is there */
86 for (i
= 0; i
< 4; i
++)
88 /* Check if this entry is empty */
89 if (!FastEntry
->NameHint
[i
])
97 /* How large is the name and how many characters to compare */
98 NameLength
= SearchName
->Length
/ sizeof(WCHAR
);
99 CompareLength
= min(NameLength
, ActualNameLength
);
101 /* Loop all the chars we'll test */
102 for (i
= 0; i
< CompareLength
; i
++)
104 /* Get one char from each buffer */
105 p
= SearchName
->Buffer
[i
];
106 pp
= FastEntry
->NameHint
[i
];
108 /* See if they match and return result if they don't */
109 Result
= (LONG
)RtlUpcaseUnicodeChar(p
) -
110 (LONG
)RtlUpcaseUnicodeChar(pp
);
111 if (Result
) return (Result
> 0) ? 1 : -1;
115 /* If we got here then we have to do a full compare */
116 Result
= CmpDoCompareKeyName(Hive
, SearchName
, FastEntry
->Cell
);
117 if (Result
== 2) return Result
;
118 if (!Result
) *SubKey
= FastEntry
->Cell
;
122 /* We aren't, so do a name compare and return the subkey found */
123 Result
= CmpDoCompareKeyName(Hive
, SearchName
, Index
->List
[Count
]);
124 if (Result
== 2) return Result
;
125 if (!Result
) *SubKey
= Index
->List
[Count
];
128 /* Return the comparison result */
134 CmpFindSubKeyInRoot(IN PHHIVE Hive
,
135 IN PCM_KEY_INDEX Index
,
136 IN PUNICODE_STRING SearchName
,
137 IN PHCELL_INDEX SubKey
)
139 ULONG High
, Low
= 0, i
, ReturnIndex
;
140 HCELL_INDEX LeafCell
;
144 /* Verify Index for validity */
145 ASSERTMSG("We don't do a linear search yet!\n", FALSE
);
146 ASSERT(Index
->Count
!= 0);
147 ASSERT(Index
->Signature
== CM_KEY_INDEX_ROOT
);
149 /* Set high limit and loop */
150 High
= Index
->Count
- 1;
153 /* Choose next entry */
154 i
= ((High
- Low
) / 2) + Low
;
156 /* Get the leaf cell and then the leaf itself */
157 LeafCell
= Index
->List
[i
];
158 Leaf
= (PCM_KEY_INDEX
)HvGetCell(Hive
, LeafCell
);
161 /* Make sure the leaf is valid */
162 ASSERT((Leaf
->Signature
== CM_KEY_INDEX_LEAF
) ||
163 (Leaf
->Signature
== CM_KEY_FAST_LEAF
) ||
164 (Leaf
->Signature
== CM_KEY_HASH_LEAF
));
165 ASSERT(Leaf
->Count
!= 0);
168 Result
= CmpCompareInIndex(Hive
,
173 if (Result
== 2) goto Big
;
175 /* Check if we found the leaf */
178 /* We found the leaf */
184 /* Check for negative result */
187 /* If we got here, we should be at -1 */
188 ASSERT(Result
== -1);
190 /* Do another lookup, since we might still be in the right leaf */
191 Result
= CmpCompareInIndex(Hive
,
196 if (Result
== 2) goto Big
;
198 /* Check if it's not below */
202 * If the name was first below, and now it is above,
203 * then this means that it is somewhere in this leaf.
204 * Make sure we didn't get some weird result
206 ASSERT((Result
== 1) || (Result
== 0));
214 /* Update the limit to this index, since we know it's not higher. */
219 /* Update the base to this index, since we know it's not lower. */
226 /* This was some sort of special key */
227 ReturnIndex
= 0x80000000;
231 /* Check if there is only one entry left */
232 if ((High
- Low
) <= 1) break;
234 /* Release the leaf cell */
235 HvReleaseCell(Hive
, LeafCell
);
238 /* Make sure we got here for the right reasons */
239 ASSERT((High
- Low
== 1) || (High
== Low
));
241 /* Get the leaf cell and the leaf */
242 LeafCell
= Index
->List
[Low
];
243 Leaf
= (PCM_KEY_INDEX
)HvGetCell(Hive
, LeafCell
);
247 Result
= CmpCompareInIndex(Hive
,
252 if (Result
== 2) goto Big
;
254 /* Check if we found it */
257 /* We got lucky...return it */
263 /* It's below, so could still be in this leaf */
266 /* Make sure we're -1 */
267 ASSERT(Result
== -1);
269 /* Do a search from the bottom */
270 Result
= CmpCompareInIndex(Hive
, SearchName
, 0, Leaf
, SubKey
);
271 if (Result
== 2) goto Big
;
274 * Check if it's above, which means that it's within the ranges of our
275 * leaf (since we were below before).
280 ASSERT((Result
== 1) || (Result
== 0));
282 /* Yep, so we're in the right leaf; return it. */
288 /* It's still below us, so fail */
293 /* Release the leaf cell */
294 HvReleaseCell(Hive
, LeafCell
);
296 /* Well the low didn't work too well, so try the high. */
297 LeafCell
= Index
->List
[High
];
298 Leaf
= (PCM_KEY_INDEX
)HvGetCell(Hive
, LeafCell
);
302 Result
= CmpCompareInIndex(Hive
,
307 if (Result
== 2) goto Big
;
309 /* Check if we found it */
312 /* We got lucky... return it */
318 /* Check if we are too high */
321 /* Make sure we're -1 */
322 ASSERT(Result
== -1);
325 * Once again... since we were first too low and now too high, then
326 * this means we are within the range of this leaf... return it.
333 /* If we got here, then we are too low, again. */
340 /* Return path...check if we have a leaf to free */
342 if (Leaf
) HvReleaseCell(Hive
, LeafCell
);
344 /* Return the index */
350 CmpFindSubKeyInLeaf(IN PHHIVE Hive
,
351 IN PCM_KEY_INDEX Index
,
352 IN PUNICODE_STRING SearchName
,
353 IN PHCELL_INDEX SubKey
)
355 ULONG High
, Low
= 0, i
;
358 /* Verify Index for validity */
359 ASSERT((Index
->Signature
== CM_KEY_INDEX_LEAF
) ||
360 (Index
->Signature
== CM_KEY_FAST_LEAF
) ||
361 (Index
->Signature
== CM_KEY_HASH_LEAF
));
363 /* Get the upper bound and middle entry */
364 High
= Index
->Count
- 1;
365 #ifdef SOMEONE_WAS_NICE_ENOUGH_TO_MAKE_OUR_CELLS_LEXICALLY_SORTED
371 /* Check if we don't actually have any entries */
379 /* Start compare loop */
382 /* Do the actual comparison and check the result */
383 Result
= CmpCompareInIndex(Hive
, SearchName
, i
, Index
, SubKey
);
386 /* Fail with special value */
391 /* Check if we got lucky and found it */
392 if (!Result
) return i
;
394 #ifdef SOMEONE_WAS_NICE_ENOUGH_TO_MAKE_OUR_CELLS_LEXICALLY_SORTED
395 /* Check if the result is below us */
398 /* Set the new bound; it can't be higher then where we are now. */
399 ASSERT(Result
== -1);
404 /* Set the new bound... it can't be lower then where we are now. */
409 /* Check if this is the last entry, if so, break out and handle it */
410 if ((High
- Low
) <= 1) break;
412 /* Set the new index */
413 i
= ((High
- Low
) / 2) + Low
;
425 * If we get here, High - Low = 1 or High == Low
426 * Simply look first at Low, then at High
428 Result
= CmpCompareInIndex(Hive
, SearchName
, Low
, Index
, SubKey
);
431 /* Fail with special value */
436 /* Check if we got lucky and found it */
437 if (!Result
) return Low
;
439 /* Check if the result is below us */
442 /* Return the low entry */
443 ASSERT(Result
== -1);
448 * If we got here, then just check the high and return it no matter what
449 * the result is (since we're a leaf, it has to be near there anyway).
451 Result
= CmpCompareInIndex(Hive
, SearchName
, High
, Index
, SubKey
);
454 /* Fail with special value */
459 /* Return the high */
465 CmpComputeHashKey(IN ULONG Hash
,
466 IN PUNICODE_STRING Name
,
467 IN BOOLEAN AllowSeparators
)
472 /* Make some sanity checks on our parameters */
473 ASSERT((Name
->Length
== 0) ||
475 (Name
->Buffer
[0] != OBJ_NAME_PATH_SEPARATOR
));
477 /* If the name is empty, there is nothing to hash! */
478 if (!Name
->Length
) return Hash
;
480 /* Set the buffer and loop every character */
482 for (i
= 0; i
< Name
->Length
; i
+= sizeof(WCHAR
), Cp
++)
484 /* Make sure we don't have a separator when we shouldn't */
485 ASSERT(AllowSeparators
|| (*Cp
!= OBJ_NAME_PATH_SEPARATOR
));
487 /* Check what kind of char we have */
490 /* In the lower case region... is it truly lower case? */
493 /* Yes! Calculate it ourselves! */
494 Value
= *Cp
- L
'a' + L
'A';
498 /* No, use the API */
499 Value
= RtlUpcaseUnicodeChar(*Cp
);
504 /* Reuse the char, it's already upcased */
508 /* Multiply by a prime and add our value */
513 /* Return the hash */
519 CmpDoFindSubKeyByNumber(IN PHHIVE Hive
,
520 IN PCM_KEY_INDEX Index
,
524 HCELL_INDEX LeafCell
= 0;
525 PCM_KEY_INDEX Leaf
= NULL
;
526 PCM_KEY_FAST_INDEX FastIndex
;
529 /* Check if this is a root */
530 if (Index
->Signature
== CM_KEY_INDEX_ROOT
)
533 for (i
= 0; i
< Index
->Count
; i
++)
535 /* Check if this isn't the first iteration */
538 /* Make sure we had something valid, and release it */
539 ASSERT(Leaf
!= NULL
);
540 ASSERT(LeafCell
== Index
->List
[i
- 1]);
541 HvReleaseCell(Hive
, LeafCell
);
544 /* Get the leaf cell and the leaf for this index */
545 LeafCell
= Index
->List
[i
];
546 Leaf
= (PCM_KEY_INDEX
)HvGetCell(Hive
, LeafCell
);
547 if (!Leaf
) return HCELL_NIL
;
549 /* Check if the index may be inside it */
550 if (Number
< Leaf
->Count
)
552 /* Check if this is a fast or hash leaf */
553 if ((Leaf
->Signature
== CM_KEY_FAST_LEAF
) ||
554 (Leaf
->Signature
== CM_KEY_HASH_LEAF
))
556 /* Get the fast index */
557 FastIndex
= (PCM_KEY_FAST_INDEX
)Leaf
;
559 /* Look inside the list to get our actual cell */
560 Result
= FastIndex
->List
[Number
].Cell
;
561 HvReleaseCell(Hive
, LeafCell
);
566 /* Regular leaf, so just use the index directly */
567 Result
= Leaf
->List
[Number
];
569 /* Release and return it */
570 HvReleaseCell(Hive
,LeafCell
);
576 /* Otherwise, skip this leaf */
577 Number
= Number
- Leaf
->Count
;
581 /* Should never get here */
585 /* If we got here, then the cell is in this index */
586 ASSERT(Number
< Index
->Count
);
588 /* Check if we're a fast or hash leaf */
589 if ((Index
->Signature
== CM_KEY_FAST_LEAF
) ||
590 (Index
->Signature
== CM_KEY_HASH_LEAF
))
592 /* We are, get the fast index and get the cell from the list */
593 FastIndex
= (PCM_KEY_FAST_INDEX
)Index
;
594 return FastIndex
->List
[Number
].Cell
;
598 /* We aren't, so use the index directly to grab the cell */
599 return Index
->List
[Number
];
605 CmpFindSubKeyByNumber(IN PHHIVE Hive
,
606 IN PCM_KEY_NODE Node
,
610 HCELL_INDEX Result
= HCELL_NIL
;
612 /* Check if it's in the stable list */
613 if (Number
< Node
->SubKeyCounts
[HvStable
])
615 /* Get the actual key index */
616 Index
= (PCM_KEY_INDEX
)HvGetCell(Hive
, Node
->SubKeyLists
[HvStable
]);
617 if (!Index
) return HCELL_NIL
;
619 /* Do a search inside it */
620 Result
= CmpDoFindSubKeyByNumber(Hive
, Index
, Number
);
622 /* Release the cell and return the result */
623 HvReleaseCell(Hive
, Node
->SubKeyLists
[HvStable
]);
626 else if (Hive
->StorageTypeCount
> HvVolatile
)
628 /* It's in the volatile list */
629 Number
= Number
- Node
->SubKeyCounts
[HvStable
];
630 if (Number
< Node
->SubKeyCounts
[HvVolatile
])
632 /* Get the actual key index */
633 Index
= (PCM_KEY_INDEX
)HvGetCell(Hive
,
634 Node
->SubKeyLists
[HvVolatile
]);
635 if (!Index
) return HCELL_NIL
;
637 /* Do a search inside it */
638 Result
= CmpDoFindSubKeyByNumber(Hive
, Index
, Number
);
640 /* Release the cell and return the result */
641 HvReleaseCell(Hive
, Node
->SubKeyLists
[HvVolatile
]);
646 /* Nothing was found */
652 CmpFindSubKeyByHash(IN PHHIVE Hive
,
653 IN PCM_KEY_FAST_INDEX FastIndex
,
654 IN PUNICODE_STRING SearchName
)
659 /* Make sure it's really a hash */
660 ASSERT(FastIndex
->Signature
== CM_KEY_HASH_LEAF
);
662 /* Compute the hash key for the name */
663 HashKey
= CmpComputeHashKey(0, SearchName
, FALSE
);
665 /* Loop all the entries */
666 for (i
= 0; i
< FastIndex
->Count
; i
++)
669 FastEntry
= &FastIndex
->List
[i
];
671 /* Compare the hash first */
672 if (FastEntry
->HashKey
== HashKey
)
674 /* Go ahead for a full compare */
675 if (!(CmpDoCompareKeyName(Hive
, SearchName
, FastEntry
->Cell
)))
677 /* It matched, return the cell */
678 return FastEntry
->Cell
;
683 /* If we got here then we failed */
689 CmpFindSubKeyByName(IN PHHIVE Hive
,
690 IN PCM_KEY_NODE Parent
,
691 IN PUNICODE_STRING SearchName
)
694 PCM_KEY_INDEX IndexRoot
;
695 HCELL_INDEX SubKey
, CellToRelease
;
698 /* Loop each storage type */
699 for (i
= 0; i
< Hive
->StorageTypeCount
; i
++)
701 /* Make sure the parent node has subkeys */
702 if (Parent
->SubKeyCounts
[i
])
705 IndexRoot
= (PCM_KEY_INDEX
)HvGetCell(Hive
, Parent
->SubKeyLists
[i
]);
706 if (!IndexRoot
) return HCELL_NIL
;
708 /* Get the cell we'll need to release */
709 CellToRelease
= Parent
->SubKeyLists
[i
];
711 /* Check if this is another index root */
712 if (IndexRoot
->Signature
== CM_KEY_INDEX_ROOT
)
714 /* Lookup the name in the root */
715 Found
= CmpFindSubKeyInRoot(Hive
,
720 /* Release the previous cell */
721 ASSERT(CellToRelease
!= HCELL_NIL
);
722 HvReleaseCell(Hive
, CellToRelease
);
724 /* Make sure we found something valid */
725 if (Found
< 0) break;
727 /* Get the new Index Root and set the new cell to be released */
728 if (SubKey
== HCELL_NIL
) continue;
729 CellToRelease
= SubKey
;
730 IndexRoot
= (PCM_KEY_INDEX
)HvGetCell(Hive
, SubKey
);
733 /* Make sure the signature is what we expect it to be */
734 ASSERT((IndexRoot
->Signature
== CM_KEY_INDEX_LEAF
) ||
735 (IndexRoot
->Signature
== CM_KEY_FAST_LEAF
) ||
736 (IndexRoot
->Signature
== CM_KEY_HASH_LEAF
));
738 /* Check if this isn't a hashed leaf */
739 if (IndexRoot
->Signature
!= CM_KEY_HASH_LEAF
)
741 /* Find the subkey in the leaf */
742 Found
= CmpFindSubKeyInLeaf(Hive
,
747 /* Release the previous cell */
748 ASSERT(CellToRelease
!= HCELL_NIL
);
749 HvReleaseCell(Hive
, CellToRelease
);
751 /* Make sure we found a valid index */
752 if (Found
< 0) break;
756 /* Find the subkey in the hash */
757 SubKey
= CmpFindSubKeyByHash(Hive
,
758 (PCM_KEY_FAST_INDEX
)IndexRoot
,
761 /* Release the previous cell */
762 ASSERT(CellToRelease
!= HCELL_NIL
);
763 HvReleaseCell(Hive
, CellToRelease
);
766 /* Make sure we got a valid subkey and return it */
767 if (SubKey
!= HCELL_NIL
) return SubKey
;
771 /* If we got here, then we failed */
777 CmpMarkIndexDirty(IN PHHIVE Hive
,
778 IN HCELL_INDEX ParentKey
,
779 IN HCELL_INDEX TargetKey
)
782 UNICODE_STRING SearchName
;
783 BOOLEAN IsCompressed
;
786 HCELL_INDEX IndexCell
, Child
= HCELL_NIL
, CellToRelease
= HCELL_NIL
;
788 /* Get the target key node */
789 Node
= (PCM_KEY_NODE
)HvGetCell(Hive
, TargetKey
);
790 if (!Node
) return FALSE
;
792 /* Check if it's compressed */
793 if (Node
->Flags
& KEY_COMP_NAME
)
795 /* Remember this for later */
798 /* Build the search name */
799 SearchName
.Length
= CmpCompressedNameSize(Node
->Name
,
801 SearchName
.MaximumLength
= SearchName
.Length
;
802 SearchName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
805 if (!SearchName
.Buffer
)
808 HvReleaseCell(Hive
, TargetKey
);
813 CmpCopyCompressedName(SearchName
.Buffer
,
814 SearchName
.MaximumLength
,
820 /* Name isn't compressed, build it directly from the node */
821 IsCompressed
= FALSE
;
822 SearchName
.Length
= Node
->NameLength
;
823 SearchName
.MaximumLength
= Node
->NameLength
;
824 SearchName
.Buffer
= Node
->Name
;
827 /* We can release the target key now */
828 HvReleaseCell(Hive
, TargetKey
);
830 /* Now get the parent key node */
831 Node
= (PCM_KEY_NODE
)HvGetCell(Hive
, ParentKey
);
832 if (!Node
) goto Quickie
;
834 /* Loop all hive storage */
835 for (i
= 0; i
< Hive
->StorageTypeCount
; i
++)
837 /* Check if any subkeys are in this index */
838 if (Node
->SubKeyCounts
[i
])
840 /* Get the cell index */
841 //ASSERT(HvIsCellAllocated(Hive, Node->SubKeyLists[i]));
842 IndexCell
= Node
->SubKeyLists
[i
];
844 /* Check if we had anything to release from before */
845 if (CellToRelease
!= HCELL_NIL
)
848 HvReleaseCell(Hive
, CellToRelease
);
849 CellToRelease
= HCELL_NIL
;
852 /* Get the key index for the cell */
853 Index
= (PCM_KEY_INDEX
)HvGetCell(Hive
, IndexCell
);
854 if (!Index
) goto Quickie
;
856 /* Release it at the next iteration or below */
857 CellToRelease
= IndexCell
;
859 /* Check if this is a root */
860 if (Index
->Signature
== CM_KEY_INDEX_ROOT
)
862 /* Get the child inside the root */
863 Result
= CmpFindSubKeyInRoot(Hive
, Index
, &SearchName
, &Child
);
864 if (Result
& 0x80000000) goto Quickie
;
865 if (Child
== HCELL_NIL
) continue;
867 /* We found it, mark the cell dirty */
868 HvMarkCellDirty(Hive
, IndexCell
);
870 /* Check if we had anything to release from before */
871 if (CellToRelease
!= HCELL_NIL
)
874 HvReleaseCell(Hive
, CellToRelease
);
875 CellToRelease
= HCELL_NIL
;
878 /* Now this child is the index, get the actual key index */
880 Index
= (PCM_KEY_INDEX
)HvGetCell(Hive
, Child
);
881 if (!Index
) goto Quickie
;
883 /* Release it later */
884 CellToRelease
= Child
;
887 /* Make sure this is a valid index */
888 ASSERT((Index
->Signature
== CM_KEY_INDEX_LEAF
) ||
889 (Index
->Signature
== CM_KEY_FAST_LEAF
) ||
890 (Index
->Signature
== CM_KEY_HASH_LEAF
));
892 /* Find the child in the leaf */
893 Result
= CmpFindSubKeyInLeaf(Hive
, Index
, &SearchName
, &Child
);
894 if (Result
& 0x80000000) goto Quickie
;
895 if (Child
!= HCELL_NIL
)
897 /* We found it, free the name now */
898 if (IsCompressed
) ExFreePool(SearchName
.Buffer
);
900 /* Release the parent key */
901 HvReleaseCell(Hive
, ParentKey
);
903 /* Check if we had a left over cell to release */
904 if (CellToRelease
!= HCELL_NIL
)
907 HvReleaseCell(Hive
, CellToRelease
);
910 /* And mark the index cell dirty */
911 HvMarkCellDirty(Hive
, IndexCell
);
918 /* Release any cells that we still hold */
919 if (Node
) HvReleaseCell(Hive
, ParentKey
);
920 if (CellToRelease
!= HCELL_NIL
) HvReleaseCell(Hive
, CellToRelease
);
922 /* Free the search name and return failure */
923 if (IsCompressed
) ExFreePool(SearchName
.Buffer
);
929 CmpRemoveSubKey(IN PHHIVE Hive
,
930 IN HCELL_INDEX ParentKey
,
931 IN HCELL_INDEX TargetKey
)
934 UNICODE_STRING SearchName
;
935 BOOLEAN IsCompressed
;
937 HCELL_INDEX RootCell
= HCELL_NIL
, LeafCell
, ChildCell
;
938 PCM_KEY_INDEX Root
= NULL
, Leaf
;
939 PCM_KEY_FAST_INDEX Child
;
940 ULONG Storage
, RootIndex
= 0x80000000, LeafIndex
;
941 BOOLEAN Result
= FALSE
;
942 HCELL_INDEX CellToRelease1
= HCELL_NIL
, CellToRelease2
= HCELL_NIL
;
944 /* Get the target key node */
945 Node
= (PCM_KEY_NODE
)HvGetCell(Hive
, TargetKey
);
946 if (!Node
) return FALSE
;
948 /* Make sure it's dirty, then release it */
949 ASSERT(HvIsCellDirty(Hive
, TargetKey
));
950 HvReleaseCell(Hive
, TargetKey
);
952 /* Check if the name is compressed */
953 if (Node
->Flags
& KEY_COMP_NAME
)
955 /* Remember for later */
958 /* Build the search name */
959 SearchName
.Length
= CmpCompressedNameSize(Node
->Name
,
961 SearchName
.MaximumLength
= SearchName
.Length
;
963 /* Do we need an extra bufer? */
964 if (SearchName
.MaximumLength
> sizeof(Buffer
))
967 SearchName
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
970 if (!SearchName
.Buffer
) return FALSE
;
974 /* Otherwise, use our local stack buffer */
975 SearchName
.Buffer
= Buffer
;
978 /* Copy the compressed name */
979 CmpCopyCompressedName(SearchName
.Buffer
,
980 SearchName
.MaximumLength
,
986 /* It's not compressed, build the name directly from the node */
987 IsCompressed
= FALSE
;
988 SearchName
.Length
= Node
->NameLength
;
989 SearchName
.MaximumLength
= Node
->NameLength
;
990 SearchName
.Buffer
= Node
->Name
;
993 /* Now get the parent node */
994 Node
= (PCM_KEY_NODE
)HvGetCell(Hive
, ParentKey
);
995 if (!Node
) goto Exit
;
997 /* Make sure it's dirty, then release it */
998 ASSERT(HvIsCellDirty(Hive
, ParentKey
));
999 HvReleaseCell(Hive
, ParentKey
);
1001 /* Get the storage type and make sure it's not empty */
1002 Storage
= HvGetCellType(TargetKey
);
1003 ASSERT(Node
->SubKeyCounts
[Storage
] != 0);
1004 //ASSERT(HvIsCellAllocated(Hive, Node->SubKeyLists[Storage]));
1006 /* Get the leaf cell now */
1007 LeafCell
= Node
->SubKeyLists
[Storage
];
1008 Leaf
= (PCM_KEY_INDEX
)HvGetCell(Hive
, LeafCell
);
1009 if (!Leaf
) goto Exit
;
1011 /* Remember to release it later */
1012 CellToRelease1
= LeafCell
;
1014 /* Check if the leaf is a root */
1015 if (Leaf
->Signature
== CM_KEY_INDEX_ROOT
)
1017 /* Find the child inside the root */
1018 RootIndex
= CmpFindSubKeyInRoot(Hive
, Leaf
, &SearchName
, &ChildCell
);
1019 if (RootIndex
& 0x80000000) goto Exit
;
1020 ASSERT(ChildCell
!= FALSE
);
1022 /* The root cell is now this leaf */
1024 RootCell
= LeafCell
;
1026 /* And the new leaf is now this child */
1027 LeafCell
= ChildCell
;
1028 Leaf
= (PCM_KEY_INDEX
)HvGetCell(Hive
, LeafCell
);
1029 if (!Leaf
) goto Exit
;
1031 /* Remember to release it later */
1032 CellToRelease2
= LeafCell
;
1035 /* Make sure the leaf is valid */
1036 ASSERT((Leaf
->Signature
== CM_KEY_INDEX_LEAF
) ||
1037 (Leaf
->Signature
== CM_KEY_FAST_LEAF
) ||
1038 (Leaf
->Signature
== CM_KEY_HASH_LEAF
));
1040 /* Now get the child in the leaf */
1041 LeafIndex
= CmpFindSubKeyInLeaf(Hive
, Leaf
, &SearchName
, &ChildCell
);
1042 if (LeafIndex
& 0x80000000) goto Exit
;
1043 ASSERT(ChildCell
!= HCELL_NIL
);
1045 /* Decrement key counts and check if this was the last leaf entry */
1046 Node
->SubKeyCounts
[Storage
]--;
1047 if (!(--Leaf
->Count
))
1050 HvFreeCell(Hive
, LeafCell
);
1052 /* Check if we were inside a root */
1055 /* Decrease the root count too, since the leaf is going away */
1056 if (!(--Root
->Count
))
1058 /* The root is gone too,n ow */
1059 HvFreeCell(Hive
, RootCell
);
1060 Node
->SubKeyLists
[Storage
] = HCELL_NIL
;
1062 else if (RootIndex
< Root
->Count
)
1064 /* Bring everything up by one */
1065 RtlMoveMemory(&Root
->List
[RootIndex
],
1066 &Root
->List
[RootIndex
+ 1],
1067 (Root
->Count
- RootIndex
) * sizeof(HCELL_INDEX
));
1072 /* Otherwise, just clear the cell */
1073 Node
->SubKeyLists
[Storage
] = HCELL_NIL
;
1076 else if (LeafIndex
< Leaf
->Count
)
1078 /* Was the leaf a normal index? */
1079 if (Leaf
->Signature
== CM_KEY_INDEX_LEAF
)
1081 /* Bring everything up by one */
1082 RtlMoveMemory(&Leaf
->List
[LeafIndex
],
1083 &Leaf
->List
[LeafIndex
+ 1],
1084 (Leaf
->Count
- LeafIndex
) * sizeof(HCELL_INDEX
));
1088 /* This is a fast index, bring everything up by one */
1089 Child
= (PCM_KEY_FAST_INDEX
)Leaf
;
1090 RtlMoveMemory(&Child
->List
[LeafIndex
],
1091 &Child
->List
[LeafIndex
+1],
1092 (Child
->Count
- LeafIndex
) * sizeof(CM_INDEX
));
1096 /* If we got here, now we're done */
1100 /* Release any cells we may have been holding */
1101 if (CellToRelease1
!= HCELL_NIL
) HvReleaseCell(Hive
, CellToRelease1
);
1102 if (CellToRelease2
!= HCELL_NIL
) HvReleaseCell(Hive
, CellToRelease2
);
1104 /* Check if the name was compressed and not inside our local buffer */
1105 if ((IsCompressed
) && (SearchName
.MaximumLength
> sizeof(Buffer
)))
1107 /* Free the buffer we allocated */
1108 ExFreePool(SearchName
.Buffer
);
1111 /* Return the result */