Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[reactos.git] / reactos / boot / environ / lib / misc / bootreg.c
diff --git a/reactos/boot/environ/lib/misc/bootreg.c b/reactos/boot/environ/lib/misc/bootreg.c
deleted file mode 100644 (file)
index 88b970d..0000000
+++ /dev/null
@@ -1,947 +0,0 @@
-/*
- * COPYRIGHT:       See COPYING.ARM in the top level directory
- * PROJECT:         ReactOS UEFI Boot Library
- * FILE:            boot/environ/lib/misc/bootreg.c
- * PURPOSE:         Boot Library Boot Registry Wrapper for CMLIB
- * PROGRAMMER:      Alex Ionescu (alex.ionescu@reactos.org)
- */
-
-/* INCLUDES ******************************************************************/
-
-#include "bl.h"
-#include <bcd.h>
-
-/* DEFINITIONS ***************************************************************/
-
-#define BI_FLUSH_HIVE       0x01
-#define BI_HIVE_WRITEABLE   0x02
-
-/* DATA STRUCTURES ***********************************************************/
-
-typedef struct _BI_KEY_HIVE
-{
-    PHBASE_BLOCK BaseBlock;
-    ULONG HiveSize;
-    PBL_FILE_PATH_DESCRIPTOR FilePath;
-    CMHIVE Hive;
-    LONG ReferenceCount;
-    ULONG Flags;
-    PCM_KEY_NODE RootNode;
-} BI_KEY_HIVE, *PBI_KEY_HIVE;
-
-typedef struct _BI_KEY_OBJECT
-{
-    PBI_KEY_HIVE KeyHive;
-    PCM_KEY_NODE KeyNode;
-    HCELL_INDEX KeyCell;
-    PWCHAR KeyName;
-} BI_KEY_OBJECT, *PBI_KEY_OBJECT;
-
-/* GLOBALS *******************************************************************/
-
-BOOLEAN BiHiveHashLibraryInitialized;
-ULONGLONG HvSymcryptSeed;
-
-/* FUNCTIONS *****************************************************************/
-
-BOOLEAN
-HvIsInPlaceBaseBlockValid (
-    _In_ PHBASE_BLOCK BaseBlock
-    )
-{
-    ULONG HiveLength, HeaderSum;
-    BOOLEAN Valid;
-
-    /* Assume failure */
-    Valid = FALSE;
-
-    /* Check for incorrect signature, type, version, or format */
-    if ((BaseBlock->Signature == 'fger') &&
-        (BaseBlock->Type == 0) &&
-        (BaseBlock->Major <= 1) &&
-        (BaseBlock->Minor <= 5) &&
-        (BaseBlock->Minor >= 3) &&
-        (BaseBlock->Format == 1))
-    {
-        /* Check for invalid hive size */
-        HiveLength = BaseBlock->Length;
-        if (HiveLength)
-        {
-            /* Check for misaligned or too large hive size */
-            if (!(HiveLength & 0xFFF) && HiveLength <= 0x7FFFE000)
-            {
-                /* Check for invalid header checksum */
-                HeaderSum = HvpHiveHeaderChecksum(BaseBlock);
-                if (HeaderSum == BaseBlock->CheckSum)
-                {
-                    /* All good */
-                    Valid = TRUE;
-                }
-            }
-        }
-    }
-
-    /* Return validity */
-    return Valid;
-}
-
-PVOID
-NTAPI
-CmpAllocate (
-    _In_ SIZE_T Size,
-    _In_ BOOLEAN Paged,
-    _In_ ULONG Tag
-    )
-{
-    UNREFERENCED_PARAMETER(Paged);
-    UNREFERENCED_PARAMETER(Tag);
-
-    /* Call the heap allocator */
-    return BlMmAllocateHeap(Size);
-}
-
-VOID
-NTAPI
-CmpFree (
-    _In_ PVOID Ptr,
-    _In_ ULONG Quota
-    )
-{
-    UNREFERENCED_PARAMETER(Quota);
-
-    /* Call the heap allocator */
-    BlMmFreeHeap(Ptr);
-}
-
-VOID
-BiDereferenceHive (
-    _In_ HANDLE KeyHandle
-    )
-{
-    PBI_KEY_OBJECT KeyObject;
-
-    /* Get the key object */
-    KeyObject = (PBI_KEY_OBJECT)KeyHandle;
-
-    /* Drop a reference on the parent hive */
-    --KeyObject->KeyHive->ReferenceCount;
-}
-
-VOID
-BiFlushHive (
-    _In_ HANDLE KeyHandle
-    )
-{
-    /* Not yet implemented */
-    EfiPrintf(L"NO reg flush\r\n");
-    return;
-}
-
-VOID
-BiCloseKey (
-    _In_ HANDLE KeyHandle
-    )
-{
-    PBI_KEY_HIVE KeyHive;
-    PBI_KEY_OBJECT KeyObject;
-
-    /* Get the key object and hive */
-    KeyObject = (PBI_KEY_OBJECT)KeyHandle;
-    KeyHive = KeyObject->KeyHive;
-
-    /* Check if we have a hive, or name, or key node */
-    if ((KeyHive) || (KeyObject->KeyNode) || (KeyObject->KeyName))
-    {
-        /* Drop a reference, see if it's the last one */
-        BiDereferenceHive(KeyHandle);
-        if (!KeyHive->ReferenceCount)
-        {
-            /* Check if we should flush it */
-            if (KeyHive->Flags & BI_FLUSH_HIVE)
-            {
-                BiFlushHive(KeyHandle);
-            }
-
-            /* Unmap the hive */
-            MmPapFreePages(KeyHive->BaseBlock, BL_MM_INCLUDE_MAPPED_ALLOCATED);
-
-            /* Free the hive and hive path */
-            BlMmFreeHeap(KeyHive->FilePath);
-            BlMmFreeHeap(KeyHive);
-        }
-
-        /* Check if a key name is present */
-        if (KeyObject->KeyName)
-        {
-            /* Free it */
-            BlMmFreeHeap(KeyObject->KeyName);
-        }
-    }
-
-    /* Free the object */
-    BlMmFreeHeap(KeyObject);
-}
-
-NTSTATUS
-BiOpenKey(
-    _In_ HANDLE ParentHandle,
-    _In_ PWCHAR KeyName,
-    _Out_ PHANDLE Handle
-    )
-{
-    PBI_KEY_OBJECT ParentKey, NewKey;
-    PBI_KEY_HIVE ParentHive;
-    NTSTATUS Status;
-    ULONG NameLength, SubNameLength, NameBytes;
-    PWCHAR NameStart, NameBuffer;
-    UNICODE_STRING KeyString;
-    HCELL_INDEX KeyCell;
-    PHHIVE Hive;
-    PCM_KEY_NODE ParentNode;
-
-    /* Convert from a handle to our key object */
-    ParentKey = (PBI_KEY_OBJECT)ParentHandle;
-
-    /* Extract the hive and node information */
-    ParentHive = ParentKey->KeyHive;
-    ParentNode = ParentKey->KeyNode;
-    Hive = &ParentKey->KeyHive->Hive.Hive;
-
-    /* Initialize variables */
-    KeyCell = HCELL_NIL;
-    Status = STATUS_SUCCESS;
-    NameBuffer = NULL;
-
-    /* Loop as long as there's still portions of the key name in play */
-    NameLength = wcslen(KeyName);
-    while (NameLength)
-    {
-        /* Find the first path separator */
-        NameStart = wcschr(KeyName, OBJ_NAME_PATH_SEPARATOR);
-        if (NameStart)
-        {
-            /* Look only at the key before the separator */
-            SubNameLength = NameStart - KeyName;
-            ++NameStart;
-        }
-        else
-        {
-            /* No path separator, this is the final leaf key */
-            SubNameLength = NameLength;
-        }
-
-        /* Free the name buffer from the previous pass if needed */
-        if (NameBuffer)
-        {
-            BlMmFreeHeap(NameBuffer);
-        }
-
-        /* Allocate a buffer to hold the name of this specific subkey only */
-        NameBytes = SubNameLength * sizeof(WCHAR);
-        NameBuffer = BlMmAllocateHeap(NameBytes + sizeof(UNICODE_NULL));
-        if (!NameBuffer)
-        {
-            Status = STATUS_NO_MEMORY;
-            goto Quickie;
-        }
-
-        /* Copy and null-terminate the name of the subkey */
-        RtlCopyMemory(NameBuffer, KeyName, NameBytes);
-        NameBuffer[SubNameLength] = UNICODE_NULL;
-
-        /* Convert it into a UNICODE_STRING and try to find it */
-        RtlInitUnicodeString(&KeyString, NameBuffer);
-        KeyCell = CmpFindSubKeyByName(Hive, ParentNode, &KeyString);
-        if (KeyCell == HCELL_NIL)
-        {
-            Status = STATUS_OBJECT_NAME_NOT_FOUND;
-            goto Quickie;
-        }
-
-        /* We found it -- get the key node out of it */
-        ParentNode = (PCM_KEY_NODE)HvGetCell(Hive, KeyCell);
-        if (!ParentNode)
-        {
-            Status = STATUS_REGISTRY_CORRUPT;
-            goto Quickie;
-        }
-
-        /* Update the key name to the next remaining path element */
-        KeyName = NameStart;
-        if (NameStart)
-        {
-            /* Update the length to the remainder of the path */
-            NameLength += -1 - SubNameLength;
-        }
-        else
-        {
-            /* There's nothing left, this was the leaf key */
-            NameLength = 0;
-        }
-    }
-
-    /* Allocate a key object */
-    NewKey = BlMmAllocateHeap(sizeof(*NewKey));
-    if (!NewKey)
-    {
-        /* Bail out if we had no memory for it */
-        Status = STATUS_NO_MEMORY;
-        goto Quickie;
-    }
-
-    /* Fill out the key object data */
-    NewKey->KeyNode = ParentNode;
-    NewKey->KeyHive = ParentHive;
-    NewKey->KeyName = NameBuffer;
-    NewKey->KeyCell = KeyCell;
-
-    /* Add a reference to the hive */
-    ++ParentHive->ReferenceCount;
-
-    /* Return the object back to the caller */
-    *Handle = NewKey;
-
-Quickie:
-    /* If we had a name buffer, free it */
-    if (NameBuffer)
-    {
-        BlMmFreeHeap(NameBuffer);
-    }
-
-    /* Return status of the open operation */
-    return Status;
-}
-
-NTSTATUS
-BiInitializeAndValidateHive (
-    _In_ PBI_KEY_HIVE Hive
-    )
-{
-    ULONG HiveSize;
-    NTSTATUS Status;
-
-    /* Make sure the hive is at least the size of a base block */
-    if (Hive->HiveSize < sizeof(HBASE_BLOCK))
-    {
-        return STATUS_REGISTRY_CORRUPT;
-    }
-
-    /* Make sure that the base block accurately describes the size of the hive */
-    HiveSize = Hive->BaseBlock->Length + sizeof(HBASE_BLOCK);
-    if ((HiveSize < sizeof(HBASE_BLOCK)) || (HiveSize > Hive->HiveSize))
-    {
-        return STATUS_REGISTRY_CORRUPT;
-    }
-
-    /* Initialize a flat memory hive */
-    RtlZeroMemory(&Hive->Hive, sizeof(Hive->Hive));
-    Status = HvInitialize(&Hive->Hive.Hive,
-                          HINIT_FLAT,
-                          0,
-                          0,
-                          Hive->BaseBlock,
-                          CmpAllocate,
-                          CmpFree,
-                          NULL,
-                          NULL,
-                          NULL,
-                          NULL,
-                          0,
-                          NULL);
-    if (NT_SUCCESS(Status))
-    {
-        /* Cleanup volatile/old data */
-        CmPrepareHive(&Hive->Hive.Hive); // CmCheckRegistry 
-        Status = STATUS_SUCCESS;
-    }
-
-    /* Return the final status */
-    return Status;
-}
-
-NTSTATUS
-BiLoadHive (
-    _In_ PBL_FILE_PATH_DESCRIPTOR FilePath,
-    _Out_ PHANDLE HiveHandle
-    )
-{
-    ULONG DeviceId;
-    PHBASE_BLOCK BaseBlock, NewBaseBlock;
-    PBI_KEY_OBJECT KeyObject;
-    PBI_KEY_HIVE BcdHive;
-    PBL_DEVICE_DESCRIPTOR BcdDevice;
-    ULONG PathLength, DeviceLength, HiveSize, HiveLength, NewHiveSize;
-    PWCHAR HiveName, LogName;
-    BOOLEAN HaveWriteAccess;
-    NTSTATUS Status;
-    PVOID LogData;
-    PHHIVE Hive;
-    UNICODE_STRING KeyString;
-    PCM_KEY_NODE RootNode;
-    HCELL_INDEX CellIndex;
-
-    /* Initialize variables */
-    DeviceId = -1;
-    BaseBlock = NULL;
-    BcdHive = NULL;
-    KeyObject = NULL;
-    LogData = NULL;
-    LogName = NULL;
-
-    /* Initialize the crypto seed */
-    if (!BiHiveHashLibraryInitialized)
-    {
-        HvSymcryptSeed = 0x82EF4D887A4E55C5;
-        BiHiveHashLibraryInitialized = TRUE;
-    }
-
-    /* Extract and validate the input path */
-    BcdDevice = (PBL_DEVICE_DESCRIPTOR)&FilePath->Path;
-    PathLength = FilePath->Length;
-    DeviceLength = BcdDevice->Size;
-    HiveName = (PWCHAR)((ULONG_PTR)BcdDevice + BcdDevice->Size);
-    if (PathLength <= DeviceLength)
-    {
-        /* Doesn't make sense, bail out */
-        Status = STATUS_INVALID_PARAMETER;
-        goto Quickie;
-    }
-
-    /* Attempt to open the underlying device for RW access */
-    HaveWriteAccess = TRUE;
-    Status = BlpDeviceOpen(BcdDevice,
-                           BL_DEVICE_READ_ACCESS | BL_DEVICE_WRITE_ACCESS,
-                           0,
-                           &DeviceId);
-    if (!NT_SUCCESS(Status))
-    {
-        /* Try for RO access instead */
-        HaveWriteAccess = FALSE;
-        Status = BlpDeviceOpen(BcdDevice, BL_DEVICE_READ_ACCESS, 0, &DeviceId);
-        if (!NT_SUCCESS(Status))
-        {
-            /* No access at all -- bail out */
-            goto Quickie;
-        }
-    }
-
-    /* Now try to load the hive on disk */
-    Status = BlImgLoadImageWithProgress2(DeviceId,
-                                         BlLoaderRegistry,
-                                         HiveName,
-                                         (PVOID*)&BaseBlock,
-                                         &HiveSize,
-                                         0,
-                                         FALSE,
-                                         NULL,
-                                         NULL);
-    if (!NT_SUCCESS(Status))
-    {
-        EfiPrintf(L"Hive read failure: % lx\r\n", Status);
-        goto Quickie;
-    }
-
-    /* Allocate a hive structure */
-    BcdHive = BlMmAllocateHeap(sizeof(*BcdHive));
-    if (!BcdHive)
-    {
-        Status = STATUS_NO_MEMORY;
-        goto Quickie;
-    }
-
-    /* Initialize it */
-    RtlZeroMemory(BcdHive, sizeof(*BcdHive));
-    BcdHive->BaseBlock = BaseBlock;
-    BcdHive->HiveSize = HiveSize;
-    if (HaveWriteAccess)
-    {
-        BcdHive->Flags |= BI_HIVE_WRITEABLE;
-    }
-
-    /* Make sure the hive was at least one bin long */
-    if (HiveSize < sizeof(*BaseBlock))
-    {
-        Status = STATUS_REGISTRY_CORRUPT;
-        goto Quickie;
-    }
-
-    /* Make sure the hive contents are at least one bin long */
-    HiveLength = BaseBlock->Length;
-    if (BaseBlock->Length < sizeof(*BaseBlock))
-    {
-        Status = STATUS_REGISTRY_CORRUPT;
-        goto Quickie;
-    }
-
-    /* Validate the initial bin (the base block) */
-    if (!HvIsInPlaceBaseBlockValid(BaseBlock))
-    {
-        EfiPrintf(L"Recovery not implemented\r\n");
-        Status = STATUS_REGISTRY_CORRUPT;
-        goto Quickie;
-    }
-
-    /* Check if there's log recovery that needs to happen */
-    if (BaseBlock->Sequence1 != BaseBlock->Sequence2)
-    {
-        EfiPrintf(L"Log fix not implemented: %lx %lx\r\n");
-        Status = STATUS_REGISTRY_CORRUPT;
-        goto Quickie;
-    }
-
-    /*
-     * Check if the whole hive doesn't fit in the buffer.
-     * Note: HiveLength does not include the size of the baseblock itself
-     */
-    if (HiveSize < (HiveLength + sizeof(*BaseBlock)))
-    {
-        EfiPrintf(L"Need bigger hive buffer path\r\n");
-
-        /* Allocate a slightly bigger buffer */
-        NewHiveSize = HiveLength + sizeof(*BaseBlock);
-        Status = MmPapAllocatePagesInRange((PVOID*)&NewBaseBlock,
-                                           BlLoaderRegistry,
-                                           NewHiveSize >> PAGE_SHIFT,
-                                           0,
-                                           0,
-                                           NULL,
-                                           0);
-        if (!NT_SUCCESS(Status))
-        {
-            goto Quickie;
-        }
-
-        /* Copy the current data in there */
-        RtlCopyMemory(NewBaseBlock, BaseBlock, HiveSize);
-
-        /* Free the old data */
-        MmPapFreePages(BaseBlock, BL_MM_INCLUDE_MAPPED_ALLOCATED);
-
-        /* Update our pointers */
-        BaseBlock = NewBaseBlock;
-        HiveSize = NewHiveSize;
-        BcdHive->BaseBlock = BaseBlock;
-        BcdHive->HiveSize = HiveSize;
-    }
-
-    /* Check if any log stuff needs to happen */
-    if (LogData)
-    {
-        EfiPrintf(L"Log fix not implemented: %lx %lx\r\n");
-        Status = STATUS_REGISTRY_CORRUPT;
-        goto Quickie;
-    }
-
-    /* Call Hv to setup the hive library */
-    Status = BiInitializeAndValidateHive(BcdHive);
-    if (!NT_SUCCESS(Status))
-    {
-        goto Quickie;
-    }
-
-    /* Now get the root node */
-    Hive = &BcdHive->Hive.Hive;
-    RootNode = (PCM_KEY_NODE)HvGetCell(Hive, Hive->BaseBlock->RootCell);
-    if (!RootNode)
-    {
-        Status = STATUS_OBJECT_NAME_NOT_FOUND;
-        goto Quickie;
-    }
-
-    /* Find the Objects subkey under it to see if it's a real BCD hive */
-    RtlInitUnicodeString(&KeyString, L"Objects");
-    CellIndex = CmpFindSubKeyByName(Hive, RootNode, &KeyString);
-    if (CellIndex == HCELL_NIL)
-    {
-        EfiPrintf(L"No OBJECTS subkey found!\r\n");
-        Status = STATUS_OBJECT_NAME_NOT_FOUND;
-        goto Quickie;
-    }
-
-    /* This is a valid BCD hive, store its root node here */
-    BcdHive->RootNode = RootNode;
-
-    /* Allocate a copy of the file path */
-    BcdHive->FilePath = BlMmAllocateHeap(FilePath->Length);
-    if (!BcdHive->FilePath)
-    {
-        Status = STATUS_NO_MEMORY;
-        goto Quickie;
-    }
-
-    /* Make a copy of it */
-    RtlCopyMemory(BcdHive->FilePath, FilePath, FilePath->Length);
-
-    /* Create a key object to describe the rot */
-    KeyObject = BlMmAllocateHeap(sizeof(*KeyObject));
-    if (!KeyObject)
-    {
-        Status = STATUS_NO_MEMORY;
-        goto Quickie;
-    }
-
-    /* Fill out the details */
-    KeyObject->KeyNode = RootNode;
-    KeyObject->KeyHive = BcdHive;
-    KeyObject->KeyName = NULL;
-    KeyObject->KeyCell = Hive->BaseBlock->RootCell;
-
-    /* One reference for the key object, plus one lifetime reference */
-    BcdHive->ReferenceCount = 2;
-
-    /* This is the hive handle */
-    *HiveHandle  = KeyObject;
-
-    /* We're all good */
-    Status = STATUS_SUCCESS;
-
-Quickie:
-    /* If we had a log name, free it */
-    if (LogName)
-    {
-        BlMmFreeHeap(LogName);
-    }
-
-    /* If we had logging data, free it */
-    if (LogData)
-    {
-        MmPapFreePages(LogData, BL_MM_INCLUDE_MAPPED_ALLOCATED);
-    }
-
-    /* Check if this is the failure path */
-    if (!NT_SUCCESS(Status))
-    {
-        /* If we mapped the hive, free it */
-        if (BaseBlock)
-        {
-            MmPapFreePages(BaseBlock, BL_MM_INCLUDE_MAPPED_ALLOCATED);
-        }
-
-        /* If we opened the device, close it */
-        if (DeviceId != -1)
-        {
-            BlDeviceClose(DeviceId);
-        }
-
-        /* Did we create a hive object? */
-        if (BcdHive)
-        {
-            /* Free the file path if we made a copy of it */
-            if (BcdHive->FilePath)
-            {
-                BlMmFreeHeap(BcdHive->FilePath);
-            }
-
-            /* Free the hive itself */
-            BlMmFreeHeap(BcdHive);
-        }
-
-        /* Finally, free the root key object if we created one */
-        if (KeyObject)
-        {
-            BlMmFreeHeap(KeyObject);
-        }
-    }
-
-    /* Return the final status */
-    return Status;
-}
-
-NTSTATUS
-BiGetRegistryValue (
-    _In_ HANDLE KeyHandle,
-    _In_ PWCHAR ValueName,
-    _In_ ULONG Type,
-    _Out_ PVOID* Buffer,
-    _Out_ PULONG ValueLength
-    )
-{
-    PCM_KEY_NODE KeyNode;
-    PHHIVE KeyHive;
-    UNICODE_STRING ValueString;
-    PBI_KEY_OBJECT KeyObject;
-    PCM_KEY_VALUE KeyValue;
-    PVOID ValueCopy;
-    ULONG Size;
-    HCELL_INDEX CellIndex;
-    PCELL_DATA ValueData;
-
-    /* Get the key object, node,and hive */
-    KeyObject = (PBI_KEY_OBJECT)KeyHandle;
-    KeyNode = KeyObject->KeyNode;
-    KeyHive = &KeyObject->KeyHive->Hive.Hive;
-
-    /* Find the value cell index in the list of values */
-    RtlInitUnicodeString(&ValueString, ValueName);
-    CmpFindNameInList(KeyHive,
-                      &KeyNode->ValueList,
-                      &ValueString,
-                      NULL,
-                      &CellIndex);
-    if (CellIndex == HCELL_NIL)
-    {
-        return STATUS_OBJECT_NAME_NOT_FOUND;
-    }
-
-    /* Get the cell data for it */
-    KeyValue = (PCM_KEY_VALUE)HvGetCell(KeyHive, CellIndex);
-    if (!KeyValue)
-    {
-        return STATUS_REGISTRY_CORRUPT;
-    }
-
-    /* Make sure the type matches */
-    if (KeyValue->Type != Type)
-    {
-        return STATUS_OBJECT_TYPE_MISMATCH;
-    }
-
-    /* Now get the data cell */
-    ValueData = CmpValueToData(KeyHive, KeyValue, &Size);
-
-    /* Make a copy of it */
-    ValueCopy = BlMmAllocateHeap(Size);
-    if (!ValueCopy)
-    {
-        return STATUS_NO_MEMORY;
-    }
-
-    /* Copy it in the buffer, and return it and its size */
-    RtlCopyMemory(ValueCopy, ValueData, Size);
-    *Buffer = ValueCopy;
-    *ValueLength = Size;
-    return STATUS_SUCCESS;
-}
-
-NTSTATUS
-BiEnumerateSubKeys (
-    _In_ HANDLE KeyHandle,
-    _Out_ PWCHAR** SubKeyList,
-    _Out_ PULONG SubKeyCount
-    )
-{
-    PCM_KEY_NODE KeyNode, Node;
-    PBI_KEY_OBJECT KeyObject;
-    ULONG KeyCount;
-    ULONG NameLength, NewTotalNameLength, FinalLength, TotalNameLength;
-    PHHIVE Hive;
-    PWCHAR KeyName, NameEnd;
-    HCELL_INDEX CellIndex;
-    PWCHAR* SubKeys;
-    NTSTATUS Status;
-    ULONG i;
-
-    /* Get the key object, node, and hive */
-    KeyObject = (PBI_KEY_OBJECT)KeyHandle;
-    KeyNode = KeyObject->KeyNode;
-    Hive = &KeyObject->KeyHive->Hive.Hive;
-
-    /* Assume it's empty */
-    *SubKeyList = 0;
-    *SubKeyCount = 0;
-
-    /* Initialize locals */
-    KeyCount = 0;
-    SubKeys = 0;
-    TotalNameLength = 0;
-
-    /* Find the first subkey cell index */
-    CellIndex = CmpFindSubKeyByNumber(Hive, KeyNode, KeyCount);
-    while (CellIndex != HCELL_NIL)
-    {
-        /* Move to the next one */
-        KeyCount++;
-
-        /* Get the cell data for it */
-        Node = (PCM_KEY_NODE)HvGetCell(Hive, CellIndex);
-        if (!Node)
-        {
-            return STATUS_REGISTRY_CORRUPT;
-        }
-
-        /* Check if the value is compressed */
-        if (Node->Flags & KEY_COMP_NAME)
-        {
-            /* Get the compressed name size */
-            NameLength = CmpCompressedNameSize(Node->Name, Node->NameLength);
-        }
-        else
-        {
-            /* Get the real size */
-            NameLength = Node->NameLength;
-        }
-
-        /* Add up the new length, protecting against overflow */
-        NewTotalNameLength = TotalNameLength + NameLength + sizeof(UNICODE_NULL);
-        if (NewTotalNameLength < TotalNameLength)
-        {
-            Status = STATUS_NAME_TOO_LONG;
-            goto Quickie;
-        }
-
-        /* We're good, use the new length */
-        TotalNameLength = NewTotalNameLength;
-
-        /* Find the next subkey cell index */
-        CellIndex = CmpFindSubKeyByNumber(Hive, KeyNode, KeyCount);
-    }
-
-    /* Were there no keys? We're done, if so */
-    if (!KeyCount)
-    {
-        return STATUS_SUCCESS;
-    }
-
-    /* Safely compute the size of the array needed */
-    Status = RtlULongLongToULong(sizeof(PWCHAR) * KeyCount, &FinalLength);
-    if (!NT_SUCCESS(Status))
-    {
-        goto Quickie;
-    }
-
-    /* Safely add that to the name length */
-    Status = RtlULongAdd(TotalNameLength, FinalLength, &FinalLength);
-    if (!NT_SUCCESS(Status))
-    {
-        goto Quickie;
-    }
-
-    /* Allocate an array big enough for the names and pointers */
-    SubKeys = BlMmAllocateHeap(FinalLength);
-    if (!SubKeys)
-    {
-        Status = STATUS_NO_MEMORY;
-        goto Quickie;
-    }
-
-    /* Go over each key again */
-    NameEnd = (PWCHAR)&SubKeys[KeyCount];
-    for (i = 0; i < KeyCount; i++)
-    {
-        /* Get the cell index for this subkey */
-        CellIndex = CmpFindSubKeyByNumber(Hive, KeyNode, i);
-        if (CellIndex == HCELL_NIL)
-        {
-            break;
-        }
-
-        /* Get the cell data for it */
-        Node = HvGetCell(Hive, CellIndex);
-        if (!Node)
-        {
-            Status = STATUS_REGISTRY_CORRUPT;
-            goto Quickie;
-        }
-
-        /* Check if the value is compressed */
-        KeyName = Node->Name;
-        if (Node->Flags & KEY_COMP_NAME)
-        {
-            /* Get the compressed name size */
-            NameLength = CmpCompressedNameSize(KeyName, Node->NameLength);
-            CmpCopyCompressedName(NameEnd, NameLength, KeyName, Node->NameLength);
-        }
-        else
-        {
-            /* Get the real size */
-            NameLength = Node->NameLength;
-            RtlCopyMemory(NameEnd, KeyName, NameLength);
-        }
-
-        /* Move the name buffer to the next spot, and NULL-terminate */
-        SubKeys[i] = NameEnd;
-        NameEnd += (NameLength / sizeof(WCHAR));
-        *NameEnd = UNICODE_NULL;
-
-        /* Keep going */
-        NameEnd++;
-    }
-
-    /* Check if the subkeys were empty */
-    if (i == 0)
-    {
-        /* They disappeared in the middle of enumeration */
-        Status = STATUS_OBJECT_NAME_NOT_FOUND;
-        goto Quickie;
-    }
-
-    /* Return the count and the array of names */
-    *SubKeyList = SubKeys;
-    *SubKeyCount = i;
-    SubKeys = NULL;
-    Status = STATUS_SUCCESS;
-
-Quickie:
-    /* On the failure path, free the subkeys if any exist */
-    if (SubKeys)
-    {
-        BlMmFreeHeap(SubKeys);
-    }
-
-    /* All done, return the result */
-    return Status;
-}
-
-NTSTATUS
-BiDeleteKey (
-    _In_ HANDLE KeyHandle
-    )
-{
-    NTSTATUS Status;
-    PBI_KEY_OBJECT KeyObject;
-    PHHIVE Hive;
-    ULONG SubKeyCount, i;
-    PWCHAR* SubKeyList;
-    HANDLE SubKeyHandle;
-
-    /* Get the key object and hive */
-    KeyObject = (PBI_KEY_OBJECT)KeyHandle;
-    Hive = &KeyObject->KeyHive->Hive.Hive;
-
-    /* Make sure the hive is writeable */
-    if (!(KeyObject->KeyHive->Flags & BI_HIVE_WRITEABLE))
-    {
-        return STATUS_MEDIA_WRITE_PROTECTED;
-    }
-
-    /* Enumerate all of the subkeys */
-    Status = BiEnumerateSubKeys(KeyHandle, &SubKeyList, &SubKeyCount);
-    if ((NT_SUCCESS(Status)) && (SubKeyCount > 0))
-    {
-        /* Loop through each one */
-        for (i = 0; i < SubKeyCount; i++)
-        {
-            /* Open a handle to it */
-            Status = BiOpenKey(KeyHandle, SubKeyList[i], &SubKeyHandle);
-            if (NT_SUCCESS(Status))
-            {
-                /* Recursively call us to delete it */
-                Status = BiDeleteKey(SubKeyHandle);
-                if (Status != STATUS_SUCCESS)
-                {
-                    /* Close the key on failure */
-                    BiCloseKey(SubKeyHandle);
-                }
-            }
-        }
-    }
-
-    /* Check if we had a list of subkeys */
-    if (SubKeyList)
-    {
-        /* Free it */
-        BlMmFreeHeap(SubKeyList);
-    }
-
-    /* Delete this key cell */
-    Status = CmpFreeKeyByCell(Hive, KeyObject->KeyCell, TRUE);
-    if (NT_SUCCESS(Status))
-    {
-        /* Mark the hive as requiring a flush */
-        KeyObject->KeyHive->Flags |= BI_FLUSH_HIVE;
-        BiCloseKey(KeyHandle);
-    }
-
-    /* All done */
-    return Status;
-}
\ No newline at end of file