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 %u)\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 %u)\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 %u)\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 %u)\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 == %u)", 481 KeyIndex->Signature); 482 ASSERT(FALSE); 483 } 484 485 /* 486 * If we successfully removed the offending key 487 * cell mark down the parent as dirty and punt down 488 * the subkey count as well. Mark the hive as in 489 * self heal mode as well. 490 */ 491 if (ParentRepaired) 492 { 493 HvMarkCellDirty(Hive, ParentKey, FALSE); 494 KeyNode->SubKeyCounts[Stable]--; 495 Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL; 496 DPRINT1("The subkey has been removed, the parent is now repaired\n"); 497 } 498 499 HvReleaseCell(Hive, KeyNode->SubKeyLists[Stable]); 500 HvReleaseCell(Hive, ParentKey); 501 return ParentRepaired; 502 } 503 504 /** 505 * @brief 506 * Repairs the parent of the node from damage due 507 * to parent cell and parent node incosistency. 508 * 509 * @param[in,out] Hive 510 * A pointer to a hive descriptor containing faulty data. 511 * 512 * @param[in] CurrentCell 513 * The current cell to be marked as dirty. 514 * 515 * @param[in] ParentCell 516 * The sane parent cell which is used by the 517 * function for new parent node assignment. 518 * 519 * @param[in,out] CellData 520 * The cell data of the current cell of which 521 * its parent node is to be repaired. 522 * 523 * @param[in] FixHive 524 * If set to TRUE, self heal is triggered and the target 525 * hive will be fixed. Otherwise the hive will not be fixed. 526 * 527 * @return 528 * Returns TRUE if the function successfully healed the 529 * parent node, FALSE otherwise. 530 */ 531 BOOLEAN 532 CMAPI 533 CmpRepairParentNode( 534 _Inout_ PHHIVE Hive, 535 _In_ HCELL_INDEX CurrentCell, 536 _In_ HCELL_INDEX ParentCell, 537 _Inout_ PCELL_DATA CellData, 538 _In_ BOOLEAN FixHive) 539 { 540 PAGED_CODE(); 541 542 /* Is self healing possible? */ 543 if (!CmIsSelfHealEnabled(FixHive)) 544 { 545 DPRINT1("Self healing not possible\n"); 546 return FALSE; 547 } 548 549 /* 550 * Mark the cell where we got the actual 551 * cell data as dirty and fix the node. 552 */ 553 HvMarkCellDirty(Hive, CurrentCell, FALSE); 554 CellData->u.KeyNode.Parent = ParentCell; 555 556 /* Mark the hive as in self healing mode since we repaired it */ 557 Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL; 558 return TRUE; 559 } 560 561 /** 562 * @brief 563 * Repairs the key node signature from damage 564 * due to signature corruption. 565 * 566 * @param[in,out] Hive 567 * A pointer to a hive descriptor containing faulty data. 568 * 569 * @param[in] CurrentCell 570 * The current cell to be marked as dirty. 571 * 572 * @param[in,out] CellData 573 * The cell data of the current cell of which 574 * its signature is to be repaired. 575 * 576 * @param[in] FixHive 577 * If set to TRUE, self heal is triggered and the target 578 * hive will be fixed. Otherwise the hive will not be fixed. 579 * 580 * @return 581 * Returns TRUE if the function successfully healed the 582 * key node signature, FALSE otherwise. 583 */ 584 BOOLEAN 585 CMAPI 586 CmpRepairKeyNodeSignature( 587 _Inout_ PHHIVE Hive, 588 _In_ HCELL_INDEX CurrentCell, 589 _Inout_ PCELL_DATA CellData, 590 _In_ BOOLEAN FixHive) 591 { 592 PAGED_CODE(); 593 594 /* Is self healing possible? */ 595 if (!CmIsSelfHealEnabled(FixHive)) 596 { 597 DPRINT1("Self healing not possible\n"); 598 return FALSE; 599 } 600 601 /* 602 * Mark the cell where we got the actual 603 * cell data as dirty and fix the key signature. 604 */ 605 HvMarkCellDirty(Hive, CurrentCell, FALSE); 606 CellData->u.KeyNode.Signature = CM_KEY_NODE_SIGNATURE; 607 608 /* Mark the hive as in self healing mode since we repaired it */ 609 Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL; 610 return TRUE; 611 } 612 613 /** 614 * @brief 615 * Repairs the class from damage due to class 616 * corruption within the node key. 617 * 618 * @param[in,out] Hive 619 * A pointer to a hive descriptor containing faulty data. 620 * 621 * @param[in] CurrentCell 622 * The current cell to be marked as dirty. 623 * 624 * @param[in,out] CellData 625 * The cell data of the current cell of which 626 * its class is to be repaired. 627 * 628 * @param[in] FixHive 629 * If set to TRUE, self heal is triggered and the target 630 * hive will be fixed. Otherwise the hive will not be fixed. 631 * 632 * @return 633 * Returns TRUE if the function successfully healed the 634 * class of node key, FALSE otherwise. 635 */ 636 BOOLEAN 637 CMAPI 638 CmpRepairClassOfNodeKey( 639 _Inout_ PHHIVE Hive, 640 _In_ HCELL_INDEX CurrentCell, 641 _Inout_ PCELL_DATA CellData, 642 _In_ BOOLEAN FixHive) 643 { 644 PAGED_CODE(); 645 646 /* Is self healing possible? */ 647 if (!CmIsSelfHealEnabled(FixHive)) 648 { 649 DPRINT1("Self healing not possible\n"); 650 return FALSE; 651 } 652 653 /* 654 * Mark the cell where we got the actual 655 * cell data as dirty and fix the class field 656 * of key node. 657 */ 658 HvMarkCellDirty(Hive, CurrentCell, FALSE); 659 CellData->u.KeyNode.Class = HCELL_NIL; 660 CellData->u.KeyNode.ClassLength = 0; 661 662 /* Mark the hive as in self healing mode since we repaired it */ 663 Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL; 664 return TRUE; 665 } 666 667 /** 668 * @brief 669 * Repairs the value list count of key due to 670 * corruption. The process involves by removing 671 * one damaged value less from the list. 672 * 673 * @param[in,out] Hive 674 * A pointer to a hive descriptor containing faulty data. 675 * 676 * @param[in] CurrentCell 677 * The current cell to be marked as dirty. 678 * 679 * @param[in] ListCountIndex 680 * The value count index which points to the actual 681 * value in the list to be removed. 682 * 683 * @param[in,out] ValueListData 684 * The value list cell data containing the actual list 685 * of which the damaged is to be removed from. 686 * 687 * @param[in] FixHive 688 * If set to TRUE, self heal is triggered and the target 689 * hive will be fixed. Otherwise the hive will not be fixed. 690 * 691 * @return 692 * Returns TRUE if the function successfully healed the 693 * value list count, FALSE otherwise. 694 */ 695 BOOLEAN 696 CMAPI 697 CmpRepairValueListCount( 698 _Inout_ PHHIVE Hive, 699 _In_ HCELL_INDEX CurrentCell, 700 _In_ ULONG ListCountIndex, 701 _Inout_ PCELL_DATA ValueListData, 702 _In_ BOOLEAN FixHive) 703 { 704 PCM_KEY_NODE ValueListNode; 705 706 PAGED_CODE(); 707 708 /* Is self healing possible? */ 709 if (!CmIsSelfHealEnabled(FixHive)) 710 { 711 DPRINT1("Self healing not possible\n"); 712 return FALSE; 713 } 714 715 /* 716 * Obtain a node from the cell that we mark it as dirty. 717 * The node is that of the current cell of which its 718 * value list is being validated. 719 */ 720 ValueListNode = (PCM_KEY_NODE)HvGetCell(Hive, CurrentCell); 721 if (!ValueListNode) 722 { 723 DPRINT1("Could not get a node from the current cell\n"); 724 return FALSE; 725 } 726 727 /* 728 * Mark the current cell and value list as dirty 729 * as we will be making changes onto them. 730 */ 731 HvMarkCellDirty(Hive, CurrentCell, FALSE); 732 HvMarkCellDirty(Hive, ValueListNode->ValueList.List, FALSE); 733 734 /* 735 * Now remove the value from the list and mark the 736 * hive as in self healing mode. 737 */ 738 CmpRemoveValueFromValueList(ValueListNode, ValueListData, ListCountIndex); 739 Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL; 740 HvReleaseCell(Hive, CurrentCell); 741 return TRUE; 742 } 743 744 /** 745 * @brief 746 * Repairs the value list due to corruption. The 747 * process involes by purging the whole damaged 748 * list. 749 * 750 * @param[in,out] Hive 751 * A pointer to a hive descriptor containing faulty data. 752 * 753 * @param[in] CurrentCell 754 * The current cell to be marked as dirty. 755 * 756 * @param[in] FixHive 757 * If set to TRUE, self heal is triggered and the target 758 * hive will be fixed. Otherwise the hive will not be fixed. 759 * 760 * @return 761 * Returns TRUE if the function successfully healed the 762 * value list, FALSE otherwise. 763 */ 764 BOOLEAN 765 CMAPI 766 CmpRepairValueList( 767 _Inout_ PHHIVE Hive, 768 _In_ HCELL_INDEX CurrentCell, 769 _In_ BOOLEAN FixHive) 770 { 771 PCM_KEY_NODE ValueListNode; 772 773 PAGED_CODE(); 774 775 /* Is self healing possible? */ 776 if (!CmIsSelfHealEnabled(FixHive)) 777 { 778 DPRINT1("Self healing not possible\n"); 779 return FALSE; 780 } 781 782 /* Obtain a node */ 783 ValueListNode = (PCM_KEY_NODE)HvGetCell(Hive, CurrentCell); 784 if (!ValueListNode) 785 { 786 DPRINT1("Could not get a node from the current cell\n"); 787 return FALSE; 788 } 789 790 /* Purge out the whole list */ 791 HvMarkCellDirty(Hive, CurrentCell, FALSE); 792 ValueListNode->ValueList.List = HCELL_NIL; 793 ValueListNode->ValueList.Count = 0; 794 795 Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL; 796 HvReleaseCell(Hive, CurrentCell); 797 return TRUE; 798 } 799 800 /** 801 * @brief 802 * Repairs the subkey list count due to corruption. 803 * The process involves by fixing the count itself 804 * with a sane count. 805 * 806 * @param[in,out] Hive 807 * A pointer to a hive descriptor containing faulty data. 808 * 809 * @param[in] CurrentCell 810 * The current cell to be marked as dirty. 811 * 812 * @param[in] Count 813 * The healthy count which is used by the function 814 * to fix the subkeys list count. 815 * 816 * @param[in,out] CellData 817 * The cell data of the current cell of which its 818 * subkeys list is to be fixed. 819 * 820 * @param[in] FixHive 821 * If set to TRUE, self heal is triggered and the target 822 * hive will be fixed. Otherwise the hive will not be fixed. 823 * 824 * @return 825 * Returns TRUE if the function successfully healed the 826 * subkeys list count, FALSE otherwise. 827 */ 828 BOOLEAN 829 CMAPI 830 CmpRepairSubKeyCounts( 831 _Inout_ PHHIVE Hive, 832 _In_ HCELL_INDEX CurrentCell, 833 _In_ ULONG Count, 834 _Inout_ PCELL_DATA CellData, 835 _In_ BOOLEAN FixHive) 836 { 837 PAGED_CODE(); 838 839 /* Is self healing possible? */ 840 if (!CmIsSelfHealEnabled(FixHive)) 841 { 842 DPRINT1("Self healing not possible\n"); 843 return FALSE; 844 } 845 846 /* 847 * Mark the cell where we got the actual 848 * cell data as dirty and fix the subkey 849 * counts. 850 */ 851 HvMarkCellDirty(Hive, CurrentCell, FALSE); 852 CellData->u.KeyNode.SubKeyCounts[Stable] = Count; 853 854 /* Mark the hive as in self healing mode since we repaired it */ 855 Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL; 856 return TRUE; 857 } 858 859 /** 860 * @brief 861 * Repairs the subkey list due to corruption. The process 862 * involves by purging the whole damaged subkeys list. 863 * 864 * @param[in,out] Hive 865 * A pointer to a hive descriptor containing faulty data. 866 * 867 * @param[in] CurrentCell 868 * The current cell to be marked as dirty. 869 * 870 * @param[in,out] CellData 871 * The cell data of the current cell of which its 872 * subkeys list is to be fixed. 873 * 874 * @param[in] FixHive 875 * If set to TRUE, self heal is triggered and the target 876 * hive will be fixed. Otherwise the hive will not be fixed. 877 * 878 * @return 879 * Returns TRUE if the function successfully healed the 880 * subkeys list, FALSE otherwise. 881 */ 882 BOOLEAN 883 CMAPI 884 CmpRepairSubKeyList( 885 _Inout_ PHHIVE Hive, 886 _In_ HCELL_INDEX CurrentCell, 887 _Inout_ PCELL_DATA CellData, 888 _In_ BOOLEAN FixHive) 889 { 890 PAGED_CODE(); 891 892 /* Is self healing possible? */ 893 if (!CmIsSelfHealEnabled(FixHive)) 894 { 895 DPRINT1("Self healing not possible\n"); 896 return FALSE; 897 } 898 899 /* 900 * Mark the cell where we got the actual 901 * cell data as dirty and fix the subkey 902 * list. 903 */ 904 HvMarkCellDirty(Hive, CurrentCell, FALSE); 905 CellData->u.KeyNode.SubKeyLists[Stable] = HCELL_NIL; 906 CellData->u.KeyNode.SubKeyCounts[Stable] = 0; 907 908 /* Mark the hive as in self healing mode since we repaired it */ 909 Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL; 910 return TRUE; 911 } 912 913 /* EOF */ 914