Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygencmvalche.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/cmvalche.c 00005 * PURPOSE: Configuration Manager - Value Cell Cache 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 FORCEINLINE 00016 BOOLEAN 00017 CmpIsValueCached(IN HCELL_INDEX CellIndex) 00018 { 00019 /* Make sure that the cell is valid in the first place */ 00020 if (CellIndex == HCELL_NIL) return FALSE; 00021 00022 /*Is this cell actually a pointer to the cached value data? */ 00023 if (CellIndex & 1) return TRUE; 00024 00025 /* This is a regular cell */ 00026 return FALSE; 00027 } 00028 00029 FORCEINLINE 00030 VOID 00031 CmpSetValueCached(IN PHCELL_INDEX CellIndex) 00032 { 00033 /* Set the cached bit */ 00034 *CellIndex |= 1; 00035 } 00036 00037 #define ASSERT_VALUE_CACHE() \ 00038 ASSERTMSG("Cached Values Not Yet Supported!", FALSE); 00039 00040 /* FUNCTIONS *****************************************************************/ 00041 00042 VALUE_SEARCH_RETURN_TYPE 00043 NTAPI 00044 CmpGetValueListFromCache(IN PCM_KEY_CONTROL_BLOCK Kcb, 00045 OUT PCELL_DATA *CellData, 00046 OUT BOOLEAN *IndexIsCached, 00047 OUT PHCELL_INDEX ValueListToRelease) 00048 { 00049 PHHIVE Hive; 00050 PCACHED_CHILD_LIST ChildList; 00051 HCELL_INDEX CellToRelease; 00052 00053 /* Set defaults */ 00054 *ValueListToRelease = HCELL_NIL; 00055 *IndexIsCached = FALSE; 00056 00057 /* Get the hive and value cache */ 00058 Hive = Kcb->KeyHive; 00059 ChildList = &Kcb->ValueCache; 00060 00061 /* Check if the value is cached */ 00062 if (CmpIsValueCached(ChildList->ValueList)) 00063 { 00064 /* It is: we don't expect this yet! */ 00065 ASSERT_VALUE_CACHE(); 00066 *IndexIsCached = TRUE; 00067 *CellData = NULL; 00068 } 00069 else 00070 { 00071 /* Make sure the KCB is locked exclusive */ 00072 if (!(CmpIsKcbLockedExclusive(Kcb)) && 00073 !(CmpTryToConvertKcbSharedToExclusive(Kcb))) 00074 { 00075 /* We need the exclusive lock */ 00076 return SearchNeedExclusiveLock; 00077 } 00078 00079 /* Select the value list as our cell, and get the actual list array */ 00080 CellToRelease = ChildList->ValueList; 00081 *CellData = (PCELL_DATA)HvGetCell(Hive, CellToRelease); 00082 if (!(*CellData)) return SearchFail; 00083 00084 /* FIXME: Here we would cache the value */ 00085 00086 /* Return the cell to be released */ 00087 *ValueListToRelease = CellToRelease; 00088 } 00089 00090 /* If we got here, then the value list was found */ 00091 return SearchSuccess; 00092 } 00093 00094 VALUE_SEARCH_RETURN_TYPE 00095 NTAPI 00096 CmpGetValueKeyFromCache(IN PCM_KEY_CONTROL_BLOCK Kcb, 00097 IN PCELL_DATA CellData, 00098 IN ULONG Index, 00099 OUT PCM_CACHED_VALUE **CachedValue, 00100 OUT PCM_KEY_VALUE *Value, 00101 IN BOOLEAN IndexIsCached, 00102 OUT BOOLEAN *ValueIsCached, 00103 OUT PHCELL_INDEX CellToRelease) 00104 { 00105 PHHIVE Hive; 00106 PCM_KEY_VALUE KeyValue; 00107 HCELL_INDEX Cell; 00108 00109 /* Set defaults */ 00110 *CellToRelease = HCELL_NIL; 00111 *Value = NULL; 00112 *ValueIsCached = FALSE; 00113 00114 /* Get the hive */ 00115 Hive = Kcb->KeyHive; 00116 00117 /* Check if the index was cached */ 00118 if (IndexIsCached) 00119 { 00120 /* Not expected yet! */ 00121 ASSERT_VALUE_CACHE(); 00122 *ValueIsCached = TRUE; 00123 } 00124 else 00125 { 00126 /* Get the cell index and the key value associated to it */ 00127 Cell = CellData->u.KeyList[Index]; 00128 KeyValue = (PCM_KEY_VALUE)HvGetCell(Hive, Cell); 00129 if (!KeyValue) return SearchFail; 00130 00131 /* Return the cell and the actual key value */ 00132 *CellToRelease = Cell; 00133 *Value = KeyValue; 00134 } 00135 00136 /* If we got here, then we found the key value */ 00137 return SearchSuccess; 00138 } 00139 00140 VALUE_SEARCH_RETURN_TYPE 00141 NTAPI 00142 CmpGetValueDataFromCache(IN PCM_KEY_CONTROL_BLOCK Kcb, 00143 IN PCM_CACHED_VALUE *CachedValue, 00144 IN PCELL_DATA ValueKey, 00145 IN BOOLEAN ValueIsCached, 00146 OUT PVOID *DataPointer, 00147 OUT PBOOLEAN Allocated, 00148 OUT PHCELL_INDEX CellToRelease) 00149 { 00150 PHHIVE Hive; 00151 ULONG Length; 00152 00153 /* Sanity checks */ 00154 ASSERT(MAXIMUM_CACHED_DATA < CM_KEY_VALUE_BIG); 00155 ASSERT((ValueKey->u.KeyValue.DataLength & CM_KEY_VALUE_SPECIAL_SIZE) == 0); 00156 00157 /* Set defaults */ 00158 *DataPointer = NULL; 00159 *Allocated = FALSE; 00160 *CellToRelease = HCELL_NIL; 00161 00162 /* Get the hive */ 00163 Hive = Kcb->KeyHive; 00164 00165 /* Check it the value is cached */ 00166 if (ValueIsCached) 00167 { 00168 /* This isn't expected! */ 00169 ASSERT_VALUE_CACHE(); 00170 } 00171 else 00172 { 00173 /* It's not, get the value data using the typical routine */ 00174 if (!CmpGetValueData(Hive, 00175 &ValueKey->u.KeyValue, 00176 &Length, 00177 DataPointer, 00178 Allocated, 00179 CellToRelease)) 00180 { 00181 /* Nothing found: make sure no data was allocated */ 00182 ASSERT(*Allocated == FALSE); 00183 ASSERT(*DataPointer == NULL); 00184 return SearchFail; 00185 } 00186 } 00187 00188 /* We found the actual data, return success */ 00189 return SearchSuccess; 00190 } 00191 00192 VALUE_SEARCH_RETURN_TYPE 00193 NTAPI 00194 CmpFindValueByNameFromCache(IN PCM_KEY_CONTROL_BLOCK Kcb, 00195 IN PCUNICODE_STRING Name, 00196 OUT PCM_CACHED_VALUE **CachedValue, 00197 OUT ULONG *Index, 00198 OUT PCM_KEY_VALUE *Value, 00199 OUT BOOLEAN *ValueIsCached, 00200 OUT PHCELL_INDEX CellToRelease) 00201 { 00202 PHHIVE Hive; 00203 VALUE_SEARCH_RETURN_TYPE SearchResult = SearchFail; 00204 LONG Result; 00205 UNICODE_STRING SearchName; 00206 PCELL_DATA CellData; 00207 PCACHED_CHILD_LIST ChildList; 00208 PCM_KEY_VALUE KeyValue; 00209 BOOLEAN IndexIsCached; 00210 ULONG i = 0; 00211 HCELL_INDEX Cell = HCELL_NIL; 00212 00213 /* Set defaults */ 00214 *CellToRelease = HCELL_NIL; 00215 *Value = NULL; 00216 00217 /* Get the hive and child list */ 00218 Hive = Kcb->KeyHive; 00219 ChildList = &Kcb->ValueCache; 00220 00221 /* Check if the child list has any entries */ 00222 if (ChildList->Count != 0) 00223 { 00224 /* Get the value list associated to this child list */ 00225 SearchResult = CmpGetValueListFromCache(Kcb, 00226 &CellData, 00227 &IndexIsCached, 00228 &Cell); 00229 if (SearchResult != SearchSuccess) 00230 { 00231 /* We either failed or need the exclusive lock */ 00232 ASSERT((SearchResult == SearchFail) || !(CmpIsKcbLockedExclusive(Kcb))); 00233 ASSERT(Cell == HCELL_NIL); 00234 return SearchResult; 00235 } 00236 00237 /* The index shouldn't be cached right now */ 00238 if (IndexIsCached) ASSERT_VALUE_CACHE(); 00239 00240 /* Loop every value */ 00241 while (TRUE) 00242 { 00243 /* Check if there's any cell to release */ 00244 if (*CellToRelease != HCELL_NIL) 00245 { 00246 /* Release it now */ 00247 HvReleaseCell(Hive, *CellToRelease); 00248 *CellToRelease = HCELL_NIL; 00249 } 00250 00251 /* Get the key value for this index */ 00252 SearchResult = CmpGetValueKeyFromCache(Kcb, 00253 CellData, 00254 i, 00255 CachedValue, 00256 Value, 00257 IndexIsCached, 00258 ValueIsCached, 00259 CellToRelease); 00260 if (SearchResult != SearchSuccess) 00261 { 00262 /* We either failed or need the exclusive lock */ 00263 ASSERT((SearchResult == SearchFail) || !(CmpIsKcbLockedExclusive(Kcb))); 00264 ASSERT(Cell == HCELL_NIL); 00265 return SearchResult; 00266 } 00267 00268 /* Check if the both the index and the value are cached */ 00269 if ((IndexIsCached) && (*ValueIsCached)) 00270 { 00271 /* We don't expect this yet */ 00272 ASSERT_VALUE_CACHE(); 00273 Result = -1; 00274 } 00275 else 00276 { 00277 /* No cache, so try to compare the name. Is it compressed? */ 00278 KeyValue = *Value; 00279 if (KeyValue->Flags & VALUE_COMP_NAME) 00280 { 00281 /* It is, do a compressed name comparison */ 00282 Result = CmpCompareCompressedName(Name, 00283 KeyValue->Name, 00284 KeyValue->NameLength); 00285 } 00286 else 00287 { 00288 /* It's not compressed, so do a standard comparison */ 00289 SearchName.Length = KeyValue->NameLength; 00290 SearchName.MaximumLength = SearchName.Length; 00291 SearchName.Buffer = KeyValue->Name; 00292 Result = RtlCompareUnicodeString(Name, &SearchName, TRUE); 00293 } 00294 } 00295 00296 /* Check if we found the value data */ 00297 if (!Result) 00298 { 00299 /* We have, return the index of the value and success */ 00300 *Index = i; 00301 SearchResult = SearchSuccess; 00302 goto Quickie; 00303 } 00304 00305 /* We didn't find it, try the next entry */ 00306 if (++i == ChildList->Count) 00307 { 00308 /* The entire list was parsed, fail */ 00309 *Value = NULL; 00310 SearchResult = SearchFail; 00311 goto Quickie; 00312 } 00313 } 00314 } 00315 00316 /* We should only get here if the child list is empty */ 00317 ASSERT(ChildList->Count == 0); 00318 00319 Quickie: 00320 /* Release the value list cell if required, and return search result */ 00321 if (Cell != HCELL_NIL) HvReleaseCell(Hive, Cell); 00322 return SearchResult; 00323 } 00324 00325 VALUE_SEARCH_RETURN_TYPE 00326 NTAPI 00327 CmpQueryKeyValueData(IN PCM_KEY_CONTROL_BLOCK Kcb, 00328 IN PCM_CACHED_VALUE *CachedValue, 00329 IN PCM_KEY_VALUE ValueKey, 00330 IN BOOLEAN ValueIsCached, 00331 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, 00332 IN PVOID KeyValueInformation, 00333 IN ULONG Length, 00334 OUT PULONG ResultLength, 00335 OUT PNTSTATUS Status) 00336 { 00337 PKEY_VALUE_INFORMATION Info = (PKEY_VALUE_INFORMATION)KeyValueInformation; 00338 PCELL_DATA CellData; 00339 USHORT NameSize; 00340 ULONG Size, MinimumSize, SizeLeft, KeySize, AlignedData = 0, DataOffset; 00341 PVOID Buffer; 00342 BOOLEAN IsSmall, BufferAllocated = FALSE; 00343 HCELL_INDEX CellToRelease = HCELL_NIL; 00344 VALUE_SEARCH_RETURN_TYPE Result = SearchSuccess; 00345 00346 /* Get the value data */ 00347 CellData = (PCELL_DATA)ValueKey; 00348 00349 /* Check if the value is compressed */ 00350 if (CellData->u.KeyValue.Flags & VALUE_COMP_NAME) 00351 { 00352 /* Get the compressed name size */ 00353 NameSize = CmpCompressedNameSize(CellData->u.KeyValue.Name, 00354 CellData->u.KeyValue.NameLength); 00355 } 00356 else 00357 { 00358 /* Get the real size */ 00359 NameSize = CellData->u.KeyValue.NameLength; 00360 } 00361 00362 /* Check what kind of information the caller is requesting */ 00363 switch (KeyValueInformationClass) 00364 { 00365 /* Basic information */ 00366 case KeyValueBasicInformation: 00367 00368 /* This is how much size we'll need */ 00369 Size = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name) + NameSize; 00370 00371 /* This is the minimum we can work with */ 00372 MinimumSize = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name); 00373 00374 /* Return the size we'd like, and assume success */ 00375 *ResultLength = Size; 00376 *Status = STATUS_SUCCESS; 00377 00378 /* Check if the caller gave us below our minimum */ 00379 if (Length < MinimumSize) 00380 { 00381 /* Then we must fail */ 00382 *Status = STATUS_BUFFER_TOO_SMALL; 00383 break; 00384 } 00385 00386 /* Fill out the basic information */ 00387 Info->KeyValueBasicInformation.TitleIndex = 0; 00388 Info->KeyValueBasicInformation.Type = CellData->u.KeyValue.Type; 00389 Info->KeyValueBasicInformation.NameLength = NameSize; 00390 00391 /* Now only the name is left */ 00392 SizeLeft = Length - MinimumSize; 00393 Size = NameSize; 00394 00395 /* Check if the remaining buffer is too small for the name */ 00396 if (SizeLeft < Size) 00397 { 00398 /* Copy only as much as can fit, and tell the caller */ 00399 Size = SizeLeft; 00400 *Status = STATUS_BUFFER_OVERFLOW; 00401 } 00402 00403 /* Check if this is a compressed name */ 00404 if (CellData->u.KeyValue.Flags & VALUE_COMP_NAME) 00405 { 00406 /* Copy as much as we can of the compressed name */ 00407 CmpCopyCompressedName(Info->KeyValueBasicInformation.Name, 00408 Size, 00409 CellData->u.KeyValue.Name, 00410 CellData->u.KeyValue.NameLength); 00411 } 00412 else 00413 { 00414 /* Copy as much as we can of the raw name */ 00415 RtlCopyMemory(Info->KeyValueBasicInformation.Name, 00416 CellData->u.KeyValue.Name, 00417 Size); 00418 } 00419 00420 /* We're all done */ 00421 break; 00422 00423 /* Full key information */ 00424 case KeyValueFullInformation: 00425 case KeyValueFullInformationAlign64: 00426 00427 /* Check if this is a small key and compute key size */ 00428 IsSmall = CmpIsKeyValueSmall(&KeySize, 00429 CellData->u.KeyValue.DataLength); 00430 00431 /* Calculate the total size required */ 00432 Size = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name) + 00433 NameSize + 00434 KeySize; 00435 00436 /* And this is the least we can work with */ 00437 MinimumSize = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name); 00438 00439 /* Check if there's any key data */ 00440 if (KeySize > 0) 00441 { 00442 /* Calculate the data offset */ 00443 DataOffset = Size - KeySize; 00444 00445 #ifdef _WIN64 00446 /* On 64-bit, always align to 8 bytes */ 00447 AlignedData = ALIGN_UP(DataOffset, ULONGLONG); 00448 #else 00449 /* On 32-bit, align the offset to 4 or 8 bytes */ 00450 if (KeyValueInformationClass == KeyValueFullInformationAlign64) 00451 { 00452 AlignedData = ALIGN_UP(DataOffset, ULONGLONG); 00453 } 00454 else 00455 { 00456 AlignedData = ALIGN_UP(DataOffset, ULONG); 00457 } 00458 #endif 00459 /* If alignment was required, we'll need more space */ 00460 if (AlignedData > DataOffset) Size += (AlignedData-DataOffset); 00461 } 00462 00463 /* Tell the caller the size we'll finally need, and set success */ 00464 *ResultLength = Size; 00465 *Status = STATUS_SUCCESS; 00466 00467 /* Check if the caller is giving us too little */ 00468 if (Length < MinimumSize) 00469 { 00470 /* Then fail right now */ 00471 *Status = STATUS_BUFFER_TOO_SMALL; 00472 break; 00473 } 00474 00475 /* Fill out the basic information */ 00476 Info->KeyValueFullInformation.TitleIndex = 0; 00477 Info->KeyValueFullInformation.Type = CellData->u.KeyValue.Type; 00478 Info->KeyValueFullInformation.DataLength = KeySize; 00479 Info->KeyValueFullInformation.NameLength = NameSize; 00480 00481 /* Only the name is left now */ 00482 SizeLeft = Length - MinimumSize; 00483 Size = NameSize; 00484 00485 /* Check if the name fits */ 00486 if (SizeLeft < Size) 00487 { 00488 /* It doesn't, truncate what we'll copy, and tell the caller */ 00489 Size = SizeLeft; 00490 *Status = STATUS_BUFFER_OVERFLOW; 00491 } 00492 00493 /* Check if this key value is compressed */ 00494 if (CellData->u.KeyValue.Flags & VALUE_COMP_NAME) 00495 { 00496 /* It is, copy the compressed name */ 00497 CmpCopyCompressedName(Info->KeyValueFullInformation.Name, 00498 Size, 00499 CellData->u.KeyValue.Name, 00500 CellData->u.KeyValue.NameLength); 00501 } 00502 else 00503 { 00504 /* It's not, copy the raw name */ 00505 RtlCopyMemory(Info->KeyValueFullInformation.Name, 00506 CellData->u.KeyValue.Name, 00507 Size); 00508 } 00509 00510 /* Now check if the key had any data */ 00511 if (KeySize > 0) 00512 { 00513 /* Was it a small key? */ 00514 if (IsSmall) 00515 { 00516 /* Then the data is directly into the cell */ 00517 Buffer = &CellData->u.KeyValue.Data; 00518 } 00519 else 00520 { 00521 /* Otherwise, we must retrieve it from the value cache */ 00522 Result = CmpGetValueDataFromCache(Kcb, 00523 CachedValue, 00524 CellData, 00525 ValueIsCached, 00526 &Buffer, 00527 &BufferAllocated, 00528 &CellToRelease); 00529 if (Result != SearchSuccess) 00530 { 00531 /* We failed, nothing should be allocated */ 00532 ASSERT(Buffer == NULL); 00533 ASSERT(BufferAllocated == FALSE); 00534 *Status = STATUS_INSUFFICIENT_RESOURCES; 00535 } 00536 } 00537 00538 /* Now that we know we truly have data, set its offset */ 00539 Info->KeyValueFullInformation.DataOffset = AlignedData; 00540 00541 /* Only the data remains to be copied */ 00542 SizeLeft = (((LONG)Length - (LONG)AlignedData) < 0) ? 00543 0 : (Length - AlignedData); 00544 Size = KeySize; 00545 00546 /* Check if the caller has no space for it */ 00547 if (SizeLeft < Size) 00548 { 00549 /* Truncate what we'll copy, and tell the caller */ 00550 Size = SizeLeft; 00551 *Status = STATUS_BUFFER_OVERFLOW; 00552 } 00553 00554 /* Sanity check */ 00555 ASSERT((IsSmall ? (Size <= CM_KEY_VALUE_SMALL) : TRUE)); 00556 00557 /* Make sure we have a valid buffer */ 00558 if (Buffer) 00559 { 00560 /* Copy the data into the aligned offset */ 00561 RtlCopyMemory((PVOID)((ULONG_PTR)Info + AlignedData), 00562 Buffer, 00563 Size); 00564 } 00565 } 00566 else 00567 { 00568 /* We don't have any data, set the offset to -1, not 0! */ 00569 Info->KeyValueFullInformation.DataOffset = 0xFFFFFFFF; 00570 } 00571 00572 /* We're done! */ 00573 break; 00574 00575 /* Partial information requested (no name or alignment!) */ 00576 case KeyValuePartialInformation: 00577 00578 /* Check if this is a small key and compute key size */ 00579 IsSmall = CmpIsKeyValueSmall(&KeySize, 00580 CellData->u.KeyValue.DataLength); 00581 00582 /* Calculate the total size required */ 00583 Size = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + KeySize; 00584 00585 /* And this is the least we can work with */ 00586 MinimumSize = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data); 00587 00588 /* Tell the caller the size we'll finally need, and set success */ 00589 *ResultLength = Size; 00590 *Status = STATUS_SUCCESS; 00591 00592 /* Check if the caller is giving us too little */ 00593 if (Length < MinimumSize) 00594 { 00595 /* Then fail right now */ 00596 *Status = STATUS_BUFFER_TOO_SMALL; 00597 break; 00598 } 00599 00600 /* Fill out the basic information */ 00601 Info->KeyValuePartialInformation.TitleIndex = 0; 00602 Info->KeyValuePartialInformation.Type = CellData->u.KeyValue.Type; 00603 Info->KeyValuePartialInformation.DataLength = KeySize; 00604 00605 /* Now check if the key had any data */ 00606 if (KeySize > 0) 00607 { 00608 /* Was it a small key? */ 00609 if (IsSmall) 00610 { 00611 /* Then the data is directly into the cell */ 00612 Buffer = &CellData->u.KeyValue.Data; 00613 } 00614 else 00615 { 00616 /* Otherwise, we must retrieve it from the value cache */ 00617 Result = CmpGetValueDataFromCache(Kcb, 00618 CachedValue, 00619 CellData, 00620 ValueIsCached, 00621 &Buffer, 00622 &BufferAllocated, 00623 &CellToRelease); 00624 if (Result != SearchSuccess) 00625 { 00626 /* We failed, nothing should be allocated */ 00627 ASSERT(Buffer == NULL); 00628 ASSERT(BufferAllocated == FALSE); 00629 *Status = STATUS_INSUFFICIENT_RESOURCES; 00630 } 00631 } 00632 00633 /* Only the data remains to be copied */ 00634 SizeLeft = Length - MinimumSize; 00635 Size = KeySize; 00636 00637 /* Check if the caller has no space for it */ 00638 if (SizeLeft < Size) 00639 { 00640 /* Truncate what we'll copy, and tell the caller */ 00641 Size = SizeLeft; 00642 *Status = STATUS_BUFFER_OVERFLOW; 00643 } 00644 00645 /* Sanity check */ 00646 ASSERT((IsSmall ? (Size <= CM_KEY_VALUE_SMALL) : TRUE)); 00647 00648 /* Make sure we have a valid buffer */ 00649 if (Buffer) 00650 { 00651 /* Copy the data into the aligned offset */ 00652 RtlCopyMemory(Info->KeyValuePartialInformation.Data, 00653 Buffer, 00654 Size); 00655 } 00656 } 00657 00658 /* We're done! */ 00659 break; 00660 00661 /* Other information class */ 00662 default: 00663 00664 /* We got some class that we don't support */ 00665 DPRINT1("Caller requested unknown class: %lx\n", KeyValueInformationClass); 00666 *Status = STATUS_INVALID_PARAMETER; 00667 break; 00668 } 00669 00670 /* Return the search result as well */ 00671 return Result; 00672 } 00673 00674 VALUE_SEARCH_RETURN_TYPE 00675 NTAPI 00676 CmpCompareNewValueDataAgainstKCBCache(IN PCM_KEY_CONTROL_BLOCK Kcb, 00677 IN PUNICODE_STRING ValueName, 00678 IN ULONG Type, 00679 IN PVOID Data, 00680 IN ULONG DataSize) 00681 { 00682 VALUE_SEARCH_RETURN_TYPE SearchResult; 00683 PCM_KEY_NODE KeyNode; 00684 PCM_CACHED_VALUE *CachedValue; 00685 ULONG Index; 00686 PCM_KEY_VALUE Value; 00687 BOOLEAN ValueCached, BufferAllocated = FALSE; 00688 PVOID Buffer; 00689 HCELL_INDEX ValueCellToRelease = HCELL_NIL, CellToRelease = HCELL_NIL; 00690 BOOLEAN IsSmall; 00691 ULONG_PTR CompareResult; 00692 PAGED_CODE(); 00693 00694 /* Check if this is a symlink */ 00695 if (Kcb->Flags & KEY_SYM_LINK) 00696 { 00697 /* We need the exclusive lock */ 00698 if (!(CmpIsKcbLockedExclusive(Kcb)) && 00699 !(CmpTryToConvertKcbSharedToExclusive(Kcb))) 00700 { 00701 /* We need the exclusive lock */ 00702 return SearchNeedExclusiveLock; 00703 } 00704 00705 /* Otherwise, get the key node */ 00706 KeyNode = (PCM_KEY_NODE)HvGetCell(Kcb->KeyHive, Kcb->KeyCell); 00707 if (!KeyNode) return SearchFail; 00708 00709 /* Cleanup the KCB cache */ 00710 CmpCleanUpKcbValueCache(Kcb); 00711 00712 /* Sanity checks */ 00713 ASSERT(!(CMP_IS_CELL_CACHED(Kcb->ValueCache.ValueList))); 00714 ASSERT(!(Kcb->ExtFlags & CM_KCB_SYM_LINK_FOUND)); 00715 00716 /* Set the value cache */ 00717 Kcb->ValueCache.Count = KeyNode->ValueList.Count; 00718 Kcb->ValueCache.ValueList = KeyNode->ValueList.List; 00719 00720 /* Release the cell */ 00721 HvReleaseCell(Kcb->KeyHive, Kcb->KeyCell); 00722 } 00723 00724 /* Do the search */ 00725 SearchResult = CmpFindValueByNameFromCache(Kcb, 00726 ValueName, 00727 &CachedValue, 00728 &Index, 00729 &Value, 00730 &ValueCached, 00731 &ValueCellToRelease); 00732 if (SearchResult == SearchNeedExclusiveLock) 00733 { 00734 /* We need the exclusive lock */ 00735 ASSERT(!CmpIsKcbLockedExclusive(Kcb)); 00736 ASSERT(ValueCellToRelease == HCELL_NIL); 00737 ASSERT(Value == NULL); 00738 goto Quickie; 00739 } 00740 else if (SearchResult == SearchSuccess) 00741 { 00742 /* Sanity check */ 00743 ASSERT(Value); 00744 00745 /* First of all, check if the key size and type matches */ 00746 if ((Type == Value->Type) && 00747 (DataSize == (Value->DataLength & ~CM_KEY_VALUE_SPECIAL_SIZE))) 00748 { 00749 /* Check if this is a small key */ 00750 IsSmall = (DataSize <= CM_KEY_VALUE_SMALL) ? TRUE: FALSE; 00751 if (IsSmall) 00752 { 00753 /* Compare against the data directly */ 00754 Buffer = &Value->Data; 00755 } 00756 else 00757 { 00758 /* Do a search */ 00759 SearchResult = CmpGetValueDataFromCache(Kcb, 00760 CachedValue, 00761 (PCELL_DATA)Value, 00762 ValueCached, 00763 &Buffer, 00764 &BufferAllocated, 00765 &CellToRelease); 00766 if (SearchResult != SearchSuccess) 00767 { 00768 /* Sanity checks */ 00769 ASSERT(Buffer == NULL); 00770 ASSERT(BufferAllocated == FALSE); 00771 goto Quickie; 00772 } 00773 } 00774 00775 /* Now check the data size */ 00776 if (DataSize) 00777 { 00778 /* Do the compare */ 00779 CompareResult = RtlCompareMemory(Buffer, 00780 Data, 00781 DataSize & 00782 ~CM_KEY_VALUE_SPECIAL_SIZE); 00783 } 00784 else 00785 { 00786 /* It's equal */ 00787 CompareResult = 0; 00788 } 00789 00790 /* Now check if the compare wasn't equal */ 00791 if (CompareResult != DataSize) SearchResult = SearchFail; 00792 } 00793 else 00794 { 00795 /* The length or type isn't equal */ 00796 SearchResult = SearchFail; 00797 } 00798 } 00799 00800 Quickie: 00801 /* Release the value cell */ 00802 if (ValueCellToRelease) HvReleaseCell(Kcb->KeyHive, ValueCellToRelease); 00803 00804 /* Free the buffer */ 00805 if (BufferAllocated) CmpFree(Buffer, 0); 00806 00807 /* Free the cell */ 00808 if (CellToRelease) HvReleaseCell(Kcb->KeyHive, CellToRelease); 00809 00810 /* Return the search result */ 00811 return SearchResult; 00812 } Generated on Sat May 26 2012 04:35:59 for ReactOS by
1.7.6.1
|