1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Configuration Manager Library - Registry Self-Heal Routines 5 * COPYRIGHT: Copyright 2022 George Bișoc <george.bisoc@reactos.org> 6 */ 7 8 #include "cmlib.h" 9 #define NDEBUG 10 #include <debug.h> 11 12 /* GLOBALS ********************************************************************/ 13 14 #if !defined(CMLIB_HOST) && !defined(_BLDR_) 15 extern BOOLEAN CmpSelfHeal; 16 extern ULONG CmpBootType; 17 #endif 18 19 /* PRIVATE FUNCTIONS **********************************************************/ 20 21 /** 22 * @brief 23 * Removes a cell from a fast key index. 24 * 25 * @param[in,out] FastIndex 26 * The fast key index where a cell has to be removed. 27 * 28 * @param[in] Index 29 * The index which points to the location of the 30 * cell that is to be removed. 31 * 32 * @param[in] UpdateCount 33 * If set to TRUE, the function will update the fast 34 * index count accordingly by one value less. If set 35 * to FALSE, the count won't be updated. See Remarks 36 * for further information. 37 * 38 * @remarks 39 * In case where the fast index count is not updated is 40 * when the key index is not a root but a leaf. In such 41 * scenario such leaf is the actual key index itself 42 * so updating the fast index count is not necessary (aka 43 * UpdateCount is set to FALSE). 44 */ 45 static 46 VOID 47 CmpRemoveFastIndexKeyCell( 48 _Inout_ PCM_KEY_FAST_INDEX FastIndex, 49 _In_ ULONG Index, 50 _In_ BOOLEAN UpdateCount) 51 { 52 ULONG MoveCount; 53 ASSERT(Index < FastIndex->Count); 54 55 /* Calculate the number of trailing cells */ 56 MoveCount = FastIndex->Count - Index - 1; 57 if (MoveCount != 0) 58 { 59 /* Remove the cell now by moving one location ahead */ 60 RtlMoveMemory(&FastIndex->List[Index], 61 &FastIndex->List[Index + 1], 62 MoveCount * sizeof(CM_INDEX)); 63 } 64 65 /* Update the fast index count if asked */ 66 if (UpdateCount) 67 FastIndex->Count--; 68 } 69 70 /** 71 * @brief 72 * Removes a cell from a normal key index. 73 * 74 * @param[in,out] KeyIndex 75 * The key index where a cell has to be removed. 76 * 77 * @param[in] Index 78 * The index which points to the location of the 79 * cell that is to be removed. 80 */ 81 static 82 VOID 83 CmpRemoveIndexKeyCell( 84 _Inout_ PCM_KEY_INDEX KeyIndex, 85 _In_ ULONG Index) 86 { 87 ULONG MoveCount; 88 ASSERT(Index < KeyIndex->Count); 89 90 /* Calculate the number of trailing cells */ 91 MoveCount = KeyIndex->Count - Index - 1; 92 if (MoveCount != 0) 93 { 94 /* Remove the cell now by moving one location ahead */ 95 RtlMoveMemory(&KeyIndex->List[Index], 96 &KeyIndex->List[Index + 1], 97 MoveCount * sizeof(HCELL_INDEX)); 98 } 99 100 /* Update the key index count */ 101 KeyIndex->Count--; 102 } 103 104 /** 105 * @brief 106 * Removes a cell from a key value list node. 107 * 108 * @param[in,out] ValueListNode 109 * The value list node which is used by the 110 * function to update the value list count. 111 * 112 * @param[in,out] ValueListData 113 * The value list data of which a cell has to be removed. 114 * 115 * @param[in] Index 116 * The index which points to the location of the 117 * cell that is to be removed. 118 */ 119 static 120 VOID 121 CmpRemoveValueFromValueList( 122 _Inout_ PCM_KEY_NODE ValueListNode, 123 _Inout_ PCELL_DATA ValueListData, 124 _In_ ULONG Index) 125 { 126 ULONG MoveCount; 127 ASSERT(Index < ValueListNode->ValueList.Count); 128 129 /* Calculate the number of trailing values */ 130 MoveCount = ValueListNode->ValueList.Count - Index - 1; 131 if (MoveCount != 0) 132 { 133 /* Remove the value now by moving one location ahead */ 134 RtlMoveMemory(&ValueListData->u.KeyList[Index], 135 &ValueListData->u.KeyList[Index + 1], 136 MoveCount * sizeof(HCELL_INDEX)); 137 } 138 139 /* Update the value list count */ 140 ValueListNode->ValueList.Count--; 141 } 142 143 /** 144 * @brief 145 * Removes the offending subkey from a root index. 146 * 147 * @param[in] Hive 148 * A pointer to a hive descriptor containing faulty data. 149 * 150 * @param[in] RootIndex 151 * The root index where a leaf is obtained from. Such 152 * leaf is used to check deep down the leaf for the offending 153 * subkey. 154 * 155 * @param[in] TargetKey 156 * The offending target subkey to be removed. 157 * 158 * @return 159 * Returns TRUE if the function successfully removed the target 160 * key, FALSE otherwise. 161 */ 162 static 163 BOOLEAN 164 CmpRemoveSubkeyInRoot( 165 _In_ PHHIVE Hive, 166 _In_ PCM_KEY_INDEX RootIndex, 167 _In_ HCELL_INDEX TargetKey) 168 { 169 PCM_KEY_INDEX Leaf; 170 PCM_KEY_FAST_INDEX FastIndex; 171 HCELL_INDEX LeafCell; 172 ULONG RootCountIndex; 173 ULONG LeafCountIndex; 174 175 PAGED_CODE(); 176 177 ASSERT(RootIndex); 178 179 /* Loop the root index */ 180 for (RootCountIndex = 0; RootCountIndex < RootIndex->Count; RootCountIndex++) 181 { 182 /* 183 * Release the leaf cell from previous iteration 184 * of the loop. Make sure what we're releasing is 185 * valid to begin with. 186 */ 187 if (RootCountIndex) 188 { 189 ASSERT(Leaf); 190 ASSERT(LeafCell == RootIndex->List[RootCountIndex - 1]); 191 HvReleaseCell(Hive, LeafCell); 192 } 193 194 /* Get the leaf cell and the leaf for this index */ 195 LeafCell = RootIndex->List[RootCountIndex]; 196 Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell); 197 if (!Leaf) 198 { 199 DPRINT1("Couldn't get the leaf from cell\n"); 200 return FALSE; 201 } 202 203 /* Start looping the leaf */ 204 for (LeafCountIndex = 0; LeafCountIndex < Leaf->Count; LeafCountIndex++) 205 { 206 /* Is the leaf a fast leaf or a hash one? */ 207 if ((Leaf->Signature == CM_KEY_FAST_LEAF) || 208 (Leaf->Signature == CM_KEY_HASH_LEAF)) 209 { 210 /* It is one of the two, get the fast index */ 211 FastIndex = (PCM_KEY_FAST_INDEX)Leaf; 212 213 /* 214 * Is the subkey cell from the fast 215 * index the one we one we're actually 216 * searching? 217 */ 218 if (FastIndex->List[LeafCountIndex].Cell == TargetKey) 219 { 220 HvReleaseCell(Hive, LeafCell); 221 HvMarkCellDirty(Hive, LeafCell, FALSE); 222 CmpRemoveFastIndexKeyCell(FastIndex, LeafCountIndex, TRUE); 223 DPRINT1("The offending key cell has BEEN FOUND in fast index (fast index 0x%p, index %lu)\n", 224 FastIndex, LeafCountIndex); 225 return TRUE; 226 } 227 } 228 else 229 { 230 /* 231 * The leaf is neither of the two. Check if 232 * the target offending cell is inside the leaf 233 * itself. 234 */ 235 if (Leaf->List[LeafCountIndex] == TargetKey) 236 { 237 HvReleaseCell(Hive, LeafCell); 238 HvMarkCellDirty(Hive, LeafCell, FALSE); 239 CmpRemoveIndexKeyCell(Leaf, LeafCountIndex); 240 DPRINT1("The offending key cell has BEEN FOUND in leaf (leaf 0x%p, index %lu)\n", 241 Leaf, LeafCountIndex); 242 return TRUE; 243 } 244 } 245 } 246 } 247 248 /* 249 * We have searched everywhere but we couldn't 250 * hunt the offending target key cell. 251 */ 252 DPRINT1("No target key has been found to remove\n"); 253 return FALSE; 254 } 255 256 /** 257 * @brief 258 * Removes the offending subkey from a leaf index. 259 * 260 * @param[in] Hive 261 * A pointer to a hive descriptor containing faulty data. 262 * 263 * @param[in] KeyNode 264 * A pointer to a key node of the parent. This node is 265 * used by the function to mark the whole subkeys list 266 * of the parent dirty. 267 * 268 * @param[in] Leaf 269 * A pointer to a leaf key index of which the offending 270 * subkey is to be removed from. 271 * 272 * @param[in] TargetKey 273 * The offending target subkey to remove. 274 * 275 * @return 276 * Returns TRUE if the function successfully removed the target 277 * key, FALSE otherwise. 278 */ 279 static 280 BOOLEAN 281 CmpRemoveSubKeyInLeaf( 282 _In_ PHHIVE Hive, 283 _In_ PCM_KEY_NODE KeyNode, 284 _In_ PCM_KEY_INDEX Leaf, 285 _In_ HCELL_INDEX TargetKey) 286 { 287 PCM_KEY_FAST_INDEX FastIndex; 288 ULONG LeafIndex; 289 290 /* Loop the leaf index */ 291 for (LeafIndex = 0; LeafIndex < Leaf->Count; LeafIndex++) 292 { 293 /* 294 * Check if the main leaf is a fast 295 * leaf or a hash one. 296 */ 297 if ((Leaf->Signature == CM_KEY_FAST_LEAF) || 298 (Leaf->Signature == CM_KEY_HASH_LEAF)) 299 { 300 /* It is one of the two, get the fast index */ 301 FastIndex = (PCM_KEY_FAST_INDEX)Leaf; 302 303 /* 304 * Is the subkey cell from the fast 305 * index the one we're actually 306 * searching? 307 */ 308 if (FastIndex->List[LeafIndex].Cell == TargetKey) 309 { 310 HvMarkCellDirty(Hive, KeyNode->SubKeyLists[Stable], FALSE); 311 CmpRemoveFastIndexKeyCell(FastIndex, LeafIndex, FALSE); 312 313 /* 314 * Since this fast index actually came from the 315 * actual leaf index itself, just update its count 316 * rather than that of the fast index. 317 */ 318 Leaf->Count--; 319 DPRINT1("The offending key cell has BEEN FOUND in fast index (fast index 0x%p, leaf index %lu)\n", 320 FastIndex, LeafIndex); 321 return TRUE; 322 } 323 } 324 else 325 { 326 /* 327 * The leaf is neither of the two. The offending 328 * cell must come directly from the normal leaf 329 * at this point. 330 */ 331 if (Leaf->List[LeafIndex] == TargetKey) 332 { 333 HvMarkCellDirty(Hive, KeyNode->SubKeyLists[Stable], FALSE); 334 CmpRemoveIndexKeyCell(Leaf, LeafIndex); 335 DPRINT1("The offending key cell has BEEN FOUND in leaf (leaf 0x%p, index %lu)\n", 336 Leaf, LeafIndex); 337 return TRUE; 338 } 339 } 340 } 341 342 /* 343 * We have searched everywhere but we couldn't 344 * hunt the offending target key cell. 345 */ 346 DPRINT1("No target key has been found to remove\n"); 347 return FALSE; 348 } 349 350 /* PUBLIC FUNCTIONS ***********************************************************/ 351 352 /** 353 * @brief 354 * Checks if self healing is permitted by the kernel and/or 355 * bootloader. Self healing is also triggered if such a 356 * request was prompted by the user to fix a broken hive. 357 * Such a request tipically comes from a registry repair 358 * tool such as the ReactOS Check Registry Utility. 359 * 360 * @param[in] FixHive 361 * If set to TRUE, self heal is triggered and the target 362 * hive will be fixed. Otherwise the hive will not be fixed. 363 * 364 * @return 365 * Returns TRUE if self healing is possible, FALSE otherwise. 366 */ 367 BOOLEAN 368 CMAPI 369 CmIsSelfHealEnabled( 370 _In_ BOOLEAN FixHive) 371 { 372 PAGED_CODE(); 373 374 if (FixHive) 375 return TRUE; 376 377 #if !defined(CMLIB_HOST) && !defined(_BLDR_) 378 if (CmpSelfHeal || (CmpBootType & HBOOT_TYPE_SELF_HEAL)) 379 return TRUE; 380 #endif 381 382 return FALSE; 383 } 384 385 /** 386 * @brief 387 * Repairs the parent key from damage by removing the 388 * offending subkey cell. 389 * 390 * @param[in,out] Hive 391 * A pointer to a hive descriptor containing faulty data. 392 * 393 * @param[in] TargetKey 394 * The offending target cell to remove from the parent. 395 * 396 * @param[in] ParentKey 397 * The damaged parent key cell to heal. 398 * 399 * @param[in] FixHive 400 * If set to TRUE, self heal is triggered and the target 401 * hive will be fixed. Otherwise the hive will not be fixed. 402 * 403 * @return 404 * Returns TRUE if the function successfully healed the parent 405 * key, FALSE otherwise. 406 */ 407 BOOLEAN 408 CMAPI 409 CmpRepairParentKey( 410 _Inout_ PHHIVE Hive, 411 _In_ HCELL_INDEX TargetKey, 412 _In_ HCELL_INDEX ParentKey, 413 _In_ BOOLEAN FixHive) 414 { 415 PCM_KEY_INDEX KeyIndex; 416 PCM_KEY_NODE KeyNode; 417 BOOLEAN ParentRepaired; 418 419 PAGED_CODE(); 420 421 /* The target key must NEVER be NIL! */ 422 ASSERT(TargetKey != HCELL_NIL); 423 424 /* Assume the parent hasn't been repaired yet */ 425 ParentRepaired = FALSE; 426 427 /* Is self healing possible? */ 428 if (!CmIsSelfHealEnabled(FixHive)) 429 { 430 DPRINT1("Self healing not possible\n"); 431 return ParentRepaired; 432 } 433 434 /* Obtain a node from the parent */ 435 KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, ParentKey); 436 if (!KeyNode) 437 { 438 DPRINT1("Couldn't get the parent key node\n"); 439 return ParentRepaired; 440 } 441 442 /* Obtain the index as well since we got the parent node */ 443 KeyIndex = (PCM_KEY_INDEX)HvGetCell(Hive, KeyNode->SubKeyLists[Stable]); 444 if (!KeyIndex) 445 { 446 DPRINT1("Couldn't get the key index from parent node\n"); 447 HvReleaseCell(Hive, ParentKey); 448 return ParentRepaired; 449 } 450 451 /* Check if this is a root */ 452 if (KeyIndex->Signature == CM_KEY_INDEX_ROOT) 453 { 454 /* It is, call the specific helper to discard the damaged key down the root */ 455 ParentRepaired = CmpRemoveSubkeyInRoot(Hive, 456 KeyIndex, 457 TargetKey); 458 } 459 else if ((KeyIndex->Signature == CM_KEY_INDEX_LEAF) || 460 (KeyIndex->Signature == CM_KEY_FAST_LEAF) || 461 (KeyIndex->Signature == CM_KEY_HASH_LEAF)) 462 { 463 /* Otherwise call the leaf helper */ 464 ParentRepaired = CmpRemoveSubKeyInLeaf(Hive, 465 KeyNode, 466 KeyIndex, 467 TargetKey); 468 } 469 else 470 { 471 /* 472 * Generally CmCheckRegistry detects if a key index 473 * in the subkeys list is totally broken (we understand 474 * that if its signature is not root or leaf) and it will 475 * purge the whole subkeys list in such cases. With that 476 * being said, we should never reach this code path. But 477 * if for whatever reason we reach here then something 478 * is seriously wrong. 479 */ 480 DPRINT1("The key index signature is invalid (KeyIndex->Signature == %lu)", KeyIndex->Signature); 481 ASSERT(FALSE); 482 } 483 484 /* 485 * If we successfully removed the offending key 486 * cell mark down the parent as dirty and punt down 487 * the subkey count as well. Mark the hive as in 488 * self heal mode as well. 489 */ 490 if (ParentRepaired) 491 { 492 HvMarkCellDirty(Hive, ParentKey, FALSE); 493 KeyNode->SubKeyCounts[Stable]--; 494 Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL; 495 DPRINT1("The subkey has been removed, the parent is now repaired\n"); 496 } 497 498 HvReleaseCell(Hive, KeyNode->SubKeyLists[Stable]); 499 HvReleaseCell(Hive, ParentKey); 500 return ParentRepaired; 501 } 502 503 /** 504 * @brief 505 * Repairs the parent of the node from damage due 506 * to parent cell and parent node incosistency. 507 * 508 * @param[in,out] Hive 509 * A pointer to a hive descriptor containing faulty data. 510 * 511 * @param[in] CurrentCell 512 * The current cell to be marked as dirty. 513 * 514 * @param[in] ParentCell 515 * The sane parent cell which is used by the 516 * function for new parent node assignment. 517 * 518 * @param[in,out] CellData 519 * The cell data of the current cell of which 520 * its parent node is to be repaired. 521 * 522 * @param[in] FixHive 523 * If set to TRUE, self heal is triggered and the target 524 * hive will be fixed. Otherwise the hive will not be fixed. 525 * 526 * @return 527 * Returns TRUE if the function successfully healed the 528 * parent node, FALSE otherwise. 529 */ 530 BOOLEAN 531 CMAPI 532 CmpRepairParentNode( 533 _Inout_ PHHIVE Hive, 534 _In_ HCELL_INDEX CurrentCell, 535 _In_ HCELL_INDEX ParentCell, 536 _Inout_ PCELL_DATA CellData, 537 _In_ BOOLEAN FixHive) 538 { 539 PAGED_CODE(); 540 541 /* Is self healing possible? */ 542 if (!CmIsSelfHealEnabled(FixHive)) 543 { 544 DPRINT1("Self healing not possible\n"); 545 return FALSE; 546 } 547 548 /* 549 * Mark the cell where we got the actual 550 * cell data as dirty and fix the node. 551 */ 552 HvMarkCellDirty(Hive, CurrentCell, FALSE); 553 CellData->u.KeyNode.Parent = ParentCell; 554 555 /* Mark the hive as in self healing mode since we repaired it */ 556 Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL; 557 return TRUE; 558 } 559 560 /** 561 * @brief 562 * Repairs the key node signature from damage 563 * due to signature corruption. 564 * 565 * @param[in,out] Hive 566 * A pointer to a hive descriptor containing faulty data. 567 * 568 * @param[in] CurrentCell 569 * The current cell to be marked as dirty. 570 * 571 * @param[in,out] CellData 572 * The cell data of the current cell of which 573 * its signature is to be repaired. 574 * 575 * @param[in] FixHive 576 * If set to TRUE, self heal is triggered and the target 577 * hive will be fixed. Otherwise the hive will not be fixed. 578 * 579 * @return 580 * Returns TRUE if the function successfully healed the 581 * key node signature, FALSE otherwise. 582 */ 583 BOOLEAN 584 CMAPI 585 CmpRepairKeyNodeSignature( 586 _Inout_ PHHIVE Hive, 587 _In_ HCELL_INDEX CurrentCell, 588 _Inout_ PCELL_DATA CellData, 589 _In_ BOOLEAN FixHive) 590 { 591 PAGED_CODE(); 592 593 /* Is self healing possible? */ 594 if (!CmIsSelfHealEnabled(FixHive)) 595 { 596 DPRINT1("Self healing not possible\n"); 597 return FALSE; 598 } 599 600 /* 601 * Mark the cell where we got the actual 602 * cell data as dirty and fix the key signature. 603 */ 604 HvMarkCellDirty(Hive, CurrentCell, FALSE); 605 CellData->u.KeyNode.Signature = CM_KEY_NODE_SIGNATURE; 606 607 /* Mark the hive as in self healing mode since we repaired it */ 608 Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL; 609 return TRUE; 610 } 611 612 /** 613 * @brief 614 * Repairs the class from damage due to class 615 * corruption within the node key. 616 * 617 * @param[in,out] Hive 618 * A pointer to a hive descriptor containing faulty data. 619 * 620 * @param[in] CurrentCell 621 * The current cell to be marked as dirty. 622 * 623 * @param[in,out] CellData 624 * The cell data of the current cell of which 625 * its class is to be repaired. 626 * 627 * @param[in] FixHive 628 * If set to TRUE, self heal is triggered and the target 629 * hive will be fixed. Otherwise the hive will not be fixed. 630 * 631 * @return 632 * Returns TRUE if the function successfully healed the 633 * class of node key, FALSE otherwise. 634 */ 635 BOOLEAN 636 CMAPI 637 CmpRepairClassOfNodeKey( 638 _Inout_ PHHIVE Hive, 639 _In_ HCELL_INDEX CurrentCell, 640 _Inout_ PCELL_DATA CellData, 641 _In_ BOOLEAN FixHive) 642 { 643 PAGED_CODE(); 644 645 /* Is self healing possible? */ 646 if (!CmIsSelfHealEnabled(FixHive)) 647 { 648 DPRINT1("Self healing not possible\n"); 649 return FALSE; 650 } 651 652 /* 653 * Mark the cell where we got the actual 654 * cell data as dirty and fix the class field 655 * of key node. 656 */ 657 HvMarkCellDirty(Hive, CurrentCell, FALSE); 658 CellData->u.KeyNode.Class = HCELL_NIL; 659 CellData->u.KeyNode.ClassLength = 0; 660 661 /* Mark the hive as in self healing mode since we repaired it */ 662 Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL; 663 return TRUE; 664 } 665 666 /** 667 * @brief 668 * Repairs the value list count of key due to 669 * corruption. The process involves by removing 670 * one damaged value less from the list. 671 * 672 * @param[in,out] Hive 673 * A pointer to a hive descriptor containing faulty data. 674 * 675 * @param[in] CurrentCell 676 * The current cell to be marked as dirty. 677 * 678 * @param[in] ListCountIndex 679 * The value count index which points to the actual 680 * value in the list to be removed. 681 * 682 * @param[in,out] ValueListData 683 * The value list cell data containing the actual list 684 * of which the damaged is to be removed from. 685 * 686 * @param[in] FixHive 687 * If set to TRUE, self heal is triggered and the target 688 * hive will be fixed. Otherwise the hive will not be fixed. 689 * 690 * @return 691 * Returns TRUE if the function successfully healed the 692 * value list count, FALSE otherwise. 693 */ 694 BOOLEAN 695 CMAPI 696 CmpRepairValueListCount( 697 _Inout_ PHHIVE Hive, 698 _In_ HCELL_INDEX CurrentCell, 699 _In_ ULONG ListCountIndex, 700 _Inout_ PCELL_DATA ValueListData, 701 _In_ BOOLEAN FixHive) 702 { 703 PCM_KEY_NODE ValueListNode; 704 705 PAGED_CODE(); 706 707 /* Is self healing possible? */ 708 if (!CmIsSelfHealEnabled(FixHive)) 709 { 710 DPRINT1("Self healing not possible\n"); 711 return FALSE; 712 } 713 714 /* 715 * Obtain a node from the cell that we mark it as dirty. 716 * The node is that of the current cell of which its 717 * value list is being validated. 718 */ 719 ValueListNode = (PCM_KEY_NODE)HvGetCell(Hive, CurrentCell); 720 if (!ValueListNode) 721 { 722 DPRINT1("Could not get a node from the current cell\n"); 723 return FALSE; 724 } 725 726 /* 727 * Mark the current cell and value list as dirty 728 * as we will be making changes onto them. 729 */ 730 HvMarkCellDirty(Hive, CurrentCell, FALSE); 731 HvMarkCellDirty(Hive, ValueListNode->ValueList.List, FALSE); 732 733 /* 734 * Now remove the value from the list and mark the 735 * hive as in self healing mode. 736 */ 737 CmpRemoveValueFromValueList(ValueListNode, ValueListData, ListCountIndex); 738 Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL; 739 HvReleaseCell(Hive, CurrentCell); 740 return TRUE; 741 } 742 743 /** 744 * @brief 745 * Repairs the value list due to corruption. The 746 * process involes by purging the whole damaged 747 * list. 748 * 749 * @param[in,out] Hive 750 * A pointer to a hive descriptor containing faulty data. 751 * 752 * @param[in] CurrentCell 753 * The current cell to be marked as dirty. 754 * 755 * @param[in] FixHive 756 * If set to TRUE, self heal is triggered and the target 757 * hive will be fixed. Otherwise the hive will not be fixed. 758 * 759 * @return 760 * Returns TRUE if the function successfully healed the 761 * value list, FALSE otherwise. 762 */ 763 BOOLEAN 764 CMAPI 765 CmpRepairValueList( 766 _Inout_ PHHIVE Hive, 767 _In_ HCELL_INDEX CurrentCell, 768 _In_ BOOLEAN FixHive) 769 { 770 PCM_KEY_NODE ValueListNode; 771 772 PAGED_CODE(); 773 774 /* Is self healing possible? */ 775 if (!CmIsSelfHealEnabled(FixHive)) 776 { 777 DPRINT1("Self healing not possible\n"); 778 return FALSE; 779 } 780 781 /* Obtain a node */ 782 ValueListNode = (PCM_KEY_NODE)HvGetCell(Hive, CurrentCell); 783 if (!ValueListNode) 784 { 785 DPRINT1("Could not get a node from the current cell\n"); 786 return FALSE; 787 } 788 789 /* Purge out the whole list */ 790 HvMarkCellDirty(Hive, CurrentCell, FALSE); 791 ValueListNode->ValueList.List = HCELL_NIL; 792 ValueListNode->ValueList.Count = 0; 793 794 Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL; 795 HvReleaseCell(Hive, CurrentCell); 796 return TRUE; 797 } 798 799 /** 800 * @brief 801 * Repairs the subkey list count due to corruption. 802 * The process involves by fixing the count itself 803 * with a sane count. 804 * 805 * @param[in,out] Hive 806 * A pointer to a hive descriptor containing faulty data. 807 * 808 * @param[in] CurrentCell 809 * The current cell to be marked as dirty. 810 * 811 * @param[in] Count 812 * The healthy count which is used by the function 813 * to fix the subkeys list count. 814 * 815 * @param[in,out] CellData 816 * The cell data of the current cell of which its 817 * subkeys list is to be fixed. 818 * 819 * @param[in] FixHive 820 * If set to TRUE, self heal is triggered and the target 821 * hive will be fixed. Otherwise the hive will not be fixed. 822 * 823 * @return 824 * Returns TRUE if the function successfully healed the 825 * subkeys list count, FALSE otherwise. 826 */ 827 BOOLEAN 828 CMAPI 829 CmpRepairSubKeyCounts( 830 _Inout_ PHHIVE Hive, 831 _In_ HCELL_INDEX CurrentCell, 832 _In_ ULONG Count, 833 _Inout_ PCELL_DATA CellData, 834 _In_ BOOLEAN FixHive) 835 { 836 PAGED_CODE(); 837 838 /* Is self healing possible? */ 839 if (!CmIsSelfHealEnabled(FixHive)) 840 { 841 DPRINT1("Self healing not possible\n"); 842 return FALSE; 843 } 844 845 /* 846 * Mark the cell where we got the actual 847 * cell data as dirty and fix the subkey 848 * counts. 849 */ 850 HvMarkCellDirty(Hive, CurrentCell, FALSE); 851 CellData->u.KeyNode.SubKeyCounts[Stable] = Count; 852 853 /* Mark the hive as in self healing mode since we repaired it */ 854 Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL; 855 return TRUE; 856 } 857 858 /** 859 * @brief 860 * Repairs the subkey list due to corruption. The process 861 * involves by purging the whole damaged subkeys list. 862 * 863 * @param[in,out] Hive 864 * A pointer to a hive descriptor containing faulty data. 865 * 866 * @param[in] CurrentCell 867 * The current cell to be marked as dirty. 868 * 869 * @param[in,out] CellData 870 * The cell data of the current cell of which its 871 * subkeys list is to be fixed. 872 * 873 * @param[in] FixHive 874 * If set to TRUE, self heal is triggered and the target 875 * hive will be fixed. Otherwise the hive will not be fixed. 876 * 877 * @return 878 * Returns TRUE if the function successfully healed the 879 * subkeys list, FALSE otherwise. 880 */ 881 BOOLEAN 882 CMAPI 883 CmpRepairSubKeyList( 884 _Inout_ PHHIVE Hive, 885 _In_ HCELL_INDEX CurrentCell, 886 _Inout_ PCELL_DATA CellData, 887 _In_ BOOLEAN FixHive) 888 { 889 PAGED_CODE(); 890 891 /* Is self healing possible? */ 892 if (!CmIsSelfHealEnabled(FixHive)) 893 { 894 DPRINT1("Self healing not possible\n"); 895 return FALSE; 896 } 897 898 /* 899 * Mark the cell where we got the actual 900 * cell data as dirty and fix the subkey 901 * list. 902 */ 903 HvMarkCellDirty(Hive, CurrentCell, FALSE); 904 CellData->u.KeyNode.SubKeyLists[Stable] = HCELL_NIL; 905 CellData->u.KeyNode.SubKeyCounts[Stable] = 0; 906 907 /* Mark the hive as in self healing mode since we repaired it */ 908 Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL; 909 return TRUE; 910 } 911 912 /* EOF */ 913