[FREELDR/CMLIB]
[reactos.git] / reactos / boot / freeldr / freeldr / reactos / registry.c
index cd8e074..8126a5c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  FreeLoader
  *
- *  Copyright (C) 2001, 2002  Eric Kohl
+ *  Copyright (C) 2014  Timo Kreuzer <timo.kreuzer@reactos.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  */
 
 #include <freeldr.h>
+#include <cmlib.h>
 #include <debug.h>
 
-static FRLDRHKEY RootKey;
+DBG_DEFAULT_CHANNEL(REGISTRY);
 
+static PCMHIVE CmHive;
+static PCM_KEY_NODE RootKeyNode;
+static FRLDRHKEY CurrentControlSetKey;
 
-VOID
-RegInitializeRegistry (VOID)
+BOOLEAN
+RegImportBinaryHive(
+    _In_ PCHAR ChunkBase,
+    _In_ ULONG ChunkSize)
 {
-    /* Create root key */
-    RootKey = MmHeapAlloc(sizeof(KEY));
-
-    InitializeListHead(&RootKey->SubKeyList);
-    InitializeListHead(&RootKey->ValueList);
-    InitializeListHead(&RootKey->KeyList);
-
-    RootKey->SubKeyCount = 0;
-    RootKey->ValueCount = 0;
+    NTSTATUS Status;
+    TRACE("RegImportBinaryHive(%p, 0x%lx)\n", ChunkBase, ChunkSize);
+
+    /* Allocate and initialize the hive */
+    CmHive = FrLdrTempAlloc(sizeof(CMHIVE), 'eviH');
+    Status = HvInitialize(&CmHive->Hive,
+                          HINIT_FLAT,
+                          0,
+                          0,
+                          ChunkBase,
+                          NULL,
+                          NULL,
+                          NULL,
+                          NULL,
+                          NULL,
+                          NULL,
+                          1,
+                          NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        FrLdrTempFree(CmHive, 'eviH');
+        ERR("Invalid hive Signature!\n");
+        return FALSE;
+    }
 
-    RootKey->NameSize = 4;
-    RootKey->Name = MmHeapAlloc(4);
-    wcscpy (RootKey->Name, L"\\");
+    /* Save the root key node */
+    RootKeyNode = HvGetCell(&CmHive->Hive, CmHive->Hive.BaseBlock->RootCell);
 
-    RootKey->DataType = 0;
-    RootKey->DataSize = 0;
-    RootKey->Data = NULL;
+    TRACE("RegImportBinaryHive done\n");
+    return TRUE;
+}
 
-    /* Create 'SYSTEM' key */
-    RegCreateKey (RootKey,
-                  L"Registry\\Machine\\SYSTEM",
-                  NULL);
+VOID
+RegInitializeRegistry(VOID)
+{
+    /* Nothing to do */
 }
 
 
 LONG
-RegInitCurrentControlSet(BOOLEAN LastKnownGood)
+RegInitCurrentControlSet(
+    _In_ BOOLEAN LastKnownGood)
 {
     WCHAR ControlSetKeyName[80];
     FRLDRHKEY SelectKey;
     FRLDRHKEY SystemKey;
-    FRLDRHKEY ControlSetKey;
-    FRLDRHKEY LinkKey;
     ULONG CurrentSet = 0;
     ULONG DefaultSet = 0;
     ULONG LastKnownGoodSet = 0;
     ULONG DataSize;
     LONG Error;
+    TRACE("RegInitCurrentControlSet\n");
 
     Error = RegOpenKey(NULL,
                        L"\\Registry\\Machine\\SYSTEM\\Select",
                        &SelectKey);
     if (Error != ERROR_SUCCESS)
     {
-        DPRINTM(DPRINT_REGISTRY, "RegOpenKey() failed (Error %u)\n", (int)Error);
+        ERR("RegOpenKey() failed (Error %u)\n", (int)Error);
         return Error;
     }
 
@@ -83,7 +103,7 @@ RegInitCurrentControlSet(BOOLEAN LastKnownGood)
                           &DataSize);
     if (Error != ERROR_SUCCESS)
     {
-        DPRINTM(DPRINT_REGISTRY, "RegQueryValue('Default') failed (Error %u)\n", (int)Error);
+        ERR("RegQueryValue('Default') failed (Error %u)\n", (int)Error);
         return Error;
     }
 
@@ -95,7 +115,7 @@ RegInitCurrentControlSet(BOOLEAN LastKnownGood)
                           &DataSize);
     if (Error != ERROR_SUCCESS)
     {
-        DPRINTM(DPRINT_REGISTRY, "RegQueryValue('Default') failed (Error %u)\n", (int)Error);
+        ERR("RegQueryValue('Default') failed (Error %u)\n", (int)Error);
         return Error;
     }
 
