xref: /reactos/sdk/lib/cmlib/cmheal.c (revision 44662eaf)
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