[FREELDR]
[reactos.git] / reactos / boot / freeldr / freeldr / reactos / registry.c
index db72f33..d88688a 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 = (FRLDRHKEY) 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;
-
-  Error = RegOpenKey(NULL,
-                    L"\\Registry\\Machine\\SYSTEM\\Select",
-                    &SelectKey);
-  if (Error != ERROR_SUCCESS)
+    WCHAR ControlSetKeyName[80];
+    FRLDRHKEY SelectKey;
+    FRLDRHKEY SystemKey;
+    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);
-      return(Error);
+        ERR("RegOpenKey() failed (Error %u)\n", (int)Error);
+        return Error;
     }
 
-  DataSize = sizeof(ULONG);
-  Error = RegQueryValue(SelectKey,
-                       L"Default",
-                       NULL,
-                       (PUCHAR)&DefaultSet,
-                       &DataSize);
-  if (Error != ERROR_SUCCESS)
+    DataSize = sizeof(ULONG);
+    Error = RegQueryValue(SelectKey,
+                          L"Default",
+                          NULL,
+                          (PUCHAR)&DefaultSet,
+                          &DataSize);
+    if (Error != ERROR_SUCCESS)
     {
-      DPRINTM(DPRINT_REGISTRY, "RegQueryValue('Default') failed (Error %u)\n", (int)Error);
-      return(Error);
+        ERR("RegQueryValue('Default') failed (Error %u)\n", (int)Error);
+        return Error;
     }
 
-  DataSize = sizeof(ULONG);
-  Error = RegQueryValue(SelectKey,
-                       L"LastKnownGood",
-                       NULL,
-                       (PUCHAR)&LastKnownGoodSet,
-                       &DataSize);
-  if (Error != ERROR_SUCCESS)
+    DataSize = sizeof(ULONG);
+    Error = RegQueryValue(SelectKey,
+                          L"LastKnownGood",
+                          NULL,
+                          (PUCHAR)&LastKnownGoodSet,
+                          &DataSize);
+    if (Error != ERROR_SUCCESS)
     {
-      DPRINTM(DPRINT_REGISTRY, "RegQueryValue('Default') failed (Error %u)\n", (int)Error);
-      return(Error);
+        ERR("RegQueryValue('Default') failed (Error %u)\n", (int)Error);
+        return Error;
     }
 
-  CurrentSet = (LastKnownGood == TRUE) ? LastKnownGoodSet : DefaultSet;
-  wcscpy(ControlSetKeyName, L"ControlSet");
-  switch(CurrentSet)
+    CurrentSet = (LastKnownGood == TRUE) ? LastKnownGoodSet : DefaultSet;
+    wcscpy(ControlSetKeyName, L"ControlSet");
+    switch(CurrentSet)
     {
-      case 1:
-       wcscat(ControlSetKeyName, L"001");
-       break;
-      case 2:
-       wcscat(ControlSetKeyName, L"002");
-       break;
-      case 3:
-       wcscat(ControlSetKeyName, L"003");
-       break;
-      case 4:
-       wcscat(ControlSetKeyName, L"004");
-       break;
-      case 5:
-       wcscat(ControlSetKeyName, L"005");
-       break;
+        case 1:
+            wcscat(ControlSetKeyName, L"001");
+            break;
+        case 2:
+            wcscat(ControlSetKeyName, L"002");
+            break;
+        case 3:
+            wcscat(ControlSetKeyName, L"003");
+            break;
+        case 4:
+            wcscat(ControlSetKeyName, L"004");
+            break;
+        case 5:
+            wcscat(ControlSetKeyName, L"005");
+            break;
     }
 
-  Error = RegOpenKey(NULL,
-                    L"\\Registry\\Machine\\SYSTEM",
-                    &SystemKey);
-  if (Error != ERROR_SUCCESS)
+    Error = RegOpenKey(NULL,
+                       L"\\Registry\\Machine\\SYSTEM",
+                       &SystemKey);
+    if (Error != ERROR_SUCCESS)
     {
-      DPRINTM(DPRINT_REGISTRY, "RegOpenKey(SystemKey) failed (Error %u)\n", (int)Error);
-      return(Error);
+        ERR("RegOpenKey(SystemKey) failed (Error %lu)\n", Error);
+        return Error;
     }
 