@@ -125,633 +145,444 @@ RegInitCurrentControlSet(BOOLEAN LastKnownGood)
                        &SystemKey);
     if (Error != ERROR_SUCCESS)
     {
-        DPRINTM(DPRINT_REGISTRY, "RegOpenKey(SystemKey) failed (Error %lu)\n", Error);
+        ERR("RegOpenKey(SystemKey) failed (Error %lu)\n", Error);
         return Error;
     }
 
     Error = RegOpenKey(SystemKey,
                        ControlSetKeyName,
-                       &ControlSetKey);
-    if (Error != ERROR_SUCCESS)
-    {
-        DPRINTM(DPRINT_REGISTRY, "RegOpenKey(ControlSetKey) failed (Error %lu)\n", Error);
-        return Error;
-    }
-
-    Error = RegCreateKey(SystemKey,
-                         L"CurrentControlSet",
-                         &LinkKey);
+                       &CurrentControlSetKey);
     if (Error != ERROR_SUCCESS)
     {
-        DPRINTM(DPRINT_REGISTRY, "RegCreateKey(LinkKey) failed (Error %lu)\n", Error);
-        return Error;
-    }
-
-    Error = RegSetValue(LinkKey,
-                        NULL,
-                        REG_LINK,
-                        (PCHAR)&ControlSetKey,
-                        sizeof(PVOID));
-    if (Error != ERROR_SUCCESS)
-    {
-        DPRINTM(DPRINT_REGISTRY, "RegSetValue(LinkKey) failed (Error %lu)\n", Error);
+        ERR("RegOpenKey(CurrentControlSetKey) failed (Error %lu)\n", Error);
         return Error;
     }
 
+    TRACE("RegInitCurrentControlSet done\n");
     return ERROR_SUCCESS;
 }
 
