https://git.reactos.org/?p=reactos.git;a=commitdiff;h=279f8f88644246b95521f2deb7c99badcf726f12

commit 279f8f88644246b95521f2deb7c99badcf726f12
Author:     George Bișoc <[email protected]>
AuthorDate: Thu Nov 9 20:40:23 2023 +0100
Commit:     George Bișoc <[email protected]>
CommitDate: Sun Nov 19 20:44:29 2023 +0100

    [CMLIB] Fix the bin during hive initialization from memory if it's corrupt
    
    As we iterate over the chunk hive data pointer for hive bins that we are 
going
    to enlist, we might encounter one or several bins that would get corrupted
    during a premature abortion of a registry writing operation such as due to
    a power outage of the system, hardware malfunction, etc.
    
    Corruption at the level of hive bins is nasty because they contain actual 
cell
    data of registry information such as keys, values etc. Assuming a bin is 
corrupt
    in part we can fix it by recovering some of the bin properties that, 
theoretically,
    could be fixed -- namely the signature, size and offset.
    
    For size and offset we are more or less safe because a bin typically has a 
size
    of a block, and the offset is the coordinate index of where a hive bin 
should lay at.
---
 sdk/lib/cmlib/hiveinit.c | 28 +++++++++++++++++++++++-----
 1 file changed, 23 insertions(+), 5 deletions(-)

diff --git a/sdk/lib/cmlib/hiveinit.c b/sdk/lib/cmlib/hiveinit.c
index 0b03ddf258b..a89a5050c21 100644
--- a/sdk/lib/cmlib/hiveinit.c
+++ b/sdk/lib/cmlib/hiveinit.c
@@ -368,13 +368,31 @@ HvpInitializeMemoryHive(
     {
         Bin = (PHBIN)((ULONG_PTR)ChunkBase + (BlockIndex + 1) * HBLOCK_SIZE);
         if (Bin->Signature != HV_HBIN_SIGNATURE ||
-           (Bin->Size % HBLOCK_SIZE) != 0)
+           (Bin->Size % HBLOCK_SIZE) != 0 ||
+           (Bin->FileOffset / HBLOCK_SIZE) != BlockIndex)
         {
-            DPRINT1("Invalid bin at BlockIndex %lu, Signature 0x%x, Size 
0x%x\n",
+            /*
+             * Bin is toast but luckily either the signature, size or offset
+             * is out of order. For the signature it is obvious what we are 
going
+             * to do, for the offset we are re-positioning the bin back to 
where it
+             * was and for the size we will set it up to a block size, since 
technically
+             * a hive bin is large as a block itself to accommodate cells.
+             */
+            if (!CmIsSelfHealEnabled(FALSE))
+            {
+                DPRINT1("Invalid bin at BlockIndex %lu, Signature 0x%x, Size 
0x%x. Self-heal not possible!\n",
                     (unsigned long)BlockIndex, (unsigned)Bin->Signature, 
(unsigned)Bin->Size);
-            Hive->Free(Hive->Storage[Stable].BlockList, 0);
-            Hive->Free(Hive->BaseBlock, Hive->BaseBlockAlloc);
-            return STATUS_REGISTRY_CORRUPT;
+                Hive->Free(Hive->Storage[Stable].BlockList, 0);
+                Hive->Free(Hive->BaseBlock, Hive->BaseBlockAlloc);
+                return STATUS_REGISTRY_CORRUPT;
+            }
+
+            /* Fix this bin */
+            Bin->Signature = HV_HBIN_SIGNATURE;
+            Bin->Size = HBLOCK_SIZE;
+            Bin->FileOffset = BlockIndex * HBLOCK_SIZE;
+            ChunkBase->BootType |= HBOOT_TYPE_SELF_HEAL;
+            DPRINT1("Bin at index %lu is corrupt and it has been repaired!\n", 
(unsigned long)BlockIndex);
         }
 
         NewBin = Hive->Allocate(Bin->Size, TRUE, TAG_CM);

Reply via email to