1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/config/cmvalche.c 5 * PURPOSE: Configuration Manager - Value Cell Cache 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 */ 8 9 /* INCLUDES ******************************************************************/ 10 11 #include "ntoskrnl.h" 12 #define NDEBUG 13 #include "debug.h" 14 15 FORCEINLINE 16 BOOLEAN 17 CmpIsValueCached(IN HCELL_INDEX CellIndex) 18 { 19 /* Make sure that the cell is valid in the first place */ 20 if (CellIndex == HCELL_NIL) return FALSE; 21 22 /*Is this cell actually a pointer to the cached value data? */ 23 if (CellIndex & 1) return TRUE; 24 25 /* This is a regular cell */ 26 return FALSE; 27 } 28 29 FORCEINLINE 30 VOID 31 CmpSetValueCached(IN PHCELL_INDEX CellIndex) 32 { 33 /* Set the cached bit */ 34 *CellIndex |= 1; 35 } 36 37 #define ASSERT_VALUE_CACHE() \ 38 ASSERTMSG("Cached Values Not Yet Supported!\n", FALSE); 39 40 /* FUNCTIONS *****************************************************************/ 41 42 VALUE_SEARCH_RETURN_TYPE 43 NTAPI 44 CmpGetValueListFromCache(IN PCM_KEY_CONTROL_BLOCK Kcb, 45 OUT PCELL_DATA *CellData, 46 OUT BOOLEAN *IndexIsCached, 47 OUT PHCELL_INDEX ValueListToRelease) 48 { 49 PHHIVE Hive; 50 PCACHED_CHILD_LIST ChildList; 51 HCELL_INDEX CellToRelease; 52 53 /* Set defaults */ 54 *ValueListToRelease = HCELL_NIL; 55 *IndexIsCached = FALSE; 56 57 /* Get the hive and value cache */ 58 Hive = Kcb->KeyHive; 59 ChildList = &Kcb->ValueCache; 60 61 /* Check if the value is cached */ 62 if (CmpIsValueCached(ChildList->ValueList)) 63 { 64 /* It is: we don't expect this yet! */ 65 ASSERT_VALUE_CACHE(); 66 *IndexIsCached = TRUE; 67 *CellData = NULL; 68 } 69 else 70 { 71 /* Make sure the KCB is locked exclusive */ 72 if (!(CmpIsKcbLockedExclusive(Kcb)) && 73 !(CmpTryToConvertKcbSharedToExclusive(Kcb))) 74 { 75 /* We need the exclusive lock */ 76 return SearchNeedExclusiveLock; 77 } 78 79 /* Select the value list as our cell, and get the actual list array */ 80 CellToRelease = ChildList->ValueList; 81 *CellData = (PCELL_DATA)HvGetCell(Hive, CellToRelease); 82 if (!(*CellData)) return SearchFail; 83 84 /* FIXME: Here we would cache the value */ 85 86 /* Return the cell to be released */ 87 *ValueListToRelease = CellToRelease; 88 } 89 90 /* If we got here, then the value list was found */ 91 return SearchSuccess; 92 } 93 94 VALUE_SEARCH_RETURN_TYPE 95 NTAPI 96 CmpGetValueKeyFromCache(IN PCM_KEY_CONTROL_BLOCK Kcb, 97 IN PCELL_DATA CellData, 98 IN ULONG Index, 99 OUT PCM_CACHED_VALUE **CachedValue, 100 OUT PCM_KEY_VALUE *Value, 101 IN BOOLEAN IndexIsCached, 102 OUT BOOLEAN *ValueIsCached, 103 OUT PHCELL_INDEX CellToRelease) 104 { 105 PHHIVE Hive; 106 PCM_KEY_VALUE KeyValue; 107 HCELL_INDEX Cell; 108 109 /* Set defaults */ 110 *CellToRelease = HCELL_NIL; 111 *Value = NULL; 112 *ValueIsCached = FALSE; 113 114 /* Get the hive */ 115 Hive = Kcb->KeyHive; 116 117 /* Check if the index was cached */ 118 if (IndexIsCached) 119 { 120 /* Not expected yet! */ 121 ASSERT_VALUE_CACHE(); 122 *ValueIsCached = TRUE; 123 } 124 else 125 { 126 /* Get the cell index and the key value associated to it */ 127 Cell = CellData->u.KeyList[Index]; 128 KeyValue = (PCM_KEY_VALUE)HvGetCell(Hive, Cell); 129 if (!KeyValue) return SearchFail; 130 131 /* Return the cell and the actual key value */ 132 *CellToRelease = Cell; 133 *Value = KeyValue; 134 } 135 136 /* If we got here, then we found the key value */ 137 return SearchSuccess; 138 } 139 140 VALUE_SEARCH_RETURN_TYPE 141 NTAPI 142 CmpGetValueDataFromCache(IN PCM_KEY_CONTROL_BLOCK Kcb, 143 IN PCM_CACHED_VALUE *CachedValue, 144 IN PCELL_DATA ValueKey, 145 IN BOOLEAN ValueIsCached, 146 OUT PVOID *DataPointer, 147 OUT PBOOLEAN Allocated, 148 OUT PHCELL_INDEX CellToRelease) 149 { 150 PHHIVE Hive; 151 ULONG Length; 152 153 /* Sanity checks */ 154 ASSERT(MAXIMUM_CACHED_DATA < CM_KEY_VALUE_BIG); 155 ASSERT((ValueKey->u.KeyValue.DataLength & CM_KEY_VALUE_SPECIAL_SIZE) == 0); 156 157 /* Set defaults */ 158 *DataPointer = NULL; 159 *Allocated = FALSE; 160 *CellToRelease = HCELL_NIL; 161 162 /* Get the hive */ 163 Hive = Kcb->KeyHive; 164 165 /* Check it the value is cached */ 166 if (ValueIsCached) 167 { 168 /* This isn't expected! */ 169 ASSERT_VALUE_CACHE(); 170 } 171 else 172 { 173 /* It's not, get the value data using the typical routine */ 174 if (!CmpGetValueData(Hive, 175 &ValueKey->u.KeyValue, 176 &Length, 177 DataPointer, 178 Allocated, 179 CellToRelease)) 180 { 181 /* Nothing found: make sure no data was allocated */ 182 ASSERT(*Allocated == FALSE); 183 ASSERT(*DataPointer == NULL); 184 return SearchFail; 185 } 186 } 187 188 /* We found the actual data, return success */ 189 return SearchSuccess; 190 } 191 192 VALUE_SEARCH_RETURN_TYPE 193 NTAPI 194 CmpFindValueByNameFromCache(IN PCM_KEY_CONTROL_BLOCK Kcb, 195 IN PCUNICODE_STRING Name, 196 OUT PCM_CACHED_VALUE **CachedValue, 197 OUT ULONG *Index, 198 OUT PCM_KEY_VALUE *Value, 199 OUT BOOLEAN *ValueIsCached, 200 OUT PHCELL_INDEX CellToRelease) 201 { 202 PHHIVE Hive; 203 VALUE_SEARCH_RETURN_TYPE SearchResult = SearchFail; 204 LONG Result; 205 UNICODE_STRING SearchName; 206 PCELL_DATA CellData; 207 PCACHED_CHILD_LIST ChildList; 208 PCM_KEY_VALUE KeyValue; 209 BOOLEAN IndexIsCached; 210 ULONG i = 0; 211 HCELL_INDEX Cell = HCELL_NIL; 212 213 /* Set defaults */ 214 *CellToRelease = HCELL_NIL; 215 *Value = NULL; 216 217 /* Get the hive and child list */ 218 Hive = Kcb->KeyHive; 219 ChildList = &Kcb->ValueCache; 220 221 /* Check if the child list has any entries */ 222 if (ChildList->Count != 0) 223 { 224 /* Get the value list associated to this child list */ 225 SearchResult = CmpGetValueListFromCache(Kcb, 226 &CellData, 227 &IndexIsCached, 228 &Cell); 229 if (SearchResult != SearchSuccess) 230 { 231 /* We either failed or need the exclusive lock */ 232 ASSERT((SearchResult == SearchFail) || !(CmpIsKcbLockedExclusive(Kcb))); 233 ASSERT(Cell == HCELL_NIL); 234 return SearchResult; 235 } 236 237 /* The index shouldn't be cached right now */ 238 if (IndexIsCached) ASSERT_VALUE_CACHE(); 239 240 /* Loop every value */ 241 while (TRUE) 242 { 243 /* Check if there's any cell to release */ 244 if (*CellToRelease != HCELL_NIL) 245 { 246 /* Release it now */ 247 HvReleaseCell(Hive, *CellToRelease); 248 *CellToRelease = HCELL_NIL; 249 } 250 251 /* Get the key value for this index */ 252 SearchResult = CmpGetValueKeyFromCache(Kcb, 253 CellData, 254 i, 255 CachedValue, 256 Value, 257 IndexIsCached, 258 ValueIsCached, 259 CellToRelease); 260 if (SearchResult != SearchSuccess) 261 { 262 /* We either failed or need the exclusive lock */ 263 ASSERT((SearchResult == SearchFail) || !(CmpIsKcbLockedExclusive(Kcb))); 264 ASSERT(Cell == HCELL_NIL); 265 return SearchResult; 266 } 267 268 /* Check if the both the index and the value are cached */ 269 if (IndexIsCached && *ValueIsCached) 270 { 271 /* We don't expect this yet */ 272 ASSERT_VALUE_CACHE(); 273 Result = -1; 274 } 275 else 276 { 277 /* No cache, so try to compare the name. Is it compressed? */ 278 KeyValue = *Value; 279 if (KeyValue->Flags & VALUE_COMP_NAME) 280 { 281 /* It is, do a compressed name comparison */ 282 Result = CmpCompareCompressedName(Name, 283 KeyValue->Name, 284 KeyValue->NameLength); 285 } 286 else 287 { 288 /* It's not compressed, so do a standard comparison */ 289 SearchName.Length = KeyValue->NameLength; 290 SearchName.MaximumLength = SearchName.Length; 291 SearchName.Buffer = KeyValue->Name; 292 Result = RtlCompareUnicodeString(Name, &SearchName, TRUE); 293 } 294 } 295 296 /* Check if we found the value data */ 297 if (!Result) 298 { 299 /* We have, return the index of the value and success */ 300 *Index = i; 301 SearchResult = SearchSuccess; 302 goto Quickie; 303 } 304 305 /* We didn't find it, try the next entry */ 306 if (++i == ChildList->Count) 307 { 308 /* The entire list was parsed, fail */ 309 *Value = NULL; 310 SearchResult = SearchFail; 311 goto Quickie; 312 } 313 } 314 } 315 316 /* We should only get here if the child list is empty */ 317 ASSERT(ChildList->Count == 0); 318 319 Quickie: 320 /* Release the value list cell if required, and return search result */ 321 if (Cell != HCELL_NIL) HvReleaseCell(Hive, Cell); 322 return SearchResult; 323 } 324 325 VALUE_SEARCH_RETURN_TYPE 326 NTAPI 327 CmpQueryKeyValueData(IN PCM_KEY_CONTROL_BLOCK Kcb, 328 IN PCM_CACHED_VALUE *CachedValue, 329 IN PCM_KEY_VALUE ValueKey, 330 IN BOOLEAN ValueIsCached, 331 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, 332 IN PVOID KeyValueInformation, 333 IN ULONG Length, 334 OUT PULONG ResultLength, 335 OUT PNTSTATUS Status) 336 { 337 PKEY_VALUE_INFORMATION Info = (PKEY_VALUE_INFORMATION)KeyValueInformation; 338 PCELL_DATA CellData; 339 USHORT NameSize; 340 ULONG Size, MinimumSize, SizeLeft, KeySize, AlignedData = 0, DataOffset; 341 PVOID Buffer; 342 BOOLEAN IsSmall, BufferAllocated = FALSE; 343 HCELL_INDEX CellToRelease = HCELL_NIL; 344 VALUE_SEARCH_RETURN_TYPE Result = SearchSuccess; 345 346 /* Get the value data */ 347 CellData = (PCELL_DATA)ValueKey; 348 349 /* Check if the value is compressed */ 350 if (CellData->u.KeyValue.Flags & VALUE_COMP_NAME) 351 { 352 /* Get the compressed name size */ 353 NameSize = CmpCompressedNameSize(CellData->u.KeyValue.Name, 354 CellData->u.KeyValue.NameLength); 355 } 356 else 357 { 358 /* Get the real size */ 359 NameSize = CellData->u.KeyValue.NameLength; 360 } 361 362 /* Check what kind of information the caller is requesting */ 363 switch (KeyValueInformationClass) 364 { 365 /* Basic information */ 366 case KeyValueBasicInformation: 367 368 /* This is how much size we'll need */ 369 Size = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name) + NameSize; 370 371 /* This is the minimum we can work with */ 372 MinimumSize = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name); 373 374 /* Return the size we'd like, and assume success */ 375 *ResultLength = Size; 376 *Status = STATUS_SUCCESS; 377 378 /* Check if the caller gave us below our minimum */ 379 if (Length < MinimumSize) 380 { 381 /* Then we must fail */ 382 *Status = STATUS_BUFFER_TOO_SMALL; 383 break; 384 } 385 386 /* Fill out the basic information */ 387 Info->KeyValueBasicInformation.TitleIndex = 0; 388 Info->KeyValueBasicInformation.Type = CellData->u.KeyValue.Type; 389 Info->KeyValueBasicInformation.NameLength = NameSize; 390 391 /* Now only the name is left */ 392 SizeLeft = Length - MinimumSize; 393 Size = NameSize; 394 395 /* Check if the remaining buffer is too small for the name */ 396 if (SizeLeft < Size) 397 { 398 /* Copy only as much as can fit, and tell the caller */ 399 Size = SizeLeft; 400 *Status = STATUS_BUFFER_OVERFLOW; 401 } 402 403 /* Check if this is a compressed name */ 404 if (CellData->u.KeyValue.Flags & VALUE_COMP_NAME) 405 { 406 /* Copy as much as we can of the compressed name */ 407 CmpCopyCompressedName(Info->KeyValueBasicInformation.Name, 408 Size, 409 CellData->u.KeyValue.Name, 410 CellData->u.KeyValue.NameLength); 411 } 412 else 413 { 414 /* Copy as much as we can of the raw name */ 415 RtlCopyMemory(Info->KeyValueBasicInformation.Name, 416 CellData->u.KeyValue.Name, 417 Size); 418 } 419 420 /* We're all done */ 421 break; 422 423 /* Full key information */ 424 case KeyValueFullInformation: 425 case KeyValueFullInformationAlign64: 426 427 /* Check if this is a small key and compute key size */ 428 IsSmall = CmpIsKeyValueSmall(&KeySize, 429 CellData->u.KeyValue.DataLength); 430 431 /* Calculate the total size required */ 432 Size = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name) + 433 NameSize + 434 KeySize; 435 436 /* And this is the least we can work with */ 437 MinimumSize = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name); 438 439 /* Check if there's any key data */ 440 if (KeySize > 0) 441 { 442 /* Calculate the data offset */ 443 DataOffset = Size - KeySize; 444 445 #ifdef _WIN64 446 /* On 64-bit, always align to 8 bytes */ 447 AlignedData = ALIGN_UP(DataOffset, ULONGLONG); 448 #else 449 /* On 32-bit, align the offset to 4 or 8 bytes */ 450 if (KeyValueInformationClass == KeyValueFullInformationAlign64) 451 { 452 AlignedData = ALIGN_UP(DataOffset, ULONGLONG); 453 } 454 else 455 { 456 AlignedData = ALIGN_UP(DataOffset, ULONG); 457 } 458 #endif 459 /* If alignment was required, we'll need more space */ 460 if (AlignedData > DataOffset) Size += (AlignedData-DataOffset); 461 } 462 463 /* Tell the caller the size we'll finally need, and set success */ 464 *ResultLength = Size; 465 *Status = STATUS_SUCCESS; 466 467 /* Check if the caller is giving us too little */ 468 if (Length < MinimumSize) 469 { 470 /* Then fail right now */ 471 *Status = STATUS_BUFFER_TOO_SMALL; 472 break; 473 } 474 475 /* Fill out the basic information */ 476 Info->KeyValueFullInformation.TitleIndex = 0; 477 Info->KeyValueFullInformation.Type = CellData->u.KeyValue.Type; 478 Info->KeyValueFullInformation.DataLength = KeySize; 479 Info->KeyValueFullInformation.NameLength = NameSize; 480 481 /* Only the name is left now */ 482 SizeLeft = Length - MinimumSize; 483 Size = NameSize; 484 485 /* Check if the name fits */ 486 if (SizeLeft < Size) 487 { 488 /* It doesn't, truncate what we'll copy, and tell the caller */ 489 Size = SizeLeft; 490 *Status = STATUS_BUFFER_OVERFLOW; 491 } 492 493 /* Check if this key value is compressed */ 494 if (CellData->u.KeyValue.Flags & VALUE_COMP_NAME) 495 { 496 /* It is, copy the compressed name */ 497 CmpCopyCompressedName(Info->KeyValueFullInformation.Name, 498 Size, 499 CellData->u.KeyValue.Name, 500 CellData->u.KeyValue.NameLength); 501 } 502 else 503 { 504 /* It's not, copy the raw name */ 505 RtlCopyMemory(Info->KeyValueFullInformation.Name, 506 CellData->u.KeyValue.Name, 507 Size); 508 } 509 510 /* Now check if the key had any data */ 511 if (KeySize > 0) 512 { 513 /* Was it a small key? */ 514 if (IsSmall) 515 { 516 /* Then the data is directly into the cell */ 517 Buffer = &CellData->u.KeyValue.Data; 518 } 519 else 520 { 521 /* Otherwise, we must retrieve it from the value cache */ 522 Result = CmpGetValueDataFromCache(Kcb, 523 CachedValue, 524 CellData, 525 ValueIsCached, 526 &Buffer, 527 &BufferAllocated, 528 &CellToRelease); 529 if (Result != SearchSuccess) 530 { 531 /* We failed, nothing should be allocated */ 532 ASSERT(Buffer == NULL); 533 ASSERT(BufferAllocated == FALSE); 534 *Status = STATUS_INSUFFICIENT_RESOURCES; 535 } 536 } 537 538 /* Now that we know we truly have data, set its offset */ 539 Info->KeyValueFullInformation.DataOffset = AlignedData; 540 541 /* Only the data remains to be copied */ 542 SizeLeft = (((LONG)Length - (LONG)AlignedData) < 0) ? 543 0 : (Length - AlignedData); 544 Size = KeySize; 545 546 /* Check if the caller has no space for it */ 547 if (SizeLeft < Size) 548 { 549 /* Truncate what we'll copy, and tell the caller */ 550 Size = SizeLeft; 551 *Status = STATUS_BUFFER_OVERFLOW; 552 } 553 554 /* Sanity check */ 555 ASSERT((IsSmall ? (Size <= CM_KEY_VALUE_SMALL) : TRUE)); 556 557 /* Make sure we have a valid buffer */ 558 if (Buffer) 559 { 560 /* Copy the data into the aligned offset */ 561 RtlCopyMemory((PVOID)((ULONG_PTR)Info + AlignedData), 562 Buffer, 563 Size); 564 } 565 } 566 else 567 { 568 /* We don't have any data, set the offset to -1, not 0! */ 569 Info->KeyValueFullInformation.DataOffset = 0xFFFFFFFF; 570 } 571 572 /* We're done! */ 573 break; 574 575 /* Partial information requested (no name or alignment!) */ 576 case KeyValuePartialInformation: 577 578 /* Check if this is a small key and compute key size */ 579 IsSmall = CmpIsKeyValueSmall(&KeySize, 580 CellData->u.KeyValue.DataLength); 581 582 /* Calculate the total size required */ 583 Size = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + KeySize; 584 585 /* And this is the least we can work with */ 586 MinimumSize = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data); 587 588 /* Tell the caller the size we'll finally need, and set success */ 589 *ResultLength = Size; 590 *Status = STATUS_SUCCESS; 591 592 /* Check if the caller is giving us too little */ 593 if (Length < MinimumSize) 594 { 595 /* Then fail right now */ 596 *Status = STATUS_BUFFER_TOO_SMALL; 597 break; 598 } 599 600 /* Fill out the basic information */ 601 Info->KeyValuePartialInformation.TitleIndex = 0; 602 Info->KeyValuePartialInformation.Type = CellData->u.KeyValue.Type; 603 Info->KeyValuePartialInformation.DataLength = KeySize; 604 605 /* Now check if the key had any data */ 606 if (KeySize > 0) 607 { 608 /* Was it a small key? */ 609 if (IsSmall) 610 { 611 /* Then the data is directly into the cell */ 612 Buffer = &CellData->u.KeyValue.Data; 613 } 614 else 615 { 616 /* Otherwise, we must retrieve it from the value cache */ 617 Result = CmpGetValueDataFromCache(Kcb, 618 CachedValue, 619 CellData, 620 ValueIsCached, 621 &Buffer, 622 &BufferAllocated, 623 &CellToRelease); 624 if (Result != SearchSuccess) 625 { 626 /* We failed, nothing should be allocated */ 627 ASSERT(Buffer == NULL); 628 ASSERT(BufferAllocated == FALSE); 629 *Status = STATUS_INSUFFICIENT_RESOURCES; 630 } 631 } 632 633 /* Only the data remains to be copied */ 634 SizeLeft = Length - MinimumSize; 635 Size = KeySize; 636 637 /* Check if the caller has no space for it */ 638 if (SizeLeft < Size) 639 { 640 /* Truncate what we'll copy, and tell the caller */ 641 Size = SizeLeft; 642 *Status = STATUS_BUFFER_OVERFLOW; 643 } 644 645 /* Sanity check */ 646 ASSERT((IsSmall ? (Size <= CM_KEY_VALUE_SMALL) : TRUE)); 647 648 /* Make sure we have a valid buffer */ 649 if (Buffer) 650 { 651 /* Copy the data into the aligned offset */ 652 RtlCopyMemory(Info->KeyValuePartialInformation.Data, 653 Buffer, 654 Size); 655 } 656 } 657 658 /* We're done! */ 659 break; 660 661 /* Other information class */ 662 default: 663 664 /* We got some class that we don't support */ 665 DPRINT1("Caller requested unknown class: %lx\n", KeyValueInformationClass); 666 *Status = STATUS_INVALID_PARAMETER; 667 break; 668 } 669 670 /* Return the search result as well */ 671 return Result; 672 } 673 674 VALUE_SEARCH_RETURN_TYPE 675 NTAPI 676 CmpCompareNewValueDataAgainstKCBCache(IN PCM_KEY_CONTROL_BLOCK Kcb, 677 IN PUNICODE_STRING ValueName, 678 IN ULONG Type, 679 IN PVOID Data, 680 IN ULONG DataSize) 681 { 682 VALUE_SEARCH_RETURN_TYPE SearchResult; 683 PCM_KEY_NODE KeyNode; 684 PCM_CACHED_VALUE *CachedValue; 685 ULONG Index; 686 PCM_KEY_VALUE Value; 687 BOOLEAN ValueCached, BufferAllocated = FALSE; 688 PVOID Buffer; 689 HCELL_INDEX ValueCellToRelease = HCELL_NIL, CellToRelease = HCELL_NIL; 690 BOOLEAN IsSmall; 691 ULONG_PTR CompareResult; 692 PAGED_CODE(); 693 694 /* Check if this is a symlink */ 695 if (Kcb->Flags & KEY_SYM_LINK) 696 { 697 /* We need the exclusive lock */ 698 if (!(CmpIsKcbLockedExclusive(Kcb)) && 699 !(CmpTryToConvertKcbSharedToExclusive(Kcb))) 700 { 701 /* We need the exclusive lock */ 702 return SearchNeedExclusiveLock; 703 } 704 705 /* Otherwise, get the key node */ 706 KeyNode = (PCM_KEY_NODE)HvGetCell(Kcb->KeyHive, Kcb->KeyCell); 707 if (!KeyNode) return SearchFail; 708 709 /* Cleanup the KCB cache */ 710 CmpCleanUpKcbValueCache(Kcb); 711 712 /* Sanity checks */ 713 ASSERT(!(CMP_IS_CELL_CACHED(Kcb->ValueCache.ValueList))); 714 ASSERT(!(Kcb->ExtFlags & CM_KCB_SYM_LINK_FOUND)); 715 716 /* Set the value cache */ 717 Kcb->ValueCache.Count = KeyNode->ValueList.Count; 718 Kcb->ValueCache.ValueList = KeyNode->ValueList.List; 719 720 /* Release the cell */ 721 HvReleaseCell(Kcb->KeyHive, Kcb->KeyCell); 722 } 723 724 /* Do the search */ 725 SearchResult = CmpFindValueByNameFromCache(Kcb, 726 ValueName, 727 &CachedValue, 728 &Index, 729 &Value, 730 &ValueCached, 731 &ValueCellToRelease); 732 if (SearchResult == SearchNeedExclusiveLock) 733 { 734 /* We need the exclusive lock */ 735 ASSERT(!CmpIsKcbLockedExclusive(Kcb)); 736 ASSERT(ValueCellToRelease == HCELL_NIL); 737 ASSERT(Value == NULL); 738 goto Quickie; 739 } 740 else if (SearchResult == SearchSuccess) 741 { 742 /* Sanity check */ 743 ASSERT(Value); 744 745 /* First of all, check if the key size and type matches */ 746 if ((Type == Value->Type) && 747 (DataSize == (Value->DataLength & ~CM_KEY_VALUE_SPECIAL_SIZE))) 748 { 749 /* Check if this is a small key */ 750 IsSmall = (DataSize <= CM_KEY_VALUE_SMALL) ? TRUE: FALSE; 751 if (IsSmall) 752 { 753 /* Compare against the data directly */ 754 Buffer = &Value->Data; 755 } 756 else 757 { 758 /* Do a search */ 759 SearchResult = CmpGetValueDataFromCache(Kcb, 760 CachedValue, 761 (PCELL_DATA)Value, 762 ValueCached, 763 &Buffer, 764 &BufferAllocated, 765 &CellToRelease); 766 if (SearchResult != SearchSuccess) 767 { 768 /* Sanity checks */ 769 ASSERT(Buffer == NULL); 770 ASSERT(BufferAllocated == FALSE); 771 goto Quickie; 772 } 773 } 774 775 /* Now check the data size */ 776 if (DataSize) 777 { 778 /* Do the compare */ 779 CompareResult = RtlCompareMemory(Buffer, 780 Data, 781 DataSize & 782 ~CM_KEY_VALUE_SPECIAL_SIZE); 783 } 784 else 785 { 786 /* It's equal */ 787 CompareResult = 0; 788 } 789 790 /* Now check if the compare wasn't equal */ 791 if (CompareResult != DataSize) SearchResult = SearchFail; 792 } 793 else 794 { 795 /* The length or type isn't equal */ 796 SearchResult = SearchFail; 797 } 798 } 799 800 Quickie: 801 /* Release the value cell */ 802 if (ValueCellToRelease) HvReleaseCell(Kcb->KeyHive, ValueCellToRelease); 803 804 /* Free the buffer */ 805 if (BufferAllocated) CmpFree(Buffer, 0); 806 807 /* Free the cell */ 808 if (CellToRelease) HvReleaseCell(Kcb->KeyHive, CellToRelease); 809 810 /* Return the search result */ 811 return SearchResult; 812 } 813