-
-LONG
-RegCreateKey(FRLDRHKEY ParentKey,
-             PCWSTR KeyName,
-             PFRLDRHKEY Key)
+static
+BOOLEAN
+GetNextPathElement(
+    _Out_ PUNICODE_STRING NextElement,
+    _Inout_ PUNICODE_STRING RemainingPath)
 {
-    PLIST_ENTRY Ptr;
-    FRLDRHKEY SearchKey = NULL;
-    FRLDRHKEY CurrentKey;
-    FRLDRHKEY NewKey;
-    PWCHAR p;
-    PCWSTR name;
-    int subkeyLength;
-    int stringLength;
-    ULONG NameSize;
-    int CmpResult;
-
-    DPRINTM(DPRINT_REGISTRY, "KeyName '%S'\n", KeyName);
-
-    if (*KeyName == L'\\')
-    {
-        KeyName++;
-        CurrentKey = RootKey;
-    }
-    else if (ParentKey == NULL)
+    /* Check if there are any characters left */
+    if (RemainingPath->Length < sizeof(WCHAR))
     {
-        CurrentKey = RootKey;
-    }
-    else
-    {
-        CurrentKey = ParentKey;
+        /* Nothing left, bail out early */
+        return FALSE;
     }
 
-    /* Check whether current key is a link */
-    if (CurrentKey->DataType == REG_LINK)
-    {
-        CurrentKey = (FRLDRHKEY)CurrentKey->Data;
-    }
+    /* The next path elements starts with the remaining path */
+    NextElement->Buffer = RemainingPath->Buffer;
 
-    while (*KeyName != 0)
+    /* Loop until the path element ends */
+    while ((RemainingPath->Length >= sizeof(WCHAR)) &&
+           (RemainingPath->Buffer[0] != '\\'))
     {
-        DPRINTM(DPRINT_REGISTRY, "KeyName '%S'\n", KeyName);
+        /* Skip this character */
+        RemainingPath->Buffer++;
+        RemainingPath->Length -= sizeof(WCHAR);
+    }
 
-        if (*KeyName == L'\\')
-            KeyName++;
-        p = wcschr(KeyName, L'\\');
-        if ((p != NULL) && (p != KeyName))
-        {
-            subkeyLength = p - KeyName;
-            stringLength = subkeyLength + 1;
-            name = KeyName;
-        }
-        else
-        {
-            subkeyLength = wcslen(KeyName);
-            stringLength = subkeyLength;
-            name = KeyName;
-        }
-        NameSize = (subkeyLength + 1) * sizeof(WCHAR);
+    NextElement->Length = (RemainingPath->Buffer - NextElement->Buffer) * sizeof(WCHAR);
+    NextElement->MaximumLength = NextElement->Length;
 
-        Ptr = CurrentKey->SubKeyList.Flink;
-        CmpResult = 1;
-        while (Ptr != &CurrentKey->SubKeyList)
-        {
-            DPRINTM(DPRINT_REGISTRY, "Ptr 0x%x\n", Ptr);
+    /* Check if the path element ended with a path separator */
+    if (RemainingPath->Length >= sizeof(WCHAR))
+    {
+        /* Skip the path separator */
+        ASSERT(RemainingPath->Buffer[0] == '\\');
+        RemainingPath->Buffer++;
+        RemainingPath->Length -= sizeof(WCHAR);
+    }
 
-            SearchKey = CONTAINING_RECORD(Ptr, KEY, KeyList);
-            DPRINTM(DPRINT_REGISTRY, "SearchKey 0x%x\n", SearchKey);
-            DPRINTM(DPRINT_REGISTRY, "Searching '%S'\n", SearchKey->Name);
-            CmpResult = _wcsnicmp(SearchKey->Name, name, subkeyLength);
+    /* Return whether we got any characters */
+    return TRUE;
+}
 
-            if (CmpResult == 0 && SearchKey->NameSize == NameSize) break;
-            else if (CmpResult == -1) break;
+static
+PCM_KEY_NODE
+RegpFindSubkeyInIndex(
+    _In_ PHHIVE Hive,
+    _In_ PCM_KEY_INDEX IndexCell,
+    _In_ PUNICODE_STRING SubKeyName)
+{
+    PCM_KEY_NODE SubKeyNode;
+    ULONG i;
+    TRACE("RegpFindSubkeyInIndex('%wZ')\n", SubKeyName);
 
-            Ptr = Ptr->Flink;
-        }
+    /* Check the cell type */
+    if ((IndexCell->Signature == CM_KEY_INDEX_ROOT) ||
+        (IndexCell->Signature == CM_KEY_INDEX_LEAF))
+    {
+        ASSERT(FALSE);
 
-        if (CmpResult != 0)
+        /* Enumerate subindex cells */
+        for (i = 0; i < IndexCell->Count; i++)
         {
-            /* no key found -> create new subkey */
-            NewKey = MmHeapAlloc(sizeof(KEY));
-            if (NewKey == NULL) return ERROR_OUTOFMEMORY;
-
-            InitializeListHead(&NewKey->SubKeyList);
-            InitializeListHead(&NewKey->ValueList);
-
-            NewKey->SubKeyCount = 0;
-            NewKey->ValueCount = 0;
-
-            NewKey->DataType = 0;
-            NewKey->DataSize = 0;
-            NewKey->Data = NULL;
-
-            InsertTailList(Ptr, &NewKey->KeyList);
-            CurrentKey->SubKeyCount++;
-
-            NewKey->NameSize = NameSize;
-            NewKey->Name = (PWCHAR)MmHeapAlloc(NewKey->NameSize);
-            if (NewKey->Name == NULL) return ERROR_OUTOFMEMORY;
+            /* Get the subindex cell and call the function recursively */
+            PCM_KEY_INDEX SubIndexCell = HvGetCell(Hive, IndexCell->List[i]);
 
-            memcpy(NewKey->Name, name, NewKey->NameSize - sizeof(WCHAR));
-            NewKey->Name[subkeyLength] = 0;
-
-            DPRINTM(DPRINT_REGISTRY, "NewKey 0x%x\n", NewKey);
-            DPRINTM(DPRINT_REGISTRY, "NewKey '%S'  Length %d\n", NewKey->Name, NewKey->NameSize);
-
-            CurrentKey = NewKey;
+            SubKeyNode = RegpFindSubkeyInIndex(Hive, SubIndexCell, SubKeyName);
+            if (SubKeyNode != NULL)
+            {
+                return SubKeyNode;
+            }
         }
-        else
+    }
+    else if ((IndexCell->Signature == CM_KEY_FAST_LEAF) ||
+             (IndexCell->Signature == CM_KEY_HASH_LEAF))
+    {
+        /* Directly enumerate subkey nodes */
+        PCM_KEY_FAST_INDEX HashCell = (PCM_KEY_FAST_INDEX)IndexCell;
+        for (i = 0; i < HashCell->Count; i++)
         {
-            CurrentKey = SearchKey;
+            SubKeyNode = HvGetCell(Hive, HashCell->List[i].Cell);
+            ASSERT(SubKeyNode->Signature == CM_KEY_NODE_SIGNATURE);
 
-            /* Check whether current key is a link */
-            if (CurrentKey->DataType == REG_LINK)
+            TRACE(" RegpFindSubkeyInIndex: checking '%.*s'\n",
+                  SubKeyNode->NameLength, SubKeyNode->Name);
+            if (CmCompareKeyName(SubKeyNode, SubKeyName, TRUE))
             {
-                CurrentKey = (FRLDRHKEY)CurrentKey->Data;
+                return SubKeyNode;
             }
         }
-
-        KeyName = KeyName + stringLength;
+    }
+    else
+    {
+        ASSERT(FALSE);
     }
 
-    if (Key != NULL) *Key = CurrentKey;
-
-    return ERROR_SUCCESS;
-}
-
-
-LONG
-RegDeleteKey(FRLDRHKEY Key,
-             PCWSTR Name)
-{
-
-    if (wcschr(Name, L'\\') != NULL) return ERROR_INVALID_PARAMETER;
-
-    return ERROR_SUCCESS;
+    return NULL;
 }
 
-
+// FIXME: optionally return the subkey node/handle as optimization
 LONG
