[MKHIVE]
[reactos.git] / reactos / tools / mkhive / registry.c
index 105f897..a6d7d4b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  ReactOS kernel
- *  Copyright (C) 2003 ReactOS Team
+ *  Copyright (C) 2006 ReactOS Team
  *
  *  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
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
-/* $Id$
- * COPYRIGHT:       See COPYING in the top level directory
+/* COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS hive maker
  * FILE:            tools/mkhive/registry.c
  * PURPOSE:         Registry code
- * PROGRAMMER:      Eric Kohl
+ * PROGRAMMER:      HervĂ© Poussineau
  */
 
 /*
  * TODO:
- *     - Implement RegDeleteKey().
- *     - Fix RegEnumValue().
+ *     - Implement RegDeleteKeyW()
+ *     - Implement RegEnumValue()
+ *     - Implement RegQueryValueExW()
  */
 
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 
+#define NDEBUG
 #include "mkhive.h"
-#include "registry.h"
 
-
-static HKEY RootKey;
-
-
-VOID
-RegInitializeRegistry(VOID)
+#define REG_DATA_SIZE_MASK                 0x7FFFFFFF
+#define REG_DATA_IN_OFFSET                 0x80000000
+
+static CMHIVE RootHive;
+static MEMKEY RootKey;
+CMHIVE DefaultHive;  /* \Registry\User\.DEFAULT */
+CMHIVE SamHive;      /* \Registry\Machine\SAM */
+CMHIVE SecurityHive; /* \Registry\Machine\SECURITY */
+CMHIVE SoftwareHive; /* \Registry\Machine\SOFTWARE */
+CMHIVE SystemHive;   /* \Registry\Machine\SYSTEM */
+
+static MEMKEY
+CreateInMemoryStructure(
+       IN PCMHIVE RegistryHive,
+       IN HCELL_INDEX KeyCellOffset,
+       IN PCUNICODE_STRING KeyName)
 {
-  HKEY ControlSetKey;
-  HKEY LinkKey;
-
-  /* Create root key */
-  RootKey = (HKEY)malloc(sizeof(KEY));
-
-  InitializeListHead(&RootKey->SubKeyList);
-  InitializeListHead(&RootKey->ValueList);
-  InitializeListHead(&RootKey->KeyList);
-
-  RootKey->SubKeyCount = 0;
-  RootKey->ValueCount = 0;
-
-  RootKey->NameSize = 2;
-  RootKey->Name = (PCHAR)malloc(2);
-  strcpy(RootKey->Name, "\\");
-
-  RootKey->DataType = 0;
-  RootKey->DataSize = 0;
-  RootKey->Data = NULL;
-
-  /* Create SYSTEM key */
-  RegCreateKey(RootKey,
-              "Registry\\Machine\\SYSTEM",
-              NULL);
-
-  /* Create link 'CurrentControlSet' --> 'ControlSet001' */
-  RegCreateKey(RootKey,
-              "Registry\\Machine\\SYSTEM\\ControlSet001",
-              &ControlSetKey);
-
-  RegCreateKey(RootKey,
-              "Registry\\Machine\\SYSTEM\\CurrentControlSet",
-              &LinkKey);
-
-  RegSetValue(LinkKey,
-             NULL,
-             REG_LINK,
-             (PCHAR)&ControlSetKey,
-             sizeof(PVOID));
-
-  /* Create HARDWARE key */
-  RegCreateKey(RootKey,
-              "Registry\\Machine\\HARDWARE",
-              NULL);
-
-  /* Create SAM key */
-  RegCreateKey(RootKey,
-              "Registry\\Machine\\SAM",
-              NULL);
-
-  /* Create SECURITY key */
-  RegCreateKey(RootKey,
-              "Registry\\Machine\\SECURITY",
-              NULL);
-
-  /* Create SOFTWARE key */
-  RegCreateKey(RootKey,
-              "Registry\\Machine\\SOFTWARE",
-              NULL);
-
-  /* Create DEFAULT key */
-  RegCreateKey(RootKey,
-              "Registry\\User\\.DEFAULT",
-              NULL);
+       MEMKEY Key;
+
+       Key = (MEMKEY) malloc (sizeof(KEY));
+       if (!Key)
+               return NULL;
+
+       InitializeListHead (&Key->SubKeyList);
+       InitializeListHead (&Key->ValueList);
+       InitializeListHead (&Key->KeyList);
+
+       Key->SubKeyCount = 0;
+       Key->ValueCount = 0;
+
+       Key->NameSize = KeyName->Length;
+       /* FIXME: It's not enough to allocate this way, because later
+                 this memory gets overwritten with bigger names */
+       Key->Name = malloc (Key->NameSize);
+       if (!Key->Name)
+               return NULL;
+       memcpy(Key->Name, KeyName->Buffer, KeyName->Length);
+
+       Key->DataType = 0;
+       Key->DataSize = 0;
+       Key->Data = NULL;
+
+       Key->RegistryHive = RegistryHive;
+       Key->KeyCellOffset = KeyCellOffset;
+       Key->KeyCell = (PCM_KEY_NODE)HvGetCell (&RegistryHive->Hive, Key->KeyCellOffset);
+       if (!Key->KeyCell)
+       {
+               free(Key);
+               return NULL;
+       }
+       Key->LinkedKey = NULL;
+       return Key;
 }
 