-  Error = RegOpenKey(SystemKey,
-                    ControlSetKeyName,
-                    &ControlSetKey);
-  if (Error != ERROR_SUCCESS)
+    Error = RegOpenKey(SystemKey,
+                       ControlSetKeyName,
+                       &CurrentControlSetKey);
+    if (Error != ERROR_SUCCESS)
     {
-      DPRINTM(DPRINT_REGISTRY, "RegOpenKey(ControlSetKey) failed (Error %u)\n", (int)Error);
-      return(Error);
+        ERR("RegOpenKey(CurrentControlSetKey) failed (Error %lu)\n", Error);
+        return Error;
     }
 
-  Error = RegCreateKey(SystemKey,
-                      L"CurrentControlSet",
-                      &LinkKey);
-  if (Error != ERROR_SUCCESS)
-    {
-      DPRINTM(DPRINT_REGISTRY, "RegCreateKey(LinkKey) failed (Error %u)\n", (int)Error);
-      return(Error);
-    }
-
-  Error = RegSetValue(LinkKey,
-                     NULL,
-                     REG_LINK,
-                     (PCHAR)&ControlSetKey,
-                     sizeof(PVOID));
-  if (Error != ERROR_SUCCESS)
-    {
-      DPRINTM(DPRINT_REGISTRY, "RegSetValue(LinkKey) failed (Error %u)\n", (int)Error);
-      return(Error);
-    }
-
-  return(ERROR_SUCCESS);
+    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)
-    {
-      CurrentKey = RootKey;
-    }
-  else
+    /* Check if there are any characters left */
+    if (RemainingPath->Length < sizeof(WCHAR))
     {
-      CurrentKey = ParentKey;
+        /* Nothing left, bail out early */
+        return FALSE;
     }
 
-  /* Check whether current key is a link */
-  if (CurrentKey->DataType == REG_LINK)
+    /* The next path elements starts with the remaining path */
+    NextElement->Buffer = RemainingPath->Buffer;
+
+    /* Loop until the path element ends */
+    while ((RemainingPath->Length >= sizeof(WCHAR)) &&
+           (RemainingPath->Buffer[0] != '\\'))
     {
-      CurrentKey = (FRLDRHKEY)CurrentKey->Data;
+        /* Skip this character */
+        RemainingPath->Buffer++;
+        RemainingPath->Length -= sizeof(WCHAR);
     }
 
-  while (*KeyName != 0)
+    NextElement->Length = (RemainingPath->Buffer - NextElement->Buffer) * sizeof(WCHAR);
+    NextElement->MaximumLength = NextElement->Length;
+
+    /* Check if the path element ended with a path separator */
+    if (RemainingPath->Length >= sizeof(WCHAR))
     {
-      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
-       {
-         subkeyLength = wcslen(KeyName);
-         stringLength = subkeyLength;
-         name = KeyName;
-       }
-      NameSize = (subkeyLength + 1) * sizeof(WCHAR);
-
-      Ptr = CurrentKey->SubKeyList.Flink;
-      CmpResult = 1;
-      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);
-         CmpResult = _wcsnicmp(SearchKey->Name, name, subkeyLength);
-         if (CmpResult == 0 && SearchKey->NameSize == NameSize)
-           break;
-         else if (CmpResult == -1)
-           break;
-
-         Ptr = Ptr->Flink;
-       }
-
-      if (CmpResult != 0)
-       {
-         /* no key found -> create new subkey */
-         NewKey = (FRLDRHKEY)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);
-         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;
-       }
-      else
-       {
-         CurrentKey = SearchKey;
-
-         /* Check whether current key is a link */
-         if (CurrentKey->DataType == REG_LINK)
-           {
-             CurrentKey = (FRLDRHKEY)CurrentKey->Data;
-           }
-       }
-
-      KeyName = KeyName + stringLength;
+        /* Skip the path separator */
+        ASSERT(RemainingPath->Buffer[0] == '\\');
+        RemainingPath->Buffer++;
+        RemainingPath->Length -= sizeof(WCHAR);
     }
 
-  if (Key != NULL)
-    *Key = CurrentKey;
-
-  return(ERROR_SUCCESS);
+    /* Return whether we got any characters */
+    return TRUE;
 }
 
-
-LONG
-RegDeleteKey(FRLDRHKEY Key,
-            PCWSTR Name)
+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);
 