-RegEnumKey(FRLDRHKEY Key,
-           ULONG Index,
-           PWCHAR Name,
-           ULONG* NameSize)
+RegEnumKey(
+    _In_ FRLDRHKEY Key,
+    _In_ ULONG Index,
+    _Out_ PWCHAR Name,
+    _Inout_ ULONG* NameSize)
 {
-    PLIST_ENTRY Ptr;
-    FRLDRHKEY SearchKey;
-    ULONG Count = 0;
-    ULONG Size;
-
-    Ptr = Key->SubKeyList.Flink;
-    while (Ptr != &Key->SubKeyList)
+    PHHIVE Hive = &CmHive->Hive;
+    PCM_KEY_NODE KeyNode, SubKeyNode;
+    PCM_KEY_INDEX IndexCell;
+    PCM_KEY_FAST_INDEX HashCell;
+    TRACE("RegEnumKey(%p, %lu, %p, %p->%u)\n",
+          Key, Index, Name, NameSize, NameSize ? *NameSize : 0);
+
+    /* Get the key node */
+    KeyNode = (PCM_KEY_NODE)Key;
+    ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE);
+
+    /* Check if the index is valid */
+    if ((KeyNode->SubKeyCounts[Stable] == 0) ||
+        (Index >= KeyNode->SubKeyCounts[Stable]))
     {
-        if (Index == Count) break;
-
-        Count++;
-        Ptr = Ptr->Flink;
+        TRACE("RegEnumKey index out of bounds\n");
+        return ERROR_NO_MORE_ITEMS;
     }
 
-    if (Ptr == &Key->SubKeyList) return ERROR_NO_MORE_ITEMS;
-
-    SearchKey = CONTAINING_RECORD(Ptr, KEY, KeyList);
+    /* Get the index cell */
+    IndexCell = HvGetCell(Hive, KeyNode->SubKeyLists[Stable]);
+    TRACE("IndexCell: %x, SubKeyCounts: %x\n", IndexCell, KeyNode->SubKeyCounts[Stable]);
 
-    DPRINTM(DPRINT_REGISTRY, "Name '%S'  Length %d\n", SearchKey->Name, SearchKey->NameSize);
+    /* Check the cell type */
+    if ((IndexCell->Signature == CM_KEY_FAST_LEAF) ||
+        (IndexCell->Signature == CM_KEY_HASH_LEAF))
+    {
+        /* Get the value cell */
+        HashCell = (PCM_KEY_FAST_INDEX)IndexCell;
+        SubKeyNode = HvGetCell(Hive, HashCell->List[Index].Cell);
+    }
+    else
+    {
+        ASSERT(FALSE);
+    }
 
-    Size = min(SearchKey->NameSize, *NameSize);
-    *NameSize = Size;
-    memcpy(Name, SearchKey->Name, Size);
+    *NameSize = CmCopyKeyName(SubKeyNode, Name, *NameSize);
 
-    return ERROR_SUCCESS;
+    TRACE("RegEnumKey done -> %u, '%.*s'\n", *NameSize, *NameSize, Name);
+    return STATUS_SUCCESS;
 }
 
-
 LONG
