Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygencmindex.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: ntoskrnl/config/cmindex.c 00005 * PURPOSE: Configuration Manager - Cell Indexes 00006 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 00007 */ 00008 00009 /* INCLUDES ******************************************************************/ 00010 00011 #include "ntoskrnl.h" 00012 #define NDEBUG 00013 #include "debug.h" 00014 00015 /* GLOBALS *******************************************************************/ 00016 00017 ULONG CmpMaxFastIndexPerHblock = 00018 (HBLOCK_SIZE - (sizeof(HBIN) + 00019 sizeof(HCELL) + 00020 FIELD_OFFSET(CM_KEY_FAST_INDEX, List))) / sizeof(CM_INDEX); 00021 00022 ULONG CmpMaxIndexPerHblock = 00023 (HBLOCK_SIZE - (sizeof(HBIN) + 00024 sizeof(HCELL) + 00025 FIELD_OFFSET(CM_KEY_INDEX, List))) / sizeof(HCELL_INDEX) - 1; 00026 00027 /* FUNCTIONS *****************************************************************/ 00028 00029 LONG 00030 NTAPI 00031 CmpDoCompareKeyName(IN PHHIVE Hive, 00032 IN PCUNICODE_STRING SearchName, 00033 IN HCELL_INDEX Cell) 00034 { 00035 PCM_KEY_NODE Node; 00036 UNICODE_STRING KeyName; 00037 LONG Result; 00038 00039 /* Get the node */ 00040 Node = (PCM_KEY_NODE)HvGetCell(Hive, Cell); 00041 if (!Node) return 2; 00042 00043 /* Check if it's compressed */ 00044 if (Node->Flags & KEY_COMP_NAME) 00045 { 00046 /* Compare compressed names */ 00047 Result = CmpCompareCompressedName(SearchName, 00048 Node->Name, 00049 Node->NameLength); 00050 } 00051 else 00052 { 00053 /* Compare the Unicode name directly */ 00054 KeyName.Buffer = Node->Name; 00055 KeyName.Length = Node->NameLength; 00056 KeyName.MaximumLength = KeyName.Length; 00057 Result = RtlCompareUnicodeString(SearchName, &KeyName, TRUE); 00058 } 00059 00060 /* Release the cell and return the normalized result */ 00061 HvReleaseCell(Hive, Cell); 00062 return (Result == 0) ? Result : ((Result > 0) ? 1 : -1); 00063 } 00064 00065 LONG 00066 NTAPI 00067 CmpCompareInIndex(IN PHHIVE Hive, 00068 IN PCUNICODE_STRING SearchName, 00069 IN ULONG Count, 00070 IN PCM_KEY_INDEX Index, 00071 IN PHCELL_INDEX SubKey) 00072 { 00073 PCM_KEY_FAST_INDEX FastIndex; 00074 PCM_INDEX FastEntry; 00075 LONG Result; 00076 ULONG i; 00077 ULONG ActualNameLength = 4, CompareLength, NameLength; 00078 WCHAR p, pp; 00079 00080 /* Assume failure */ 00081 *SubKey = HCELL_NIL; 00082 00083 /* Check if we are a fast or hashed leaf */ 00084 if ((Index->Signature == CM_KEY_FAST_LEAF) || 00085 (Index->Signature == CM_KEY_HASH_LEAF)) 00086 { 00087 /* Get the Fast/Hash Index */ 00088 FastIndex = (PCM_KEY_FAST_INDEX)Index; 00089 FastEntry = &FastIndex->List[Count]; 00090 00091 /* Check if we are a hash leaf, in which case we skip all this */ 00092 if (Index->Signature == CM_KEY_FAST_LEAF) 00093 { 00094 /* Find out just how much of the name is there */ 00095 for (i = 0; i < 4; i++) 00096 { 00097 /* Check if this entry is empty */ 00098 if (!FastEntry->NameHint[i]) 00099 { 00100 /* Only this much! */ 00101 ActualNameLength = i; 00102 break; 00103 } 00104 } 00105 00106 /* How large is the name and how many characters to compare */ 00107 NameLength = SearchName->Length / sizeof(WCHAR); 00108 CompareLength = min(NameLength, ActualNameLength); 00109 00110 /* Loop all the chars we'll test */ 00111 for (i = 0; i < CompareLength; i++) 00112 { 00113 /* Get one char from each buffer */ 00114 p = SearchName->Buffer[i]; 00115 pp = FastEntry->NameHint[i]; 00116 00117 /* See if they match and return result if they don't */ 00118 Result = (LONG)RtlUpcaseUnicodeChar(p) - 00119 (LONG)RtlUpcaseUnicodeChar(pp); 00120 if (Result) return (Result > 0) ? 1 : -1; 00121 } 00122 } 00123 00124 /* If we got here then we have to do a full compare */ 00125 Result = CmpDoCompareKeyName(Hive, SearchName, FastEntry->Cell); 00126 if (Result == 2) return Result; 00127 if (!Result) *SubKey = FastEntry->Cell; 00128 } 00129 else 00130 { 00131 /* We aren't, so do a name compare and return the subkey found */ 00132 Result = CmpDoCompareKeyName(Hive, SearchName, Index->List[Count]); 00133 if (Result == 2) return Result; 00134 if (!Result) *SubKey = Index->List[Count]; 00135 } 00136 00137 /* Return the comparison result */ 00138 return Result; 00139 } 00140 00141 ULONG 00142 NTAPI 00143 CmpFindSubKeyInRoot(IN PHHIVE Hive, 00144 IN PCM_KEY_INDEX Index, 00145 IN PCUNICODE_STRING SearchName, 00146 IN PHCELL_INDEX SubKey) 00147 { 00148 ULONG High, Low = 0, i = 0, ReturnIndex; 00149 HCELL_INDEX LeafCell; 00150 PCM_KEY_INDEX Leaf; 00151 LONG Result; 00152 00153 /* Verify Index for validity */ 00154 ASSERT(Index->Count != 0); 00155 ASSERT(Index->Signature == CM_KEY_INDEX_ROOT); 00156 00157 /* Set high limit and loop */ 00158 High = Index->Count - 1; 00159 while (TRUE) 00160 { 00161 /* Choose next entry */ 00162 #ifdef SOMEONE_WAS_NICE_ENOUGH_TO_MAKE_OUR_CELLS_LEXICALLY_SORTED 00163 i = ((High - Low) / 2) + Low; 00164 #endif 00165 00166 /* Get the leaf cell and then the leaf itself */ 00167 LeafCell = Index->List[i]; 00168 Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell); 00169 if (Leaf) 00170 { 00171 /* Make sure the leaf is valid */ 00172 ASSERT((Leaf->Signature == CM_KEY_INDEX_LEAF) || 00173 (Leaf->Signature == CM_KEY_FAST_LEAF) || 00174 (Leaf->Signature == CM_KEY_HASH_LEAF)); 00175 ASSERT(Leaf->Count != 0); 00176 00177 /* Do the compare */ 00178 Result = CmpCompareInIndex(Hive, 00179 SearchName, 00180 Leaf->Count - 1, 00181 Leaf, 00182 SubKey); 00183 if (Result == 2) goto Big; 00184 00185 /* Check if we found the leaf */ 00186 if (!Result) 00187 { 00188 /* We found the leaf */ 00189 *SubKey = LeafCell; 00190 ReturnIndex = i; 00191 goto Return; 00192 } 00193 00194 #ifdef SOMEONE_WAS_NICE_ENOUGH_TO_MAKE_OUR_CELLS_LEXICALLY_SORTED 00195 /* Check for negative result */ 00196 if (Result < 0) 00197 { 00198 /* If we got here, we should be at -1 */ 00199 ASSERT(Result == -1); 00200 00201 /* Do another lookup, since we might still be in the right leaf */ 00202 Result = CmpCompareInIndex(Hive, 00203 SearchName, 00204 0, 00205 Leaf, 00206 SubKey); 00207 if (Result == 2) goto Big; 00208 00209 /* Check if it's not below */ 00210 if (Result >= 0) 00211 { 00212 /* 00213 * If the name was first below, and now it is above, 00214 * then this means that it is somewhere in this leaf. 00215 * Make sure we didn't get some weird result 00216 */ 00217 ASSERT((Result == 1) || (Result == 0)); 00218 00219 /* Return it */ 00220 *SubKey = LeafCell; 00221 ReturnIndex = Low; 00222 goto Return; 00223 } 00224 00225 /* Update the limit to this index, since we know it's not higher. */ 00226 High = i; 00227 } 00228 else 00229 { 00230 /* Update the base to this index, since we know it's not lower. */ 00231 Low = i; 00232 } 00233 #endif 00234 } 00235 else 00236 { 00237 Big: 00238 /* This was some sort of special key */ 00239 ReturnIndex = 0x80000000; 00240 goto ReturnFailure; 00241 } 00242 00243 /* Check if there is only one entry left */ 00244 if ((High - Low) <= 1) break; 00245 00246 /* Release the leaf cell */ 00247 HvReleaseCell(Hive, LeafCell); 00248 00249 #ifndef SOMEONE_WAS_NICE_ENOUGH_TO_MAKE_OUR_CELLS_LEXICALLY_SORTED 00250 /* Go to the next index, and return failure if we reach the end */ 00251 if (++i > High) 00252 { 00253 /* Return failure */ 00254 *SubKey = HCELL_NIL; 00255 return 0; 00256 } 00257 #endif 00258 } 00259 00260 /* Make sure we got here for the right reasons */ 00261 ASSERT((High - Low == 1) || (High == Low)); 00262 00263 /* Get the leaf cell and the leaf */ 00264 LeafCell = Index->List[Low]; 00265 Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell); 00266 if (!Leaf) goto Big; 00267 00268 /* Do the compare */ 00269 Result = CmpCompareInIndex(Hive, 00270 SearchName, 00271 Leaf->Count-1, 00272 Leaf, 00273 SubKey); 00274 if (Result == 2) goto Big; 00275 00276 /* Check if we found it */ 00277 if (!Result) 00278 { 00279 /* We got lucky...return it */ 00280 *SubKey = LeafCell; 00281 ReturnIndex = Low; 00282 goto Return; 00283 } 00284 00285 /* It's below, so could still be in this leaf */ 00286 if (Result < 0) 00287 { 00288 /* Make sure we're -1 */ 00289 ASSERT(Result == -1); 00290 00291 /* Do a search from the bottom */ 00292 Result = CmpCompareInIndex(Hive, SearchName, 0, Leaf, SubKey); 00293 if (Result == 2) goto Big; 00294 00295 /* 00296 * Check if it's above, which means that it's within the ranges of our 00297 * leaf (since we were below before). 00298 */ 00299 if (Result >= 0) 00300 { 00301 /* Sanity check */ 00302 ASSERT((Result == 1) || (Result == 0)); 00303 00304 /* Yep, so we're in the right leaf; return it. */ 00305 *SubKey = LeafCell; 00306 ReturnIndex = Low; 00307 goto Return; 00308 } 00309 00310 /* It's still below us, so fail */ 00311 ReturnIndex = Low; 00312 goto ReturnFailure; 00313 } 00314 00315 /* Release the leaf cell */ 00316 HvReleaseCell(Hive, LeafCell); 00317 00318 /* Well the low didn't work too well, so try the high. */ 00319 LeafCell = Index->List[High]; 00320 Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell); 00321 if (!Leaf) goto Big; 00322 00323 /* Do the compare */ 00324 Result = CmpCompareInIndex(Hive, 00325 SearchName, 00326 Leaf->Count - 1, 00327 Leaf, 00328 SubKey); 00329 if (Result == 2) goto Big; 00330 00331 /* Check if we found it */ 00332 if (Result == 0) 00333 { 00334 /* We got lucky... return it */ 00335 *SubKey = LeafCell; 00336 ReturnIndex = High; 00337 goto Return; 00338 } 00339 00340 /* Check if we are too high */ 00341 if (Result < 0) 00342 { 00343 /* Make sure we're -1 */ 00344 ASSERT(Result == -1); 00345 00346 /* 00347 * Once again... since we were first too low and now too high, then 00348 * this means we are within the range of this leaf... return it. 00349 */ 00350 *SubKey = LeafCell; 00351 ReturnIndex = High; 00352 goto Return; 00353 } 00354 00355 /* If we got here, then we are too low, again. */ 00356 ReturnIndex = High; 00357 00358 /* Failure path */ 00359 ReturnFailure: 00360 *SubKey = HCELL_NIL; 00361 00362 /* Return path...check if we have a leaf to free */ 00363 Return: 00364 if (Leaf) HvReleaseCell(Hive, LeafCell); 00365 00366 /* Return the index */ 00367 return ReturnIndex; 00368 } 00369 00370 ULONG 00371 NTAPI 00372 CmpFindSubKeyInLeaf(IN PHHIVE Hive, 00373 IN PCM_KEY_INDEX Index, 00374 IN PCUNICODE_STRING SearchName, 00375 IN PHCELL_INDEX SubKey) 00376 { 00377 ULONG High, Low = 0, i; 00378 LONG Result; 00379 00380 /* Verify Index for validity */ 00381 ASSERT((Index->Signature == CM_KEY_INDEX_LEAF) || 00382 (Index->Signature == CM_KEY_FAST_LEAF) || 00383 (Index->Signature == CM_KEY_HASH_LEAF)); 00384 00385 /* Get the upper bound and middle entry */ 00386 High = Index->Count - 1; 00387 #ifdef SOMEONE_WAS_NICE_ENOUGH_TO_MAKE_OUR_CELLS_LEXICALLY_SORTED 00388 i = High / 2; 00389 #else 00390 i = 0; 00391 #endif 00392 00393 /* Check if we don't actually have any entries */ 00394 if (!Index->Count) 00395 { 00396 /* Return failure */ 00397 *SubKey = HCELL_NIL; 00398 return 0; 00399 } 00400 00401 /* Start compare loop */ 00402 while (TRUE) 00403 { 00404 /* Do the actual comparison and check the result */ 00405 Result = CmpCompareInIndex(Hive, SearchName, i, Index, SubKey); 00406 if (Result == 2) 00407 { 00408 /* Fail with special value */ 00409 *SubKey = HCELL_NIL; 00410 return 0x80000000; 00411 } 00412 00413 /* Check if we got lucky and found it */ 00414 if (!Result) return i; 00415 00416 #ifdef SOMEONE_WAS_NICE_ENOUGH_TO_MAKE_OUR_CELLS_LEXICALLY_SORTED 00417 /* Check if the result is below us */ 00418 if (Result < 0) 00419 { 00420 /* Set the new bound; it can't be higher then where we are now. */ 00421 ASSERT(Result == -1); 00422 High = i; 00423 } 00424 else 00425 { 00426 /* Set the new bound... it can't be lower then where we are now. */ 00427 ASSERT(Result == 1); 00428 Low = i; 00429 } 00430 00431 /* Check if this is the last entry, if so, break out and handle it */ 00432 if ((High - Low) <= 1) break; 00433 00434 /* Set the new index */ 00435 i = ((High - Low) / 2) + Low; 00436 #else 00437 if (++i > High) 00438 { 00439 /* Return failure */ 00440 *SubKey = HCELL_NIL; 00441 return 0; 00442 } 00443 #endif 00444 } 00445 00446 /* 00447 * If we get here, High - Low = 1 or High == Low 00448 * Simply look first at Low, then at High 00449 */ 00450 Result = CmpCompareInIndex(Hive, SearchName, Low, Index, SubKey); 00451 if (Result == 2) 00452 { 00453 /* Fail with special value */ 00454 *SubKey = HCELL_NIL; 00455 return 0x80000000; 00456 } 00457 00458 /* Check if we got lucky and found it */ 00459 if (!Result) return Low; 00460 00461 /* Check if the result is below us */ 00462 if (Result < 0) 00463 { 00464 /* Return the low entry */ 00465 ASSERT(Result == -1); 00466 return Low; 00467 } 00468 00469 /* 00470 * If we got here, then just check the high and return it no matter what 00471 * the result is (since we're a leaf, it has to be near there anyway). 00472 */ 00473 Result = CmpCompareInIndex(Hive, SearchName, High, Index, SubKey); 00474 if (Result == 2) 00475 { 00476 /* Fail with special value */ 00477 *SubKey = HCELL_NIL; 00478 return 0x80000000; 00479 } 00480 00481 /* Return the high */ 00482 return High; 00483 } 00484 00485 ULONG 00486 NTAPI 00487 CmpComputeHashKey(IN ULONG Hash, 00488 IN PCUNICODE_STRING Name, 00489 IN BOOLEAN AllowSeparators) 00490 { 00491 LPWSTR Cp; 00492 ULONG Value, i; 00493 00494 /* Make some sanity checks on our parameters */ 00495 ASSERT((Name->Length == 0) || 00496 (AllowSeparators) || 00497 (Name->Buffer[0] != OBJ_NAME_PATH_SEPARATOR)); 00498 00499 /* If the name is empty, there is nothing to hash! */ 00500 if (!Name->Length) return Hash; 00501 00502 /* Set the buffer and loop every character */ 00503 Cp = Name->Buffer; 00504 for (i = 0; i < Name->Length; i += sizeof(WCHAR), Cp++) 00505 { 00506 /* Make sure we don't have a separator when we shouldn't */ 00507 ASSERT(AllowSeparators || (*Cp != OBJ_NAME_PATH_SEPARATOR)); 00508 00509 /* Check what kind of char we have */ 00510 if (*Cp >= L'a') 00511 { 00512 /* In the lower case region... is it truly lower case? */ 00513 if (*Cp < L'z') 00514 { 00515 /* Yes! Calculate it ourselves! */ 00516 Value = *Cp - L'a' + L'A'; 00517 } 00518 else 00519 { 00520 /* No, use the API */ 00521 Value = RtlUpcaseUnicodeChar(*Cp); 00522 } 00523 } 00524 else 00525 { 00526 /* Reuse the char, it's already upcased */ 00527 Value = *Cp; 00528 } 00529 00530 /* Multiply by a prime and add our value */ 00531 Hash *= 37; 00532 Hash += Value; 00533 } 00534 00535 /* Return the hash */ 00536 return Hash; 00537 } 00538 00539 HCELL_INDEX 00540 NTAPI 00541 CmpDoFindSubKeyByNumber(IN PHHIVE Hive, 00542 IN PCM_KEY_INDEX Index, 00543 IN ULONG Number) 00544 { 00545 ULONG i; 00546 HCELL_INDEX LeafCell = 0; 00547 PCM_KEY_INDEX Leaf = NULL; 00548 PCM_KEY_FAST_INDEX FastIndex; 00549 HCELL_INDEX Result; 00550 00551 /* Check if this is a root */ 00552 if (Index->Signature == CM_KEY_INDEX_ROOT) 00553 { 00554 /* Loop the index */ 00555 for (i = 0; i < Index->Count; i++) 00556 { 00557 /* Check if this isn't the first iteration */ 00558 if (i) 00559 { 00560 /* Make sure we had something valid, and release it */ 00561 ASSERT(Leaf != NULL ); 00562 ASSERT(LeafCell == Index->List[i - 1]); 00563 HvReleaseCell(Hive, LeafCell); 00564 } 00565 00566 /* Get the leaf cell and the leaf for this index */ 00567 LeafCell = Index->List[i]; 00568 Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell); 00569 if (!Leaf) return HCELL_NIL; 00570 00571 /* Check if the index may be inside it */ 00572 if (Number < Leaf->Count) 00573 { 00574 /* Check if this is a fast or hash leaf */ 00575 if ((Leaf->Signature == CM_KEY_FAST_LEAF) || 00576 (Leaf->Signature == CM_KEY_HASH_LEAF)) 00577 { 00578 /* Get the fast index */ 00579 FastIndex = (PCM_KEY_FAST_INDEX)Leaf; 00580 00581 /* Look inside the list to get our actual cell */ 00582 Result = FastIndex->List[Number].Cell; 00583 HvReleaseCell(Hive, LeafCell); 00584 return Result; 00585 } 00586 else 00587 { 00588 /* Regular leaf, so just use the index directly */ 00589 Result = Leaf->List[Number]; 00590 00591 /* Release and return it */ 00592 HvReleaseCell(Hive,LeafCell); 00593 return Result; 00594 } 00595 } 00596 else 00597 { 00598 /* Otherwise, skip this leaf */ 00599 Number = Number - Leaf->Count; 00600 } 00601 } 00602 00603 /* Should never get here */ 00604 ASSERT(FALSE); 00605 } 00606 00607 /* If we got here, then the cell is in this index */ 00608 ASSERT(Number < Index->Count); 00609 00610 /* Check if we're a fast or hash leaf */ 00611 if ((Index->Signature == CM_KEY_FAST_LEAF) || 00612 (Index->Signature == CM_KEY_HASH_LEAF)) 00613 { 00614 /* We are, get the fast index and get the cell from the list */ 00615 FastIndex = (PCM_KEY_FAST_INDEX)Index; 00616 return FastIndex->List[Number].Cell; 00617 } 00618 else 00619 { 00620 /* We aren't, so use the index directly to grab the cell */ 00621 return Index->List[Number]; 00622 } 00623 } 00624 00625 HCELL_INDEX 00626 NTAPI 00627 CmpFindSubKeyByNumber(IN PHHIVE Hive, 00628 IN PCM_KEY_NODE Node, 00629 IN ULONG Number) 00630 { 00631 PCM_KEY_INDEX Index; 00632 HCELL_INDEX Result = HCELL_NIL; 00633 00634 /* Check if it's in the stable list */ 00635 if (Number < Node->SubKeyCounts[Stable]) 00636 { 00637 /* Get the actual key index */ 00638 Index = (PCM_KEY_INDEX)HvGetCell(Hive, Node->SubKeyLists[Stable]); 00639 if (!Index) return HCELL_NIL; 00640 00641 /* Do a search inside it */ 00642 Result = CmpDoFindSubKeyByNumber(Hive, Index, Number); 00643 00644 /* Release the cell and return the result */ 00645 HvReleaseCell(Hive, Node->SubKeyLists[Stable]); 00646 return Result; 00647 } 00648 else if (Hive->StorageTypeCount > Volatile) 00649 { 00650 /* It's in the volatile list */ 00651 Number = Number - Node->SubKeyCounts[Stable]; 00652 if (Number < Node->SubKeyCounts[Volatile]) 00653 { 00654 /* Get the actual key index */ 00655 Index = (PCM_KEY_INDEX)HvGetCell(Hive, 00656 Node->SubKeyLists[Volatile]); 00657 if (!Index) return HCELL_NIL; 00658 00659 /* Do a search inside it */ 00660 Result = CmpDoFindSubKeyByNumber(Hive, Index, Number); 00661 00662 /* Release the cell and return the result */ 00663 HvReleaseCell(Hive, Node->SubKeyLists[Volatile]); 00664 return Result; 00665 } 00666 } 00667 00668 /* Nothing was found */ 00669 return HCELL_NIL; 00670 } 00671 00672 static HCELL_INDEX 00673 NTAPI 00674 CmpFindSubKeyByHash(IN PHHIVE Hive, 00675 IN PCM_KEY_FAST_INDEX FastIndex, 00676 IN PCUNICODE_STRING SearchName) 00677 { 00678 ULONG HashKey, i; 00679 PCM_INDEX FastEntry; 00680 00681 /* Make sure it's really a hash */ 00682 ASSERT(FastIndex->Signature == CM_KEY_HASH_LEAF); 00683 00684 /* Compute the hash key for the name */ 00685 HashKey = CmpComputeHashKey(0, SearchName, FALSE); 00686 00687 /* Loop all the entries */ 00688 for (i = 0; i < FastIndex->Count; i++) 00689 { 00690 /* Get the entry */ 00691 FastEntry = &FastIndex->List[i]; 00692 00693 /* Compare the hash first */ 00694 if (FastEntry->HashKey == HashKey) 00695 { 00696 /* Go ahead for a full compare */ 00697 if (!(CmpDoCompareKeyName(Hive, SearchName, FastEntry->Cell))) 00698 { 00699 /* It matched, return the cell */ 00700 return FastEntry->Cell; 00701 } 00702 } 00703 } 00704 00705 /* If we got here then we failed */ 00706 return HCELL_NIL; 00707 } 00708 00709 HCELL_INDEX 00710 NTAPI 00711 CmpFindSubKeyByName(IN PHHIVE Hive, 00712 IN PCM_KEY_NODE Parent, 00713 IN PCUNICODE_STRING SearchName) 00714 { 00715 ULONG i; 00716 PCM_KEY_INDEX IndexRoot; 00717 HCELL_INDEX SubKey, CellToRelease; 00718 ULONG Found; 00719 00720 /* Loop each storage type */ 00721 for (i = 0; i < Hive->StorageTypeCount; i++) 00722 { 00723 /* Make sure the parent node has subkeys */ 00724 if (Parent->SubKeyCounts[i]) 00725 { 00726 /* Get the Index */ 00727 IndexRoot = (PCM_KEY_INDEX)HvGetCell(Hive, Parent->SubKeyLists[i]); 00728 if (!IndexRoot) return HCELL_NIL; 00729 00730 /* Get the cell we'll need to release */ 00731 CellToRelease = Parent->SubKeyLists[i]; 00732 00733 /* Check if this is another index root */ 00734 if (IndexRoot->Signature == CM_KEY_INDEX_ROOT) 00735 { 00736 00737 #ifndef SOMEONE_WAS_NICE_ENOUGH_TO_MAKE_OUR_CELLS_LEXICALLY_SORTED 00738 /* CmpFindSubKeyInRoot is useless for actually finding the correct leaf when keys are not sorted */ 00739 LONG ii; 00740 PCM_KEY_INDEX Leaf; 00741 /* Loop through each leaf in the index root */ 00742 for (ii=0; ii<IndexRoot->Count; ii++) 00743 { 00744 Leaf = HvGetCell(Hive, IndexRoot->List[ii]); 00745 if (Leaf) 00746 { 00747 Found = CmpFindSubKeyInLeaf(Hive, Leaf, SearchName, &SubKey); 00748 HvReleaseCell(Hive, IndexRoot->List[ii]); 00749 if (Found & 0x80000000) 00750 { 00751 HvReleaseCell(Hive, CellToRelease); 00752 return HCELL_NIL; 00753 } 00754 00755 if (SubKey != HCELL_NIL) 00756 { 00757 HvReleaseCell(Hive, CellToRelease); 00758 return SubKey; 00759 } 00760 } 00761 } 00762 #endif 00763 /* Lookup the name in the root */ 00764 Found = CmpFindSubKeyInRoot(Hive, 00765 IndexRoot, 00766 SearchName, 00767 &SubKey); 00768 00769 /* Release the previous cell */ 00770 ASSERT(CellToRelease != HCELL_NIL); 00771 HvReleaseCell(Hive, CellToRelease); 00772 00773 /* Make sure we found something valid */ 00774 if (Found & 0x80000000) break; 00775 00776 /* Get the new Index Root and set the new cell to be released */ 00777 if (SubKey == HCELL_NIL) continue; 00778 CellToRelease = SubKey; 00779 IndexRoot = (PCM_KEY_INDEX)HvGetCell(Hive, SubKey); 00780 } 00781 00782 /* Make sure the signature is what we expect it to be */ 00783 ASSERT((IndexRoot->Signature == CM_KEY_INDEX_LEAF) || 00784 (IndexRoot->Signature == CM_KEY_FAST_LEAF) || 00785 (IndexRoot->Signature == CM_KEY_HASH_LEAF)); 00786 00787 /* Check if this isn't a hashed leaf */ 00788 if (IndexRoot->Signature != CM_KEY_HASH_LEAF) 00789 { 00790 /* Find the subkey in the leaf */ 00791 Found = CmpFindSubKeyInLeaf(Hive, 00792 IndexRoot, 00793 SearchName, 00794 &SubKey); 00795 00796 /* Release the previous cell */ 00797 ASSERT(CellToRelease != HCELL_NIL); 00798 HvReleaseCell(Hive, CellToRelease); 00799 00800 /* Make sure we found a valid index */ 00801 if (Found & 0x80000000) break; 00802 } 00803 else 00804 { 00805 /* Find the subkey in the hash */ 00806 SubKey = CmpFindSubKeyByHash(Hive, 00807 (PCM_KEY_FAST_INDEX)IndexRoot, 00808 SearchName); 00809 00810 /* Release the previous cell */ 00811 ASSERT(CellToRelease != HCELL_NIL); 00812 HvReleaseCell(Hive, CellToRelease); 00813 } 00814 00815 /* Make sure we got a valid subkey and return it */ 00816 if (SubKey != HCELL_NIL) return SubKey; 00817 } 00818 } 00819 00820 /* If we got here, then we failed */ 00821 return HCELL_NIL; 00822 } 00823 00824 BOOLEAN 00825 NTAPI 00826 CmpMarkIndexDirty(IN PHHIVE Hive, 00827 IN HCELL_INDEX ParentKey, 00828 IN HCELL_INDEX TargetKey) 00829 { 00830 PCM_KEY_NODE Node; 00831 UNICODE_STRING SearchName; 00832 BOOLEAN IsCompressed; 00833 ULONG i, Result; 00834 PCM_KEY_INDEX Index; 00835 HCELL_INDEX IndexCell, Child = HCELL_NIL, CellToRelease = HCELL_NIL; 00836 00837 /* Get the target key node */ 00838 Node = (PCM_KEY_NODE)HvGetCell(Hive, TargetKey); 00839 if (!Node) return FALSE; 00840 00841 /* Check if it's compressed */ 00842 if (Node->Flags & KEY_COMP_NAME) 00843 { 00844 /* Remember this for later */ 00845 IsCompressed = TRUE; 00846 00847 /* Build the search name */ 00848 SearchName.Length = CmpCompressedNameSize(Node->Name, 00849 Node->NameLength); 00850 SearchName.MaximumLength = SearchName.Length; 00851 SearchName.Buffer = CmpAllocate(SearchName.Length, 00852 TRUE, 00853 TAG_CM); 00854 if (!SearchName.Buffer) 00855 { 00856 /* Fail */ 00857 HvReleaseCell(Hive, TargetKey); 00858 return FALSE; 00859 } 00860 00861 /* Copy it */ 00862 CmpCopyCompressedName(SearchName.Buffer, 00863 SearchName.MaximumLength, 00864 Node->Name, 00865 Node->NameLength); 00866 } 00867 else 00868 { 00869 /* Name isn't compressed, build it directly from the node */ 00870 IsCompressed = FALSE; 00871 SearchName.Length = Node->NameLength; 00872 SearchName.MaximumLength = Node->NameLength; 00873 SearchName.Buffer = Node->Name; 00874 } 00875 00876 /* We can release the target key now */ 00877 HvReleaseCell(Hive, TargetKey); 00878 00879 /* Now get the parent key node */ 00880 Node = (PCM_KEY_NODE)HvGetCell(Hive, ParentKey); 00881 if (!Node) goto Quickie; 00882 00883 /* Loop all hive storage */ 00884 for (i = 0; i < Hive->StorageTypeCount; i++) 00885 { 00886 /* Check if any subkeys are in this index */ 00887 if (Node->SubKeyCounts[i]) 00888 { 00889 /* Get the cell index */ 00890 //ASSERT(HvIsCellAllocated(Hive, Node->SubKeyLists[i])); 00891 IndexCell = Node->SubKeyLists[i]; 00892 00893 /* Check if we had anything to release from before */ 00894 if (CellToRelease != HCELL_NIL) 00895 { 00896 /* Release it now */ 00897 HvReleaseCell(Hive, CellToRelease); 00898 CellToRelease = HCELL_NIL; 00899 } 00900 00901 /* Get the key index for the cell */ 00902 Index = (PCM_KEY_INDEX)HvGetCell(Hive, IndexCell); 00903 if (!Index) goto Quickie; 00904 00905 /* Release it at the next iteration or below */ 00906 CellToRelease = IndexCell; 00907 00908 /* Check if this is a root */ 00909 if (Index->Signature == CM_KEY_INDEX_ROOT) 00910 { 00911 /* Get the child inside the root */ 00912 Result = CmpFindSubKeyInRoot(Hive, Index, &SearchName, &Child); 00913 if (Result & 0x80000000) goto Quickie; 00914 if (Child == HCELL_NIL) continue; 00915 00916 /* We found it, mark the cell dirty */ 00917 HvMarkCellDirty(Hive, IndexCell, FALSE); 00918 00919 /* Check if we had anything to release from before */ 00920 if (CellToRelease != HCELL_NIL) 00921 { 00922 /* Release it now */ 00923 HvReleaseCell(Hive, CellToRelease); 00924 CellToRelease = HCELL_NIL; 00925 } 00926 00927 /* Now this child is the index, get the actual key index */ 00928 IndexCell = Child; 00929 Index = (PCM_KEY_INDEX)HvGetCell(Hive, Child); 00930 if (!Index) goto Quickie; 00931 00932 /* Release it later */ 00933 CellToRelease = Child; 00934 } 00935 00936 /* Make sure this is a valid index */ 00937 ASSERT((Index->Signature == CM_KEY_INDEX_LEAF) || 00938 (Index->Signature == CM_KEY_FAST_LEAF) || 00939 (Index->Signature == CM_KEY_HASH_LEAF)); 00940 00941 /* Find the child in the leaf */ 00942 Result = CmpFindSubKeyInLeaf(Hive, Index, &SearchName, &Child); 00943 if (Result & 0x80000000) goto Quickie; 00944 if (Child != HCELL_NIL) 00945 { 00946 /* We found it, free the name now */ 00947 if (IsCompressed) CmpFree(SearchName.Buffer, 0); 00948 00949 /* Release the parent key */ 00950 HvReleaseCell(Hive, ParentKey); 00951 00952 /* Check if we had a left over cell to release */ 00953 if (CellToRelease != HCELL_NIL) 00954 { 00955 /* Release it */ 00956 HvReleaseCell(Hive, CellToRelease); 00957 } 00958 00959 /* And mark the index cell dirty */ 00960 HvMarkCellDirty(Hive, IndexCell, FALSE); 00961 return TRUE; 00962 } 00963 } 00964 } 00965 00966 Quickie: 00967 /* Release any cells that we still hold */ 00968 if (Node) HvReleaseCell(Hive, ParentKey); 00969 if (CellToRelease != HCELL_NIL) HvReleaseCell(Hive, CellToRelease); 00970 00971 /* Free the search name and return failure */ 00972 if (IsCompressed) CmpFree(SearchName.Buffer, 0); 00973 return FALSE; 00974 } 00975 00976 HCELL_INDEX 00977 NTAPI 00978 CmpAddToLeaf(IN PHHIVE Hive, 00979 IN HCELL_INDEX LeafCell, 00980 IN HCELL_INDEX NewKey, 00981 IN PUNICODE_STRING Name) 00982 { 00983 PCM_KEY_INDEX Leaf; 00984 PCM_KEY_FAST_INDEX FastLeaf; 00985 ULONG Size, OldSize, EntrySize, i, j; 00986 HCELL_INDEX NewCell, Child; 00987 LONG Result; 00988 00989 /* Mark the leaf dirty */ 00990 HvMarkCellDirty(Hive, LeafCell, FALSE); 00991 00992 /* Get the leaf cell */ 00993 Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell); 00994 if (!Leaf) 00995 { 00996 /* Shouldn't happen */ 00997 ASSERT(FALSE); 00998 return HCELL_NIL; 00999 } 01000 01001 /* Release it */ 01002 HvReleaseCell(Hive, LeafCell); 01003 01004 /* Check if this is an index leaf */ 01005 if (Leaf->Signature == CM_KEY_INDEX_LEAF) 01006 { 01007 /* This is an old-style leaf */ 01008 FastLeaf = NULL; 01009 EntrySize = sizeof(HCELL_INDEX); 01010 } 01011 else 01012 { 01013 /* Sanity check */ 01014 ASSERT((Leaf->Signature == CM_KEY_FAST_LEAF) || 01015 (Leaf->Signature == CM_KEY_HASH_LEAF)); 01016 01017 /* This is a new-style optimized fast (or hash) leaf */ 01018 FastLeaf = (PCM_KEY_FAST_INDEX)Leaf; 01019 EntrySize = sizeof(CM_INDEX); 01020 } 01021 01022 /* Get the current size of the leaf */ 01023 OldSize = HvGetCellSize(Hive, Leaf); 01024 01025 /* Calculate the size of the free entries */ 01026 Size = OldSize; 01027 Size -= EntrySize * Leaf->Count + FIELD_OFFSET(CM_KEY_INDEX, List); 01028 01029 /* Assume we'll re-use the same leaf */ 01030 NewCell = LeafCell; 01031 01032 /* Check if we're out of space */ 01033 if ((Size / EntrySize) < 1) 01034 { 01035 /* Grow the leaf by 1.5x, making sure we can at least fit this entry */ 01036 Size = OldSize + OldSize / 2; 01037 if (Size < (OldSize + EntrySize)) Size = OldSize + EntrySize; 01038 01039 /* Re-allocate the leaf */ 01040 NewCell = HvReallocateCell(Hive, LeafCell, Size); 01041 if (NewCell == HCELL_NIL) return HCELL_NIL; 01042 01043 /* Get the leaf cell */ 01044 Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, NewCell); 01045 if (!Leaf) 01046 { 01047 /* This shouldn't happen */ 01048 ASSERT(FALSE); 01049 return HCELL_NIL; 01050 } 01051 01052 /* Release the cell */ 01053 HvReleaseCell(Hive, NewCell); 01054 01055 /* Update the fast leaf pointer if we had one */ 01056 if (FastLeaf) FastLeaf = (PCM_KEY_FAST_INDEX)Leaf; 01057 } 01058 01059 /* Find the insertion point for our entry */ 01060 i = CmpFindSubKeyInLeaf(Hive, Leaf, Name, &Child); 01061 if (i & 0x80000000) return HCELL_NIL; 01062 ASSERT(Child == HCELL_NIL); 01063 01064 /* Check if we're not last */ 01065 if (i != Leaf->Count) 01066 { 01067 /* Find out where we should go */ 01068 Result = CmpCompareInIndex(Hive, 01069 Name, 01070 i, 01071 Leaf, 01072 &Child); 01073 if (Result == 2) return HCELL_NIL; 01074 ASSERT(Result != 0); 01075 01076 /* Check if we come after */ 01077 if (Result > 0) 01078 { 01079 /* We do, insert us after the key */ 01080 ASSERT(Result == 1); 01081 i++; 01082 } 01083 01084 /* Check if we're still not last */ 01085 if (i != Leaf->Count) 01086 { 01087 /* Check if we had a fast leaf or not */ 01088 if (FastLeaf) 01089 { 01090 /* Copy the fast indexes */ 01091 RtlMoveMemory(&FastLeaf->List[i + 1], 01092 &FastLeaf->List[i], 01093 (FastLeaf->Count - i) * sizeof(CM_INDEX)); 01094 } 01095 else 01096 { 01097 /* Copy the indexes themselves */ 01098 RtlMoveMemory(&Leaf->List[i + 1], 01099 &Leaf->List[i], 01100 (Leaf->Count - i) * sizeof(HCELL_INDEX)); 01101 } 01102 } 01103 } 01104 01105 /* Check if this is a new-style leaf */ 01106 if (FastLeaf) 01107 { 01108 /* Set our cell */ 01109 FastLeaf->List[i].Cell = NewKey; 01110 01111 /* Check if this is a hash leaf */ 01112 if( FastLeaf->Signature == CM_KEY_HASH_LEAF ) 01113 { 01114 /* Set our hash key */ 01115 FastLeaf->List[i].HashKey = CmpComputeHashKey(0, Name, FALSE); 01116 } 01117 else 01118 { 01119 /* First, clear the name */ 01120 FastLeaf->List[i].NameHint[0] = 0; 01121 FastLeaf->List[i].NameHint[1] = 0; 01122 FastLeaf->List[i].NameHint[2] = 0; 01123 FastLeaf->List[i].NameHint[3] = 0; 01124 01125 /* Now, figure out if we can fit */ 01126 if (Name->Length / sizeof(WCHAR) < 4) 01127 { 01128 /* We can fit, use our length */ 01129 j = Name->Length / sizeof(WCHAR); 01130 } 01131 else 01132 { 01133 /* We can't, use a maximum of 4 */ 01134 j = 4; 01135 } 01136 01137 /* Now fill out the name hint */ 01138 do 01139 { 01140 /* Look for invalid characters and break out if we found one */ 01141 if ((USHORT)Name->Buffer[j - 1] > (UCHAR)-1) break; 01142 01143 /* Otherwise, copy the a character */ 01144 FastLeaf->List[i].NameHint[j - 1] = (UCHAR)Name->Buffer[j - 1]; 01145 } while (--j > 0); 01146 } 01147 } 01148 else 01149 { 01150 /* This is an old-style leaf, just set our index directly */ 01151 Leaf->List[i] = NewKey; 01152 } 01153 01154 /* Update the leaf count and return the new cell */ 01155 Leaf->Count += 1; 01156 return NewCell; 01157 } 01158 01159 HCELL_INDEX 01160 NTAPI 01161 CmpSplitLeaf(IN PHHIVE Hive, 01162 IN HCELL_INDEX RootCell, 01163 IN ULONG RootSelect, 01164 IN HSTORAGE_TYPE Type) 01165 { 01166 PCM_KEY_INDEX IndexKey, LeafKey, NewKey; 01167 PCM_KEY_FAST_INDEX FastLeaf; 01168 HCELL_INDEX LeafCell, NewCell; 01169 USHORT FirstHalf, LastHalf; 01170 ULONG EntrySize, TotalSize; 01171 01172 /* Get the cell */ 01173 IndexKey = (PCM_KEY_INDEX)HvGetCell(Hive, RootCell); 01174 01175 /* Check if we've got valid IndexKey */ 01176 if (!IndexKey) return HCELL_NIL; 01177 01178 /* Get the leaf cell and key */ 01179 LeafCell = IndexKey->List[RootSelect]; 01180 LeafKey = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell); 01181 01182 /* Check if we've got valid LeafKey */ 01183 if (!LeafKey) return HCELL_NIL; 01184 01185 /* We are going to divide this leaf into two halves */ 01186 FirstHalf = (LeafKey->Count / 2); 01187 LastHalf = LeafKey->Count - FirstHalf; 01188 01189 /* Now check what kind of hive we're dealing with, 01190 * and compute entry size 01191 */ 01192 if (Hive->Version >= 5) 01193 { 01194 /* XP Hive: Use hash leaf */ 01195 ASSERT(LeafKey->Signature == CM_KEY_HASH_LEAF); 01196 EntrySize = sizeof(CM_INDEX); 01197 } 01198 else 01199 { 01200 /* Use index leaf */ 01201 ASSERT(LeafKey->Signature == CM_KEY_INDEX_LEAF); 01202 EntrySize = sizeof(HCELL_INDEX); 01203 } 01204 01205 /* Compute the total size */ 01206 TotalSize = (EntrySize * LastHalf) + FIELD_OFFSET(CM_KEY_INDEX, List) + 1; 01207 01208 /* Mark the leaf cell dirty */ 01209 HvMarkCellDirty(Hive, LeafCell, FALSE); 01210 01211 /* Make sure its type is the same */ 01212 ASSERT(HvGetCellType(LeafCell) == Type); 01213 01214 /* Allocate the cell, fail in case of error */ 01215 NewCell = HvAllocateCell(Hive, TotalSize, Type, LeafCell); 01216 if (NewCell == HCELL_NIL) return NewCell; 01217 01218 /* Get the key */ 01219 NewKey = (PCM_KEY_INDEX)HvGetCell(Hive, NewCell); 01220 if (!NewKey) 01221 { 01222 /* Free the cell and exit - should not happen! */ 01223 ASSERT(FALSE); 01224 HvFreeCell(Hive, NewCell); 01225 return HCELL_NIL; 01226 } 01227 01228 /* Release the newly created cell */ 01229 HvReleaseCell(Hive, NewCell); 01230 01231 /* Set its signature according to the version of the hive */ 01232 if (Hive->Version >= 5) 01233 { 01234 /* XP Hive: Use hash leaf signature */ 01235 NewKey->Signature = CM_KEY_HASH_LEAF; 01236 } 01237 else 01238 { 01239 /* Use index leaf signature */ 01240 NewKey->Signature = CM_KEY_INDEX_LEAF; 01241 } 01242 01243 /* Calculate the size of the free entries in the root key */ 01244 TotalSize = HvGetCellSize(Hive, IndexKey) - 01245 (IndexKey->Count * sizeof(HCELL_INDEX)) - 01246 FIELD_OFFSET(CM_KEY_INDEX, List); 01247 01248 /* Check if we're out of space */ 01249 if (TotalSize / sizeof(HCELL_INDEX) < 1) 01250 { 01251 /* Grow the leaf by one more entry */ 01252 TotalSize = HvGetCellSize(Hive, IndexKey) + sizeof(HCELL_INDEX); 01253 01254 /* Re-allocate the root */ 01255 RootCell = HvReallocateCell(Hive, RootCell, TotalSize); 01256 if (RootCell == HCELL_NIL) 01257 { 01258 /* Free the cell and exit */ 01259 HvFreeCell(Hive, NewCell); 01260 return HCELL_NIL; 01261 } 01262 01263 /* Get the leaf cell */ 01264 IndexKey = (PCM_KEY_INDEX)HvGetCell(Hive, RootCell); 01265 if (!IndexKey) 01266 { 01267 /* This shouldn't happen */ 01268 ASSERT(FALSE); 01269 return HCELL_NIL; 01270 } 01271 } 01272 01273 /* Splitting is done, now we need to copy the contents, 01274 * according to the hive version 01275 */ 01276 if (Hive->Version >= 5) 01277 { 01278 /* Copy the fast indexes */ 01279 FastLeaf = (PCM_KEY_FAST_INDEX)LeafKey; 01280 RtlMoveMemory(&NewKey->List[0], 01281 &FastLeaf->List[FirstHalf], 01282 LastHalf * EntrySize); 01283 } 01284 else 01285 { 01286 /* Copy the indexes themselves */ 01287 RtlMoveMemory(&NewKey->List[0], 01288 &LeafKey->List[FirstHalf], 01289 LastHalf * EntrySize); 01290 } 01291 01292 /* Shift the data inside the root key */ 01293 if ((RootSelect + 1) < IndexKey->Count) 01294 { 01295 RtlMoveMemory(&IndexKey->List[RootSelect + 2], 01296 &IndexKey->List[RootSelect + 1], 01297 (IndexKey->Count - 01298 (RootSelect + 1)) * sizeof(HCELL_INDEX)); 01299 } 01300 01301 /* Make sure both old and new computed counts are valid */ 01302 ASSERT(FirstHalf != 0); 01303 ASSERT(LastHalf != 0); 01304 01305 /* Update the count value of old and new keys */ 01306 LeafKey->Count = FirstHalf; 01307 NewKey->Count = LastHalf; 01308 01309 /* Increase the count value of the root key */ 01310 IndexKey->Count++; 01311 01312 /* Set the new cell in root's list */ 01313 IndexKey->List[RootSelect + 1] = NewCell; 01314 01315 /* Return the root cell */ 01316 return RootCell; 01317 } 01318 01319 HCELL_INDEX 01320 NTAPI 01321 CmpSelectLeaf(IN PHHIVE Hive, 01322 IN PCM_KEY_NODE KeyNode, 01323 IN PUNICODE_STRING Name, 01324 IN HSTORAGE_TYPE Type, 01325 IN PHCELL_INDEX *RootCell) 01326 { 01327 PCM_KEY_INDEX IndexKey, LeafKey; 01328 PCM_KEY_FAST_INDEX FastLeaf; 01329 HCELL_INDEX LeafCell, CurrentCell; 01330 ULONG SubKeyIndex; 01331 LONG Result; 01332 01333 /* Mark it as dirty */ 01334 HvMarkCellDirty(Hive, KeyNode->SubKeyLists[Type], FALSE); 01335 01336 /* Get the cell */ 01337 IndexKey = (PCM_KEY_INDEX)HvGetCell(Hive, KeyNode->SubKeyLists[Type]); 01338 01339 /* Check if we've got a valid key */ 01340 if (!IndexKey) 01341 { 01342 /* Should not happen! */ 01343 ASSERTMSG("IndexKey = NULL!, it should not happen!\n", FALSE); 01344 return HCELL_NIL; 01345 } 01346 01347 /* Sanity check */ 01348 ASSERT(IndexKey->Signature == CM_KEY_INDEX_ROOT); 01349 01350 while (TRUE) 01351 { 01352 /* Find subkey */ 01353 SubKeyIndex = CmpFindSubKeyInRoot(Hive, IndexKey, Name, &LeafCell); 01354 01355 /* Make sure we found something valid */ 01356 if (SubKeyIndex & 0x80000000) return HCELL_NIL; 01357 01358 /* Try to fit it into the LeafCell, if it was found */ 01359 if (LeafCell != HCELL_NIL) 01360 { 01361 /* Get the leaf key */ 01362 LeafKey = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell); 01363 01364 /* Check for failure */ 01365 if (!LeafKey) return HCELL_NIL; 01366 01367 /* Check if it fits into this leaf and break */ 01368 if (LeafKey->Count < CmpMaxIndexPerHblock) 01369 { 01370 /* Fill in the result and return it */ 01371 *RootCell = &IndexKey->List[SubKeyIndex]; 01372 return LeafCell; 01373 } 01374 01375 /* It didn't fit, so proceed to splitting */ 01376 } 01377 else 01378 { 01379 /* Get the leaf cell at the very end */ 01380 LeafCell = IndexKey->List[SubKeyIndex]; 01381 LeafKey = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell); 01382 01383 /* Return an error in case of problems */ 01384 if (!LeafKey) return HCELL_NIL; 01385 01386 /* Choose the cell to search from depending on the key type */ 01387 if ((LeafKey->Signature == CM_KEY_FAST_LEAF) || 01388 (LeafKey->Signature == CM_KEY_HASH_LEAF)) 01389 { 01390 FastLeaf = (PCM_KEY_FAST_INDEX)LeafKey; 01391 CurrentCell = FastLeaf->List[0].Cell; 01392 } 01393 else 01394 { 01395 /* Make sure it's an index leaf */ 01396 ASSERT(LeafKey->Signature == CM_KEY_INDEX_LEAF); 01397 CurrentCell = LeafKey->List[0]; 01398 } 01399 01400 /* Do a name compare */ 01401 Result = CmpDoCompareKeyName(Hive, Name, CurrentCell); 01402 01403 /* Check for failure */ 01404 if (Result == 2) return HCELL_NIL; 01405 01406 /* Names can't be equal, ensure that */ 01407 ASSERT(Result != 0); 01408 01409 /* Check if it's above */ 01410 if (Result >= 0) 01411 { 01412 /* Get the cell in the index */ 01413 LeafCell = IndexKey->List[SubKeyIndex]; 01414 LeafKey = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell); 01415 01416 /* Return an error in case of problems */ 01417 if (!LeafKey) return HCELL_NIL; 01418 01419 /* Check if it fits into this leaf */ 01420 if (LeafKey->Count < CmpMaxIndexPerHblock) 01421 { 01422 /* Fill in the result and return the cell */ 01423 *RootCell = &IndexKey->List[SubKeyIndex]; 01424 return LeafCell; 01425 } 01426 01427 /* No, it doesn't fit, check the next adjacent leaf */ 01428 if ((SubKeyIndex + 1) < IndexKey->Count) 01429 { 01430 /* Yes, there is space */ 01431 LeafCell = IndexKey->List[SubKeyIndex + 1]; 01432 LeafKey = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell); 01433 01434 /* Return an error in case of problems */ 01435 if (!LeafKey) return HCELL_NIL; 01436 01437 /* Check if it fits and break */ 01438 if (LeafKey->Count < CmpMaxIndexPerHblock) 01439 { 01440 /* Fill in the result and return the cell */ 01441 *RootCell = &IndexKey->List[SubKeyIndex + 1]; 01442 return LeafCell; 01443 } 01444 } 01445 01446 /* It didn't fit, so proceed to splitting */ 01447 } 01448 else 01449 { 01450 /* No, it's below, check the subkey index */ 01451 if (SubKeyIndex > 0) 01452 { 01453 /* There should be space at the leaf one before that */ 01454 LeafCell = IndexKey->List[SubKeyIndex - 1]; 01455 LeafKey = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell); 01456 01457 /* Return an error in case of problems */ 01458 if (!LeafKey) return HCELL_NIL; 01459 01460 /* Check if it fits and break */ 01461 if (LeafKey->Count < CmpMaxIndexPerHblock) 01462 { 01463 /* Fill in the result and return the cell */ 01464 *RootCell = &IndexKey->List[SubKeyIndex - 1]; 01465 return LeafCell; 01466 } 01467 } 01468 else 01469 { 01470 /* Use the first leaf, if possible */ 01471 LeafCell = IndexKey->List[0]; 01472 LeafKey = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell); 01473 01474 /* Return an error in case of problems */ 01475 if (!LeafKey) return HCELL_NIL; 01476 01477 /* Check if it fits and break */ 01478 if (LeafKey->Count < CmpMaxIndexPerHblock) 01479 { 01480 /* Fill in the result and return the cell */ 01481 *RootCell = &IndexKey->List[0]; 01482 return LeafCell; 01483 } 01484 } 01485 01486 /* It didn't fit into either, so proceed to splitting */ 01487 } 01488 } 01489 01490 /* We need to split */ 01491 CurrentCell = CmpSplitLeaf(Hive, 01492 KeyNode->SubKeyLists[Type], 01493 SubKeyIndex, 01494 Type); 01495 01496 /* Return failure in case splitting failed */ 01497 if (CurrentCell == HCELL_NIL) return CurrentCell; 01498 01499 /* Set the SubKeyLists value with the new key */ 01500 KeyNode->SubKeyLists[Type] = CurrentCell; 01501 01502 /* Get the new cell */ 01503 IndexKey = (PCM_KEY_INDEX)HvGetCell(Hive, KeyNode->SubKeyLists[Type]); 01504 01505 /* Return in case of failure */ 01506 if (!IndexKey) return HCELL_NIL; 01507 01508 /* Make sure the new key became index root */ 01509 ASSERT(IndexKey->Signature == CM_KEY_INDEX_ROOT); 01510 01511 /* Now loop over with the new IndexKey value, which definately 01512 * has the space now 01513 */ 01514 } 01515 01516 /* Shouldn't come here */ 01517 return HCELL_NIL; 01518 } 01519 01520 BOOLEAN 01521 NTAPI 01522 CmpAddSubKey(IN PHHIVE Hive, 01523 IN HCELL_INDEX Parent, 01524 IN HCELL_INDEX Child) 01525 { 01526 PCM_KEY_NODE KeyNode; 01527 PCM_KEY_INDEX Index; 01528 PCM_KEY_FAST_INDEX OldIndex; 01529 UNICODE_STRING Name; 01530 HCELL_INDEX IndexCell = HCELL_NIL, CellToRelease = HCELL_NIL, LeafCell; 01531 PHCELL_INDEX RootPointer = NULL; 01532 ULONG Type, i; 01533 BOOLEAN IsCompressed; 01534 PAGED_CODE(); 01535 01536 /* Get the key node */ 01537 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Child); 01538 if (!KeyNode) 01539 { 01540 /* Shouldn't happen */ 01541 ASSERT(FALSE); 01542 return FALSE; 01543 } 01544 01545 /* Check if the name is compressed */ 01546 if (KeyNode->Flags & KEY_COMP_NAME) 01547 { 01548 /* Remember for later */ 01549 IsCompressed = TRUE; 01550 01551 /* Create the compressed name and allocate it */ 01552 Name.Length = CmpCompressedNameSize(KeyNode->Name, KeyNode->NameLength); 01553 Name.MaximumLength = Name.Length; 01554 Name.Buffer = Hive->Allocate(Name.Length, TRUE, TAG_CM); 01555 if (!Name.Buffer) 01556 { 01557 /* Release the cell and fail */ 01558 HvReleaseCell(Hive, Child); 01559 ASSERT(FALSE); 01560 return FALSE; 01561 } 01562 01563 /* Copy the compressed name */ 01564 CmpCopyCompressedName(Name.Buffer, 01565 Name.MaximumLength, 01566 KeyNode->Name, 01567 KeyNode->NameLength); 01568 } 01569 else 01570 { 01571 /* Remember for later */ 01572 IsCompressed = FALSE; 01573 01574 /* Build the unicode string */ 01575 Name.Length = KeyNode->NameLength; 01576 Name.MaximumLength = KeyNode->NameLength; 01577 Name.Buffer = &KeyNode->Name[0]; 01578 } 01579 01580 /* Release the cell */ 01581 HvReleaseCell(Hive, Child); 01582 01583 /* Get the parent node */ 01584 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, Parent); 01585 if (!KeyNode) 01586 { 01587 /* Not handled */ 01588 ASSERT(FALSE); 01589 } 01590 01591 /* Find out the type of the cell, and check if this is the first subkey */ 01592 Type = HvGetCellType(Child); 01593 if (!KeyNode->SubKeyCounts[Type]) 01594 { 01595 /* Allocate a fast leaf */ 01596 IndexCell = HvAllocateCell(Hive, sizeof(CM_KEY_FAST_INDEX), Type, HCELL_NIL); 01597 if (IndexCell == HCELL_NIL) 01598 { 01599 /* Not handled */ 01600 ASSERT(FALSE); 01601 } 01602 01603 /* Get the leaf cell */ 01604 Index = (PCM_KEY_INDEX)HvGetCell(Hive, IndexCell); 01605 if (!Index) 01606 { 01607 /* Shouldn't happen */ 01608 ASSERT(FALSE); 01609 } 01610 01611 /* Now check what kind of hive we're dealing with */ 01612 if (Hive->Version >= 5) 01613 { 01614 /* XP Hive: Use hash leaf */ 01615 Index->Signature = CM_KEY_HASH_LEAF; 01616 } 01617 else if (Hive->Version >= 3) 01618 { 01619 /* Windows 2000 and ReactOS: Use fast leaf */ 01620 Index->Signature = CM_KEY_FAST_LEAF; 01621 } 01622 else 01623 { 01624 /* NT 4: Use index leaf */ 01625 Index->Signature = CM_KEY_INDEX_LEAF; 01626 } 01627 01628 /* Setup the index list */ 01629 Index->Count = 0; 01630 KeyNode->SubKeyLists[Type] = IndexCell; 01631 } 01632 else 01633 { 01634 /* We already have an index, get it */ 01635 Index = (PCM_KEY_INDEX)HvGetCell(Hive, KeyNode->SubKeyLists[Type]); 01636 if (!Index) 01637 { 01638 /* Not handled */ 01639 ASSERT(FALSE); 01640 } 01641 01642 /* Remember to release the cell later */ 01643 CellToRelease = KeyNode->SubKeyLists[Type]; 01644 01645 /* Check if this is a fast leaf that's gotten too full */ 01646 if ((Index->Signature == CM_KEY_FAST_LEAF) && 01647 (Index->Count >= CmpMaxFastIndexPerHblock)) 01648 { 01649 DPRINT("Doing Fast->Slow Leaf conversion\n"); 01650 01651 /* Mark this cell as dirty */ 01652 HvMarkCellDirty(Hive, CellToRelease, FALSE); 01653 01654 /* Convert */ 01655 OldIndex = (PCM_KEY_FAST_INDEX)Index; 01656 01657 for (i = 0; i < OldIndex->Count; i++) 01658 { 01659 Index->List[i] = OldIndex->List[i].Cell; 01660 } 01661 01662 /* Set the new type value */ 01663 Index->Signature = CM_KEY_INDEX_LEAF; 01664 } 01665 else if (((Index->Signature == CM_KEY_INDEX_LEAF) || 01666 (Index->Signature == CM_KEY_HASH_LEAF)) && 01667 (Index->Count >= CmpMaxIndexPerHblock)) 01668 { 01669 /* This is an old/hashed leaf that's gotten too large, root it */ 01670 IndexCell = HvAllocateCell(Hive, 01671 sizeof(CM_KEY_INDEX) + 01672 sizeof(HCELL_INDEX), 01673 Type, 01674 HCELL_NIL); 01675 if (IndexCell == HCELL_NIL) 01676 { 01677 /* Not handled */ 01678 ASSERT(FALSE); 01679 } 01680 01681 /* Get the index cell */ 01682 Index = (PCM_KEY_INDEX)HvGetCell(Hive, IndexCell); 01683 if (!Index) 01684 { 01685 /* Shouldn't happen */ 01686 ASSERT(FALSE); 01687 } 01688 01689 /* Mark the index as a root, and set the index cell */ 01690 Index->Signature = CM_KEY_INDEX_ROOT; 01691 Index->Count = 1; 01692 Index->List[0] = KeyNode->SubKeyLists[Type]; 01693 KeyNode->SubKeyLists[Type] = IndexCell; 01694 } 01695 } 01696 01697 /* Now we can choose the leaf cell */ 01698 LeafCell = KeyNode->SubKeyLists[Type]; 01699 01700 /* Check if we turned the index into a root */ 01701 if (Index->Signature == CM_KEY_INDEX_ROOT) 01702 { 01703 DPRINT("Leaf->Root Index Conversion\n"); 01704 01705 /* Get the leaf where to add the new entry (the routine will do 01706 * the splitting if necessary) 01707 */ 01708 LeafCell = CmpSelectLeaf(Hive, KeyNode, &Name, Type, &RootPointer); 01709 if (LeafCell == HCELL_NIL) 01710 { 01711 /* Not handled */ 01712 ASSERT(FALSE); 01713 } 01714 } 01715 01716 /* Add our leaf cell */ 01717 LeafCell = CmpAddToLeaf(Hive, LeafCell, Child, &Name); 01718 if (LeafCell == HCELL_NIL) 01719 { 01720 /* Not handled */ 01721 ASSERT(FALSE); 01722 } 01723 01724 /* Update the key counts */ 01725 KeyNode->SubKeyCounts[Type]++; 01726 01727 /* Check if caller wants us to return the leaf */ 01728 if (RootPointer) 01729 { 01730 /* Return it */ 01731 *RootPointer = LeafCell; 01732 } 01733 else 01734 { 01735 /* Otherwise, mark it as the list index for the cell */ 01736 KeyNode->SubKeyLists[Type] = LeafCell; 01737 } 01738 01739 /* If the name was compressed, free our copy */ 01740 if (IsCompressed) Hive->Free(Name.Buffer, 0); 01741 01742 /* Release all our cells */ 01743 if (IndexCell != HCELL_NIL) HvReleaseCell(Hive, IndexCell); 01744 if (CellToRelease != HCELL_NIL) HvReleaseCell(Hive, CellToRelease); 01745 HvReleaseCell(Hive, Parent); 01746 return TRUE; 01747 } 01748 01749 BOOLEAN 01750 NTAPI 01751 CmpRemoveSubKey(IN PHHIVE Hive, 01752 IN HCELL_INDEX ParentKey, 01753 IN HCELL_INDEX TargetKey) 01754 { 01755 PCM_KEY_NODE Node; 01756 UNICODE_STRING SearchName; 01757 BOOLEAN IsCompressed; 01758 WCHAR Buffer[50]; 01759 HCELL_INDEX RootCell = HCELL_NIL, LeafCell, ChildCell; 01760 PCM_KEY_INDEX Root = NULL, Leaf; 01761 PCM_KEY_FAST_INDEX Child; 01762 ULONG Storage, RootIndex = 0x80000000, LeafIndex; 01763 BOOLEAN Result = FALSE; 01764 HCELL_INDEX CellToRelease1 = HCELL_NIL, CellToRelease2 = HCELL_NIL; 01765 01766 /* Get the target key node */ 01767 Node = (PCM_KEY_NODE)HvGetCell(Hive, TargetKey); 01768 if (!Node) return FALSE; 01769 01770 /* Make sure it's dirty, then release it */ 01771 ASSERT(HvIsCellDirty(Hive, TargetKey)); 01772 HvReleaseCell(Hive, TargetKey); 01773 01774 /* Check if the name is compressed */ 01775 if (Node->Flags & KEY_COMP_NAME) 01776 { 01777 /* Remember for later */ 01778 IsCompressed = TRUE; 01779 01780 /* Build the search name */ 01781 SearchName.Length = CmpCompressedNameSize(Node->Name, 01782 Node->NameLength); 01783 SearchName.MaximumLength = SearchName.Length; 01784 01785 /* Do we need an extra bufer? */ 01786 if (SearchName.MaximumLength > sizeof(Buffer)) 01787 { 01788 /* Allocate one */ 01789 SearchName.Buffer = CmpAllocate(SearchName.Length, 01790 TRUE, 01791 TAG_CM); 01792 if (!SearchName.Buffer) return FALSE; 01793 } 01794 else 01795 { 01796 /* Otherwise, use our local stack buffer */ 01797 SearchName.Buffer = Buffer; 01798 } 01799 01800 /* Copy the compressed name */ 01801 CmpCopyCompressedName(SearchName.Buffer, 01802 SearchName.MaximumLength, 01803 Node->Name, 01804 Node->NameLength); 01805 } 01806 else 01807 { 01808 /* It's not compressed, build the name directly from the node */ 01809 IsCompressed = FALSE; 01810 SearchName.Length = Node->NameLength; 01811 SearchName.MaximumLength = Node->NameLength; 01812 SearchName.Buffer = Node->Name; 01813 } 01814 01815 /* Now get the parent node */ 01816 Node = (PCM_KEY_NODE)HvGetCell(Hive, ParentKey); 01817 if (!Node) goto Exit; 01818 01819 /* Make sure it's dirty, then release it */ 01820 ASSERT(HvIsCellDirty(Hive, ParentKey)); 01821 HvReleaseCell(Hive, ParentKey); 01822 01823 /* Get the storage type and make sure it's not empty */ 01824 Storage = HvGetCellType(TargetKey); 01825 ASSERT(Node->SubKeyCounts[Storage] != 0); 01826 //ASSERT(HvIsCellAllocated(Hive, Node->SubKeyLists[Storage])); 01827 01828 /* Get the leaf cell now */ 01829 LeafCell = Node->SubKeyLists[Storage]; 01830 Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell); 01831 if (!Leaf) goto Exit; 01832 01833 /* Remember to release it later */ 01834 CellToRelease1 = LeafCell; 01835 01836 /* Check if the leaf is a root */ 01837 if (Leaf->Signature == CM_KEY_INDEX_ROOT) 01838 { 01839 /* Find the child inside the root */ 01840 RootIndex = CmpFindSubKeyInRoot(Hive, Leaf, &SearchName, &ChildCell); 01841 if (RootIndex & 0x80000000) goto Exit; 01842 ASSERT(ChildCell != FALSE); 01843 01844 /* The root cell is now this leaf */ 01845 Root = Leaf; 01846 RootCell = LeafCell; 01847 01848 /* And the new leaf is now this child */ 01849 LeafCell = ChildCell; 01850 Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell); 01851 if (!Leaf) goto Exit; 01852 01853 /* Remember to release it later */ 01854 CellToRelease2 = LeafCell; 01855 } 01856 01857 /* Make sure the leaf is valid */ 01858 ASSERT((Leaf->Signature == CM_KEY_INDEX_LEAF) || 01859 (Leaf->Signature == CM_KEY_FAST_LEAF) || 01860 (Leaf->Signature == CM_KEY_HASH_LEAF)); 01861 01862 /* Now get the child in the leaf */ 01863 LeafIndex = CmpFindSubKeyInLeaf(Hive, Leaf, &SearchName, &ChildCell); 01864 if (LeafIndex & 0x80000000) goto Exit; 01865 ASSERT(ChildCell != HCELL_NIL); 01866 01867 /* Decrement key counts and check if this was the last leaf entry */ 01868 Node->SubKeyCounts[Storage]--; 01869 if (!(--Leaf->Count)) 01870 { 01871 /* Free the leaf */ 01872 HvFreeCell(Hive, LeafCell); 01873 01874 /* Check if we were inside a root */ 01875 if (Root) 01876 { 01877 /* Decrease the root count too, since the leaf is going away */ 01878 if (!(--Root->Count)) 01879 { 01880 /* The root is gone too,n ow */ 01881 HvFreeCell(Hive, RootCell); 01882 Node->SubKeyLists[Storage] = HCELL_NIL; 01883 } 01884 else if (RootIndex < Root->Count) 01885 { 01886 /* Bring everything up by one */ 01887 RtlMoveMemory(&Root->List[RootIndex], 01888 &Root->List[RootIndex + 1], 01889 (Root->Count - RootIndex) * sizeof(HCELL_INDEX)); 01890 } 01891 } 01892 else 01893 { 01894 /* Otherwise, just clear the cell */ 01895 Node->SubKeyLists[Storage] = HCELL_NIL; 01896 } 01897 } 01898 else if (LeafIndex < Leaf->Count) 01899 { 01900 /* Was the leaf a normal index? */ 01901 if (Leaf->Signature == CM_KEY_INDEX_LEAF) 01902 { 01903 /* Bring everything up by one */ 01904 RtlMoveMemory(&Leaf->List[LeafIndex], 01905 &Leaf->List[LeafIndex + 1], 01906 (Leaf->Count - LeafIndex) * sizeof(HCELL_INDEX)); 01907 } 01908 else 01909 { 01910 /* This is a fast index, bring everything up by one */ 01911 Child = (PCM_KEY_FAST_INDEX)Leaf; 01912 RtlMoveMemory(&Child->List[LeafIndex], 01913 &Child->List[LeafIndex+1], 01914 (Child->Count - LeafIndex) * sizeof(CM_INDEX)); 01915 } 01916 } 01917 01918 /* If we got here, now we're done */ 01919 Result = TRUE; 01920 01921 Exit: 01922 /* Release any cells we may have been holding */ 01923 if (CellToRelease1 != HCELL_NIL) HvReleaseCell(Hive, CellToRelease1); 01924 if (CellToRelease2 != HCELL_NIL) HvReleaseCell(Hive, CellToRelease2); 01925 01926 /* Check if the name was compressed and not inside our local buffer */ 01927 if ((IsCompressed) && (SearchName.MaximumLength > sizeof(Buffer))) 01928 { 01929 /* Free the buffer we allocated */ 01930 CmpFree(SearchName.Buffer, 0); 01931 } 01932 01933 /* Return the result */ 01934 return Result; 01935 } Generated on Fri May 25 2012 04:35:29 for ReactOS by
1.7.6.1
|