+    /* Check the cell type */
+    if ((IndexCell->Signature == CM_KEY_INDEX_ROOT) ||
+        (IndexCell->Signature == CM_KEY_INDEX_LEAF))
+    {
+        ASSERT(FALSE);
 
-  if (wcschr(Name, L'\\') != NULL)
-    return(ERROR_INVALID_PARAMETER);
+        /* Enumerate subindex cells */
+        for (i = 0; i < IndexCell->Count; i++)
+        {
+            /* Get the subindex cell and call the function recursively */
+            PCM_KEY_INDEX SubIndexCell = HvGetCell(Hive, IndexCell->List[i]);
 
+            SubKeyNode = RegpFindSubkeyInIndex(Hive, SubIndexCell, SubKeyName);
+            if (SubKeyNode != NULL)
+            {
+                return SubKeyNode;
+            }
+        }
+    }
+    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++)
+        {
+            SubKeyNode = HvGetCell(Hive, HashCell->List[i].Cell);
+            ASSERT(SubKeyNode->Signature == CM_KEY_NODE_SIGNATURE);
 
+            TRACE(" RegpFindSubkeyInIndex: checking '%.*s'\n",
+                  SubKeyNode->NameLength, SubKeyNode->Name);
+            if (CmCompareKeyName(SubKeyNode, SubKeyName, TRUE))
+            {
+                return SubKeyNode;
+            }
+        }
+    }
+    else
+    {
+        ASSERT(FALSE);
+    }
 
-  return(ERROR_SUCCESS);
+    return NULL;
 }
 
-
 LONG
-RegEnumKey(FRLDRHKEY Key,
-          ULONG Index,
-          PWCHAR Name,
-          ULONG* NameSize)
+RegEnumKey(
+    _In_ FRLDRHKEY Key,
+    _In_ ULONG Index,
+    _Out_ PWCHAR Name,
+    _Inout_ ULONG* NameSize,
+    _Out_opt_ FRLDRHKEY *SubKey)
 {
-  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);
+    /* Get the index cell */
+    IndexCell = HvGetCell(Hive, KeyNode->SubKeyLists[Stable]);
+    TRACE("IndexCell: %x, SubKeyCounts: %x\n", IndexCell, KeyNode->SubKeyCounts[Stable]);
 
-  SearchKey = CONTAINING_RECORD(Ptr,
-                               KEY,
-                               KeyList);
+    /* 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);
+    }
 
-  DPRINTM(DPRINT_REGISTRY, "Name '%S'  Length %d\n", SearchKey->Name, SearchKey->NameSize);
+    *NameSize = CmCopyKeyName(SubKeyNode, Name, *NameSize);
 
-  Size = min(SearchKey->NameSize, *NameSize);
-  *NameSize = Size;
-  memcpy(Name, SearchKey->Name, Size);
+    if (SubKey != NULL)
+    {
+        *SubKey = (FRLDRHKEY)SubKeyNode;
+    }
 
-  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'\\')
-    {
-      KeyName++;
-      CurrentKey = RootKey;
-    }
-  else if (ParentKey == NULL)
-    {
-      CurrentKey = RootKey;
-    }
-  else
+    /* Check if we have a parent key */
+    if (KeyNode == NULL)
     {
-      CurrentKey = ParentKey;
-    }
+        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] != '\\')
+        {
+            /* The key path is not absolute */
+            ERR("RegOpenKey: invalid path '%S' (%wZ)\n", KeyName, &RemainingPath);
+            return ERROR_PATH_NOT_FOUND;
+        }
 
-  /* Check whether current key is a link */
-  if (CurrentKey->DataType == REG_LINK)
-    {
-      CurrentKey = (FRLDRHKEY)CurrentKey->Data;
-    }
+        /* Skip initial path separator */
+        RemainingPath.Buffer++;
+        RemainingPath.Length -= sizeof(WCHAR);
 
-  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
-       {
-         subkeyLength = wcslen(KeyName);
-         stringLength = subkeyLength;
-         name = KeyName;
-       }
-      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);
-
-         if (SearchKey->NameSize == NameSize &&
-             _wcsnicmp(SearchKey->Name, name, subkeyLength) == 0)
-           break;
-
-         Ptr = Ptr->Flink;
-       }
-
-      if (Ptr == &CurrentKey->SubKeyList)
-       {
-         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;
-    }
+        /* Get the first 3 path elements */
+        GetNextPathElement(&SubKeyName1, &RemainingPath);
+        GetNextPathElement(&SubKeyName2, &RemainingPath);
+        GetNextPathElement(&SubKeyName3, &RemainingPath);
+        TRACE("RegOpenKey: %wZ / %wZ / %wZ\n", &SubKeyName1, &SubKeyName2, &SubKeyName3);
 
