ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

cmindex.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.