xref: /reactos/sdk/lib/cmlib/cmheal.c (revision ee5338ff)
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
CmpRemoveFastIndexKeyCell(_Inout_ PCM_KEY_FAST_INDEX FastIndex,_In_ ULONG Index,_In_ BOOLEAN UpdateCount)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
CmpRemoveIndexKeyCell(_Inout_ PCM_KEY_INDEX KeyIndex,_In_ ULONG Index)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
CmpRemoveValueFromValueList(_Inout_ PCM_KEY_NODE ValueListNode,_Inout_ PCELL_DATA ValueListData,_In_ ULONG Index)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
CmpRemoveSubkeyInRoot(_In_ PHHIVE Hive,_In_ PCM_KEY_INDEX RootIndex,_In_ HCELL_INDEX TargetKey)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
CmpRemoveSubKeyInLeaf(_In_ PHHIVE Hive,_In_ PCM_KEY_NODE KeyNode,_In_ PCM_KEY_INDEX Leaf,_In_ HCELL_INDEX TargetKey)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
CmIsSelfHealEnabled(_In_ BOOLEAN FixHive)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
CmpRepairParentKey(_Inout_ PHHIVE Hive,_In_ HCELL_INDEX TargetKey,_In_ HCELL_INDEX ParentKey,_In_ BOOLEAN FixHive)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
CmpRepairParentNode(_Inout_ PHHIVE Hive,_In_ HCELL_INDEX CurrentCell,_In_ HCELL_INDEX ParentCell,_Inout_ PCELL_DATA CellData,_In_ BOOLEAN FixHive)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
CmpRepairKeyNodeSignature(_Inout_ PHHIVE Hive,_In_ HCELL_INDEX CurrentCell,_Inout_ PCELL_DATA CellData,_In_ BOOLEAN FixHive)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
CmpRepairClassOfNodeKey(_Inout_ PHHIVE Hive,_In_ HCELL_INDEX CurrentCell,_Inout_ PCELL_DATA CellData,_In_ BOOLEAN FixHive)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
CmpRepairValueListCount(_Inout_ PHHIVE Hive,_In_ HCELL_INDEX CurrentCell,_In_ ULONG ListCountIndex,_Inout_ PCELL_DATA ValueListData,_In_ BOOLEAN FixHive)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
CmpRepairValueList(_Inout_ PHHIVE Hive,_In_ HCELL_INDEX CurrentCell,_In_ BOOLEAN FixHive)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
CmpRepairSubKeyCounts(_Inout_ PHHIVE Hive,_In_ HCELL_INDEX CurrentCell,_In_ ULONG Count,_Inout_ PCELL_DATA CellData,_In_ BOOLEAN FixHive)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
CmpRepairSubKeyList(_Inout_ PHHIVE Hive,_In_ HCELL_INDEX CurrentCell,_Inout_ PCELL_DATA CellData,_In_ BOOLEAN FixHive)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