reactos/sdk/lib/cmlib/cmheal.c
George Bișoc 54c552392f
[SDK][CMLIB] Implement self-heal registry helpers
This implements cmheal.c file which provides the basic registry self-heal infrastructure needed by the public CmCheckRegistry function. The infrastructure provides a range of various self-heal helpers for the hive, such as subkey, class, values and node healing functions.
2023-11-19 20:44:27 +01:00

912 lines
25 KiB
C

/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
* PURPOSE: Configuration Manager Library - Registry Self-Heal Routines
* COPYRIGHT: Copyright 2022 George Bișoc <george.bisoc@reactos.org>
*/
#include "cmlib.h"
#define NDEBUG
#include <debug.h>
/* GLOBALS ********************************************************************/
#if !defined(CMLIB_HOST) && !defined(_BLDR_)
extern BOOLEAN CmpSelfHeal;
extern ULONG CmpBootType;
#endif
/* PRIVATE FUNCTIONS **********************************************************/
/**
* @brief
* Removes a cell from a fast key index.
*
* @param[in,out] FastIndex
* The fast key index where a cell has to be removed.
*
* @param[in] Index
* The index which points to the location of the
* cell that is to be removed.
*
* @param[in] UpdateCount
* If set to TRUE, the function will update the fast
* index count accordingly by one value less. If set
* to FALSE, the count won't be updated. See Remarks
* for further information.
*
* @remarks
* In case where the fast index count is not updated is
* when the key index is not a root but a leaf. In such
* scenario such leaf is the actual key index itself
* so updating the fast index count is not necessary (aka
* UpdateCount is set to FALSE).
*/
static
VOID
CmpRemoveFastIndexKeyCell(
_Inout_ PCM_KEY_FAST_INDEX FastIndex,
_In_ ULONG Index,
_In_ BOOLEAN UpdateCount)
{
ULONG MoveCount;
ASSERT(Index < FastIndex->Count);
/* Calculate the number of trailing cells */
MoveCount = FastIndex->Count - Index - 1;
if (MoveCount != 0)
{
/* Remove the cell now by moving one location ahead */
RtlMoveMemory(&FastIndex->List[Index],
&FastIndex->List[Index + 1],
MoveCount * sizeof(CM_INDEX));
}
/* Update the fast index count if asked */
if (UpdateCount)
FastIndex->Count--;
}
/**
* @brief
* Removes a cell from a normal key index.
*
* @param[in,out] KeyIndex
* The key index where a cell has to be removed.
*
* @param[in] Index
* The index which points to the location of the
* cell that is to be removed.
*/
static
VOID
CmpRemoveIndexKeyCell(
_Inout_ PCM_KEY_INDEX KeyIndex,
_In_ ULONG Index)
{
ULONG MoveCount;
ASSERT(Index < KeyIndex->Count);
/* Calculate the number of trailing cells */
MoveCount = KeyIndex->Count - Index - 1;
if (MoveCount != 0)
{
/* Remove the cell now by moving one location ahead */
RtlMoveMemory(&KeyIndex->List[Index],
&KeyIndex->List[Index + 1],
MoveCount * sizeof(HCELL_INDEX));
}
/* Update the key index count */
KeyIndex->Count--;
}
/**
* @brief
* Removes a cell from a key value list node.
*
* @param[in,out] ValueListNode
* The value list node which is used by the
* function to update the value list count.
*
* @param[in,out] ValueListData
* The value list data of which a cell has to be removed.
*
* @param[in] Index
* The index which points to the location of the
* cell that is to be removed.
*/
static
VOID
CmpRemoveValueFromValueList(
_Inout_ PCM_KEY_NODE ValueListNode,
_Inout_ PCELL_DATA ValueListData,
_In_ ULONG Index)
{
ULONG MoveCount;
ASSERT(Index < ValueListNode->ValueList.Count);
/* Calculate the number of trailing values */
MoveCount = ValueListNode->ValueList.Count - Index - 1;
if (MoveCount != 0)
{
/* Remove the value now by moving one location ahead */
RtlMoveMemory(&ValueListData->u.KeyList[Index],
&ValueListData->u.KeyList[Index + 1],
MoveCount * sizeof(HCELL_INDEX));
}
/* Update the value list count */
ValueListNode->ValueList.Count--;
}
/**
* @brief
* Removes the offending subkey from a root index.
*
* @param[in] Hive
* A pointer to a hive descriptor containing faulty data.
*
* @param[in] RootIndex
* The root index where a leaf is obtained from. Such
* leaf is used to check deep down the leaf for the offending
* subkey.
*
* @param[in] TargetKey
* The offending target subkey to be removed.
*
* @return
* Returns TRUE if the function successfully removed the target
* key, FALSE otherwise.
*/
static
BOOLEAN
CmpRemoveSubkeyInRoot(
_In_ PHHIVE Hive,
_In_ PCM_KEY_INDEX RootIndex,
_In_ HCELL_INDEX TargetKey)
{
PCM_KEY_INDEX Leaf;
PCM_KEY_FAST_INDEX FastIndex;
HCELL_INDEX LeafCell;
ULONG RootCountIndex;
ULONG LeafCountIndex;
PAGED_CODE();
ASSERT(RootIndex);
/* Loop the root index */
for (RootCountIndex = 0; RootCountIndex < RootIndex->Count; RootCountIndex++)
{
/*
* Release the leaf cell from previous iteration
* of the loop. Make sure what we're releasing is
* valid to begin with.
*/
if (RootCountIndex)
{
ASSERT(Leaf);
ASSERT(LeafCell == RootIndex->List[RootCountIndex - 1]);
HvReleaseCell(Hive, LeafCell);
}
/* Get the leaf cell and the leaf for this index */
LeafCell = RootIndex->List[RootCountIndex];
Leaf = (PCM_KEY_INDEX)HvGetCell(Hive, LeafCell);
if (!Leaf)
{
DPRINT1("Couldn't get the leaf from cell\n");
return FALSE;
}
/* Start looping the leaf */
for (LeafCountIndex = 0; LeafCountIndex < Leaf->Count; LeafCountIndex++)
{
/* Is the leaf a fast leaf or a hash one? */
if ((Leaf->Signature == CM_KEY_FAST_LEAF) ||
(Leaf->Signature == CM_KEY_HASH_LEAF))
{
/* It is one of the two, get the fast index */
FastIndex = (PCM_KEY_FAST_INDEX)Leaf;
/*
* Is the subkey cell from the fast
* index the one we one we're actually
* searching?
*/
if (FastIndex->List[LeafCountIndex].Cell == TargetKey)
{
HvReleaseCell(Hive, LeafCell);
HvMarkCellDirty(Hive, LeafCell, FALSE);
CmpRemoveFastIndexKeyCell(FastIndex, LeafCountIndex, TRUE);
DPRINT1("The offending key cell has BEEN FOUND in fast index (fast index 0x%p, index %lu)\n",
FastIndex, LeafCountIndex);
return TRUE;
}
}
else
{
/*
* The leaf is neither of the two. Check if
* the target offending cell is inside the leaf
* itself.
*/
if (Leaf->List[LeafCountIndex] == TargetKey)
{
HvReleaseCell(Hive, LeafCell);
HvMarkCellDirty(Hive, LeafCell, FALSE);
CmpRemoveIndexKeyCell(Leaf, LeafCountIndex);
DPRINT1("The offending key cell has BEEN FOUND in leaf (leaf 0x%p, index %lu)\n",
Leaf, LeafCountIndex);
return TRUE;
}
}
}
}
/*
* We have searched everywhere but we couldn't
* hunt the offending target key cell.
*/
DPRINT1("No target key has been found to remove\n");
return FALSE;
}
/**
* @brief
* Removes the offending subkey from a leaf index.
*
* @param[in] Hive
* A pointer to a hive descriptor containing faulty data.
*
* @param[in] KeyNode
* A pointer to a key node of the parent. This node is
* used by the function to mark the whole subkeys list
* of the parent dirty.
*
* @param[in] Leaf
* A pointer to a leaf key index of which the offending
* subkey is to be removed from.
*
* @param[in] TargetKey
* The offending target subkey to remove.
*
* @return
* Returns TRUE if the function successfully removed the target
* key, FALSE otherwise.
*/
static
BOOLEAN
CmpRemoveSubKeyInLeaf(
_In_ PHHIVE Hive,
_In_ PCM_KEY_NODE KeyNode,
_In_ PCM_KEY_INDEX Leaf,
_In_ HCELL_INDEX TargetKey)
{
PCM_KEY_FAST_INDEX FastIndex;
ULONG LeafIndex;
/* Loop the leaf index */
for (LeafIndex = 0; LeafIndex < Leaf->Count; LeafIndex++)
{
/*
* Check if the main leaf is a fast
* leaf or a hash one.
*/
if ((Leaf->Signature == CM_KEY_FAST_LEAF) ||
(Leaf->Signature == CM_KEY_HASH_LEAF))
{
/* It is one of the two, get the fast index */
FastIndex = (PCM_KEY_FAST_INDEX)Leaf;
/*
* Is the subkey cell from the fast
* index the one we're actually
* searching?
*/
if (FastIndex->List[LeafIndex].Cell == TargetKey)
{
HvMarkCellDirty(Hive, KeyNode->SubKeyLists[Stable], FALSE);
CmpRemoveFastIndexKeyCell(FastIndex, LeafIndex, FALSE);
/*
* Since this fast index actually came from the
* actual leaf index itself, just update its count
* rather than that of the fast index.
*/
Leaf->Count--;
DPRINT1("The offending key cell has BEEN FOUND in fast index (fast index 0x%p, leaf index %lu)\n",
FastIndex, LeafIndex);
return TRUE;
}
}
else
{
/*
* The leaf is neither of the two. The offending
* cell must come directly from the normal leaf
* at this point.
*/
if (Leaf->List[LeafIndex] == TargetKey)
{
HvMarkCellDirty(Hive, KeyNode->SubKeyLists[Stable], FALSE);
CmpRemoveIndexKeyCell(Leaf, LeafIndex);
DPRINT1("The offending key cell has BEEN FOUND in leaf (leaf 0x%p, index %lu)\n",
Leaf, LeafIndex);
return TRUE;
}
}
}
/*
* We have searched everywhere but we couldn't
* hunt the offending target key cell.
*/
DPRINT1("No target key has been found to remove\n");
return FALSE;
}
/* PUBLIC FUNCTIONS ***********************************************************/
/**
* @brief
* Checks if self healing is permitted by the kernel and/or
* bootloader. Self healing is also triggered if such a
* request was prompted by the user to fix a broken hive.
* Such a request tipically comes from a registry repair
* tool such as the ReactOS Check Registry Utility.
*
* @param[in] FixHive
* If set to TRUE, self heal is triggered and the target
* hive will be fixed. Otherwise the hive will not be fixed.
*
* @return
* Returns TRUE if self healing is possible, FALSE otherwise.
*/
BOOLEAN
CMAPI
CmIsSelfHealEnabled(
_In_ BOOLEAN FixHive)
{
PAGED_CODE();
if (FixHive)
return TRUE;
#if !defined(CMLIB_HOST) && !defined(_BLDR_)
if (CmpSelfHeal || (CmpBootType & HBOOT_TYPE_SELF_HEAL))
return TRUE;
#endif
return FALSE;
}
/**
* @brief
* Repairs the parent key from damage by removing the
* offending subkey cell.
*
* @param[in,out] Hive
* A pointer to a hive descriptor containing faulty data.
*
* @param[in] TargetKey
* The offending target cell to remove from the parent.
*
* @param[in] ParentKey
* The damaged parent key cell to heal.
*
* @param[in] FixHive
* If set to TRUE, self heal is triggered and the target
* hive will be fixed. Otherwise the hive will not be fixed.
*
* @return
* Returns TRUE if the function successfully healed the parent
* key, FALSE otherwise.
*/
BOOLEAN
CMAPI
CmpRepairParentKey(
_Inout_ PHHIVE Hive,
_In_ HCELL_INDEX TargetKey,
_In_ HCELL_INDEX ParentKey,
_In_ BOOLEAN FixHive)
{
PCM_KEY_INDEX KeyIndex;
PCM_KEY_NODE KeyNode;
BOOLEAN ParentRepaired;
PAGED_CODE();
/* The target key must NEVER be NIL! */
ASSERT(TargetKey != HCELL_NIL);
/* Assume the parent hasn't been repaired yet */
ParentRepaired = FALSE;
/* Is self healing possible? */
if (!CmIsSelfHealEnabled(FixHive))
{
DPRINT1("Self healing not possible\n");
return ParentRepaired;
}
/* Obtain a node from the parent */
KeyNode = (PCM_KEY_NODE)HvGetCell(Hive, ParentKey);
if (!KeyNode)
{
DPRINT1("Couldn't get the parent key node\n");
return ParentRepaired;
}
/* Obtain the index as well since we got the parent node */
KeyIndex = (PCM_KEY_INDEX)HvGetCell(Hive, KeyNode->SubKeyLists[Stable]);
if (!KeyIndex)
{
DPRINT1("Couldn't get the key index from parent node\n");
HvReleaseCell(Hive, ParentKey);
return ParentRepaired;
}
/* Check if this is a root */
if (KeyIndex->Signature == CM_KEY_INDEX_ROOT)
{
/* It is, call the specific helper to discard the damaged key down the root */
ParentRepaired = CmpRemoveSubkeyInRoot(Hive,
KeyIndex,
TargetKey);
}
else if ((KeyIndex->Signature == CM_KEY_INDEX_LEAF) ||
(KeyIndex->Signature == CM_KEY_FAST_LEAF) ||
(KeyIndex->Signature == CM_KEY_HASH_LEAF))
{
/* Otherwise call the leaf helper */
ParentRepaired = CmpRemoveSubKeyInLeaf(Hive,
KeyNode,
KeyIndex,
TargetKey);
}
else
{
/*
* Generally CmCheckRegistry detects if a key index
* in the subkeys list is totally broken (we understand
* that if its signature is not root or leaf) and it will
* purge the whole subkeys list in such cases. With that
* being said, we should never reach this code path. But
* if for whatever reason we reach here then something
* is seriously wrong.
*/
DPRINT1("The key index signature is invalid (KeyIndex->Signature == %lu)", KeyIndex->Signature);
ASSERT(FALSE);
}
/*
* If we successfully removed the offending key
* cell mark down the parent as dirty and punt down
* the subkey count as well. Mark the hive as in
* self heal mode as well.
*/
if (ParentRepaired)
{
HvMarkCellDirty(Hive, ParentKey, FALSE);
KeyNode->SubKeyCounts[Stable]--;
Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL;
DPRINT1("The subkey has been removed, the parent is now repaired\n");
}
HvReleaseCell(Hive, KeyNode->SubKeyLists[Stable]);
HvReleaseCell(Hive, ParentKey);
return ParentRepaired;
}
/**
* @brief
* Repairs the parent of the node from damage due
* to parent cell and parent node incosistency.
*
* @param[in,out] Hive
* A pointer to a hive descriptor containing faulty data.
*
* @param[in] CurrentCell
* The current cell to be marked as dirty.
*
* @param[in] ParentCell
* The sane parent cell which is used by the
* function for new parent node assignment.
*
* @param[in,out] CellData
* The cell data of the current cell of which
* its parent node is to be repaired.
*
* @param[in] FixHive
* If set to TRUE, self heal is triggered and the target
* hive will be fixed. Otherwise the hive will not be fixed.
*
* @return
* Returns TRUE if the function successfully healed the
* parent node, FALSE otherwise.
*/
BOOLEAN
CMAPI
CmpRepairParentNode(
_Inout_ PHHIVE Hive,
_In_ HCELL_INDEX CurrentCell,
_In_ HCELL_INDEX ParentCell,
_Inout_ PCELL_DATA CellData,
_In_ BOOLEAN FixHive)
{
PAGED_CODE();
/* Is self healing possible? */
if (!CmIsSelfHealEnabled(FixHive))
{
DPRINT1("Self healing not possible\n");
return FALSE;
}
/*
* Mark the cell where we got the actual
* cell data as dirty and fix the node.
*/
HvMarkCellDirty(Hive, CurrentCell, FALSE);
CellData->u.KeyNode.Parent = ParentCell;
/* Mark the hive as in self healing mode since we repaired it */
Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL;
return TRUE;
}
/**
* @brief
* Repairs the key node signature from damage
* due to signature corruption.
*
* @param[in,out] Hive
* A pointer to a hive descriptor containing faulty data.
*
* @param[in] CurrentCell
* The current cell to be marked as dirty.
*
* @param[in,out] CellData
* The cell data of the current cell of which
* its signature is to be repaired.
*
* @param[in] FixHive
* If set to TRUE, self heal is triggered and the target
* hive will be fixed. Otherwise the hive will not be fixed.
*
* @return
* Returns TRUE if the function successfully healed the
* key node signature, FALSE otherwise.
*/
BOOLEAN
CMAPI
CmpRepairKeyNodeSignature(
_Inout_ PHHIVE Hive,
_In_ HCELL_INDEX CurrentCell,
_Inout_ PCELL_DATA CellData,
_In_ BOOLEAN FixHive)
{
PAGED_CODE();
/* Is self healing possible? */
if (!CmIsSelfHealEnabled(FixHive))
{
DPRINT1("Self healing not possible\n");
return FALSE;
}
/*
* Mark the cell where we got the actual
* cell data as dirty and fix the key signature.
*/
HvMarkCellDirty(Hive, CurrentCell, FALSE);
CellData->u.KeyNode.Signature = CM_KEY_NODE_SIGNATURE;
/* Mark the hive as in self healing mode since we repaired it */
Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL;
return TRUE;
}
/**
* @brief
* Repairs the class from damage due to class
* corruption within the node key.
*
* @param[in,out] Hive
* A pointer to a hive descriptor containing faulty data.
*
* @param[in] CurrentCell
* The current cell to be marked as dirty.
*
* @param[in,out] CellData
* The cell data of the current cell of which
* its class is to be repaired.
*
* @param[in] FixHive
* If set to TRUE, self heal is triggered and the target
* hive will be fixed. Otherwise the hive will not be fixed.
*
* @return
* Returns TRUE if the function successfully healed the
* class of node key, FALSE otherwise.
*/
BOOLEAN
CMAPI
CmpRepairClassOfNodeKey(
_Inout_ PHHIVE Hive,
_In_ HCELL_INDEX CurrentCell,
_Inout_ PCELL_DATA CellData,
_In_ BOOLEAN FixHive)
{
PAGED_CODE();
/* Is self healing possible? */
if (!CmIsSelfHealEnabled(FixHive))
{
DPRINT1("Self healing not possible\n");
return FALSE;
}
/*
* Mark the cell where we got the actual
* cell data as dirty and fix the class field
* of key node.
*/
HvMarkCellDirty(Hive, CurrentCell, FALSE);
CellData->u.KeyNode.Class = HCELL_NIL;
CellData->u.KeyNode.ClassLength = 0;
/* Mark the hive as in self healing mode since we repaired it */
Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL;
return TRUE;
}
/**
* @brief
* Repairs the value list count of key due to
* corruption. The process involves by removing
* one damaged value less from the list.
*
* @param[in,out] Hive
* A pointer to a hive descriptor containing faulty data.
*
* @param[in] CurrentCell
* The current cell to be marked as dirty.
*
* @param[in] ListCountIndex
* The value count index which points to the actual
* value in the list to be removed.
*
* @param[in,out] ValueListData
* The value list cell data containing the actual list
* of which the damaged is to be removed from.
*
* @param[in] FixHive
* If set to TRUE, self heal is triggered and the target
* hive will be fixed. Otherwise the hive will not be fixed.
*
* @return
* Returns TRUE if the function successfully healed the
* value list count, FALSE otherwise.
*/
BOOLEAN
CMAPI
CmpRepairValueListCount(
_Inout_ PHHIVE Hive,
_In_ HCELL_INDEX CurrentCell,
_In_ ULONG ListCountIndex,
_Inout_ PCELL_DATA ValueListData,
_In_ BOOLEAN FixHive)
{
PCM_KEY_NODE ValueListNode;
PAGED_CODE();
/* Is self healing possible? */
if (!CmIsSelfHealEnabled(FixHive))
{
DPRINT1("Self healing not possible\n");
return FALSE;
}
/*
* Obtain a node from the cell that we mark it as dirty.
* The node is that of the current cell of which its
* value list is being validated.
*/
ValueListNode = (PCM_KEY_NODE)HvGetCell(Hive, CurrentCell);
if (!ValueListNode)
{
DPRINT1("Could not get a node from the current cell\n");
return FALSE;
}
/*
* Mark the current cell and value list as dirty
* as we will be making changes onto them.
*/
HvMarkCellDirty(Hive, CurrentCell, FALSE);
HvMarkCellDirty(Hive, ValueListNode->ValueList.List, FALSE);
/*
* Now remove the value from the list and mark the
* hive as in self healing mode.
*/
CmpRemoveValueFromValueList(ValueListNode, ValueListData, ListCountIndex);
Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL;
HvReleaseCell(Hive, CurrentCell);
return TRUE;
}
/**
* @brief
* Repairs the value list due to corruption. The
* process involes by purging the whole damaged
* list.
*
* @param[in,out] Hive
* A pointer to a hive descriptor containing faulty data.
*
* @param[in] CurrentCell
* The current cell to be marked as dirty.
*
* @param[in] FixHive
* If set to TRUE, self heal is triggered and the target
* hive will be fixed. Otherwise the hive will not be fixed.
*
* @return
* Returns TRUE if the function successfully healed the
* value list, FALSE otherwise.
*/
BOOLEAN
CMAPI
CmpRepairValueList(
_Inout_ PHHIVE Hive,
_In_ HCELL_INDEX CurrentCell,
_In_ BOOLEAN FixHive)
{
PCM_KEY_NODE ValueListNode;
PAGED_CODE();
/* Is self healing possible? */
if (!CmIsSelfHealEnabled(FixHive))
{
DPRINT1("Self healing not possible\n");
return FALSE;
}
/* Obtain a node */
ValueListNode = (PCM_KEY_NODE)HvGetCell(Hive, CurrentCell);
if (!ValueListNode)
{
DPRINT1("Could not get a node from the current cell\n");
return FALSE;
}
/* Purge out the whole list */
HvMarkCellDirty(Hive, CurrentCell, FALSE);
ValueListNode->ValueList.List = HCELL_NIL;
ValueListNode->ValueList.Count = 0;
Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL;
HvReleaseCell(Hive, CurrentCell);
return TRUE;
}
/**
* @brief
* Repairs the subkey list count due to corruption.
* The process involves by fixing the count itself
* with a sane count.
*
* @param[in,out] Hive
* A pointer to a hive descriptor containing faulty data.
*
* @param[in] CurrentCell
* The current cell to be marked as dirty.
*
* @param[in] Count
* The healthy count which is used by the function
* to fix the subkeys list count.
*
* @param[in,out] CellData
* The cell data of the current cell of which its
* subkeys list is to be fixed.
*
* @param[in] FixHive
* If set to TRUE, self heal is triggered and the target
* hive will be fixed. Otherwise the hive will not be fixed.
*
* @return
* Returns TRUE if the function successfully healed the
* subkeys list count, FALSE otherwise.
*/
BOOLEAN
CMAPI
CmpRepairSubKeyCounts(
_Inout_ PHHIVE Hive,
_In_ HCELL_INDEX CurrentCell,
_In_ ULONG Count,
_Inout_ PCELL_DATA CellData,
_In_ BOOLEAN FixHive)
{
PAGED_CODE();
/* Is self healing possible? */
if (!CmIsSelfHealEnabled(FixHive))
{
DPRINT1("Self healing not possible\n");
return FALSE;
}
/*
* Mark the cell where we got the actual
* cell data as dirty and fix the subkey
* counts.
*/
HvMarkCellDirty(Hive, CurrentCell, FALSE);
CellData->u.KeyNode.SubKeyCounts[Stable] = Count;
/* Mark the hive as in self healing mode since we repaired it */
Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL;
return TRUE;
}
/**
* @brief
* Repairs the subkey list due to corruption. The process
* involves by purging the whole damaged subkeys list.
*
* @param[in,out] Hive
* A pointer to a hive descriptor containing faulty data.
*
* @param[in] CurrentCell
* The current cell to be marked as dirty.
*
* @param[in,out] CellData
* The cell data of the current cell of which its
* subkeys list is to be fixed.
*
* @param[in] FixHive
* If set to TRUE, self heal is triggered and the target
* hive will be fixed. Otherwise the hive will not be fixed.
*
* @return
* Returns TRUE if the function successfully healed the
* subkeys list, FALSE otherwise.
*/
BOOLEAN
CMAPI
CmpRepairSubKeyList(
_Inout_ PHHIVE Hive,
_In_ HCELL_INDEX CurrentCell,
_Inout_ PCELL_DATA CellData,
_In_ BOOLEAN FixHive)
{
PAGED_CODE();
/* Is self healing possible? */
if (!CmIsSelfHealEnabled(FixHive))
{
DPRINT1("Self healing not possible\n");
return FALSE;
}
/*
* Mark the cell where we got the actual
* cell data as dirty and fix the subkey
* list.
*/
HvMarkCellDirty(Hive, CurrentCell, FALSE);
CellData->u.KeyNode.SubKeyLists[Stable] = HCELL_NIL;
CellData->u.KeyNode.SubKeyCounts[Stable] = 0;
/* Mark the hive as in self healing mode since we repaired it */
Hive->BaseBlock->BootType |= HBOOT_TYPE_SELF_HEAL;
return TRUE;
}
/* EOF */