-RegOpenKey(FRLDRHKEY ParentKey,
-           PCWSTR KeyName,
-           PFRLDRHKEY Key)
+RegOpenKey(
+    _In_ FRLDRHKEY ParentKey,
+    _In_z_ PCWSTR KeyName,
+    _Out_ PFRLDRHKEY Key)
 {
-    PLIST_ENTRY Ptr;
-    FRLDRHKEY SearchKey = NULL;
-    FRLDRHKEY CurrentKey;
-    PWCHAR p;
-    PCWSTR name;
-    int subkeyLength;
-    int stringLength;
-    ULONG NameSize;
+    UNICODE_STRING RemainingPath, SubKeyName;
+    UNICODE_STRING CurrentControlSet = RTL_CONSTANT_STRING(L"CurrentControlSet");
+    PHHIVE Hive = &CmHive->Hive;
+    PCM_KEY_NODE KeyNode;
+    PCM_KEY_INDEX IndexCell;
+    TRACE("RegOpenKey(%p, '%S', %p)\n", ParentKey, KeyName, Key);
 
-    DPRINTM(DPRINT_REGISTRY, "KeyName '%S'\n", KeyName);
+    /* Initialize the remaining path name */
+    RtlInitUnicodeString(&RemainingPath, KeyName);
 
-    *Key = NULL;
+    /* Get the parent key node */
+    KeyNode = (PCM_KEY_NODE)ParentKey;
 
-    if (*KeyName == L'\\')
+    /* Check if we have a parent key */
+    if (KeyNode == NULL)
     {
-        KeyName++;
-        CurrentKey = RootKey;
-    }
-    else if (ParentKey == NULL)
-    {
-        CurrentKey = RootKey;
-    }
-    else
-    {
-        CurrentKey = ParentKey;
-    }
-
-    /* Check whether current key is a link */
-    if (CurrentKey->DataType == REG_LINK)
-    {
-        CurrentKey = (FRLDRHKEY)CurrentKey->Data;
-    }
-
-    while (*KeyName != 0)
-    {
-        DPRINTM(DPRINT_REGISTRY, "KeyName '%S'\n", KeyName);
-
-        if (*KeyName == L'\\') KeyName++;
-        p = wcschr(KeyName, L'\\');
-        if ((p != NULL) && (p != KeyName))
-        {
-            subkeyLength = p - KeyName;
-            stringLength = subkeyLength + 1;
-            name = KeyName;
-        }
-        else
+        UNICODE_STRING SubKeyName1, SubKeyName2, SubKeyName3;
+        UNICODE_STRING RegistryPath = RTL_CONSTANT_STRING(L"Registry");
+        UNICODE_STRING MachinePath = RTL_CONSTANT_STRING(L"MACHINE");
+        UNICODE_STRING SystemPath = RTL_CONSTANT_STRING(L"SYSTEM");
+        TRACE("RegOpenKey: absolute path\n");
+
+        if ((RemainingPath.Length < sizeof(WCHAR)) ||
+            RemainingPath.Buffer[0] != '\\')
         {
-            subkeyLength = wcslen(KeyName);
-            stringLength = subkeyLength;
-            name = KeyName;
+            /* The key path is not absolute */
+            ERR("RegOpenKey: invalid path '%S' (%wZ)\n", KeyName, &RemainingPath);
+            return ERROR_PATH_NOT_FOUND;
         }
-        NameSize = (subkeyLength + 1) * sizeof(WCHAR);
-
-        Ptr = CurrentKey->SubKeyList.Flink;
-        while (Ptr != &CurrentKey->SubKeyList)
-        {
-            DPRINTM(DPRINT_REGISTRY, "Ptr 0x%x\n", Ptr);
-
-            SearchKey = CONTAINING_RECORD(Ptr, KEY, KeyList);
 
-            DPRINTM(DPRINT_REGISTRY, "SearchKey 0x%x\n", SearchKey);
-            DPRINTM(DPRINT_REGISTRY, "Searching '%S'\n", SearchKey->Name);
+        /* Skip initial path separator */
+        RemainingPath.Buffer++;
+        RemainingPath.Length -= sizeof(WCHAR);
 
-            if (SearchKey->NameSize == NameSize &&
-                _wcsnicmp(SearchKey->Name, name, subkeyLength) == 0) break;
+        /* Get the first 3 path elements */
+        GetNextPathElement(&SubKeyName1, &RemainingPath);
+        GetNextPathElement(&SubKeyName2, &RemainingPath);
+        GetNextPathElement(&SubKeyName3, &RemainingPath);
+        TRACE("RegOpenKey: %wZ / %wZ / %wZ\n", &SubKeyName1, &SubKeyName2, &SubKeyName3);
 
-            Ptr = Ptr->Flink;
-        }
-
-        if (Ptr == &CurrentKey->SubKeyList)
+        /* Check if we have the correct path */
+        if (!RtlEqualUnicodeString(&SubKeyName1, &RegistryPath, TRUE) ||
+            !RtlEqualUnicodeString(&SubKeyName2, &MachinePath, TRUE) ||
+            !RtlEqualUnicodeString(&SubKeyName3, &SystemPath, TRUE))
         {
+            /* The key path is not inside HKLM\Machine\System */
+            ERR("RegOpenKey: invalid path '%S' (%wZ)\n", KeyName, &RemainingPath);
             return ERROR_PATH_NOT_FOUND;
         }
-        else
-        {
-            CurrentKey = SearchKey;
 
-            /* Check whether current key is a link */
-            if (CurrentKey->DataType == REG_LINK)
-            {
-                CurrentKey = (FRLDRHKEY)CurrentKey->Data;
-            }
-        }
-
-        KeyName = KeyName + stringLength;
+        /* Use the root key */
+        KeyNode = RootKeyNode;
     }
 
-    if (Key != NULL)
-        *Key = CurrentKey;
-
-    return ERROR_SUCCESS;
-}
-
-
-LONG
-RegSetValue(FRLDRHKEY Key,
-            PCWSTR ValueName,
-            ULONG Type,
-            PCSTR Data,
-            ULONG DataSize)
-{
-    PLIST_ENTRY Ptr;
-    PVALUE Value = NULL;
+    ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE);
 
-    DPRINTM(DPRINT_REGISTRY, "Key 0x%p, ValueName '%S', Type %ld, Data 0x%p, DataSize %ld\n",
-            Key, ValueName, Type, Data, DataSize);
-
-    if ((ValueName == NULL) || (*ValueName == 0))
+    /* Check if this is the root key */
+    if (KeyNode == RootKeyNode)
     {
-        /* set default value */
-        if ((Key->Data != NULL) && (Key->DataSize > sizeof(PUCHAR)))
-        {
-            MmHeapFree(Key->Data);
-        }
+        UNICODE_STRING TempPath = RemainingPath;
 
-        if (DataSize <= sizeof(PUCHAR))
-        {
-            Key->DataSize = DataSize;
-            Key->DataType = Type;
-            memcpy(&Key->Data, Data, DataSize);
-        }
-        else
+        /* Get the first path element */
+        GetNextPathElement(&SubKeyName, &TempPath);
+
+        /* Check if this is CurrentControlSet */
+        if (RtlEqualUnicodeString(&SubKeyName, &CurrentControlSet, TRUE))
         {
-            Key->Data = MmHeapAlloc(DataSize);
-            Key->DataSize = DataSize;
-            Key->DataType = Type;
-            memcpy(Key->Data, Data, DataSize);
+            /* Use the CurrentControlSetKey and update the remaining path */
+            KeyNode = (PCM_KEY_NODE)CurrentControlSetKey;
+            RemainingPath = TempPath;
         }
     }