-
-LONG
-RegCreateKey(HKEY ParentKey,
-            PCHAR KeyName,
-            PHKEY Key)
+static LONG
+RegpOpenOrCreateKey(
+       IN HKEY hParentKey,
+       IN PCWSTR KeyName,
+       IN BOOL AllowCreation,
+       OUT PHKEY Key)
 {
-  PLIST_ENTRY Ptr;
-  HKEY SearchKey = INVALID_HANDLE_VALUE;
-  HKEY CurrentKey;
-  HKEY NewKey;
-  PCHAR p;
-  PCHAR name;
-  int subkeyLength;
-  int stringLength;
-
-  DPRINT ("RegCreateKey('%s')\n", KeyName);
-
-  if (*KeyName == '\\')
-    {
-      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 = (HKEY)CurrentKey->Data;
-    }
-
-  while (*KeyName != 0)
-    {
-      DPRINT ("KeyName '%s'\n", KeyName);
-
-      if (*KeyName == '\\')
-       KeyName++;
-      p = strchr (KeyName, '\\');
-      if ((p != NULL) && (p != KeyName))
+       PWSTR LocalKeyName;
+       PWSTR End;
+       UNICODE_STRING KeyString;
+       NTSTATUS Status;
+       MEMKEY ParentKey;
+       MEMKEY CurrentKey;
+       PLIST_ENTRY Ptr;
+       PCM_KEY_NODE SubKeyCell;
+       HCELL_INDEX BlockOffset;
+
+       DPRINT("RegpCreateOpenKey('%S')\n", KeyName);
+
+       if (*KeyName == L'\\')
        {
-         subkeyLength = p - KeyName;
-         stringLength = subkeyLength + 1;
-         name = KeyName;
+               KeyName++;
+               ParentKey = RootKey;
        }
-      else
+       else if (hParentKey == NULL)
        {
-         subkeyLength = strlen (KeyName);
-         stringLength = subkeyLength;
-         name = KeyName;
+               ParentKey = RootKey;
        }
-
-      Ptr = CurrentKey->SubKeyList.Flink;
-      while (Ptr != &CurrentKey->SubKeyList)
+       else
        {
-         DPRINT ("Ptr 0x%p\n", Ptr);
-
-         SearchKey = CONTAINING_RECORD(Ptr,
-                                       KEY,
-                                       KeyList);
-         DPRINT ("SearchKey 0x%p\n", SearchKey);
-         DPRINT ("Searching '%s'\n", SearchKey->Name);
-         if (strncasecmp (SearchKey->Name, name, subkeyLength) == 0)
-           break;
-
-         Ptr = Ptr->Flink;
+               ParentKey = HKEY_TO_MEMKEY(RootKey);
        }
 
-      if (Ptr == &CurrentKey->SubKeyList)
-       {
-         /* no key found -> create new subkey */
-         NewKey = (HKEY)malloc (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 (&CurrentKey->SubKeyList, &NewKey->KeyList);
-         CurrentKey->SubKeyCount++;
-
-         NewKey->NameSize = subkeyLength + 1;
-         NewKey->Name = (PCHAR)malloc (NewKey->NameSize);
-         if (NewKey->Name == NULL)
-          return(ERROR_OUTOFMEMORY);
-         memcpy(NewKey->Name, name, subkeyLength);
-         NewKey->Name[subkeyLength] = 0;
-
-         DPRINT ("NewKey 0x%p\n", NewKey);
-         DPRINT ("NewKey '%s'  Length %ld\n", NewKey->Name, NewKey->NameSize);
-
-         CurrentKey = NewKey;
-       }
-      else
+       LocalKeyName = (PWSTR)KeyName;
+       for (;;)
        {
-         CurrentKey = SearchKey;
-
-         /* Check whether current key is a link */
-         if (CurrentKey->DataType == REG_LINK)
-           {
-             CurrentKey = (HKEY)CurrentKey->Data;
-           }
+               End = (PWSTR) utf16_wcschr(LocalKeyName, '\\');
+               if (End)
+               {
+                       KeyString.Buffer = LocalKeyName;
+                       KeyString.Length = KeyString.MaximumLength =
+                               (USHORT)((ULONG_PTR)End - (ULONG_PTR)LocalKeyName);
+               }
+               else
+                       RtlInitUnicodeString(&KeyString, LocalKeyName);
+
+               /* Redirect from 'CurrentControlSet' to 'ControlSet001' */
+               if (!utf16_wcsncmp(LocalKeyName, L"CurrentControlSet", 17) &&
+                           ParentKey->NameSize == 12 &&
+                           !memcmp(ParentKey->Name, L"SYSTEM", 12))
+                       RtlInitUnicodeString(&KeyString, L"ControlSet001");
+
+               /* Check subkey in memory structure */
+               Ptr = ParentKey->SubKeyList.Flink;
+               while (Ptr != &ParentKey->SubKeyList)
+               {
+                       CurrentKey = CONTAINING_RECORD(Ptr, KEY, KeyList);
+                       if (CurrentKey->NameSize == KeyString.Length
+                        && memcmp(CurrentKey->Name, KeyString.Buffer, KeyString.Length) == 0)
+                       {
+                               goto nextsubkey;
+                       }
+
+                       Ptr = Ptr->Flink;
+               }
+
+               Status = CmiScanForSubKey(
+                       ParentKey->RegistryHive,
+                       ParentKey->KeyCell,
+                       &KeyString,
+                       OBJ_CASE_INSENSITIVE,
+                       &SubKeyCell,
+                       &BlockOffset);
+               if (AllowCreation && Status == STATUS_OBJECT_NAME_NOT_FOUND)
+               {
+                       Status = CmiAddSubKey(
+                               ParentKey->RegistryHive,
+                               ParentKey->KeyCell,
+                               ParentKey->KeyCellOffset,
+                               &KeyString,
+                               0,
+                               &SubKeyCell,
+                               &BlockOffset);
+               }
+               if (!NT_SUCCESS(Status))
+                       return ERROR_UNSUCCESSFUL;
+
+               /* Now, SubKeyCell/BlockOffset are valid */
+               CurrentKey = CreateInMemoryStructure(
+                       ParentKey->RegistryHive,
+                       BlockOffset,
+                       &KeyString);
+               if (!CurrentKey)
+                       return ERROR_OUTOFMEMORY;
+
+               /* Add CurrentKey in ParentKey */
+               InsertTailList(&ParentKey->SubKeyList, &CurrentKey->KeyList);
+               ParentKey->SubKeyCount++;
+
+nextsubkey:
+               ParentKey = CurrentKey;
+               if (End)
+                       LocalKeyName = End + 1;
+               else
+                       break;
        }
 
-      KeyName = KeyName + stringLength;
-    }
+       *Key = MEMKEY_TO_HKEY(ParentKey);
 
-  if (Key != NULL)
-    *Key = CurrentKey;
-
-  return ERROR_SUCCESS;
+       return ERROR_SUCCESS;
 }
 
-
-LONG
-RegDeleteKey(HKEY Key,
-            PCHAR Name)
+LONG WINAPI
+RegCreateKeyW(
+       IN HKEY hKey,
+       IN LPCWSTR lpSubKey,
+       OUT PHKEY phkResult)
 {
-  if (Name != NULL && strchr(Name, '\\') != NULL)
-    return(ERROR_INVALID_PARAMETER);
-
-  DPRINT1("FIXME!\n");
-
-  return(ERROR_SUCCESS);
+       return RegpOpenOrCreateKey(hKey, lpSubKey, TRUE, phkResult);
 }
 
-
-LONG
-RegEnumKey(HKEY Key,
-          ULONG Index,
-          PCHAR Name,
-          PULONG NameSize)
+static PWSTR
+MultiByteToWideChar(
+       IN PCSTR MultiByteString)
 {
-  PLIST_ENTRY Ptr;
-  HKEY SearchKey;
-  ULONG Count = 0;
-  ULONG Size;
-
-  Ptr = Key->SubKeyList.Flink;
-  while (Ptr != &Key->SubKeyList)
-    {
-      if (Index == Count)
-       break;
-
-      Count++;
-      Ptr = Ptr->Flink;
-    }
-
-  if (Ptr == &Key->SubKeyList)
-    return(ERROR_NO_MORE_ITEMS);
-
-  SearchKey = CONTAINING_RECORD(Ptr,
-                               KEY,
-                               KeyList);
-
-  DPRINT ("Name '%s'  Length %ld\n", SearchKey->Name, SearchKey->NameSize);
-
-  Size = min(SearchKey->NameSize, *NameSize);
-  *NameSize = Size;
-  memcpy(Name, SearchKey->Name, Size);
-
-  return(ERROR_SUCCESS);
+       ANSI_STRING Source;
+       UNICODE_STRING Destination;
+       NTSTATUS Status;
+
+       RtlInitAnsiString(&Source, MultiByteString);
+       Status = RtlAnsiStringToUnicodeString(&Destination, &Source, TRUE);
+       if (!NT_SUCCESS(Status))
+               return NULL;
+       return Destination.Buffer;
 }
 
-
-LONG
-RegOpenKey(HKEY ParentKey,
-          PCHAR KeyName,
-          PHKEY Key)
+LONG WINAPI
+RegCreateKeyA(
+       IN HKEY hKey,
+       IN LPCSTR lpSubKey,
+       OUT PHKEY phkResult)
 {
-  PLIST_ENTRY Ptr;
-  HKEY SearchKey = INVALID_HANDLE_VALUE;
-  HKEY CurrentKey;
-  PCHAR p;
-  PCHAR name;
-  int subkeyLength;
-  int stringLength;
-
-  DPRINT("KeyName '%s'\n", KeyName);
-
-  *Key = NULL;
-
-  if (*KeyName == '\\')
-    {
-      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 = (HKEY)CurrentKey->Data;
-    }
-
-  while (*KeyName != 0)
-    {
-      DPRINT ("KeyName '%s'\n", KeyName);
-
-      if (*KeyName == '\\')
-       KeyName++;
-      p = strchr(KeyName, '\\');
-      if ((p != NULL) && (p != KeyName))
-       {
-         subkeyLength = p - KeyName;
-         stringLength = subkeyLength + 1;
-         name = KeyName;
-       }
-      else
-       {
-         subkeyLength = strlen(KeyName);
-         stringLength = subkeyLength;
-         name = KeyName;
-       }
+       PWSTR lpSubKeyW;
+       LONG rc;
 
-      Ptr = CurrentKey->SubKeyList.Flink;
-      while (Ptr != &CurrentKey->SubKeyList)
-       {
-         DPRINT ("Ptr 0x%p\n", Ptr);
+       lpSubKeyW = MultiByteToWideChar(lpSubKey);
+       if (!lpSubKeyW)
+               return ERROR_OUTOFMEMORY;
 
-         SearchKey = CONTAINING_RECORD(Ptr,
-                                       KEY,
-                                       KeyList);
+       rc = RegCreateKeyW(hKey, lpSubKeyW, phkResult);
+       free(lpSubKeyW);
+       return rc;
+}
 
-         DPRINT ("SearchKey 0x%p\n", SearchKey);
-         DPRINT ("Searching '%s'\n", SearchKey->Name);
+LONG WINAPI
+RegDeleteKeyW(
+       IN HKEY hKey,
+       IN LPCWSTR lpSubKey)
+{
+       DPRINT1("FIXME!\n");
+       return ERROR_SUCCESS;
+}
 
-         if (strncasecmp(SearchKey->Name, name, subkeyLength) == 0)
-           break;
+LONG WINAPI
+RegDeleteKeyA(
+       IN HKEY hKey,
+       IN LPCSTR lpSubKey)
+{
+       PWSTR lpSubKeyW = NULL;
+       LONG rc;
 
-         Ptr = Ptr->Flink;
-       }
+       if (lpSubKey != NULL && strchr(lpSubKey, '\\') != NULL)
+               return ERROR_INVALID_PARAMETER;
 
-      if (Ptr == &CurrentKey->SubKeyList)
+       if (lpSubKey)
        {
-         return(ERROR_PATH_NOT_FOUND);
-       }
-      else
-       {
-         CurrentKey = SearchKey;
-
-         /* Check whether current key is a link */
-         if (CurrentKey->DataType == REG_LINK)
-           {
-             CurrentKey = (HKEY)CurrentKey->Data;
-           }
+               lpSubKeyW = MultiByteToWideChar(lpSubKey);
+               if (!lpSubKeyW)
+                       return ERROR_OUTOFMEMORY;
        }
 
-      KeyName = KeyName + stringLength;
-    }
+       rc = RegDeleteKeyW(hKey, lpSubKeyW);
 
-  if (Key != NULL)
-    *Key = CurrentKey;
+       if (lpSubKey)
+               free(lpSubKeyW);
 
-  return(ERROR_SUCCESS);
+       return rc;
 }
 
+LONG WINAPI
+RegOpenKeyW(
+       IN HKEY hKey,
+       IN LPCWSTR lpSubKey,
+       OUT PHKEY phkResult)
+{
+       return RegpOpenOrCreateKey(hKey, lpSubKey, FALSE, phkResult);
+}
 
-LONG
-RegSetValue(HKEY Key,
-           PCHAR ValueName,
-           ULONG Type,
-           PCHAR Data,
-           ULONG DataSize)
+LONG WINAPI
+RegOpenKeyA(
+       IN HKEY hKey,
+       IN LPCSTR lpSubKey,
+       OUT PHKEY phkResult)
 {
-  PLIST_ENTRY Ptr;
-  PVALUE Value = NULL;
+       PWSTR lpSubKeyW;
+       LONG rc;
 
-  DPRINT ("Key 0x%x, ValueName '%s', Type %d, Data 0x%x, DataSize %d\n",
-         (int)Key, ValueName, (int)Type, (int)Data, (int)DataSize);
+       lpSubKeyW = MultiByteToWideChar(lpSubKey);
+       if (!lpSubKeyW)
+               return ERROR_OUTOFMEMORY;
 
-  if ((ValueName == NULL) || (*ValueName == 0))
-    {
-      /* set default value */
-      if ((Key->Data != NULL) && (Key->DataSize > sizeof(PCHAR)))
-       {
-         free(Key->Data);
-       }
+       rc = RegOpenKeyW(hKey, lpSubKeyW, phkResult);
+       free(lpSubKeyW);
+       return rc;
+}
 
-      if (DataSize <= sizeof(PCHAR))
+static LONG
+RegpOpenOrCreateValue(
+       IN HKEY hKey,
+       IN LPCWSTR ValueName,
+       IN BOOL AllowCreation,
+       OUT PCM_KEY_VALUE *ValueCell,
+       OUT PHCELL_INDEX ValueCellOffset)
+{
+       MEMKEY ParentKey;
+       UNICODE_STRING ValueString;
+       NTSTATUS Status;
+
+       ParentKey = HKEY_TO_MEMKEY(hKey);
+       RtlInitUnicodeString(&ValueString, ValueName);
+
+       Status = CmiScanForValueKey(
+               ParentKey->RegistryHive,
+               ParentKey->KeyCell,
+               &ValueString,
+               ValueCell,
+               ValueCellOffset);
+       if (AllowCreation && Status == STATUS_OBJECT_NAME_NOT_FOUND)
        {
-         Key->DataSize = DataSize;
-         Key->DataType = Type;
-         memcpy(&Key->Data, Data, DataSize);
+               Status = CmiAddValueKey(
+                       ParentKey->RegistryHive,
+                       ParentKey->KeyCell,
+                       ParentKey->KeyCellOffset,
+                       &ValueString,
+                       ValueCell,
+                       ValueCellOffset);
        }
-      else
+       if (!NT_SUCCESS(Status))
+               return ERROR_UNSUCCESSFUL;
+       return ERROR_SUCCESS;
+}
+
+LONG WINAPI
+RegSetValueExW(
+       IN HKEY hKey,
+       IN LPCWSTR lpValueName OPTIONAL,
+       IN ULONG Reserved,
+       IN ULONG dwType,
+       IN const UCHAR* lpData,
+       IN USHORT cbData)
+{
+       MEMKEY Key, DestKey;
+       PHKEY phKey;
+       PCM_KEY_VALUE ValueCell;
+       HCELL_INDEX ValueCellOffset;
+       PVOID DataCell;
+       LONG DataCellSize;
+       NTSTATUS Status;
+
+       if (dwType == REG_LINK)
        {
-         Key->Data = (PCHAR)malloc(DataSize);
-         Key->DataSize = DataSize;
-         Key->DataType = Type;
-         memcpy(Key->Data, Data, DataSize);
+               /* Special handling of registry links */
+               if (cbData != sizeof(PVOID))
+                       return STATUS_INVALID_PARAMETER;
+               phKey = (PHKEY)lpData;
+               Key = HKEY_TO_MEMKEY(hKey);
+               DestKey = HKEY_TO_MEMKEY(*phKey);
+
+               /* Create the link in memory */
+               Key->DataType = REG_LINK;
+               Key->LinkedKey = DestKey;
+
+               /* Create the link in registry hive (if applicable) */
+               if (Key->RegistryHive != DestKey->RegistryHive)
+                       return STATUS_SUCCESS;
+               DPRINT1("Save link to registry\n");
+               return STATUS_NOT_IMPLEMENTED;
        }
-    }
-  else
-    {
-      /* set non-default value */
-      Ptr = Key->ValueList.Flink;
-      while (Ptr != &Key->ValueList)
-       {
-         Value = CONTAINING_RECORD(Ptr,
-                                   VALUE,
-                                   ValueList);
 
-         DPRINT ("Value->Name '%s'\n", Value->Name);
+       if ((cbData & REG_DATA_SIZE_MASK) != cbData)
+               return STATUS_UNSUCCESSFUL;
 
-         if (strcasecmp(Value->Name, ValueName) == 0)
-           break;
+       Key = HKEY_TO_MEMKEY(hKey);
 
-         Ptr = Ptr->Flink;
-       }
+       Status = RegpOpenOrCreateValue(hKey, lpValueName, TRUE, &ValueCell, &ValueCellOffset);
+       if (!NT_SUCCESS(Status))
+               return ERROR_UNSUCCESSFUL;
 
-      if (Ptr == &Key->ValueList)
+       /* Get size of the allocated cellule (if any) */
+       if (!(ValueCell->DataLength & REG_DATA_IN_OFFSET) &&
+               (ValueCell->DataLength & REG_DATA_SIZE_MASK) != 0)
        {
-         /* add new value */
-         DPRINT("No value found - adding new value\n");
-
-         Value = (PVALUE)malloc(sizeof(VALUE));
-         if (Value == NULL)
-           return(ERROR_OUTOFMEMORY);
-         InsertTailList(&Key->ValueList, &Value->ValueList);
-         Key->ValueCount++;
-         Value->NameSize = strlen(ValueName)+1;
-         Value->Name = (PCHAR)malloc(Value->NameSize);
-         if (Value->Name == NULL)
-           return(ERROR_OUTOFMEMORY);
-         strcpy(Value->Name, ValueName);
-         Value->DataType = REG_NONE;
-         Value->DataSize = 0;
-         Value->Data = NULL;
+               DataCell = HvGetCell(&Key->RegistryHive->Hive, ValueCell->Data);
+               if (!DataCell)
+                       return ERROR_UNSUCCESSFUL;
+               DataCellSize = -HvGetCellSize(&Key->RegistryHive->Hive, DataCell);
        }
-
-      /* set new value */
-      if ((Value->Data != NULL) && (Value->DataSize > sizeof(PCHAR)))
+       else
        {
-         free(Value->Data);
+               DataCell = NULL;
+               DataCellSize = 0;
        }
 
-      if (DataSize <= sizeof(PCHAR))
+       if (cbData <= sizeof(HCELL_INDEX))
        {
-         Value->DataSize = DataSize;
-         Value->DataType = Type;
-         memcpy(&Value->Data, Data, DataSize);
+               /* If data size <= sizeof(HCELL_INDEX) then store data in the data offset */
+               DPRINT("ValueCell->DataLength %u\n", ValueCell->DataLength);
+               if (DataCell)
+                       HvFreeCell(&Key->RegistryHive->Hive, ValueCell->Data);
+
+               RtlCopyMemory(&ValueCell->Data, lpData, cbData);
+               ValueCell->DataLength = (ULONG)(cbData | REG_DATA_IN_OFFSET);
+               ValueCell->Type = dwType;
+               HvMarkCellDirty(&Key->RegistryHive->Hive, ValueCellOffset, FALSE);
        }
-      else
+       else
        {
-         Value->Data = (PCHAR)malloc(DataSize);
-         if (Value->Data == NULL)
-           return(ERROR_OUTOFMEMORY);
-         Value->DataType = Type;
-         Value->DataSize = DataSize;
-         memcpy(Value->Data, Data, DataSize);
+               if (cbData > (SIZE_T)DataCellSize)
+               {
+                       /* New data size is larger than the current, destroy current
+                        * data block and allocate a new one. */
+                       HCELL_INDEX NewOffset;
+
+                       DPRINT("ValueCell->DataLength %u\n", ValueCell->DataLength);
+
+                       NewOffset = HvAllocateCell(&Key->RegistryHive->Hive, cbData, Stable, HCELL_NIL);
+                       if (NewOffset == HCELL_NIL)
+                       {
+                               DPRINT("HvAllocateCell() failed with status 0x%08x\n", Status);
+                               return ERROR_UNSUCCESSFUL;
+                       }
+
+                       if (DataCell)
+                               HvFreeCell(&Key->RegistryHive->Hive, ValueCell->Data);
+
+                       ValueCell->Data = NewOffset;
+                       DataCell = (PVOID)HvGetCell(&Key->RegistryHive->Hive, NewOffset);
+               }
+
+               /* Copy new contents to cellule */
+               RtlCopyMemory(DataCell, lpData, cbData);
+               ValueCell->DataLength = (ULONG)(cbData & REG_DATA_SIZE_MASK);
+               ValueCell->Type = dwType;
+               HvMarkCellDirty(&Key->RegistryHive->Hive, ValueCell->Data, FALSE);
+               HvMarkCellDirty(&Key->RegistryHive->Hive, ValueCellOffset, FALSE);
        }
-    }
-  return(ERROR_SUCCESS);
-}
-
 
-LONG
-RegQueryValue(HKEY Key,
-             PCHAR ValueName,
-             PULONG Type,
-             PCHAR Data,
-             PULONG DataSize)
-{
-  ULONG Size;
-  PLIST_ENTRY Ptr;
-  PVALUE Value = 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(PCHAR))
-           {
-             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);
+       HvMarkCellDirty(&Key->RegistryHive->Hive, Key->KeyCellOffset, FALSE);
 
-         DPRINT("Searching for '%s'. Value name '%s'\n", ValueName, Value->Name);
+       DPRINT("Return status 0x%08x\n", Status);
+       return Status;
+}
 