-  if (Key != NULL)
-    *Key = CurrentKey;
+        /* 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;
+        }
 
-  return(ERROR_SUCCESS);
-}
+        /* Use the root key */
+        KeyNode = RootKeyNode;
+    }
 
+    ASSERT(KeyNode->Signature == CM_KEY_NODE_SIGNATURE);
 
-LONG
-RegSetValue(FRLDRHKEY Key,
-           PCWSTR ValueName,
-           ULONG Type,
-           PCSTR Data,
-           ULONG DataSize)
-{
-  PLIST_ENTRY Ptr;
-  PVALUE Value = NULL;
+    /* Check if this is the root key */
+    if (KeyNode == RootKeyNode)
+    {
+        UNICODE_STRING TempPath = RemainingPath;
 
-  DPRINTM(DPRINT_REGISTRY, "Key 0x%p, ValueName '%S', Type %ld, Data 0x%p, DataSize %ld\n",
-    Key, ValueName, Type, Data, DataSize);
+        /* Get the first path element */
+        GetNextPathElement(&SubKeyName, &TempPath);
 
-  if ((ValueName == NULL) || (*ValueName == 0))
-    {
-      /* set default value */
-      if ((Key->Data != NULL) && (Key->DataSize > sizeof(PUCHAR)))
-       {
-         MmHeapFree(Key->Data);
-       }
-
-      if (DataSize <= sizeof(PUCHAR))
-       {
-         Key->DataSize = DataSize;
-         Key->DataType = Type;
-         memcpy(&Key->Data, Data, DataSize);
-       }
-      else
-       {
-         Key->Data = MmHeapAlloc(DataSize);
-         Key->DataSize = DataSize;
-         Key->DataType = Type;
-         memcpy(Key->Data, Data, DataSize);
-       }
+        /* Check if this is CurrentControlSet */
+        if (RtlEqualUnicodeString(&SubKeyName, &CurrentControlSet, TRUE))
+        {
+            /* Use the CurrentControlSetKey and update the remaining path */
+            KeyNode = (PCM_KEY_NODE)CurrentControlSetKey;
+            RemainingPath = TempPath;
+        }
     }
-  else
+
+    TRACE("RegOpenKey: RemainingPath '%wZ'\n", &RemainingPath);
+
+    /* Loop while there are path elements */
+    while (GetNextPathElement(&SubKeyName, &RemainingPath))
     {
-      /* 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);
-
-         if (_wcsicmp(Value->Name, ValueName) == 0)
-           break;
-
-         Ptr = Ptr->Flink;
-       }
-
-      if (Ptr == &Key->ValueList)
-       {
-         /* 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 = (PWCHAR)MmHeapAlloc(Value->NameSize);
-         if (Value->Name == NULL)
-           return(ERROR_OUTOFMEMORY);
-         wcscpy(Value->Name, ValueName);
-         Value->DataType = REG_NONE;
-         Value->DataSize = 0;
-         Value->Data = NULL;
-       }
-
-      /* set new value */
-      if ((Value->Data != NULL) && (Value->DataSize > sizeof(PUCHAR)))
-       {
-         MmHeapFree(Value->Data);
-       }
-
-      if (DataSize <= sizeof(PUCHAR))
-       {
-         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);
-       }
-    }
-  return(ERROR_SUCCESS);
-}
+        TRACE("RegOpenKey: next element '%wZ'\n", &SubKeyName);
+
+        /* Check if there is any subkey */
+        if (KeyNode->SubKeyCounts[Stable] == 0)
+        {
+            return ERROR_PATH_NOT_FOUND;
+        }
 
+        /* Get the top level index cell */
+        IndexCell = HvGetCell(Hive, KeyNode->SubKeyLists[Stable]);
 