-    else
-    {
-        /* set non-default value */
-        Ptr = Key->ValueList.Flink;
-        while (Ptr != &Key->ValueList)
-        {
-            Value = CONTAINING_RECORD(Ptr, VALUE, ValueList);
 
-            DPRINTM(DPRINT_REGISTRY, "Value->Name '%S'\n", Value->Name);
+    TRACE("RegOpenKey: RemainingPath '%wZ'\n", &RemainingPath);
 
-            if (_wcsicmp(Value->Name, ValueName) == 0) break;
-
-            Ptr = Ptr->Flink;
-        }
+    /* Loop while there are path elements */
+    while (GetNextPathElement(&SubKeyName, &RemainingPath))
+    {
+        TRACE("RegOpenKey: next element '%wZ'\n", &SubKeyName);
 
-        if (Ptr == &Key->ValueList)
+        /* Check if there is any subkey */
+        if (KeyNode->SubKeyCounts[Stable] == 0)
         {
-            /* add new value */
-            DPRINTM(DPRINT_REGISTRY, "No value found - adding new value\n");
-
-            Value = (PVALUE)MmHeapAlloc(sizeof(VALUE));
-            if (Value == NULL) return ERROR_OUTOFMEMORY;
-
-            InsertTailList(&Key->ValueList, &Value->ValueList);
-            Key->ValueCount++;
-
-            Value->NameSize = (wcslen(ValueName)+1) * sizeof(WCHAR);
-            Value->Name = MmHeapAlloc(Value->NameSize);
-            if (Value->Name == NULL) return ERROR_OUTOFMEMORY;
-            wcscpy(Value->Name, ValueName);
-            Value->DataType = REG_NONE;
-            Value->DataSize = 0;
-            Value->Data = NULL;
+            return ERROR_PATH_NOT_FOUND;
         }
 
-        /* set new value */
-        if ((Value->Data != NULL) && (Value->DataSize > sizeof(PUCHAR)))
-        {
-            MmHeapFree(Value->Data);
-        }
+        /* Get the top level index cell */
+        IndexCell = HvGetCell(Hive, KeyNode->SubKeyLists[Stable]);
 
-        if (DataSize <= sizeof(PUCHAR))
+        /* Get the next sub key */
+        KeyNode = RegpFindSubkeyInIndex(Hive, IndexCell, &SubKeyName);
+        if (KeyNode == NULL)
         {
-            Value->DataSize = DataSize;
-            Value->DataType = Type;
-            memcpy(&Value->Data, Data, DataSize);
-        }
-        else
-        {
-            Value->Data = MmHeapAlloc(DataSize);
-            if (Value->Data == NULL) return ERROR_OUTOFMEMORY;
-            Value->DataType = Type;
-            Value->DataSize = DataSize;
-            memcpy(Value->Data, Data, DataSize);
+
+            ERR("Did not find sub key '%wZ' (full %S)\n", &RemainingPath, KeyName);
+            return ERROR_PATH_NOT_FOUND;
         }
     }
-    return(ERROR_SUCCESS);
-}
 
+    TRACE("RegOpenKey done\n");
+    *Key = (FRLDRHKEY)KeyNode;
+    return ERROR_SUCCESS;
+}
 
-LONG
-RegQueryValue(FRLDRHKEY Key,
-              PCWSTR ValueName,
-              ULONG* Type,
-              PUCHAR Data,
-              ULONG* DataSize)
+static
+VOID
+RepGetValueData(
+    _In_ PHHIVE Hive,
+    _In_ PCM_KEY_VALUE ValueCell,
+    _Out_opt_ ULONG* Type,
+    _Out_opt_ PUCHAR Data,
+    _Inout_opt_ ULONG* DataSize)
 {
-    ULONG Size;
-    PLIST_ENTRY Ptr;
-    PVALUE Value = NULL;
+    ULONG DataLength;
 
-    if ((ValueName == NULL) || (*ValueName == 0))
+    /* Does the caller want the type? */
+    if (Type != NULL)
     {
-        /* query default value */
-        if (Key->Data == NULL) return ERROR_INVALID_PARAMETER;
-
-        if (Type != NULL)
-            *Type = Key->DataType;
-        if ((Data != NULL) && (DataSize != NULL))
-        {
-            if (Key->DataSize <= sizeof(PUCHAR))
-            {
-                Size = min(Key->DataSize, *DataSize);
-                memcpy(Data, &Key->Data, Size);
-                *DataSize = Size;
-            }
-            else
-            {
-                Size = min(Key->DataSize, *DataSize);
-                memcpy(Data, Key->Data, Size);
-                *DataSize = Size;
-            }
-        }
-        else if ((Data == NULL) && (DataSize != NULL))
-        {
-            *DataSize = Key->DataSize;
-        }
+        *Type = ValueCell->Type;
     }
-    else
-    {
-        /* query non-default value */
-        Ptr = Key->ValueList.Flink;
-        while (Ptr != &Key->ValueList)
-        {
-            Value = CONTAINING_RECORD(Ptr, VALUE, ValueList);
 
-            DPRINTM(DPRINT_REGISTRY, "Searching for '%S'. Value name '%S'\n", ValueName, Value->Name);
-
-            if (_wcsicmp(Value->Name, ValueName) == 0) break;
-
-            Ptr = Ptr->Flink;
-        }
-
-        if (Ptr == &Key->ValueList) return ERROR_INVALID_PARAMETER;
+    /* Does the caller provide DataSize? */
+    if (DataSize != NULL)
+    {
+        /* Get the data length */
+        DataLength = ValueCell->DataLength & REG_DATA_SIZE_MASK;
 
-        if (Type != NULL) *Type = Value->DataType;
-        if ((Data != NULL) && (DataSize != NULL))
+        /* Does the caller want the data? */
+        if ((Data != NULL) && (*DataSize != 0))
         {
-            if (Value->DataSize <= sizeof(PUCHAR))
+            /* Check where the data is stored */
+            if ((DataLength <= sizeof(HCELL_INDEX)) &&
+                 (ValueCell->DataLength & REG_DATA_IN_OFFSET))
             {
-                Size = min(Value->DataSize, *DataSize);
-                memcpy(Data, &Value->Data, Size);
-                *DataSize = Size;
+                /* The data member contains the data */
+                RtlCopyMemory(Data,
+                              &ValueCell->Data,
+                              min(*DataSize, DataLength));
             }
             else
             {
-                Size = min(Value->DataSize, *DataSize);
-                memcpy(Data, Value->Data, Size);
-                *DataSize = Size;
+                /* The data member contains the data cell index */
+                PVOID DataCell = HvGetCell(Hive, ValueCell->Data);
+                RtlCopyMemory(Data,
+                              DataCell,
+                              min(*DataSize, ValueCell->DataLength));
             }
+
         }
-        else if ((Data == NULL) && (DataSize != NULL))
-        {
-            *DataSize = Value->DataSize;
-        }
-    }
 
-    return ERROR_SUCCESS;
+        /* Return the actual data length */
+        *DataSize = DataLength;
+    }
 }
 