-         if (strcasecmp(Value->Name, ValueName) == 0)
-           break;
+LONG WINAPI
+RegSetValueExA(
+       IN HKEY hKey,
+       IN LPCSTR lpValueName OPTIONAL,
+       IN ULONG Reserved,
+       IN ULONG dwType,
+       IN const UCHAR* lpData,
+       IN ULONG cbData)
+{
+       LPWSTR lpValueNameW = NULL;
+       const UCHAR* lpDataW;
+       USHORT cbDataW;
+       LONG rc = ERROR_SUCCESS;
 
-         Ptr = Ptr->Flink;
+       DPRINT("RegSetValueA(%s)\n", lpValueName);
+       if (lpValueName)
+       {
+               lpValueNameW = MultiByteToWideChar(lpValueName);
+               if (!lpValueNameW)
+                       return ERROR_OUTOFMEMORY;
        }
 
-      if (Ptr == &Key->ValueList)
-       return(ERROR_INVALID_PARAMETER);
-
-      if (Type != NULL)
-       *Type = Value->DataType;
-      if ((Data != NULL) && (DataSize != NULL))
+       if ((dwType == REG_SZ || dwType == REG_EXPAND_SZ || dwType == REG_MULTI_SZ)
+        && cbData != 0)
        {
-         if (Value->DataSize <= sizeof(PCHAR))
-           {
-             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;
-           }
+               ANSI_STRING AnsiString;
+               UNICODE_STRING Data;
+
+               if (lpData[cbData - 1] != '\0')
+                       cbData++;
+               RtlInitAnsiString(&AnsiString, NULL);
+               AnsiString.Buffer = (PSTR)lpData;
+               AnsiString.Length = (USHORT)cbData - 1;
+               AnsiString.MaximumLength = (USHORT)cbData;
+               RtlAnsiStringToUnicodeString (&Data, &AnsiString, TRUE);
+               lpDataW = (const UCHAR*)Data.Buffer;
+               cbDataW = Data.MaximumLength;
        }
-      else if ((Data == NULL) && (DataSize != NULL))
+       else
        {
-         *DataSize = Value->DataSize;
+               lpDataW = lpData;
+               cbDataW = (USHORT)cbData;
        }
-    }
 