-LONG
-RegQueryValue(FRLDRHKEY Key,
-             PCWSTR ValueName,
-             ULONG* Type,
-             PUCHAR Data,
-             ULONG* DataSize)
-{
-  ULONG Size;
-  PLIST_ENTRY Ptr;
-  PVALUE Value = NULL;
+        /* Get the next sub key */
+        KeyNode = RegpFindSubkeyInIndex(Hive, IndexCell, &SubKeyName);
+        if (KeyNode == NULL)
+        {
 
-  if ((ValueName == NULL) || (*ValueName == 0))
-    {
-      /* 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;
-       }
-    }
-  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);
-
-      if (Type != NULL)
-       *Type = Value->DataType;
-      if ((Data != NULL) && (DataSize != NULL))
-       {
-         if (Value->DataSize <= sizeof(PUCHAR))
-           {
-             Size = min(Value->DataSize, *DataSize);
-             memcpy(Data, &Value->Data, Size);
-             *DataSize = Size;
-           }
-         else
-           {
-             Size = min(Value->DataSize, *DataSize);
-             memcpy(Data, Value->Data, Size);
-             *DataSize = Size;
-           }
-       }
-      else if ((Data == NULL) && (DataSize != NULL))
-       {
-         *DataSize = Value->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
-RegDeleteValue(FRLDRHKEY Key,
-              PCWSTR ValueName)
+static
+VOID
+RepGetValueData(
+    _In_ PHHIVE Hive,
+    _In_ PCM_KEY_VALUE ValueCell,
+    _Out_opt_ ULONG* Type,
+    _Out_opt_ PUCHAR Data,
+    _Inout_opt_ ULONG* DataSize)
 {
-  PLIST_ENTRY Ptr;
-  PVALUE Value = NULL;
+    ULONG DataLength;
 
-  if ((ValueName == NULL) || (*ValueName == 0))
+    /* Does the caller want the type? */
+    if (Type != NULL)
     {
-      /* delete default value */
-      if (Key->Data != NULL)
-       MmFreeMemory(Key->Data);
-      Key->Data = NULL;
-      Key->DataSize = 0;
-      Key->DataType = 0;
+        *Type = ValueCell->Type;
     }
-  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;
-       }
-
-      if (Ptr == &Key->ValueList)
-       return(ERROR_INVALID_PARAMETER);
-
-      /* delete value */
-      Key->ValueCount--;
-      if (Value->Name != NULL)
-       MmFreeMemory(Value->Name);
-      Value->Name = NULL;
-      Value->NameSize = 0;
-
-      if (Value->DataSize > sizeof(PUCHAR))
-       {
-         if (Value->Data != NULL)
-           MmFreeMemory(Value->Data);
-       }
-      Value->Data = NULL;
-      Value->DataSize = 0;
-      Value->DataType = 0;
-
-      RemoveEntryList(&Value->ValueList);
-      MmFreeMemory(Value);
-    }
-  return(ERROR_SUCCESS);
-}
 
-
-LONG
-RegEnumValue(FRLDRHKEY Key,
-            ULONG Index,
-            PWCHAR ValueName,
-            ULONG* NameSize,
-            ULONG* Type,
-            PUCHAR Data,
-            ULONG* DataSize)
-{
-  PLIST_ENTRY Ptr;
-  PVALUE Value;
-  ULONG Count = 0;
-
-  if (Key->Data != NULL)
+    /* Does the caller provide DataSize? */
+    if (DataSize != NULL)
     {
-      if (Index > 0)
-       {
-         Index--;
-       }
-      else
-       {
-         /* enumerate default value */
-         if (ValueName != NULL)
-           *ValueName = 0;
-         if (Type != NULL)
-           *Type = Key->DataType;
-      if (Data != NULL)
+        /* Get the data length */
+        DataLength = ValueCell->DataLength & REG_DATA_SIZE_MASK;
+
+        /* Does the caller want the data? */
+        if ((Data != NULL) && (*DataSize != 0))
         {
-          if (Key->DataSize <= sizeof(PUCHAR))
+            /* Check where the data is stored */
+            if ((DataLength <= sizeof(HCELL_INDEX)) &&
+                 (ValueCell->DataLength & REG_DATA_IN_OFFSET))
             {
-              memcpy(Data, &Key->Data, min(Key->DataSize, *DataSize));
+                /* The data member contains the data */
+                RtlCopyMemory(Data,
+                              &ValueCell->Data,
+                              min(*DataSize, DataLength));
             }
-          else
+            else
             {
-              memcpy(Data, Key->Data, min(Key->DataSize, *DataSize));
+                /* The data member contains the data cell index */
+                PVOID DataCell = HvGetCell(Hive, ValueCell->Data);
+                RtlCopyMemory(Data,
+                              DataCell,
+                              min(*DataSize, ValueCell->DataLength));
             }
+
         }
-         if (DataSize != NULL)
-           *DataSize = min(Key->DataSize, *DataSize);
 
-      return(ERROR_SUCCESS);
-       }
+        /* Return the actual data length */
+        *DataSize = DataLength;
     }
+}
 