-
 LONG
-RegDeleteValue(FRLDRHKEY Key,
-               PCWSTR ValueName)
+RegQueryValue(
+    _In_ FRLDRHKEY Key,
+    _In_z_ PCWSTR ValueName,
+    _Out_opt_ ULONG* Type,
+    _Out_opt_ PUCHAR Data,
+    _Inout_opt_ ULONG* DataSize)
 {
-    PLIST_ENTRY Ptr;
-    PVALUE Value = NULL;
-
-    if ((ValueName == NULL) || (*ValueName == 0))
+    PHHIVE Hive = &CmHive->Hive;
+    PCM_KEY_NODE KeyNode;
+    PCM_KEY_VALUE ValueCell;
+    PVALUE_LIST_CELL ValueListCell;
+    UNICODE_STRING ValueNameString;
+    ULONG i;
+    TRACE("RegQueryValue(%p, '%S', %p, %p, %p)\n",
+          Key, ValueName, Type, Data, DataSize);
+
+    /* Get the key node */
+    KeyNode = (PCM_KEY_NODE)Key;
+    ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE);
+
+    /* Check if there are any values */
+    if (KeyNode->ValueList.Count == 0)
     {
-        /* delete default value */
-        if (Key->Data != NULL) MmFreeMemory(Key->Data);
-        Key->Data = NULL;
-        Key->DataSize = 0;
-        Key->DataType = 0;
+        TRACE("RegQueryValue no values in key (%.*s)\n",
+              KeyNode->NameLength, KeyNode->Name);
+        return ERROR_INVALID_PARAMETER;
     }
-    else
-    {
-        /* delete non-default value */
-        Ptr = Key->ValueList.Flink;
-        while (Ptr != &Key->ValueList)
-        {
-            Value = CONTAINING_RECORD(Ptr, VALUE, ValueList);
-            if (_wcsicmp(Value->Name, ValueName) == 0) break;
 
-            Ptr = Ptr->Flink;
-        }
+    /* Initialize value name string */
+    RtlInitUnicodeString(&ValueNameString, ValueName);
 
-        if (Ptr == &Key->ValueList) return ERROR_INVALID_PARAMETER;
+    ValueListCell = (PVALUE_LIST_CELL)HvGetCell(Hive, KeyNode->ValueList.List);
+    TRACE("ValueListCell: %x\n", ValueListCell);
 
-        /* delete value */
-        Key->ValueCount--;
-        if (Value->Name != NULL) MmFreeMemory(Value->Name);
-        Value->Name = NULL;
-        Value->NameSize = 0;
+    /* Loop all values */
+    for (i = 0; i < KeyNode->ValueList.Count; i++)
+    {
+        /* Get the subkey node and check the name */
+        ValueCell = HvGetCell(Hive, ValueListCell->ValueOffset[i]);
 
-        if (Value->DataSize > sizeof(PUCHAR))
+        /* Compare the value name */
+        TRACE("checking %.*s\n", ValueCell->NameLength, ValueCell->Name);
+        if (CmCompareKeyValueName(ValueCell, &ValueNameString, TRUE))
         {
-            if (Value->Data != NULL) MmFreeMemory(Value->Data);
+            RepGetValueData(Hive, ValueCell, Type, Data, DataSize);
+            TRACE("RegQueryValue success\n");
+            return STATUS_SUCCESS;
         }
-        Value->Data = NULL;
-        Value->DataSize = 0;
-        Value->DataType = 0;
-
-        RemoveEntryList(&Value->ValueList);
-        MmFreeMemory(Value);
     }
-    return ERROR_SUCCESS;
+
+    TRACE("RegQueryValue value not found\n");
+    return ERROR_INVALID_PARAMETER;
 }
 
 
 LONG