-  return(ERROR_SUCCESS);
+       if (rc == ERROR_SUCCESS)
+               rc = RegSetValueExW(hKey, lpValueNameW, 0, dwType, lpDataW, cbDataW);
+       if (lpValueNameW)
+               free(lpValueNameW);
+       if (lpData != lpDataW)
+               free((PVOID)lpDataW);
+       return rc;
 }
 
+LONG WINAPI
+RegQueryValueExW(
+       IN HKEY hKey,
+       IN LPCWSTR lpValueName,
+       IN PULONG lpReserved,
+       OUT PULONG lpType,
+       OUT PUCHAR lpData,
+       OUT PSIZE_T lpcbData)
+{
+       //ParentKey = HKEY_TO_MEMKEY(RootKey);
+       PCM_KEY_VALUE ValueCell;
+       HCELL_INDEX ValueCellOffset;
+       LONG rc;
+
+       rc = RegpOpenOrCreateValue(
+                       hKey,
+                       lpValueName,
+                       FALSE,
+                       &ValueCell,
+                       &ValueCellOffset);
+       if (rc != ERROR_SUCCESS)
+               return rc;
+
+       DPRINT1("RegQueryValueExW(%S) not implemented\n", lpValueName);
+       /* ValueCell and ValueCellOffset are valid */
+
+       return ERROR_UNSUCCESSFUL;
+}
 
