mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 10:04:49 +00:00
54c552392f
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.
912 lines
25 KiB
C
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 */
|