-RegEnumValue(FRLDRHKEY Key,
-             ULONG Index,
-             PWCHAR ValueName,
-             ULONG* NameSize,
-             ULONG* Type,
-             PUCHAR Data,
-             ULONG* DataSize)
+RegEnumValue(
+    _In_ FRLDRHKEY Key,
+    _In_ ULONG Index,
+    _Out_ PWCHAR ValueName,
+    _Inout_ ULONG* NameSize,
+    _Out_ ULONG* Type,
+    _Out_ PUCHAR Data,
+    _Inout_ ULONG* DataSize)
 {
-    PLIST_ENTRY Ptr;
-    PVALUE Value;
-    ULONG Count = 0;
-
-    if (Key->Data != NULL)
+    PHHIVE Hive = &CmHive->Hive;
+    PCM_KEY_NODE KeyNode;
+    PCM_KEY_VALUE ValueCell;
+    PVALUE_LIST_CELL ValueListCell;
+    TRACE("RegEnumValue(%p, %lu, %S, %p, %p, %p, %p (%lu))\n",
+          Key, Index, ValueName, NameSize, Type, Data, DataSize, *DataSize);
+
+    /* Get the key node */
+    KeyNode = (PCM_KEY_NODE)Key;
+    ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE);
+
+    /* Check if the index is valid */
+    if ((KeyNode->ValueList.Count == 0) ||
+        (Index >= KeyNode->ValueList.Count))
     {
-        if (Index > 0)
-        {
-            Index--;
-        }
-        else
-        {
-            /* enumerate default value */
-            if (ValueName != NULL) *ValueName = 0;
-            if (Type != NULL) *Type = Key->DataType;
-            if (Data != NULL)
-            {
-                if (Key->DataSize <= sizeof(PUCHAR))
-                {
-                    memcpy(Data, &Key->Data, min(Key->DataSize, *DataSize));
-                }
-                else
-                {
-                    memcpy(Data, Key->Data, min(Key->DataSize, *DataSize));
-                }
-            }
-
-            if (DataSize != NULL) *DataSize = min(Key->DataSize, *DataSize);
-
-            return ERROR_SUCCESS;
-        }
-    }
-
-    Ptr = Key->ValueList.Flink;
-    while (Ptr != &Key->ValueList)
-    {
-        if (Index == Count) break;
-
-        Count++;
-        Ptr = Ptr->Flink;
+        ERR("RegEnumValue: index invalid\n");
+        return ERROR_NO_MORE_ITEMS;
     }
 
-    if (Ptr == &Key->ValueList) return ERROR_NO_MORE_ITEMS;
+    ValueListCell = (PVALUE_LIST_CELL)HvGetCell(Hive, KeyNode->ValueList.List);
+    TRACE("ValueListCell: %x\n", ValueListCell);
 
-    Value = CONTAINING_RECORD(Ptr, VALUE, ValueList);
+    /* Get the value cell */
+    ValueCell = HvGetCell(Hive, ValueListCell->ValueOffset[Index]);
+    ASSERT(ValueCell != NULL);
 
-    /* enumerate non-default value */
-    if (ValueName != NULL)
+    if (NameSize != NULL)
     {
-        memcpy(ValueName, Value->Name, min(Value->NameSize, *NameSize));
+        *NameSize = CmCopyKeyValueName(ValueCell, ValueName, *NameSize);
     }
-    if (Type != NULL) *Type = Value->DataType;
 
-    if (Data != NULL)
+    RepGetValueData(Hive, ValueCell, Type, Data, DataSize);
+
+    if (DataSize != NULL)
     {
-        if (Value->DataSize <= sizeof(PUCHAR))
-        {
-            memcpy(Data, &Value->Data, min(Value->DataSize, *DataSize));
-        }
-        else
+        if ((Data != NULL) && (*DataSize != 0))
         {
-            memcpy(Data, Value->Data, min(Value->DataSize, *DataSize));
+            RtlCopyMemory(Data,
+                          &ValueCell->Data,
+                          min(*DataSize, ValueCell->DataLength));
         }
-    }
-
-    if (DataSize != NULL) *DataSize = min(Value->DataSize, *DataSize);
-
-    return ERROR_SUCCESS;
-}
-
 
-ULONG
-RegGetSubKeyCount (FRLDRHKEY Key)
-{
-    return Key->SubKeyCount;
-}
-
-
-ULONG
-RegGetValueCount (FRLDRHKEY Key)
-{
-    if (Key->DataSize != 0) return Key->ValueCount + 1;
+        *DataSize = ValueCell->DataLength;
+    }
 
-    return Key->ValueCount;
+    TRACE("RegEnumValue done\n");
+    return STATUS_SUCCESS;
 }
 
 /* EOF */