-LONG
-RegDeleteValue(HKEY Key,
-              PCHAR ValueName)
+LONG WINAPI
+RegQueryValueExA(
+       IN HKEY hKey,
+       IN LPCSTR lpValueName,
+       IN PULONG lpReserved,
+       OUT PULONG lpType,
+       OUT PUCHAR lpData,
+       OUT PSIZE_T lpcbData)
 {
-  PLIST_ENTRY Ptr;
-  PVALUE Value = NULL;
-
-  if ((ValueName == NULL) || (*ValueName == 0))
-    {
-      /* delete default value */
-      if (Key->Data != NULL)
-       free(Key->Data);
-      Key->Data = NULL;
-      Key->DataSize = 0;
-      Key->DataType = 0;
-    }
-  else
-    {
-      /* delete non-default value */
-      Ptr = Key->ValueList.Flink;
-      while (Ptr != &Key->ValueList)
-       {
-         Value = CONTAINING_RECORD(Ptr,
-                                   VALUE,
-                                   ValueList);
-         if (strcasecmp(Value->Name, ValueName) == 0)
-           break;
+       LPWSTR lpValueNameW = NULL;
+       LONG rc;
 
-         Ptr = Ptr->Flink;
+       if (lpValueName)
+       {
+               lpValueNameW = MultiByteToWideChar(lpValueName);
+               if (!lpValueNameW)
+                       return ERROR_OUTOFMEMORY;
        }
 
-      if (Ptr == &Key->ValueList)
-       return(ERROR_INVALID_PARAMETER);
+       rc = RegQueryValueExW(hKey, lpValueNameW, lpReserved, lpType, lpData, lpcbData);
+       if (lpValueNameW)
+               free(lpValueNameW);
+       return ERROR_UNSUCCESSFUL;
+}
+
+LONG WINAPI
+RegDeleteValueW(
+       IN HKEY hKey,
+       IN LPCWSTR lpValueName OPTIONAL)
+{
+       DPRINT1("RegDeleteValueW() unimplemented\n");
+       return ERROR_UNSUCCESSFUL;
+}
 
-      /* delete value */
-      Key->ValueCount--;
-      if (Value->Name != NULL)
-       free(Value->Name);
-      Value->Name = NULL;
-      Value->NameSize = 0;
+LONG WINAPI
+RegDeleteValueA(
+       IN HKEY hKey,
+       IN LPCSTR lpValueName OPTIONAL)
+{
+       LPWSTR lpValueNameW;
+       LONG rc;
 
-      if (Value->DataSize > sizeof(PCHAR))
+       if (lpValueName)
        {
-         if (Value->Data != NULL)
-           free(Value->Data);
+               lpValueNameW = MultiByteToWideChar(lpValueName);
+               if (!lpValueNameW)
+                       return ERROR_OUTOFMEMORY;
+               rc = RegDeleteValueW(hKey, lpValueNameW);
+               free(lpValueNameW);
        }
-      Value->Data = NULL;
-      Value->DataSize = 0;
-      Value->DataType = 0;
-
-      RemoveEntryList(&Value->ValueList);
-      free(Value);
-    }
-  return(ERROR_SUCCESS);
+       else
+               rc = RegDeleteValueW(hKey, NULL);
+       return rc;
 }
 
-
-LONG
-RegEnumValue(HKEY Key,
-            ULONG Index,
-            PCHAR ValueName,
-            PULONG NameSize,
-            PULONG Type,
-            PCHAR Data,
-            PULONG DataSize)
+static BOOL
+ConnectRegistry(
+       IN HKEY RootKey,
+       IN PCMHIVE HiveToConnect,
+       IN LPCWSTR Path)
 {
-  PLIST_ENTRY Ptr;
-  PVALUE Value;
-  ULONG Count = 0;
+       NTSTATUS Status;
+       MEMKEY NewKey;
+       LONG rc;
 
-  if (Key->Data != NULL)
-    {
-      if (Index > 0)
-       {
-         Index--;
-       }
-      else
+       Status = CmiInitializeTempHive(HiveToConnect);
+       if (!NT_SUCCESS(Status))
        {
-         /* enumerate default value */
-         if (ValueName != NULL)
-           *ValueName = 0;
-         if (Type != NULL)
-           *Type = Key->DataType;
-         if (DataSize != NULL)
-           *DataSize = Key->DataSize;
-
-         /* FIXME: return more values */
+               DPRINT1("CmiInitializeTempHive() failed with status 0x%08x\n", Status);
+               return FALSE;
        }
-    }
 
-  Ptr = Key->ValueList.Flink;
-  while (Ptr != &Key->ValueList)
-    {
-      if (Index == Count)
-       break;
-
-      Count++;
-      Ptr = Ptr->Flink;
-    }
-
-  if (Ptr == &Key->ValueList)
-    return(ERROR_NO_MORE_ITEMS);
-
-  Value = CONTAINING_RECORD(Ptr,
-                           VALUE,
-                           ValueList);
-
-  /* FIXME: return values */
-
-  return(ERROR_SUCCESS);
+       /* Create key */
+       rc = RegCreateKeyW(
+               RootKey,
+               Path,
+               (PHKEY)&NewKey);
+       if (rc != ERROR_SUCCESS)
+               return FALSE;
+
+       NewKey->RegistryHive = HiveToConnect;
+       NewKey->KeyCellOffset = HiveToConnect->Hive.BaseBlock->RootCell;
+       NewKey->KeyCell = (PCM_KEY_NODE)HvGetCell (&HiveToConnect->Hive, NewKey->KeyCellOffset);
+       return TRUE;
 }
 
+LIST_ENTRY CmiHiveListHead;
 
-USHORT
-RegGetSubKeyCount (HKEY Key)
+VOID
+RegInitializeRegistry(VOID)
 {
-  return Key->SubKeyCount;
-}
+       UNICODE_STRING RootKeyName = RTL_CONSTANT_STRING(L"\\");
+       NTSTATUS Status;
+       HKEY ControlSetKey;
 
+       InitializeListHead(&CmiHiveListHead);
 
-ULONG
-RegGetValueCount (HKEY Key)
-{
-  if (Key->DataSize != 0)
-    return Key->ValueCount + 1;
+       Status = CmiInitializeTempHive(&RootHive);
+       if (!NT_SUCCESS(Status))
+       {
+               DPRINT1("CmiInitializeTempHive() failed with status 0x%08x\n", Status);
+               return;
+       }
 
-  return Key->ValueCount;
+       RootKey = CreateInMemoryStructure(
+               &RootHive,
+               RootHive.Hive.BaseBlock->RootCell,
+               &RootKeyName);
+
+       /* Create DEFAULT key */
+       ConnectRegistry(
+               NULL,
+               &DefaultHive,
+               L"Registry\\User\\.DEFAULT");
+
+       /* Create SAM key */
+       ConnectRegistry(
+               NULL,
+               &SamHive,
+               L"Registry\\Machine\\SAM");
+
+       /* Create SECURITY key */
+       ConnectRegistry(
+               NULL,
+               &SecurityHive,
+               L"Registry\\Machine\\SECURITY");
+
+       /* Create SOFTWARE key */
+       ConnectRegistry(
+               NULL,
+               &SoftwareHive,
+               L"Registry\\Machine\\SOFTWARE");
+
+       /* Create SYSTEM key */
+       ConnectRegistry(
+               NULL,
+               &SystemHive,
+               L"Registry\\Machine\\SYSTEM");
+
+       /* Create 'ControlSet001' key */
+       RegCreateKeyW(
+               NULL,
+               L"Registry\\Machine\\SYSTEM\\ControlSet001",
+               &ControlSetKey);
 }
 
 /* EOF */