Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygencmkcbncb.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
1.7.6.1
|