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

cmkcbncb.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/cmkcbncb.c
00005  * PURPOSE:         Routines for handling KCBs, NCBs, as well as key hashes.
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 CmpHashTableSize = 2048;
00018 PCM_KEY_HASH_TABLE_ENTRY CmpCacheTable;
00019 PCM_NAME_HASH_TABLE_ENTRY CmpNameCacheTable;
00020 
00021 /* FUNCTIONS *****************************************************************/
00022 
00023 VOID
00024 NTAPI
00025 INIT_FUNCTION
00026 CmpInitializeCache(VOID)
00027 {
00028     ULONG Length, i;
00029     
00030     /* Calculate length for the table */
00031     Length = CmpHashTableSize * sizeof(CM_KEY_HASH_TABLE_ENTRY);
00032     
00033     /* Allocate it */
00034     CmpCacheTable = CmpAllocate(Length, TRUE, TAG_CM);
00035     if (!CmpCacheTable)
00036     {
00037         /* Take the system down */
00038         KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 3, 1, 0, 0);
00039     }
00040     
00041     /* Zero out the table */
00042     RtlZeroMemory(CmpCacheTable, Length);
00043     
00044     /* Initialize the locks */
00045     for (i = 0;i < CmpHashTableSize; i++)
00046     {
00047         /* Setup the pushlock */
00048         ExInitializePushLock(&CmpCacheTable[i].Lock);
00049     }
00050     
00051     /* Calculate length for the name cache */
00052     Length = CmpHashTableSize * sizeof(CM_NAME_HASH_TABLE_ENTRY);
00053     
00054     /* Now allocate the name cache table */
00055     CmpNameCacheTable = CmpAllocate(Length, TRUE, TAG_CM);
00056     if (!CmpNameCacheTable)
00057     {
00058         /* Take the system down */
00059         KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 3, 3, 0, 0);
00060     }
00061     
00062     /* Zero out the table */
00063     RtlZeroMemory(CmpNameCacheTable, Length);
00064 
00065     /* Initialize the locks */
00066     for (i = 0;i < CmpHashTableSize; i++)
00067     {
00068         /* Setup the pushlock */
00069         ExInitializePushLock(&CmpNameCacheTable[i].Lock);
00070     }
00071     
00072     /* Setup the delayed close table */
00073     CmpInitializeDelayedCloseTable();
00074 }
00075 
00076 VOID
00077 NTAPI
00078 CmpRemoveKeyHash(IN PCM_KEY_HASH KeyHash)
00079 {
00080     PCM_KEY_HASH *Prev;
00081     PCM_KEY_HASH Current;
00082     ASSERT_VALID_HASH(KeyHash);
00083 
00084     /* Lookup all the keys in this index entry */
00085     Prev = &GET_HASH_ENTRY(CmpCacheTable, KeyHash->ConvKey).Entry;
00086     while (TRUE)
00087     {
00088         /* Save the current one and make sure it's valid */
00089         Current = *Prev;
00090         ASSERT(Current != NULL);
00091         ASSERT_VALID_HASH(Current);
00092 
00093         /* Check if it matches */
00094         if (Current == KeyHash)
00095         {
00096             /* Then write the previous one */
00097             *Prev = Current->NextHash;
00098             if (*Prev) ASSERT_VALID_HASH(*Prev);
00099             break;
00100         }
00101 
00102         /* Otherwise, keep going */
00103         Prev = &Current->NextHash;
00104     }
00105 }
00106 
00107 PCM_KEY_CONTROL_BLOCK
00108 NTAPI
00109 CmpInsertKeyHash(IN PCM_KEY_HASH KeyHash,
00110                  IN BOOLEAN IsFake)
00111 {
00112     ULONG i;
00113     PCM_KEY_HASH Entry;
00114     ASSERT_VALID_HASH(KeyHash);
00115 
00116     /* Get the hash index */
00117     i = GET_HASH_INDEX(KeyHash->ConvKey);
00118 
00119     /* If this is a fake key, increase the key cell to use the parent data */
00120     if (IsFake) KeyHash->KeyCell++;
00121 
00122     /* Loop the hash table */
00123     Entry = CmpCacheTable[i].Entry;
00124     while (Entry)
00125     {
00126         /* Check if this matches */
00127         ASSERT_VALID_HASH(Entry);
00128         if ((KeyHash->ConvKey == Entry->ConvKey) &&
00129             (KeyHash->KeyCell == Entry->KeyCell) &&
00130             (KeyHash->KeyHive == Entry->KeyHive))
00131         {
00132             /* Return it */
00133             return CONTAINING_RECORD(Entry, CM_KEY_CONTROL_BLOCK, KeyHash);
00134         }
00135 
00136         /* Keep looping */
00137         Entry = Entry->NextHash;
00138     }
00139 
00140     /* No entry found, add this one and return NULL since none existed */
00141     KeyHash->NextHash = CmpCacheTable[i].Entry;
00142     CmpCacheTable[i].Entry = KeyHash;
00143     return NULL;
00144 }
00145 
00146 PCM_NAME_CONTROL_BLOCK
00147 NTAPI
00148 CmpGetNameControlBlock(IN PUNICODE_STRING NodeName)
00149 {
00150     PCM_NAME_CONTROL_BLOCK Ncb = NULL;
00151     ULONG ConvKey = 0;
00152     PWCHAR p, pp;
00153     ULONG i;
00154     BOOLEAN IsCompressed = TRUE, Found = FALSE;
00155     PCM_NAME_HASH HashEntry;
00156     ULONG NcbSize;
00157     USHORT Length;
00158 
00159     /* Loop the name */
00160     p = NodeName->Buffer;
00161     for (i = 0; i < NodeName->Length; i += sizeof(WCHAR))
00162     {
00163         /* Make sure it's not a slash */
00164         if (*p != OBJ_NAME_PATH_SEPARATOR)
00165         {
00166             /* Add it to the hash */
00167             ConvKey = 37 * ConvKey + RtlUpcaseUnicodeChar(*p);
00168         }
00169 
00170         /* Next character */
00171         p++;
00172     }
00173 
00174     /* Set assumed lengh and loop to check */
00175     Length = NodeName->Length / sizeof(WCHAR);
00176     for (i = 0; i < (NodeName->Length / sizeof(WCHAR)); i++)
00177     {
00178         /* Check if this is a 16-bit character */
00179         if (NodeName->Buffer[i] > (UCHAR)-1)
00180         {
00181             /* This is the actual size, and we know we're not compressed */
00182             Length = NodeName->Length;
00183             IsCompressed = FALSE;
00184             break;
00185         }
00186     }
00187 
00188     /* Lock the NCB entry */
00189     CmpAcquireNcbLockExclusiveByKey(ConvKey);
00190 
00191     /* Get the hash entry */
00192     HashEntry = GET_HASH_ENTRY(CmpNameCacheTable, ConvKey).Entry;
00193     while (HashEntry)
00194     {
00195         /* Get the current NCB */
00196         Ncb = CONTAINING_RECORD(HashEntry, CM_NAME_CONTROL_BLOCK, NameHash);
00197 
00198         /* Check if the hash matches */
00199         if ((ConvKey == HashEntry->ConvKey) && (Length == Ncb->NameLength))
00200         {
00201             /* Assume success */
00202             Found = TRUE;
00203 
00204             /* If the NCB is compressed, do a compressed name compare */
00205             if (Ncb->Compressed)
00206             {
00207                 /* Compare names */
00208                 if (CmpCompareCompressedName(NodeName, Ncb->Name, Length))
00209                 {
00210                     /* We failed */
00211                     Found = FALSE;
00212                 }
00213             }
00214             else
00215             {
00216                 /* Do a manual compare */
00217                 p = NodeName->Buffer;
00218                 pp = Ncb->Name;
00219                 for (i = 0; i < Ncb->NameLength; i += sizeof(WCHAR))
00220                 {
00221                     /* Compare the character */
00222                     if (RtlUpcaseUnicodeChar(*p) != RtlUpcaseUnicodeChar(*pp))
00223                     {
00224                         /* Failed */
00225                         Found = FALSE;
00226                         break;
00227                     }
00228 
00229                     /* Next chars */
00230                     p++;
00231                     pp++;
00232                 }
00233             }
00234 
00235             /* Check if we found a name */
00236             if (Found)
00237             {
00238                 /* Reference it */
00239                 ASSERT(Ncb->RefCount != 0xFFFF);
00240                 Ncb->RefCount++;
00241                 break;
00242             }
00243         }
00244 
00245         /* Go to the next hash */
00246         HashEntry = HashEntry->NextHash;
00247     }
00248 
00249     /* Check if we didn't find it */
00250     if (!Found)
00251     {
00252         /* Allocate one */
00253         NcbSize = FIELD_OFFSET(CM_NAME_CONTROL_BLOCK, Name) + Length;
00254         Ncb = CmpAllocate(NcbSize, TRUE, TAG_CM);
00255         if (!Ncb)
00256         {
00257             /* Release the lock and fail */
00258             CmpReleaseNcbLockByKey(ConvKey);
00259             return NULL;
00260         }
00261 
00262         /* Clear it out */
00263         RtlZeroMemory(Ncb, NcbSize);
00264 
00265         /* Check if the name was compressed */
00266         if (IsCompressed)
00267         {
00268             /* Copy the compressed name */
00269             for (i = 0; i < NodeName->Length / sizeof(WCHAR); i++)
00270             {
00271                 /* Copy Unicode to ANSI */
00272                 ((PCHAR)Ncb->Name)[i] = (CHAR)RtlUpcaseUnicodeChar(NodeName->Buffer[i]);
00273             }
00274         }
00275         else
00276         {
00277             /* Copy the name directly */
00278             for (i = 0; i < NodeName->Length / sizeof(WCHAR); i++)
00279             {
00280                 /* Copy each unicode character */
00281                 Ncb->Name[i] = RtlUpcaseUnicodeChar(NodeName->Buffer[i]);
00282             }
00283         }
00284 
00285         /* Setup the rest of the NCB */
00286         Ncb->Compressed = IsCompressed;
00287         Ncb->ConvKey = ConvKey;
00288         Ncb->RefCount++;
00289         Ncb->NameLength = Length;
00290 
00291         /* Insert the name in the hash table */
00292         HashEntry = &Ncb->NameHash;
00293         HashEntry->NextHash = GET_HASH_ENTRY(CmpNameCacheTable, ConvKey).Entry;
00294         GET_HASH_ENTRY(CmpNameCacheTable, ConvKey).Entry = HashEntry;
00295     }
00296 
00297     /* Release NCB lock */
00298     CmpReleaseNcbLockByKey(ConvKey);
00299 
00300     /* Return the NCB found */
00301     return Ncb;
00302 }
00303 
00304 VOID
00305 NTAPI
00306 CmpRemoveKeyControlBlock(IN PCM_KEY_CONTROL_BLOCK Kcb)
00307 {
00308     /* Make sure that the registry and KCB are utterly locked */
00309     ASSERT((CmpIsKcbLockedExclusive(Kcb) == TRUE) ||
00310            (CmpTestRegistryLockExclusive() == TRUE));
00311 
00312     /* Remove the key hash */
00313     CmpRemoveKeyHash(&Kcb->KeyHash);
00314 }
00315 
00316 VOID
00317 NTAPI
00318 CmpDereferenceNameControlBlockWithLock(IN PCM_NAME_CONTROL_BLOCK Ncb)
00319 {
00320     PCM_NAME_HASH Current, *Next;
00321     ULONG ConvKey = Ncb->ConvKey;
00322 
00323     /* Lock the NCB */
00324     CmpAcquireNcbLockExclusiveByKey(ConvKey);
00325 
00326     /* Decrease the reference count */
00327     ASSERT(Ncb->RefCount >= 1);
00328     if (!(--Ncb->RefCount))
00329     {
00330         /* Find the NCB in the table */
00331         Next = &GET_HASH_ENTRY(CmpNameCacheTable, Ncb->ConvKey).Entry;
00332         while (TRUE)
00333         {
00334             /* Check the current entry */
00335             Current = *Next;
00336             ASSERT(Current != NULL);
00337             if (Current == &Ncb->NameHash)
00338             {
00339                 /* Unlink it */
00340                 *Next = Current->NextHash;
00341                 break;
00342             }
00343 
00344             /* Get to the next one */
00345             Next = &Current->NextHash;
00346         }
00347 
00348         /* Found it, now free it */
00349         CmpFree(Ncb, 0);
00350     }
00351 
00352     /* Release the lock */
00353     CmpReleaseNcbLockByKey(ConvKey);
00354 }
00355 
00356 BOOLEAN
00357 NTAPI
00358 CmpReferenceKeyControlBlock(IN PCM_KEY_CONTROL_BLOCK Kcb)
00359 {
00360     CMTRACE(CM_REFERENCE_DEBUG,
00361             "%s - Referencing KCB: %p\n", __FUNCTION__, Kcb);
00362 
00363     /* Check if this is the KCB's first reference */
00364     if (Kcb->RefCount == 0)
00365     {
00366         /* Check if the KCB is locked in shared mode */
00367         if (!CmpIsKcbLockedExclusive(Kcb))
00368         {
00369             /* Convert it to exclusive */
00370             if (!CmpTryToConvertKcbSharedToExclusive(Kcb))
00371             {
00372                 /* Set the delayed close index so that we can be ignored */
00373                 Kcb->DelayedCloseIndex = 1;
00374 
00375                 /* Increase the reference count while we release the lock */
00376                 InterlockedIncrement((PLONG)&Kcb->RefCount);
00377                
00378                 /* Go from shared to exclusive */
00379                 CmpConvertKcbSharedToExclusive(Kcb);
00380 
00381                 /* Decrement the reference count; the lock is now held again */
00382                 InterlockedDecrement((PLONG)&Kcb->RefCount);
00383                
00384                 /* Check if we still control the index */
00385                 if (Kcb->DelayedCloseIndex == 1)
00386                 {
00387                     /* Reset it */
00388                     Kcb->DelayedCloseIndex = 0;
00389                 }
00390                 else
00391                 {
00392                     /* Sanity check */
00393                     ASSERT((Kcb->DelayedCloseIndex == CmpDelayedCloseSize) ||
00394                            (Kcb->DelayedCloseIndex == 0));
00395                 }
00396             }
00397         }
00398     }
00399 
00400     /* Increase the reference count */
00401     if ((InterlockedIncrement((PLONG)&Kcb->RefCount) & 0xFFFF) == 0)
00402     {
00403         /* We've overflown to 64K references, bail out */
00404         InterlockedDecrement((PLONG)&Kcb->RefCount);
00405         return FALSE;
00406     }
00407 
00408     /* Check if this was the last close index */
00409     if (!Kcb->DelayedCloseIndex)
00410     {
00411         /* Check if the KCB is locked in shared mode */
00412         if (!CmpIsKcbLockedExclusive(Kcb))
00413         {
00414             /* Convert it to exclusive */
00415             if (!CmpTryToConvertKcbSharedToExclusive(Kcb))
00416             {
00417                 /* Go from shared to exclusive */
00418                 CmpConvertKcbSharedToExclusive(Kcb);
00419             }
00420         }
00421 
00422         /* If we're still the last entry, remove us */
00423         if (!Kcb->DelayedCloseIndex) CmpRemoveFromDelayedClose(Kcb);
00424     }
00425 
00426     /* Return success */
00427     return TRUE;
00428 }
00429 
00430 VOID
00431 NTAPI
00432 CmpCleanUpKcbValueCache(IN PCM_KEY_CONTROL_BLOCK Kcb)
00433 {
00434     PULONG_PTR CachedList;
00435     ULONG i;
00436 
00437     /* Sanity check */
00438     ASSERT((CmpIsKcbLockedExclusive(Kcb) == TRUE) ||
00439            (CmpTestRegistryLockExclusive() == TRUE));
00440 
00441     /* Check if the value list is cached */
00442     if (CMP_IS_CELL_CACHED(Kcb->ValueCache.ValueList))
00443     {
00444         /* Get the cache list */
00445         CachedList = (PULONG_PTR)CMP_GET_CACHED_DATA(Kcb->ValueCache.ValueList);
00446         for (i = 0; i < Kcb->ValueCache.Count; i++)
00447         {
00448             /* Check if this cell is cached */
00449             if (CMP_IS_CELL_CACHED(CachedList[i]))
00450             {
00451                 /* Free it */
00452                 CmpFree((PVOID)CMP_GET_CACHED_CELL(CachedList[i]), 0);
00453             }
00454         }
00455 
00456         /* Now free the list */
00457         CmpFree((PVOID)CMP_GET_CACHED_CELL(Kcb->ValueCache.ValueList), 0);
00458         Kcb->ValueCache.ValueList = HCELL_NIL;
00459     }
00460     else if (Kcb->ExtFlags & CM_KCB_SYM_LINK_FOUND)
00461     {
00462         /* This is a sym link, check if there's only one reference left */
00463         if ((Kcb->ValueCache.RealKcb->RefCount == 1) &&
00464             !(Kcb->ValueCache.RealKcb->Delete))
00465         {
00466             /* Disable delay close for the KCB */
00467             Kcb->ValueCache.RealKcb->ExtFlags |= CM_KCB_NO_DELAY_CLOSE;
00468         }
00469 
00470         /* Dereference the KCB */
00471         CmpDelayDerefKeyControlBlock(Kcb->ValueCache.RealKcb);
00472         Kcb->ExtFlags &= ~CM_KCB_SYM_LINK_FOUND;
00473     }
00474 }
00475 
00476 VOID
00477 NTAPI
00478 CmpCleanUpKcbCacheWithLock(IN PCM_KEY_CONTROL_BLOCK Kcb,
00479                            IN BOOLEAN LockHeldExclusively)
00480 {
00481     PCM_KEY_CONTROL_BLOCK Parent;
00482     PAGED_CODE();
00483 
00484     /* Sanity checks */
00485     ASSERT((CmpIsKcbLockedExclusive(Kcb) == TRUE) ||
00486            (CmpTestRegistryLockExclusive() == TRUE));
00487     ASSERT(Kcb->RefCount == 0);
00488 
00489     /* Cleanup the value cache */
00490     CmpCleanUpKcbValueCache(Kcb);
00491 
00492     /* Dereference the NCB */
00493     CmpDereferenceNameControlBlockWithLock(Kcb->NameBlock);
00494 
00495     /* Check if we have an index hint block and free it */
00496     if (Kcb->ExtFlags & CM_KCB_SUBKEY_HINT) CmpFree(Kcb->IndexHint, 0);
00497 
00498     /* Check if we were already deleted */
00499     Parent = Kcb->ParentKcb;
00500     if (!Kcb->Delete) CmpRemoveKeyControlBlock(Kcb);
00501 
00502     /* Set invalid KCB signature */
00503     Kcb->Signature = CM_KCB_INVALID_SIGNATURE;
00504 
00505     /* Free the KCB as well */
00506     CmpFreeKeyControlBlock(Kcb);
00507 
00508     /* Check if we have a parent */
00509     if (Parent)
00510     {
00511         /* Dereference the parent */
00512         LockHeldExclusively ?
00513             CmpDereferenceKeyControlBlockWithLock(Parent,LockHeldExclusively) :
00514             CmpDelayDerefKeyControlBlock(Parent);
00515     }
00516 }
00517 
00518 VOID
00519 NTAPI
00520 CmpCleanUpSubKeyInfo(IN PCM_KEY_CONTROL_BLOCK Kcb)
00521 {
00522     PCM_KEY_NODE KeyNode;
00523 
00524     /* Sanity check */
00525     ASSERT((CmpIsKcbLockedExclusive(Kcb) == TRUE) ||
00526            (CmpTestRegistryLockExclusive() == TRUE));
00527 
00528     /* Check if there's any cached subkey */
00529     if (Kcb->ExtFlags & (CM_KCB_NO_SUBKEY | CM_KCB_SUBKEY_ONE | CM_KCB_SUBKEY_HINT))
00530     {
00531         /* Check if there's a hint */
00532         if (Kcb->ExtFlags & (CM_KCB_SUBKEY_HINT))
00533         {
00534             /* Kill it */
00535             CmpFree(Kcb->IndexHint, 0);
00536         }
00537 
00538         /* Remove subkey flags */
00539         Kcb->ExtFlags &= ~(CM_KCB_NO_SUBKEY | CM_KCB_SUBKEY_ONE | CM_KCB_SUBKEY_HINT);
00540     }
00541 
00542     /* Check if there's no linked cell */
00543     if (Kcb->KeyCell == HCELL_NIL)
00544     {
00545         /* Make sure it's a delete */
00546         ASSERT(Kcb->Delete);
00547         KeyNode = NULL;
00548     }
00549     else
00550     {
00551         /* Get the key node */
00552         KeyNode = (PCM_KEY_NODE)HvGetCell(Kcb->KeyHive, Kcb->KeyCell);
00553     }
00554 
00555     /* Check if we got the node */
00556     if (!KeyNode)
00557     {
00558         /* We didn't, mark the cached data invalid */
00559         Kcb->ExtFlags |= CM_KCB_INVALID_CACHED_INFO;
00560     }
00561     else
00562     {
00563         /* We have a keynode, update subkey counts */
00564         Kcb->ExtFlags &= ~CM_KCB_INVALID_CACHED_INFO;
00565         Kcb->SubKeyCount = KeyNode->SubKeyCounts[Stable] +
00566                            KeyNode->SubKeyCounts[Volatile];
00567 
00568         /* Release the cell */
00569         HvReleaseCell(Kcb->KeyHive, Kcb->KeyCell);
00570     }
00571 }
00572 
00573 VOID
00574 NTAPI
00575 CmpDereferenceKeyControlBlock(IN PCM_KEY_CONTROL_BLOCK Kcb)
00576 {
00577     LONG OldRefCount, NewRefCount;
00578     ULONG ConvKey;
00579     CMTRACE(CM_REFERENCE_DEBUG,
00580             "%s - Dereferencing KCB: %p\n", __FUNCTION__, Kcb);
00581 
00582     /* Get the ref count and update it */
00583     OldRefCount = *(PLONG)&Kcb->RefCount;
00584     NewRefCount = OldRefCount - 1;
00585 
00586     /* Check if we still have references */
00587     if ((NewRefCount & 0xFFFF) > 0)
00588     {
00589         /* Do the dereference */
00590         if (InterlockedCompareExchange((PLONG)&Kcb->RefCount,
00591                                        NewRefCount,
00592                                        OldRefCount) == OldRefCount)
00593         {
00594             /* We'de done */
00595             return;
00596         }
00597     }
00598 
00599     /* Save the key */
00600     ConvKey = Kcb->ConvKey;
00601 
00602     /* Do the dereference inside the lock */
00603     CmpAcquireKcbLockExclusive(Kcb);
00604     CmpDereferenceKeyControlBlockWithLock(Kcb, FALSE);
00605     CmpReleaseKcbLockByKey(ConvKey);
00606 }
00607 
00608 VOID
00609 NTAPI
00610 CmpDereferenceKeyControlBlockWithLock(IN PCM_KEY_CONTROL_BLOCK Kcb,
00611                                       IN BOOLEAN LockHeldExclusively)
00612 {
00613     CMTRACE(CM_REFERENCE_DEBUG,
00614             "%s - Dereferencing KCB: %p\n", __FUNCTION__, Kcb);
00615 
00616     /* Sanity check */
00617     ASSERT_KCB_VALID(Kcb);
00618 
00619     /* Check if this is the last reference */
00620     if ((InterlockedDecrement((PLONG)&Kcb->RefCount) & 0xFFFF) == 0)
00621     {
00622         /* Sanity check */
00623         ASSERT((CmpIsKcbLockedExclusive(Kcb) == TRUE) ||
00624                (CmpTestRegistryLockExclusive() == TRUE));
00625 
00626         /* Check if we should do a direct delete */
00627         if (((CmpHoldLazyFlush) &&
00628              !(Kcb->ExtFlags & CM_KCB_SYM_LINK_FOUND) &&
00629              !(Kcb->Flags & KEY_SYM_LINK)) ||
00630             (Kcb->ExtFlags & CM_KCB_NO_DELAY_CLOSE) ||
00631             (Kcb->Delete))
00632         {
00633             /* Clean up the KCB*/
00634             CmpCleanUpKcbCacheWithLock(Kcb, LockHeldExclusively);
00635         }
00636         else
00637         {
00638             /* Otherwise, use delayed close */
00639             CmpAddToDelayedClose(Kcb, LockHeldExclusively);
00640         }
00641     }
00642 }
00643 
00644 VOID
00645 NTAPI
00646 InitializeKCBKeyBodyList(IN PCM_KEY_CONTROL_BLOCK Kcb)
00647 {
00648     /* Initialize the list */
00649     InitializeListHead(&Kcb->KeyBodyListHead);
00650 
00651     /* Clear the bodies */
00652     Kcb->KeyBodyArray[0] =
00653     Kcb->KeyBodyArray[1] =
00654     Kcb->KeyBodyArray[2] =
00655     Kcb->KeyBodyArray[3] = NULL;
00656 }
00657 
00658 PCM_KEY_CONTROL_BLOCK
00659 NTAPI
00660 CmpCreateKeyControlBlock(IN PHHIVE Hive,
00661                          IN HCELL_INDEX Index,
00662                          IN PCM_KEY_NODE Node,
00663                          IN PCM_KEY_CONTROL_BLOCK Parent,
00664                          IN ULONG Flags,
00665                          IN PUNICODE_STRING KeyName)
00666 {
00667     PCM_KEY_CONTROL_BLOCK Kcb, FoundKcb = NULL;
00668     UNICODE_STRING NodeName;
00669     ULONG ConvKey = 0, i;
00670     BOOLEAN IsFake, HashLock;
00671     PWCHAR p;
00672 
00673     /* Make sure we own this hive in case it's being unloaded */
00674     if ((Hive->HiveFlags & HIVE_IS_UNLOADING) &&
00675         (((PCMHIVE)Hive)->CreatorOwner != KeGetCurrentThread()))
00676     {
00677         /* Fail */
00678         return NULL;
00679     }
00680 
00681     /* Check if this is a fake KCB */
00682     IsFake = Flags & CMP_CREATE_FAKE_KCB ? TRUE : FALSE;
00683 
00684     /* If we have a parent, use its ConvKey */
00685     if (Parent) ConvKey = Parent->ConvKey;
00686 
00687     /* Make a copy of the name */
00688     NodeName = *KeyName;
00689 
00690     /* Remove leading slash */
00691     while ((NodeName.Length) && (*NodeName.Buffer == OBJ_NAME_PATH_SEPARATOR))
00692     {
00693         /* Move the buffer by one */
00694         NodeName.Buffer++;
00695         NodeName.Length -= sizeof(WCHAR);
00696     }
00697 
00698     /* Make sure we didn't get just a slash or something */
00699     ASSERT(NodeName.Length > 0);
00700 
00701     /* Now setup the hash */
00702     p = NodeName.Buffer;
00703     for (i = 0; i < NodeName.Length; i += sizeof(WCHAR))
00704     {
00705         /* Make sure it's a valid character */
00706         if (*p != OBJ_NAME_PATH_SEPARATOR)
00707         {
00708             /* Add this key to the hash */
00709             ConvKey = 37 * ConvKey + RtlUpcaseUnicodeChar(*p);
00710         }
00711 
00712         /* Move on */
00713         p++;
00714     }
00715 
00716     /* Allocate the KCB */
00717     Kcb = CmpAllocateKeyControlBlock();
00718     if (!Kcb) return NULL;
00719 
00720     /* Initailize the key list */
00721     InitializeKCBKeyBodyList(Kcb);
00722 
00723     /* Set it up */
00724     Kcb->Signature = CM_KCB_SIGNATURE;
00725     Kcb->Delete = FALSE;
00726     Kcb->RefCount = 1;
00727     Kcb->KeyHive = Hive;
00728     Kcb->KeyCell = Index;
00729     Kcb->ConvKey = ConvKey;
00730     Kcb->DelayedCloseIndex = CmpDelayedCloseSize;
00731     Kcb->InDelayClose = 0;
00732     ASSERT_KCB_VALID(Kcb);
00733 
00734     /* Check if we have two hash entires */
00735     HashLock = Flags & CMP_LOCK_HASHES_FOR_KCB ? TRUE : FALSE;
00736     if (!HashLock)
00737     {
00738         /* It's not locked, do we have a parent? */
00739         if (Parent)
00740         {
00741             /* Lock the parent KCB and ourselves */
00742             CmpAcquireTwoKcbLocksExclusiveByKey(ConvKey, Parent->ConvKey);
00743         }
00744         else
00745         {
00746             /* Lock only ourselves */
00747             CmpAcquireKcbLockExclusive(Kcb);
00748         }
00749     }
00750 
00751     /* Check if we already have a KCB */
00752     FoundKcb = CmpInsertKeyHash(&Kcb->KeyHash, IsFake);
00753     if (FoundKcb)
00754     {
00755         /* Sanity check */
00756         ASSERT(!FoundKcb->Delete);
00757         Kcb->Signature = CM_KCB_INVALID_SIGNATURE;
00758 
00759         /* Free the one we allocated and reference this one */
00760         CmpFreeKeyControlBlock(Kcb);
00761         ASSERT_KCB_VALID(FoundKcb);
00762         Kcb = FoundKcb;
00763         if (!CmpReferenceKeyControlBlock(Kcb))
00764         {
00765             /* We got too many handles */
00766             ASSERT(Kcb->RefCount + 1 != 0);
00767             Kcb = NULL;
00768         }
00769         else
00770         {
00771             /* Check if we're not creating a fake one, but it used to be fake */
00772             if ((Kcb->ExtFlags & CM_KCB_KEY_NON_EXIST) && !(IsFake))
00773             {
00774                 /* Set the hive and cell */
00775                 Kcb->KeyHive = Hive;
00776                 Kcb->KeyCell = Index;
00777 
00778                 /* This means that our current information is invalid */
00779                 Kcb->ExtFlags = CM_KCB_INVALID_CACHED_INFO;
00780             }
00781 
00782             /* Check if we didn't have any valid data */
00783             if (!(Kcb->ExtFlags & (CM_KCB_NO_SUBKEY |
00784                                    CM_KCB_SUBKEY_ONE |
00785                                    CM_KCB_SUBKEY_HINT)))
00786             {
00787                 /* Calculate the index hint */
00788                 Kcb->SubKeyCount = Node->SubKeyCounts[Stable] +
00789                                    Node->SubKeyCounts[Volatile];
00790 
00791                 /* Cached information is now valid */
00792                 Kcb->ExtFlags &= ~CM_KCB_INVALID_CACHED_INFO;
00793             }
00794 
00795             /* Setup the other data */
00796             Kcb->KcbLastWriteTime = Node->LastWriteTime;
00797             Kcb->KcbMaxNameLen = (USHORT)Node->MaxNameLen;
00798             Kcb->KcbMaxValueNameLen = (USHORT)Node->MaxValueNameLen;
00799             Kcb->KcbMaxValueDataLen = Node->MaxValueDataLen;
00800         }
00801     }
00802     else
00803     {
00804         /* No KCB, do we have a parent? */
00805         if (Parent)
00806         {
00807             /* Reference the parent */
00808             if (((Parent->TotalLevels + 1) < 512) &&
00809                 (CmpReferenceKeyControlBlock(Parent)))
00810             {
00811                 /* Link it */
00812                 Kcb->ParentKcb = Parent;
00813                 Kcb->TotalLevels = Parent->TotalLevels + 1;
00814             }
00815             else
00816             {
00817                 /* Remove the KCB and free it */
00818                 CmpRemoveKeyControlBlock(Kcb);
00819                 Kcb->Signature = CM_KCB_INVALID_SIGNATURE;
00820                 CmpFreeKeyControlBlock(Kcb);
00821                 Kcb = NULL;
00822             }
00823         }
00824         else
00825         {
00826             /* No parent, this is the root node */
00827             Kcb->ParentKcb = NULL;
00828             Kcb->TotalLevels = 1;
00829         }
00830 
00831         /* Check if we have a KCB */
00832         if (Kcb)
00833         {
00834             /* Get the NCB */
00835             Kcb->NameBlock = CmpGetNameControlBlock(&NodeName);
00836             if (Kcb->NameBlock)
00837             {
00838                 /* Fill it out */
00839                 Kcb->ValueCache.Count = Node->ValueList.Count;
00840                 Kcb->ValueCache.ValueList = Node->ValueList.List;
00841                 Kcb->Flags = Node->Flags;
00842                 Kcb->ExtFlags = 0;
00843                 Kcb->DelayedCloseIndex = CmpDelayedCloseSize;
00844 
00845                 /* Remember if this is a fake key */
00846                 if (IsFake) Kcb->ExtFlags |= CM_KCB_KEY_NON_EXIST;
00847 
00848                 /* Setup the other data */
00849                 Kcb->SubKeyCount = Node->SubKeyCounts[Stable] +
00850                                    Node->SubKeyCounts[Volatile];
00851                 Kcb->KcbLastWriteTime = Node->LastWriteTime;
00852                 Kcb->KcbMaxNameLen = (USHORT)Node->MaxNameLen;
00853                 Kcb->KcbMaxValueNameLen = (USHORT)Node->MaxValueNameLen;
00854                 Kcb->KcbMaxValueDataLen = (USHORT)Node->MaxValueDataLen;
00855             }
00856             else
00857             {
00858                 /* Dereference the KCB */
00859                 CmpDereferenceKeyControlBlockWithLock(Parent, FALSE);
00860 
00861                 /* Remove the KCB and free it */
00862                 CmpRemoveKeyControlBlock(Kcb);
00863                 Kcb->Signature = CM_KCB_INVALID_SIGNATURE;
00864                 CmpFreeKeyControlBlock(Kcb);
00865                 Kcb = NULL;
00866             }
00867         }
00868     }
00869 
00870     /* Check if this is a KCB inside a frozen hive */
00871     if ((Kcb) && (((PCMHIVE)Hive)->Frozen) && (!(Kcb->Flags & KEY_SYM_LINK)))
00872     {
00873         /* Don't add these to the delay close */
00874         Kcb->ExtFlags |= CM_KCB_NO_DELAY_CLOSE;
00875     }
00876 
00877     /* Sanity check */
00878     ASSERT((!Kcb) || (Kcb->Delete == FALSE));
00879 
00880     /* Check if we had locked the hashes */
00881     if (!HashLock)
00882     {
00883         /* We locked them manually, do we have a parent? */
00884         if (Parent)
00885         {
00886             /* Unlock the parent KCB and ourselves */
00887             CmpReleaseTwoKcbLockByKey(ConvKey, Parent->ConvKey);
00888         }
00889         else
00890         {
00891             /* Unlock only ourselves */
00892             CmpReleaseKcbLockByKey(ConvKey);
00893         }
00894     }
00895 
00896     /* Return the KCB */
00897     return Kcb;
00898 }
00899 
00900 PUNICODE_STRING
00901 NTAPI
00902 CmpConstructName(IN PCM_KEY_CONTROL_BLOCK Kcb)
00903 {
00904     PUNICODE_STRING KeyName;
00905     ULONG i;
00906     USHORT NameLength;
00907     PCM_KEY_CONTROL_BLOCK MyKcb;
00908     PCM_KEY_NODE KeyNode;
00909     BOOLEAN DeletedKey = FALSE;
00910     PWCHAR TargetBuffer, CurrentNameW;
00911     PUCHAR CurrentName;
00912 
00913     /* Calculate how much size our key name is going to occupy */
00914     NameLength = 0;
00915     MyKcb = Kcb;
00916 
00917     while (MyKcb)
00918     {
00919         /* Add length of the name */
00920         if (!MyKcb->NameBlock->Compressed)
00921         {
00922             NameLength += MyKcb->NameBlock->NameLength;
00923         }
00924         else
00925         {
00926             NameLength += CmpCompressedNameSize(MyKcb->NameBlock->Name,
00927                                                 MyKcb->NameBlock->NameLength);
00928         }
00929 
00930         /* Sum up the separator too */
00931         NameLength += sizeof(WCHAR);
00932 
00933         /* Go to the parent KCB */
00934         MyKcb = MyKcb->ParentKcb;
00935     }
00936 
00937     /* Allocate the unicode string now */
00938     KeyName = CmpAllocate(NameLength + sizeof(UNICODE_STRING),
00939                           TRUE,
00940                           TAG_CM);
00941 
00942     if (!KeyName) return NULL;
00943 
00944     /* Set it up */
00945     KeyName->Buffer = (PWSTR)(KeyName + 1);
00946     KeyName->Length = NameLength;
00947     KeyName->MaximumLength = NameLength;
00948 
00949     /* Loop the keys again, now adding names */
00950     NameLength = 0;
00951     MyKcb = Kcb;
00952 
00953     while (MyKcb)
00954     {
00955         /* Sanity checks for deleted and fake keys */
00956         if ((!MyKcb->KeyCell && !MyKcb->Delete) ||
00957             !MyKcb->KeyHive ||
00958             MyKcb->ExtFlags & CM_KCB_KEY_NON_EXIST)
00959         {
00960             /* Failure */
00961             CmpFree(KeyName, 0);
00962             return NULL;
00963         }
00964 
00965         /* Try to get the name from the keynode,
00966            if the key is not deleted */
00967         if (!DeletedKey && !MyKcb->Delete)
00968         {
00969             KeyNode = HvGetCell(MyKcb->KeyHive, MyKcb->KeyCell);
00970 
00971             if (!KeyNode)
00972             {
00973                 /* Failure */
00974                 CmpFree(KeyName, 0);
00975                 return NULL;
00976             }
00977         }
00978         else
00979         {
00980             /* The key was deleted */
00981             KeyNode = NULL;
00982             DeletedKey = TRUE;
00983         }
00984 
00985         /* Get the pointer to the beginning of the current key name */
00986         NameLength += (MyKcb->NameBlock->NameLength + 1) * sizeof(WCHAR);
00987         TargetBuffer = &KeyName->Buffer[(KeyName->Length - NameLength) / sizeof(WCHAR)];
00988 
00989         /* Add a separator */
00990         TargetBuffer[0] = OBJ_NAME_PATH_SEPARATOR;
00991 
00992         /* Add the name, but remember to go from the end to the beginning */
00993         if (!MyKcb->NameBlock->Compressed)
00994         {
00995             /* Get the pointer to the name (from the keynode, if possible) */
00996             if ((MyKcb->Flags & (KEY_HIVE_ENTRY | KEY_HIVE_EXIT)) ||
00997                 !KeyNode)
00998             {
00999                 CurrentNameW = MyKcb->NameBlock->Name;
01000             }
01001             else
01002             {
01003                 CurrentNameW = KeyNode->Name;
01004             }
01005 
01006             /* Copy the name */
01007             for (i=0; i < MyKcb->NameBlock->NameLength; i++)
01008             {
01009                 TargetBuffer[i+1] = *CurrentNameW;
01010                 CurrentNameW++;
01011             }
01012         }
01013         else
01014         {
01015             /* Get the pointer to the name (from the keynode, if possible) */
01016             if ((MyKcb->Flags & (KEY_HIVE_ENTRY | KEY_HIVE_EXIT)) ||
01017                 !KeyNode)
01018             {
01019                 CurrentName = (PUCHAR)MyKcb->NameBlock->Name;
01020             }
01021             else
01022             {
01023                 CurrentName = (PUCHAR)KeyNode->Name;
01024             }
01025 
01026             /* Copy the name */
01027             for (i=0; i < MyKcb->NameBlock->NameLength; i++)
01028             {
01029                 TargetBuffer[i+1] = (WCHAR)*CurrentName;
01030                 CurrentName++;
01031             }
01032         }
01033 
01034         /* Release the cell, if needed */
01035         if (KeyNode) HvReleaseCell(MyKcb->KeyHive, MyKcb->KeyCell);
01036 
01037         /* Go to the parent KCB */
01038         MyKcb = MyKcb->ParentKcb;
01039     }
01040 
01041     /* Return resulting buffer (both UNICODE_STRING and
01042        its buffer following it) */
01043     return KeyName;
01044 }
01045 
01046 VOID
01047 NTAPI
01048 EnlistKeyBodyWithKCB(IN PCM_KEY_BODY KeyBody,
01049                      IN ULONG Flags)
01050 {
01051     ULONG i;
01052 
01053     /* Sanity check */
01054     ASSERT(KeyBody->KeyControlBlock != NULL);
01055     
01056     /* Initialize the list entry */
01057     InitializeListHead(&KeyBody->KeyBodyList);
01058 
01059     /* Check if we can use the parent KCB array */
01060     for (i = 0; i < 4; i++)
01061     {
01062         /* Add it into the list */
01063         if (!InterlockedCompareExchangePointer((PVOID*)&KeyBody->KeyControlBlock->
01064                                                KeyBodyArray[i],
01065                                                KeyBody,
01066                                                NULL))
01067         {
01068             /* Added */
01069             return;
01070         }
01071     }
01072     
01073     /* Array full, check if we need to unlock the KCB */
01074     if (Flags & CMP_ENLIST_KCB_LOCKED_SHARED)
01075     {
01076         /* It's shared, so release the KCB shared lock */
01077         CmpReleaseKcbLock(KeyBody->KeyControlBlock);
01078         ASSERT(!(Flags & CMP_ENLIST_KCB_LOCKED_EXCLUSIVE));
01079     }
01080 
01081     /* Check if we need to lock the KCB */
01082     if (!(Flags & CMP_ENLIST_KCB_LOCKED_EXCLUSIVE))
01083     {
01084         /* Acquire the lock */
01085         CmpAcquireKcbLockExclusive(KeyBody->KeyControlBlock);
01086     }
01087 
01088     /* Make sure we have the exclusive lock */
01089     ASSERT((CmpIsKcbLockedExclusive(KeyBody->KeyControlBlock) == TRUE) ||
01090            (CmpTestRegistryLockExclusive() == TRUE));
01091 
01092     /* do the insert */
01093     InsertTailList(&KeyBody->KeyControlBlock->KeyBodyListHead,
01094                    &KeyBody->KeyBodyList);
01095 
01096     /* Check if we did a manual lock */
01097     if (!(Flags & (CMP_ENLIST_KCB_LOCKED_SHARED |
01098                    CMP_ENLIST_KCB_LOCKED_EXCLUSIVE)))
01099     {
01100         /* Release the lock */
01101         CmpReleaseKcbLock(KeyBody->KeyControlBlock);
01102     }
01103 }
01104 
01105 VOID
01106 NTAPI
01107 DelistKeyBodyFromKCB(IN PCM_KEY_BODY KeyBody,
01108                      IN BOOLEAN LockHeld)
01109 {
01110     ULONG i;
01111 
01112     /* Sanity check */
01113     ASSERT(KeyBody->KeyControlBlock != NULL);
01114 
01115     /* Check if we can use the parent KCB array */
01116     for (i = 0; i < 4; i++)
01117     {
01118         /* Add it into the list */
01119         if (InterlockedCompareExchangePointer((VOID*)&KeyBody->KeyControlBlock->
01120                                               KeyBodyArray[i],
01121                                               NULL,
01122                                               KeyBody) == KeyBody)
01123         {
01124             /* Removed */
01125             return;
01126         }
01127     }
01128 
01129     /* Sanity checks */
01130     ASSERT(IsListEmpty(&KeyBody->KeyControlBlock->KeyBodyListHead) == FALSE);
01131     ASSERT(IsListEmpty(&KeyBody->KeyBodyList) == FALSE);
01132     
01133     /* Lock the KCB */
01134     if (!LockHeld) CmpAcquireKcbLockExclusive(KeyBody->KeyControlBlock);
01135     ASSERT((CmpIsKcbLockedExclusive(KeyBody->KeyControlBlock) == TRUE) ||
01136            (CmpTestRegistryLockExclusive() == TRUE));
01137     
01138     /* Remove the entry */
01139     RemoveEntryList(&KeyBody->KeyBodyList);
01140 
01141     /* Unlock it it if we did a manual lock */
01142     if (!LockHeld) CmpReleaseKcbLock(KeyBody->KeyControlBlock);
01143 }
01144 
01145 VOID
01146 NTAPI
01147 CmpFlushNotifiesOnKeyBodyList(IN PCM_KEY_CONTROL_BLOCK Kcb,
01148                               IN BOOLEAN LockHeld)
01149 {
01150     PLIST_ENTRY NextEntry, ListHead;
01151     PCM_KEY_BODY KeyBody;
01152 
01153     /* Sanity check */
01154     LockHeld ? CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK() : CmpIsKcbLockedExclusive(Kcb);
01155     while (TRUE)
01156     {
01157         /* Is the list empty? */
01158         ListHead = &Kcb->KeyBodyListHead;
01159         if (!IsListEmpty(ListHead))
01160         {
01161             /* Loop the list */
01162             NextEntry = ListHead->Flink;
01163             while (NextEntry != ListHead)
01164             {
01165                 /* Get the key body */
01166                 KeyBody = CONTAINING_RECORD(NextEntry, CM_KEY_BODY, KeyBodyList);
01167                 ASSERT(KeyBody->Type == '20yk');
01168 
01169                 /* Check for notifications */
01170                 if (KeyBody->NotifyBlock)
01171                 {
01172                     /* Is the lock held? */
01173                     if (LockHeld)
01174                     {
01175                         /* Flush it */
01176                         CmpFlushNotify(KeyBody, LockHeld);
01177                         ASSERT(KeyBody->NotifyBlock == NULL);
01178                         continue;
01179                     }
01180                     
01181                     /* Lock isn't held, so we need to take a reference */
01182                     if (ObReferenceObjectSafe(KeyBody))
01183                     {
01184                         /* Now we can flush */
01185                         CmpFlushNotify(KeyBody, LockHeld);
01186                         ASSERT(KeyBody->NotifyBlock == NULL);
01187                         
01188                         /* Release the reference we took */
01189                         ObDereferenceObjectDeferDelete(KeyBody);
01190                         continue;
01191                     }
01192                 }
01193 
01194                 /* Try the next entry */
01195                 NextEntry = NextEntry->Flink;
01196             }
01197         }
01198         
01199         /* List has been parsed, exit */
01200         break;
01201     }
01202 }

Generated on Sun May 27 2012 04:37:07 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.