-  Ptr = Key->ValueList.Flink;
-  while (Ptr != &Key->ValueList)
+LONG
+RegQueryValue(
+    _In_ FRLDRHKEY Key,
+    _In_z_ PCWSTR ValueName,
+    _Out_opt_ ULONG* Type,
+    _Out_opt_ PUCHAR Data,
+    _Inout_opt_ ULONG* DataSize)
+{
+    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)
     {
-      if (Index == Count)
-       break;
-
-      Count++;
-      Ptr = Ptr->Flink;
+        TRACE("RegQueryValue no values in key (%.*s)\n",
+              KeyNode->NameLength, KeyNode->Name);
+        return ERROR_INVALID_PARAMETER;
     }
 
-  if (Ptr == &Key->ValueList)
-    return(ERROR_NO_MORE_ITEMS);
+    /* Initialize value name string */
+    RtlInitUnicodeString(&ValueNameString, ValueName);
 
-  Value = CONTAINING_RECORD(Ptr,
-                           VALUE,
-                           ValueList);
+    ValueListCell = (PVALUE_LIST_CELL)HvGetCell(Hive, KeyNode->ValueList.List);
+    TRACE("ValueListCell: %x\n", ValueListCell);
 
-  /* enumerate non-default value */
-  if (ValueName != NULL)
-    memcpy(ValueName, Value->Name, min(Value->NameSize, *NameSize));
-  if (Type != NULL)
-    *Type = Value->DataType;
-
-  if (Data != NULL)
+    /* Loop all values */
+    for (i = 0; i < KeyNode->ValueList.Count; i++)
     {
-      if (Value->DataSize <= sizeof(PUCHAR))
-        {
-          memcpy(Data, &Value->Data, min(Value->DataSize, *DataSize));
-        }
-      else
+        /* Get the subkey node and check the name */
+        ValueCell = HvGetCell(Hive, ValueListCell->ValueOffset[i]);
+
+        /* Compare the value name */
+        TRACE("checking %.*s\n", ValueCell->NameLength, ValueCell->Name);
+        if (CmCompareKeyValueName(ValueCell, &ValueNameString, TRUE))
         {
-          memcpy(Data, Value->Data, min(Value->DataSize, *DataSize));
+            RepGetValueData(Hive, ValueCell, Type, Data, DataSize);
+            TRACE("RegQueryValue success\n");
+            return STATUS_SUCCESS;
         }
     }
 
-  if (DataSize != NULL)
-    *DataSize = min(Value->DataSize, *DataSize);
-
-  return(ERROR_SUCCESS);
+    TRACE("RegQueryValue value not found\n");
+    return ERROR_INVALID_PARAMETER;
 }
 
 
-ULONG
-RegGetSubKeyCount (FRLDRHKEY Key)
+LONG
+RegEnumValue(
+    _In_ FRLDRHKEY Key,
+    _In_ ULONG Index,
+    _Out_ PWCHAR ValueName,
+    _Inout_ ULONG* NameSize,
+    _Out_ ULONG* Type,
+    _Out_ PUCHAR Data,
+    _Inout_ ULONG* DataSize)
 {
-  return Key->SubKeyCount;
-}
+    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))
+    {
+        ERR("RegEnumValue: index invalid\n");
+        return ERROR_NO_MORE_ITEMS;
+    }
 
+    ValueListCell = (PVALUE_LIST_CELL)HvGetCell(Hive, KeyNode->ValueList.List);
+    TRACE("ValueListCell: %x\n", ValueListCell);
 
-ULONG
-RegGetValueCount (FRLDRHKEY Key)
-{
-  if (Key->DataSize != 0)
-    return Key->ValueCount + 1;
+    /* Get the value cell */
+    ValueCell = HvGetCell(Hive, ValueListCell->ValueOffset[Index]);
+    ASSERT(ValueCell != NULL);
+
+    if (NameSize != NULL)
+    {
+        *NameSize = CmCopyKeyValueName(ValueCell, ValueName, *NameSize);
+    }
+
+    RepGetValueData(Hive, ValueCell, Type, Data, DataSize);
+
+    if (DataSize != NULL)
+    {
+        if ((Data != NULL) && (*DataSize != 0))
+        {
+            RtlCopyMemory(Data,
+                          &ValueCell->Data,
+                          min(*DataSize, ValueCell->DataLength));
+        }
+
+        *DataSize = ValueCell->DataLength;
+    }
 
-  return Key->ValueCount;
+    TRACE("RegEnumValue done\n");
+    return STATUS_SUCCESS;
 }
 
 /* EOF */