forget update de.rc
[reactos.git] / reactos / ntoskrnl / cm / registry.c
index a92cfa6..c2cc4a2 100644 (file)
@@ -1,52 +1,46 @@
-/* $Id: registry.c,v 1.83 2003/02/10 21:24:45 ekohl Exp $
+/* $Id$
  *
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS kernel
  * FILE:            ntoskrnl/cm/registry.c
  * PURPOSE:         Registry functions
+ *
  * PROGRAMMERS:     Rex Jolliff
  *                  Matt Pyne
  *                  Jean Michault
- * UPDATE HISTORY:
- *                  Created 22/05/98
  */
 
-#ifdef WIN32_REGDBG
-#include "cm_win32.h"
-#else
-#include <ddk/ntddk.h>
-#include <roscfg.h>
-#include <limits.h>
-#include <string.h>
-#include <internal/pool.h>
-#include <internal/registry.h>
-#include <reactos/bugcodes.h>
-
+#include <ntoskrnl.h>
 #define NDEBUG
 #include <internal/debug.h>
 
 #include "cm.h"
+
+#if defined (ALLOC_PRAGMA)
+#pragma alloc_text(INIT, CmInitHives)
+#pragma alloc_text(INIT, CmInitializeRegistry)
+#pragma alloc_text(INIT, CmInit2)
 #endif
 
-/*  -------------------------------------------------  File Statics  */
+
+/* GLOBALS ******************************************************************/
 
 POBJECT_TYPE  CmiKeyType = NULL;
 PREGISTRY_HIVE  CmiVolatileHive = NULL;
-KSPIN_LOCK  CmiKeyListLock;
 
 LIST_ENTRY CmiHiveListHead;
-ERESOURCE CmiHiveListLock;
+
+ERESOURCE CmiRegistryLock;
+
+KTIMER CmiWorkerTimer;
+LIST_ENTRY CmiKeyObjectListHead;
+ULONG CmiTimer = 0;
 
 volatile BOOLEAN CmiHiveSyncEnabled = FALSE;
 volatile BOOLEAN CmiHiveSyncPending = FALSE;
 KDPC CmiHiveSyncDpc;
 KTIMER CmiHiveSyncTimer;
 
-static PKEY_OBJECT  CmiRootKey = NULL;
-static PKEY_OBJECT  CmiMachineKey = NULL;
-static PKEY_OBJECT  CmiUserKey = NULL;
-static PKEY_OBJECT  CmiHardwareKey = NULL;
-
 static GENERIC_MAPPING CmiKeyMapping =
        {KEY_READ, KEY_WRITE, KEY_EXECUTE, KEY_ALL_ACCESS};
 
@@ -65,6 +59,9 @@ CmiHiveSyncDpcRoutine(PKDPC Dpc,
                      PVOID SystemArgument1,
                      PVOID SystemArgument2);
 
+extern LIST_ENTRY CmiCallbackHead;
+extern FAST_MUTEX CmiCallbackLock;
+
 /* FUNCTIONS ****************************************************************/
 
 VOID
@@ -88,7 +85,7 @@ CmiCheckSubKeys(BOOLEAN Verbose,
       BufferSize = sizeof(KEY_NODE_INFORMATION) + 4096;
       KeyInfo = ExAllocatePool(PagedPool, BufferSize);
 
-      Status = NtEnumerateKey(Key,
+      Status = ZwEnumerateKey(Key,
                              Index,
                              KeyNodeInformation,
                              KeyInfo,
@@ -126,20 +123,20 @@ CmiCheckSubKeys(BOOLEAN Verbose,
                                 NULL,
                                 NULL);
 
-      Status = NtOpenKey(&SubKey,
+      Status = ZwOpenKey(&SubKey,
                         KEY_ALL_ACCESS,
                         &ObjectAttributes);
 
-      assert(NT_SUCCESS(Status));
+      ASSERT(NT_SUCCESS(Status));
 
       CmiCheckKey(Verbose, SubKey);
 
-      NtClose(SubKey);
+      ZwClose(SubKey);
 
       Index++;
     }
 
-  assert(NT_SUCCESS(Status));
+  ASSERT(NT_SUCCESS(Status));
 }
 
 
@@ -160,7 +157,7 @@ CmiCheckValues(BOOLEAN Verbose,
       BufferSize = sizeof(KEY_NODE_INFORMATION) + 4096;
       ValueInfo = ExAllocatePool(PagedPool, BufferSize);
 
-      Status = NtEnumerateValueKey(Key,
+      Status = ZwEnumerateValueKey(Key,
                                   Index,
                                   KeyNodeInformation,
                                   ValueInfo,
@@ -190,7 +187,7 @@ CmiCheckValues(BOOLEAN Verbose,
       Index++;
     }
 
-  assert(NT_SUCCESS(Status));
+  ASSERT(NT_SUCCESS(Status));
 }
 
 
@@ -224,7 +221,7 @@ CmiCheckByName(BOOLEAN Verbose,
                NULL,
                NULL);
 
-  Status = NtOpenKey(&Key,
+  Status = ZwOpenKey(&Key,
                KEY_ALL_ACCESS,
                &ObjectAttributes);
 
@@ -234,13 +231,13 @@ CmiCheckByName(BOOLEAN Verbose,
        {
           DbgPrint("KeyPath %wZ  Status: %.08x", KeyPath, Status);
           DbgPrint("KeyPath %S  Status: %.08x", KeyPath.Buffer, Status);
-          assert(NT_SUCCESS(Status));
+          ASSERT(NT_SUCCESS(Status));
        }
     }
 
   CmiCheckKey(Verbose, Key);
 
-  NtClose(Key);
+  ZwClose(Key);
 }
 
 
@@ -254,296 +251,354 @@ CmiCheckRegistry(BOOLEAN Verbose)
   CmiCheckByName(Verbose, L"User");
 }
 
+VOID STDCALL
+CmiWorkerThread(PVOID Param)
+{
+  NTSTATUS Status;
+  PLIST_ENTRY CurrentEntry;
+  PKEY_OBJECT CurrentKey;
+  ULONG Count;
+
+
+  while (1)
+  {
+    Status = KeWaitForSingleObject(&CmiWorkerTimer,
+                                  Executive,
+                                  KernelMode,
+                                  FALSE,
+                                  NULL);
+    if (Status == STATUS_SUCCESS)
+    {
+      DPRINT("CmiWorkerThread\n");
+
+      /* Acquire hive lock */
+      KeEnterCriticalRegion();
+      ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
+
+      CmiTimer++;
+
+      Count = 0;
+      CurrentEntry = CmiKeyObjectListHead.Blink;
+      while (CurrentEntry != &CmiKeyObjectListHead)
+      {
+         CurrentKey = CONTAINING_RECORD(CurrentEntry, KEY_OBJECT, ListEntry);
+        if (CurrentKey->TimeStamp + 120 > CmiTimer)
+        {
+           /* The object was accessed in the last 10min */
+           break;
+        }
+        if (1 == ObGetObjectPointerCount(CurrentKey) &&
+            !(CurrentKey->Flags & KO_MARKED_FOR_DELETE))
+        {
+           ObDereferenceObject(CurrentKey);
+            CurrentEntry = CmiKeyObjectListHead.Blink;
+           Count++;
+        }
+        else
+        {
+           CurrentEntry = CurrentEntry->Blink;
+        }
+      }
+      ExReleaseResourceLite(&CmiRegistryLock);
+      KeLeaveCriticalRegion();
+
+      DPRINT("Removed %d key objects\n", Count);
+
+    }
+    else
+    {
+      KEBUGCHECK(0);
+    }
+  }
+}
 
 VOID
+INIT_FUNCTION
+STDCALL
+CmInitHives(BOOLEAN SetupBoot)
+{
+    PCHAR BaseAddress;
+
+    /* Load Registry Hives. This one can be missing. */
+    if (CachedModules[SystemRegistry]) {
+        BaseAddress = (PCHAR)CachedModules[SystemRegistry]->ModStart;
+        CmImportSystemHive(BaseAddress,
+                           CachedModules[SystemRegistry]->ModEnd - (ULONG_PTR)BaseAddress);
+    }
+
+    BaseAddress = (PCHAR)CachedModules[HardwareRegistry]->ModStart;
+    CmImportHardwareHive(BaseAddress,
+                         CachedModules[HardwareRegistry]->ModEnd - (ULONG_PTR)BaseAddress);
+
+
+    /* Create dummy keys if no hardware hive was found */
+    CmImportHardwareHive (NULL, 0);
+
+    /* Initialize volatile registry settings */
+    if (SetupBoot == FALSE) CmInit2((PCHAR)KeLoaderBlock.CommandLine);
+}
+
+VOID 
+INIT_FUNCTION
 CmInitializeRegistry(VOID)
 {
   OBJECT_ATTRIBUTES ObjectAttributes;
-  UNICODE_STRING RootKeyName;
+  UNICODE_STRING KeyName;
+  PKEY_OBJECT RootKey;
+#if 0
+  PSECURITY_CELL RootSecurityCell;
+#endif
   HANDLE RootKeyHandle;
-  PKEY_OBJECT NewKey;
   HANDLE KeyHandle;
   NTSTATUS Status;
-
+  LARGE_INTEGER DueTime;
+  HANDLE ThreadHandle;
+  CLIENT_ID ThreadId;
+  OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
+  UNICODE_STRING Name;
+
+  DPRINT("Creating Registry Object Type\n");
+  
   /*  Initialize the Key object type  */
-  CmiKeyType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
-  assert(CmiKeyType);
-  CmiKeyType->TotalObjects = 0;
-  CmiKeyType->TotalHandles = 0;
-  CmiKeyType->MaxObjects = LONG_MAX;
-  CmiKeyType->MaxHandles = LONG_MAX;
-  CmiKeyType->PagedPoolCharge = 0;
-  CmiKeyType->NonpagedPoolCharge = sizeof(KEY_OBJECT);
-  CmiKeyType->Mapping = &CmiKeyMapping;
-  CmiKeyType->Dump = NULL;
-  CmiKeyType->Open = NULL;
-  CmiKeyType->Close = NULL;
-  CmiKeyType->Delete = CmiObjectDelete;
-  CmiKeyType->Parse = CmiObjectParse;
-  CmiKeyType->Security = NULL;
-  CmiKeyType->QueryName = NULL;
-  CmiKeyType->OkayToClose = NULL;
-  CmiKeyType->Create = CmiObjectCreate;
-  CmiKeyType->DuplicationNotify = NULL;
-  RtlInitUnicodeString(&CmiKeyType->TypeName, L"Key");
+  RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
+  RtlInitUnicodeString(&Name, L"Key");
+  ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
+  ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(KEY_OBJECT);
+  ObjectTypeInitializer.GenericMapping = CmiKeyMapping;
+  ObjectTypeInitializer.PoolType = PagedPool;
+  ObjectTypeInitializer.ValidAccessMask = KEY_ALL_ACCESS;
+  ObjectTypeInitializer.UseDefaultObject = TRUE;
+  ObjectTypeInitializer.DeleteProcedure = CmiObjectDelete;
+  ObjectTypeInitializer.ParseProcedure = CmiObjectParse;
+  ObjectTypeInitializer.SecurityProcedure = CmiObjectSecurity;
+  ObjectTypeInitializer.QueryNameProcedure = CmiObjectQueryName;
+
+  ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &CmiKeyType);
 
   /* Initialize the hive list */
   InitializeListHead(&CmiHiveListHead);
-  ExInitializeResourceLite(&CmiHiveListLock);
+
+  /* Initialize registry lock */
+  ExInitializeResourceLite(&CmiRegistryLock);
+
+  /* Initialize the key object list */
+  InitializeListHead(&CmiKeyObjectListHead);
+
+  /* Initialize the worker timer */
+  KeInitializeTimerEx(&CmiWorkerTimer, SynchronizationTimer);
+
+  /* Initialize the worker thread */
+  Status = PsCreateSystemThread(&ThreadHandle,
+                               THREAD_ALL_ACCESS,
+                               NULL,
+                               NULL,
+                               &ThreadId,
+                               CmiWorkerThread,
+                               NULL);
+  if (!NT_SUCCESS(Status))
+  {
+    KEBUGCHECK(0);
+  }
+
+  /* Start the timer */
+  DueTime.QuadPart = -1;
+  KeSetTimerEx(&CmiWorkerTimer, DueTime, 5000, NULL); /* 5sec */
 
   /*  Build volatile registry store  */
-  Status = CmiCreateRegistryHive(NULL, &CmiVolatileHive, FALSE);
-  assert(NT_SUCCESS(Status));
+  Status = CmiCreateVolatileHive (&CmiVolatileHive);
+  ASSERT(NT_SUCCESS(Status));
+
+  InitializeListHead(&CmiCallbackHead);
+  ExInitializeFastMutex(&CmiCallbackLock);
 
   /* Create '\Registry' key. */
-  RtlInitUnicodeString(&RootKeyName, REG_ROOT_KEY_NAME);
-  InitializeObjectAttributes(&ObjectAttributes, &RootKeyName, 0, NULL, NULL);
-  Status = ObCreateObject(&RootKeyHandle,
-               STANDARD_RIGHTS_REQUIRED,
-               &ObjectAttributes,
-               CmiKeyType,
-               (PVOID *) &NewKey);
-  assert(NT_SUCCESS(Status));
-  CmiRootKey = NewKey;
-  Status = ObReferenceObjectByHandle(RootKeyHandle,
-    STANDARD_RIGHTS_REQUIRED,
-               CmiKeyType,
-               KernelMode,
-               (PVOID *) &CmiRootKey,
-               NULL);
-  assert(NT_SUCCESS(Status));
-  CmiRootKey->RegistryHive = CmiVolatileHive;
-  NewKey->BlockOffset = CmiVolatileHive->HiveHeader->RootKeyCell;
-  NewKey->KeyCell = CmiGetBlock(CmiVolatileHive, NewKey->BlockOffset, NULL);
-  CmiRootKey->Flags = 0;
-  CmiRootKey->NumberOfSubKeys = 0;
-  CmiRootKey->SubKeys = NULL;
-  CmiRootKey->SizeOfSubKeys = 0;
-  CmiRootKey->Name = ExAllocatePool(PagedPool, strlen("Registry"));
-  CmiRootKey->NameSize = strlen("Registry");
-  memcpy(CmiRootKey->Name, "Registry", strlen("Registry"));
-
-  KeInitializeSpinLock(&CmiKeyListLock);
-
-  /* Create initial predefined symbolic links */
+  RtlInitUnicodeString(&KeyName, REG_ROOT_KEY_NAME);
+  InitializeObjectAttributes(&ObjectAttributes, &KeyName, 0, NULL, NULL);
+  Status = ObCreateObject(KernelMode,
+                         CmiKeyType,
+                         &ObjectAttributes,
+                         KernelMode,
+                         NULL,
+                         sizeof(KEY_OBJECT),
+                         0,
+                         0,
+                         (PVOID *) &RootKey);
+  ASSERT(NT_SUCCESS(Status));
+  Status = ObInsertObject(RootKey,
+                         NULL,
+                         KEY_ALL_ACCESS,
+                         0,
+                         NULL,
+                         &RootKeyHandle);
+  ASSERT(NT_SUCCESS(Status));
+  RootKey->RegistryHive = CmiVolatileHive;
+  RootKey->KeyCellOffset = CmiVolatileHive->HiveHeader->RootKeyOffset;
+  RootKey->KeyCell = CmiGetCell (CmiVolatileHive, RootKey->KeyCellOffset, NULL);
+  RootKey->ParentKey = RootKey;
+  RootKey->Flags = 0;
+  RootKey->NumberOfSubKeys = 0;
+  RootKey->SubKeys = NULL;
+  RootKey->SizeOfSubKeys = 0;
+  InsertTailList(&CmiKeyObjectListHead, &RootKey->ListEntry);
+  Status = RtlpCreateUnicodeString(&RootKey->Name, L"Registry", NonPagedPool);
+  ASSERT(NT_SUCCESS(Status));
+
+#if 0
+  Status = CmiAllocateCell(CmiVolatileHive,
+                          0x10, //LONG CellSize,
+                          (PVOID *)&RootSecurityCell,
+                          &RootKey->KeyCell->SecurityKeyOffset);
+  ASSERT(NT_SUCCESS(Status));
+
+  /* Copy the security descriptor */
+
+  CmiVolatileHive->RootSecurityCell = RootSecurityCell;
+#endif
+
 
   /* Create '\Registry\Machine' key. */
-  Status = ObCreateObject(&KeyHandle,
-    STANDARD_RIGHTS_REQUIRED,
-    NULL,
-    CmiKeyType,
-    (PVOID*) &NewKey);
-  assert(NT_SUCCESS(Status));
-  Status = CmiAddSubKey(CmiVolatileHive,
-               CmiRootKey,
-               NewKey,
-               L"Machine",
-               wcslen(L"Machine") * sizeof(WCHAR),
-               0,
-               NULL,
-               0);
-  assert(NT_SUCCESS(Status));
-       NewKey->RegistryHive = CmiVolatileHive;
-       NewKey->Flags = 0;
-       NewKey->NumberOfSubKeys = 0;
-       NewKey->SubKeys = NULL;
-       NewKey->SizeOfSubKeys = NewKey->KeyCell->NumberOfSubKeys;
-       NewKey->Name = ExAllocatePool(PagedPool, strlen("Machine"));
-       NewKey->NameSize = strlen("Machine");
-       memcpy(NewKey->Name, "Machine", strlen("Machine"));
-  CmiAddKeyToList(CmiRootKey, NewKey);
-  CmiMachineKey = NewKey;
+  RtlInitUnicodeString(&KeyName,
+                      L"Machine");
+  InitializeObjectAttributes(&ObjectAttributes,
+                            &KeyName,
+                            0,
+                            RootKeyHandle,
+                            NULL);
+  Status = ZwCreateKey(&KeyHandle,
+                      KEY_ALL_ACCESS,
+                      &ObjectAttributes,
+                      0,
+                      NULL,
+                      REG_OPTION_VOLATILE,
+                      NULL);
+  ASSERT(NT_SUCCESS(Status));
 
   /* Create '\Registry\User' key. */
-  Status = ObCreateObject(&KeyHandle,
-               STANDARD_RIGHTS_REQUIRED,
-               NULL,
-               CmiKeyType,
-               (PVOID*) &NewKey);
-  assert(NT_SUCCESS(Status));
-  Status = CmiAddSubKey(CmiVolatileHive,
-    CmiRootKey,
-    NewKey,
-    L"User",
-    wcslen(L"User") * sizeof(WCHAR),
-    0,
-    NULL,
-    0);
-  assert(NT_SUCCESS(Status));
-       NewKey->RegistryHive = CmiVolatileHive;
-       NewKey->Flags = 0;
-       NewKey->NumberOfSubKeys = 0;
-       NewKey->SubKeys = NULL;
-       NewKey->SizeOfSubKeys = NewKey->KeyCell->NumberOfSubKeys;
-       NewKey->Name = ExAllocatePool(PagedPool, strlen("User"));
-       NewKey->NameSize = strlen("User");
-       memcpy(NewKey->Name, "User", strlen("User"));
-       CmiAddKeyToList(CmiRootKey, NewKey);
-       CmiUserKey = NewKey;
-
-  /* Create '\Registry\Machine\HARDWARE' key. */
-  Status = ObCreateObject(&KeyHandle,
-               STANDARD_RIGHTS_REQUIRED,
-               NULL,
-               CmiKeyType,
-               (PVOID*)&NewKey);
-  assert(NT_SUCCESS(Status));
-  Status = CmiAddSubKey(CmiVolatileHive,
-    CmiMachineKey,
-    NewKey,
-    L"HARDWARE",
-    wcslen(L"HARDWARE") * sizeof(WCHAR),
-    0,
-    NULL,
-    0);
-  assert(NT_SUCCESS(Status));
-  NewKey->RegistryHive = CmiVolatileHive;
-  NewKey->Flags = 0;
-  NewKey->NumberOfSubKeys = 0;
-  NewKey->SubKeys = NULL;
-  NewKey->SizeOfSubKeys = NewKey->KeyCell->NumberOfSubKeys;
-  NewKey->Name = ExAllocatePool(PagedPool, strlen("HARDWARE"));
-  NewKey->NameSize = strlen("HARDWARE");
-  memcpy(NewKey->Name, "HARDWARE", strlen("HARDWARE"));
-  CmiAddKeyToList(CmiMachineKey, NewKey);
-  CmiHardwareKey = NewKey;
-
-  /* Create '\Registry\Machine\HARDWARE\DESCRIPTION' key. */
-  Status = ObCreateObject(&KeyHandle,
-               STANDARD_RIGHTS_REQUIRED,
-               NULL,
-               CmiKeyType,
-               (PVOID*) &NewKey);
-  assert(NT_SUCCESS(Status));
-  Status = CmiAddSubKey(CmiVolatileHive,
-               CmiHardwareKey,
-               NewKey,
-               L"DESCRIPTION",
-               wcslen(L"DESCRIPTION") * sizeof(WCHAR),
-               0,
-               NULL,
-               0);
-  assert(NT_SUCCESS(Status));
-  NewKey->RegistryHive = CmiVolatileHive;
-  NewKey->Flags = 0;
-  NewKey->NumberOfSubKeys = 0;
-  NewKey->SubKeys = NULL;
-  NewKey->SizeOfSubKeys = NewKey->KeyCell->NumberOfSubKeys;
-  NewKey->Name = ExAllocatePool(PagedPool, strlen("DESCRIPTION"));
-  NewKey->NameSize = strlen("DESCRIPTION");
-  memcpy(NewKey->Name, "DESCRIPTION", strlen("DESCRIPTION"));
-  CmiAddKeyToList(CmiHardwareKey, NewKey);
-
-  /* Create '\Registry\Machine\HARDWARE\DEVICEMAP' key. */
-  Status = ObCreateObject(&KeyHandle,
-               STANDARD_RIGHTS_REQUIRED,
-               NULL,
-               CmiKeyType,
-               (PVOID*) &NewKey);
-  assert(NT_SUCCESS(Status));
-  Status = CmiAddSubKey(CmiVolatileHive,
-    CmiHardwareKey,
-    NewKey,
-    L"DEVICEMAP",
-               wcslen(L"DEVICEMAP") * sizeof(WCHAR),
-    0,
-    NULL,
-    0);
-  assert(NT_SUCCESS(Status));
-  NewKey->RegistryHive = CmiVolatileHive;
-  NewKey->Flags = 0;
-  NewKey->NumberOfSubKeys = 0;
-  NewKey->SubKeys = NULL;
-  NewKey->SizeOfSubKeys = NewKey->KeyCell->NumberOfSubKeys;
-  NewKey->Name = ExAllocatePool(PagedPool, strlen("DEVICEMAP"));
-  NewKey->NameSize = strlen("DEVICEMAP");
-  memcpy(NewKey->Name, "DEVICEMAP", strlen("DEVICEMAP"));
-  CmiAddKeyToList(CmiHardwareKey,NewKey);
-
-  /* Create '\Registry\Machine\HARDWARE\RESOURCEMAP' key. */
-  Status = ObCreateObject(&KeyHandle,
-               STANDARD_RIGHTS_REQUIRED,
-               NULL,
-               CmiKeyType,
-               (PVOID*) &NewKey);
-  assert(NT_SUCCESS(Status));
-  Status = CmiAddSubKey(CmiVolatileHive,
-               CmiHardwareKey,
-               NewKey,
-               L"RESOURCEMAP",
-               wcslen(L"RESOURCEMAP") * sizeof(WCHAR),
-               0,
-               NULL,
-               0);
-  assert(NT_SUCCESS(Status));
-  NewKey->RegistryHive = CmiVolatileHive;
-  NewKey->Flags = 0;
-  NewKey->NumberOfSubKeys = 0;
-  NewKey->SubKeys = NULL;
-  NewKey->SizeOfSubKeys = NewKey->KeyCell->NumberOfSubKeys;
-  NewKey->Name = ExAllocatePool(PagedPool, strlen("RESOURCEMAP"));
-  NewKey->NameSize = strlen("RESOURCEMAP");
-  memcpy(NewKey->Name, "RESOURCEMAP", strlen("RESOURCEMAP"));
-  CmiAddKeyToList(CmiHardwareKey, NewKey);
-
-  /* FIXME: create remaining structure needed for default handles  */
-  /* FIXME: load volatile registry data from ROSDTECT  */
+  RtlInitUnicodeString(&KeyName,
+                      L"User");
+  InitializeObjectAttributes(&ObjectAttributes,
+                            &KeyName,
+                            0,
+                            RootKeyHandle,
+                            NULL);
+  Status = ZwCreateKey(&KeyHandle,
+                      KEY_ALL_ACCESS,
+                      &ObjectAttributes,
+                      0,
+                      NULL,
+                      REG_OPTION_VOLATILE,
+                      NULL);
+  ASSERT(NT_SUCCESS(Status));
 }
 
 
-VOID
+VOID INIT_FUNCTION
 CmInit2(PCHAR CommandLine)
 {
-  PCHAR p1, p2;
-  ULONG PiceStart;
+  ULONG PiceStart = 4;
+  BOOLEAN MiniNT = FALSE;
+  PWCHAR SystemBootDevice;
+  PWCHAR SystemStartOptions;
+  ULONG Position;
   NTSTATUS Status;
 
-  /* FIXME: Store system start options */
-
-
-
   /* Create the 'CurrentControlSet' link. */
   Status = CmiCreateCurrentControlSetLink();
-#ifndef WIN32_REGDBG
   if (!NT_SUCCESS(Status))
-    {
-      KeBugCheck(CONFIG_INITIALIZATION_FAILED);
-    }
-#endif
+    KEBUGCHECK(CONFIG_INITIALIZATION_FAILED);
+
+  /*
+   * Parse the system boot device.
+   */
+  Position = 0;
+  SystemBootDevice = ExAllocatePool(PagedPool,
+                                   (strlen(CommandLine) + 1) * sizeof(WCHAR));
+  if (SystemBootDevice == NULL)
+  {
+    KEBUGCHECK(CONFIG_INITIALIZATION_FAILED);
+  }
 
-  /* Set PICE 'Start' value to 1, if PICE debugging is enabled */
-  PiceStart = 4;
-  p1 = (PCHAR)CommandLine;
-  while (p1 && (p2 = strchr(p1, '/')))
+  while (*CommandLine != 0 && *CommandLine != ' ')
+    SystemBootDevice[Position++] = *(CommandLine++);
+  SystemBootDevice[Position++] = 0;
+
+  /*
+   * Write the system boot device to registry.
+   */
+  Status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
+                                L"\\Registry\\Machine\\System\\CurrentControlSet\\Control",
+                                L"SystemBootDevice",
+                                REG_SZ,
+                                SystemBootDevice,
+                                Position * sizeof(WCHAR));
+  if (!NT_SUCCESS(Status))
+  {
+    KEBUGCHECK(CONFIG_INITIALIZATION_FAILED);
+  }
+
+  /*
+   * Parse the system start options.
+   */
+  Position = 0;
+  SystemStartOptions = SystemBootDevice;
+  while ((CommandLine = strchr(CommandLine, '/')) != NULL)
     {
-      p2++;
-      if (_strnicmp(p2, "DEBUGPORT", 9) == 0)
-       {
-         p2 += 9;
-         if (*p2 == '=')
-           {
-             p2++;
-             if (_strnicmp(p2, "PICE", 4) == 0)
-               {
-                 p2 += 4;
-                 PiceStart = 1;
-               }
-           }
-       }
-      p1 = p2;
+      /* Skip over the slash */
+      CommandLine++;
+
+      /* Special options */
+      if (!_strnicmp(CommandLine, "MININT", 6))
+        MiniNT = TRUE;
+      else if (!_strnicmp(CommandLine, "DEBUGPORT=PICE", 14))
+        PiceStart = 1;
+
+      /* Add a space between the options */
+      if (Position != 0)
+        SystemStartOptions[Position++] = L' ';
+
+      /* Copy the command */
+      while (*CommandLine != 0 && *CommandLine != ' ')
+        SystemStartOptions[Position++] = *(CommandLine++);
     }
-#ifndef WIN32_REGDBG
-  Status = RtlWriteRegistryValue(RTL_REGISTRY_SERVICES,
-                                L"\\Pice",
-                                L"Start",
-                                REG_DWORD,
-                                &PiceStart,
-                                sizeof(ULONG));
+  SystemStartOptions[Position++] = 0;
+
+  /*
+   * Write the system start options to registry.
+   */
+  Status = RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
+                                L"\\Registry\\Machine\\System\\CurrentControlSet\\Control",
+                                L"SystemStartOptions",
+                                REG_SZ,
+                                SystemStartOptions,
+                                Position * sizeof(WCHAR));
   if (!NT_SUCCESS(Status))
+  {
+    KEBUGCHECK(CONFIG_INITIALIZATION_FAILED);
+  }
+
+  /*
+   * Create a CurrentControlSet\Control\MiniNT key that is used
+   * to detect WinPE/MiniNT systems.
+   */
+  if (MiniNT)
     {
-      KeBugCheck(CONFIG_INITIALIZATION_FAILED);
+      Status = RtlCreateRegistryKey(RTL_REGISTRY_CONTROL, L"MiniNT");
+      if (!NT_SUCCESS(Status))
+        KEBUGCHECK(CONFIG_INITIALIZATION_FAILED);
     }
-#endif
+
+  /* Set PICE 'Start' value to 1, if PICE debugging is enabled */
+  Status = RtlWriteRegistryValue(
+    RTL_REGISTRY_SERVICES,
+    L"\\Pice",
+    L"Start",
+    REG_DWORD,
+    &PiceStart,
+    sizeof(ULONG));
+  if (!NT_SUCCESS(Status))
+    KEBUGCHECK(CONFIG_INITIALIZATION_FAILED);
+
+  ExFreePool(SystemBootDevice);
 }
 
 
@@ -553,8 +608,9 @@ CmiCreateCurrentControlSetLink(VOID)
   RTL_QUERY_REGISTRY_TABLE QueryTable[5];
   WCHAR TargetNameBuffer[80];
   ULONG TargetNameLength;
-  UNICODE_STRING LinkName;
-  UNICODE_STRING LinkValue;
+  UNICODE_STRING LinkName = RTL_CONSTANT_STRING(
+                            L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
+  UNICODE_STRING LinkValue = RTL_CONSTANT_STRING(L"SymbolicLinkValue");
   ULONG CurrentSet;
   ULONG DefaultSet;
   ULONG Failed;
@@ -602,14 +658,12 @@ CmiCreateCurrentControlSetLink(VOID)
 
   DPRINT("Link target '%S'\n", TargetNameBuffer);
 
-  RtlInitUnicodeStringFromLiteral(&LinkName,
-                      L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
   InitializeObjectAttributes(&ObjectAttributes,
                             &LinkName,
                             OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_OPENLINK,
                             NULL,
                             NULL);
-  Status = NtCreateKey(&KeyHandle,
+  Status = ZwCreateKey(&KeyHandle,
                       KEY_ALL_ACCESS | KEY_CREATE_LINK,
                       &ObjectAttributes,
                       0,
@@ -618,13 +672,11 @@ CmiCreateCurrentControlSetLink(VOID)
                       NULL);
   if (!NT_SUCCESS(Status))
     {
-      DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
+      DPRINT1("ZwCreateKey() failed (Status %lx)\n", Status);
       return(Status);
     }
 
-  RtlInitUnicodeStringFromLiteral(&LinkValue,
-                      L"SymbolicLinkValue");
-  Status = NtSetValueKey(KeyHandle,
+  Status = ZwSetValueKey(KeyHandle,
                         &LinkValue,
                         0,
                         REG_LINK,
@@ -632,151 +684,333 @@ CmiCreateCurrentControlSetLink(VOID)
                         TargetNameLength);
   if (!NT_SUCCESS(Status))
     {
-      DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
+      DPRINT1("ZwSetValueKey() failed (Status %lx)\n", Status);
     }
 
-  NtClose(KeyHandle);
+  ZwClose(KeyHandle);
 
-  return(Status);
+  return Status;
 }
 
 
 NTSTATUS
-CmiConnectHive(PWSTR FileName,
-  PWSTR FullName,
-  PCHAR KeyName,
-  PKEY_OBJECT Parent,
-  BOOLEAN CreateNew)
+CmiConnectHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
+              IN PREGISTRY_HIVE RegistryHive)
 {
-  OBJECT_ATTRIBUTES ObjectAttributes;
-  PREGISTRY_HIVE RegistryHive = NULL;
-  UNICODE_STRING uKeyName;
+  UNICODE_STRING RemainingPath;
+  PKEY_OBJECT ParentKey;
   PKEY_OBJECT NewKey;
-  HANDLE KeyHandle;
   NTSTATUS Status;
+  PWSTR SubName;
+  UNICODE_STRING ObjectName;
+  OBJECT_CREATE_INFORMATION ObjectCreateInfo;
+
+  DPRINT("CmiConnectHive(%p, %p) called.\n",
+        KeyObjectAttributes, RegistryHive);
+     
+   /* Capture all the info */
+   DPRINT("Capturing Create Info\n");
+   Status = ObpCaptureObjectAttributes(KeyObjectAttributes,
+                                       KernelMode,
+                                       CmiKeyType,
+                                       &ObjectCreateInfo,
+                                       &ObjectName);
+   if (!NT_SUCCESS(Status))
+     {
+       DPRINT("ObpCaptureObjectAttributes() failed (Status %lx)\n", Status);
+       return Status;
+     }
+
+  Status = ObFindObject(&ObjectCreateInfo,
+                        &ObjectName,
+                                   (PVOID*)&ParentKey,
+                        &RemainingPath,
+                        CmiKeyType);
+     ObpReleaseCapturedAttributes(&ObjectCreateInfo);
+   if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
+  if (!NT_SUCCESS(Status))
+    {
+      return Status;
+    }
 
-  DPRINT("CmiConnectHive(%S, %S, %s, %p, %d) - Called.\n", FileName, FullName, KeyName, Parent, CreateNew);
+  DPRINT ("RemainingPath %wZ\n", &RemainingPath);
 
-  Status = CmiCreateRegistryHive(FileName, &RegistryHive, CreateNew);
-  if (!NT_SUCCESS(Status))
+  if ((RemainingPath.Buffer == NULL) || (RemainingPath.Buffer[0] == 0))
     {
-      DPRINT1("CmiCreateRegistryHive() failed (Status %lx)\n", Status);
-      KeBugCheck(0);
-      return(Status);
+      ObDereferenceObject (ParentKey);
+      RtlFreeUnicodeString(&RemainingPath);
+      return STATUS_OBJECT_NAME_COLLISION;
     }
 
-  RtlInitUnicodeString(&uKeyName, FullName);
+  /* Ignore leading backslash */
+  SubName = RemainingPath.Buffer;
+  if (*SubName == L'\\')
+    SubName++;
 
-  InitializeObjectAttributes(&ObjectAttributes,
-                            &uKeyName,
-                            0,
-                            NULL,
-                            NULL);
+  /* If RemainingPath contains \ we must return error
+     because CmiConnectHive() can not create trees */
+  if (wcschr (SubName, L'\\') != NULL)
+    {
+      ObDereferenceObject (ParentKey);
+      RtlFreeUnicodeString(&RemainingPath);
+      return STATUS_OBJECT_NAME_NOT_FOUND;
+    }
 
-  Status = ObCreateObject(&KeyHandle,
-                         STANDARD_RIGHTS_REQUIRED,
-                         &ObjectAttributes,
+  DPRINT("RemainingPath %wZ  ParentKey %p\n",
+        &RemainingPath, ParentKey);
+
+  Status = ObCreateObject(KernelMode,
                          CmiKeyType,
+                         NULL,
+                         KernelMode,
+                         NULL,
+                         sizeof(KEY_OBJECT),
+                         0,
+                         0,
                          (PVOID*)&NewKey);
+                            
   if (!NT_SUCCESS(Status))
     {
-      DPRINT1("ObCreateObject() failed (Status %lx)\n", Status);
-      KeBugCheck(0);
-      CmiRemoveRegistryHive(RegistryHive);
-      return(Status);
+      DPRINT1 ("ObCreateObject() failed (Status %lx)\n", Status);
+      ObDereferenceObject (ParentKey);
+      RtlFreeUnicodeString(&RemainingPath);
+      return Status;
     }
-
+    DPRINT("Inserting Key into Object Tree\n");
+    Status =  ObInsertObject((PVOID)NewKey,
+                             NULL,
+                             KEY_ALL_ACCESS,
+                             0,
+                             NULL,
+                             NULL);
+DPRINT("Status %x\n", Status);
   NewKey->RegistryHive = RegistryHive;
-  NewKey->BlockOffset = RegistryHive->HiveHeader->RootKeyCell;
-  NewKey->KeyCell = CmiGetBlock(RegistryHive, NewKey->BlockOffset, NULL);
+  NewKey->KeyCellOffset = RegistryHive->HiveHeader->RootKeyOffset;
+  NewKey->KeyCell = CmiGetCell (RegistryHive, NewKey->KeyCellOffset, NULL);
   NewKey->Flags = 0;
   NewKey->NumberOfSubKeys = 0;
-  NewKey->SubKeys = ExAllocatePool(PagedPool,
-  NewKey->KeyCell->NumberOfSubKeys * sizeof(DWORD));
-
-  if ((NewKey->SubKeys == NULL) && (NewKey->KeyCell->NumberOfSubKeys != 0))
+  InsertTailList(&CmiKeyObjectListHead, &NewKey->ListEntry);
+  if (NewKey->KeyCell->NumberOfSubKeys != 0)
     {
-      DPRINT("NumberOfSubKeys %d\n", NewKey->KeyCell->NumberOfSubKeys);
-      ZwClose(NewKey);
-      CmiRemoveRegistryHive(RegistryHive);
-      return(STATUS_INSUFFICIENT_RESOURCES);
+      NewKey->SubKeys = ExAllocatePool(NonPagedPool,
+                                      NewKey->KeyCell->NumberOfSubKeys * sizeof(ULONG));
+      if (NewKey->SubKeys == NULL)
+       {
+         DPRINT("ExAllocatePool() failed\n");
+         ObDereferenceObject (NewKey);
+         ObDereferenceObject (ParentKey);
+         RtlFreeUnicodeString(&RemainingPath);
+         return STATUS_INSUFFICIENT_RESOURCES;
+       }
+    }
+  else
+    {
+      NewKey->SubKeys = NULL;
     }
 
-  NewKey->SizeOfSubKeys = NewKey->KeyCell->NumberOfSubKeys;
-  NewKey->Name = ExAllocatePool(PagedPool, strlen(KeyName));
+  DPRINT ("SubName %S\n", SubName);
 
-  if ((NewKey->Name == NULL) && (strlen(KeyName) != 0))
+  Status = RtlpCreateUnicodeString(&NewKey->Name,
+              SubName, NonPagedPool);
+  RtlFreeUnicodeString(&RemainingPath);
+  if (!NT_SUCCESS(Status))
     {
-      DPRINT("strlen(KeyName) %d\n", strlen(KeyName));
+      DPRINT1("RtlpCreateUnicodeString() failed (Status %lx)\n", Status);
       if (NewKey->SubKeys != NULL)
-       ExFreePool(NewKey->SubKeys);
-      ZwClose(NewKey);
-      CmiRemoveRegistryHive(RegistryHive);
-      return(STATUS_INSUFFICIENT_RESOURCES);
+       {
+         ExFreePool (NewKey->SubKeys);
+       }
+      ObDereferenceObject (NewKey);
+      ObDereferenceObject (ParentKey);
+      return STATUS_INSUFFICIENT_RESOURCES;
     }
 
-  NewKey->NameSize = strlen(KeyName);
-  memcpy(NewKey->Name, KeyName, strlen(KeyName));
-  CmiAddKeyToList(Parent, NewKey);
+  CmiAddKeyToList (ParentKey, NewKey);
+  ObDereferenceObject (ParentKey);
 
   VERIFY_KEY_OBJECT(NewKey);
 
-  return(STATUS_SUCCESS);
+  /* Note: Do not dereference NewKey here! */
+
+  return STATUS_SUCCESS;
 }
 
 
 NTSTATUS
-CmiInitializeHive(PWSTR FileName,
-  PWSTR FullName,
-  PCHAR KeyName,
-  PKEY_OBJECT Parent,
-  BOOLEAN CreateNew)
+CmiDisconnectHive (IN POBJECT_ATTRIBUTES KeyObjectAttributes,
+                  OUT PREGISTRY_HIVE *RegistryHive)
 {
+  PKEY_OBJECT KeyObject;
+  PREGISTRY_HIVE Hive;
+  HANDLE KeyHandle;
   NTSTATUS Status;
+  PLIST_ENTRY CurrentEntry;
+  PKEY_OBJECT CurrentKey;
 
-  DPRINT("CmiInitializeHive(%s) called\n", KeyName);
+  DPRINT("CmiDisconnectHive() called\n");
 
-  /* Try to connect the hive */
-  //Status = CmiConnectHive(FileName, FullName, KeyName, Parent, FALSE);
-  Status = CmiConnectHive(FileName, FullName, KeyName, Parent, CreateNew);
+  *RegistryHive = NULL;
 
+  Status = ObOpenObjectByName (KeyObjectAttributes,
+                              CmiKeyType,
+                              NULL,
+                              KernelMode,
+                              STANDARD_RIGHTS_REQUIRED,
+                              NULL,
+                              &KeyHandle);
   if (!NT_SUCCESS(Status))
     {
-#if 0
-#ifdef WIN32_REGDBG
-      WCHAR AltFileName[MAX_PATH];
+      DPRINT1 ("ObOpenObjectByName() failed (Status %lx)\n", Status);
+      return Status;
+    }
 
-      CPRINT("WARNING! Registry file %S not found\n", FileName);
-      //DPRINT("Status %.08x\n", Status);
+  Status = ObReferenceObjectByHandle (KeyHandle,
+                                     STANDARD_RIGHTS_REQUIRED,
+                                     CmiKeyType,
+                                     KernelMode,
+                                     (PVOID*)&KeyObject,
+                                     NULL);
+  ZwClose (KeyHandle);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1 ("ObReferenceObjectByName() failed (Status %lx)\n", Status);
+      return Status;
+    }
+  DPRINT ("KeyObject %p  Hive %p\n", KeyObject, KeyObject->RegistryHive);
 
-      wcscpy(AltFileName, FileName);
-      wcscat(AltFileName, L".alt");
+  if (!(KeyObject->KeyCell->Flags & REG_KEY_ROOT_CELL))
+    {
+      DPRINT1 ("Key is not the Hive-Root-Key\n");
+      ObDereferenceObject (KeyObject);
+      return STATUS_INVALID_PARAMETER;
+    }
 
-      DPRINT("Attempting to connect the alternative hive %S\n", AltFileName);
-      /* Try to connect the alternative hive */
-      Status = CmiConnectHive(AltFileName, FullName, KeyName, Parent, TRUE);
+  /* Acquire registry lock exclusively */
+  KeEnterCriticalRegion();
+  ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
 
-      if (!NT_SUCCESS(Status)) {
-             CPRINT("WARNING! Alternative registry file %S not found\n", AltFileName);
-           //DPRINT("Status %.08x\n", Status);
-         }
-#endif
-#endif
+  CurrentEntry = CmiKeyObjectListHead.Flink;
+  while (CurrentEntry != &CmiKeyObjectListHead)
+  {
+     CurrentKey = CONTAINING_RECORD(CurrentEntry, KEY_OBJECT, ListEntry);
+     if (1 == ObGetObjectPointerCount(CurrentKey) &&
+        !(CurrentKey->Flags & KO_MARKED_FOR_DELETE))
+     {
+        ObDereferenceObject(CurrentKey);
+        CurrentEntry = CmiKeyObjectListHead.Flink;
+     }
+     else
+     {
+        CurrentEntry = CurrentEntry->Flink;
+     }
+  }
+
+  if (ObGetObjectHandleCount (KeyObject) != 0 ||
+      ObGetObjectPointerCount (KeyObject) != 2)
+    {
+      DPRINT1 ("Hive is still in use (hc %d, rc %d)\n", ObGetObjectHandleCount (KeyObject), ObGetObjectPointerCount (KeyObject));
+      ObDereferenceObject (KeyObject);
+
+      /* Release registry lock */
+      ExReleaseResourceLite (&CmiRegistryLock);
+      KeLeaveCriticalRegion();
+
+      return STATUS_UNSUCCESSFUL;
     }
 
-  DPRINT("CmiInitializeHive() done\n");
+  Hive = KeyObject->RegistryHive;
+
+  /* Dereference KeyObject twice to delete it */
+  ObDereferenceObject (KeyObject);
+  ObDereferenceObject (KeyObject);
 
-  return(Status);
+  *RegistryHive = Hive;
+
+  /* Release registry lock */
+  ExReleaseResourceLite (&CmiRegistryLock);
+  KeLeaveCriticalRegion();
+
+  DPRINT ("CmiDisconnectHive() done\n");
+
+  return STATUS_SUCCESS;
+}
+
+
+static NTSTATUS
+CmiInitControlSetLink (VOID)
+{
+  OBJECT_ATTRIBUTES ObjectAttributes;
+  UNICODE_STRING ControlSetKeyName = RTL_CONSTANT_STRING(
+                                L"\\Registry\\Machine\\SYSTEM\\ControlSet001");
+  UNICODE_STRING ControlSetLinkName =  RTL_CONSTANT_STRING(
+                            L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
+  UNICODE_STRING ControlSetValueName = RTL_CONSTANT_STRING(L"SymbolicLinkValue");
+  HANDLE KeyHandle;
+  NTSTATUS Status;
+
+  /* Create 'ControlSet001' key */
+  InitializeObjectAttributes (&ObjectAttributes,
+                             &ControlSetKeyName,
+                             OBJ_CASE_INSENSITIVE,
+                             NULL,
+                             NULL);
+  Status = ZwCreateKey (&KeyHandle,
+                       KEY_ALL_ACCESS,
+                       &ObjectAttributes,
+                       0,
+                       NULL,
+                       REG_OPTION_NON_VOLATILE,
+                       NULL);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1 ("ZwCreateKey() failed (Status %lx)\n", Status);
+      return Status;
+    }
+  ZwClose (KeyHandle);
+
+  /* Link 'CurrentControlSet' to 'ControlSet001' key */
+  InitializeObjectAttributes (&ObjectAttributes,
+                             &ControlSetLinkName,
+                             OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_OPENLINK,
+                             NULL,
+                             NULL);
+  Status = ZwCreateKey (&KeyHandle,
+                       KEY_ALL_ACCESS | KEY_CREATE_LINK,
+                       &ObjectAttributes,
+                       0,
+                       NULL,
+                       REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
+                       NULL);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1 ("ZwCreateKey() failed (Status %lx)\n", Status);
+      return Status;
+    }
+
+  Status = ZwSetValueKey (KeyHandle,
+                         &ControlSetValueName,
+                         0,
+                         REG_LINK,
+                         (PVOID)ControlSetKeyName.Buffer,
+                         ControlSetKeyName.Length);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1 ("ZwSetValueKey() failed (Status %lx)\n", Status);
+    }
+  ZwClose (KeyHandle);
+
+  return STATUS_SUCCESS;
 }
 
 
 NTSTATUS
-CmiInitHives(BOOLEAN SetUpBoot)
+CmiInitHives(BOOLEAN SetupBoot)
 {
   PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
   OBJECT_ATTRIBUTES ObjectAttributes;
-  UNICODE_STRING KeyName;
-  UNICODE_STRING ValueName;
+  UNICODE_STRING FileName;
+  UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE");
+  UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"InstallPath");
   HANDLE KeyHandle;
 
   NTSTATUS Status;
@@ -790,59 +1024,54 @@ CmiInitHives(BOOLEAN SetUpBoot)
 
   DPRINT("CmiInitHives() called\n");
 
-  if (SetUpBoot == TRUE)
-  {
-    RtlInitUnicodeStringFromLiteral(&KeyName,
-                                   L"\\Registry\\Machine\\HARDWARE");
-    InitializeObjectAttributes(&ObjectAttributes,
-                              &KeyName,
-                              OBJ_CASE_INSENSITIVE,
-                              NULL,
-                              NULL);
-    Status =  NtOpenKey(&KeyHandle,
-                       KEY_ALL_ACCESS,
-                       &ObjectAttributes);
-    if (!NT_SUCCESS(Status))
+  if (SetupBoot == TRUE)
     {
-      DPRINT1("NtOpenKey() failed (Status %lx)\n", Status);
-      return(Status);
-    }
+      InitializeObjectAttributes(&ObjectAttributes,
+                                &KeyName,
+                                OBJ_CASE_INSENSITIVE,
+                                NULL,
+                                NULL);
+      Status =  ZwOpenKey(&KeyHandle,
+                         KEY_ALL_ACCESS,
+                         &ObjectAttributes);
+      if (!NT_SUCCESS(Status))
+       {
+         DPRINT1("ZwOpenKey() failed (Status %lx)\n", Status);
+         return(Status);
+       }
 
-    RtlInitUnicodeStringFromLiteral(&ValueName,
-                                   L"InstallPath");
+      BufferSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 4096;
+      ValueInfo = ExAllocatePool(PagedPool,
+                                BufferSize);
+      if (ValueInfo == NULL)
+       {
+         ZwClose(KeyHandle);
+         return(STATUS_INSUFFICIENT_RESOURCES);
+       }
 
-    BufferSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 4096;
-    ValueInfo = ExAllocatePool(PagedPool,
-                              BufferSize);
-    if (ValueInfo == NULL)
-    {
-      NtClose(KeyHandle);
-      return(STATUS_INSUFFICIENT_RESOURCES);
-    }
+      Status = ZwQueryValueKey(KeyHandle,
+                              &ValueName,
+                              KeyValuePartialInformation,
+                              ValueInfo,
+                              BufferSize,
+                              &ResultSize);
+      ZwClose(KeyHandle);
+      if (!NT_SUCCESS(Status))
+       {
+         ExFreePool(ValueInfo);
+         return(Status);
+       }
 
-    Status = NtQueryValueKey(KeyHandle,
-                            &ValueName,
-                            KeyValuePartialInformation,
-                            ValueInfo,
-                            BufferSize,
-                            &ResultSize);
-    NtClose(KeyHandle);
-    if (ValueInfo == NULL)
-    {
+      RtlCopyMemory(ConfigPath,
+                   ValueInfo->Data,
+                   ValueInfo->DataLength);
+      ConfigPath[ValueInfo->DataLength / sizeof(WCHAR)] = (WCHAR)0;
       ExFreePool(ValueInfo);
-      return(Status);
     }
-
-    RtlCopyMemory(ConfigPath,
-                 ValueInfo->Data,
-                 ValueInfo->DataLength);
-    ConfigPath[ValueInfo->DataLength / sizeof(WCHAR)] = (WCHAR)0;
-    ExFreePool(ValueInfo);
-  }
   else
-  {
-    wcscpy(ConfigPath, L"\\SystemRoot");
-  }
+    {
+      wcscpy(ConfigPath, L"\\SystemRoot");
+    }
   wcscat(ConfigPath, L"\\system32\\config");
 
   DPRINT("ConfigPath: %S\n", ConfigPath);
@@ -853,76 +1082,127 @@ CmiInitHives(BOOLEAN SetUpBoot)
 
   /* FIXME: Save boot log */
 
-  /* FIXME: Rename \Registry\Machine\System */
+  /* Connect the SYSTEM hive only if it has been created */
+  if (SetupBoot == TRUE)
+    {
+      wcscpy(EndPtr, REG_SYSTEM_FILE_NAME);
+      DPRINT ("ConfigPath: %S\n", ConfigPath);
 
-  /* Connect the SYSTEM hive */
-//  Status = CmiInitializeHive(SYSTEM_REG_FILE, REG_SYSTEM_KEY_NAME, "System", CmiMachineKey, SetUpBoot);
-//  assert(NT_SUCCESS(Status));
+      RtlInitUnicodeString (&KeyName,
+                           REG_SYSTEM_KEY_NAME);
+      InitializeObjectAttributes(&ObjectAttributes,
+                                &KeyName,
+                                OBJ_CASE_INSENSITIVE,
+                                NULL,
+                                NULL);
 
-  /* FIXME: Synchronize old and new system hive (??) */
+      RtlInitUnicodeString (&FileName,
+                           ConfigPath);
+      Status = CmiLoadHive (&ObjectAttributes,
+                           &FileName,
+                           0);
+      if (!NT_SUCCESS(Status))
+       {
+         DPRINT1 ("CmiLoadHive() failed (Status %lx)\n", Status);
+         return Status;
+       }
 
-  /* FIXME: Delete old system hive */
+      Status = CmiInitControlSetLink ();
+      if (!NT_SUCCESS(Status))
+       {
+         DPRINT1("CmiInitControlSetLink() failed (Status %lx)\n", Status);
+         return(Status);
+       }
+    }
 
   /* Connect the SOFTWARE hive */
   wcscpy(EndPtr, REG_SOFTWARE_FILE_NAME);
-  DPRINT1("ConfigPath: %S\n", ConfigPath);
+  RtlInitUnicodeString (&FileName,
+                       ConfigPath);
+  DPRINT ("ConfigPath: %S\n", ConfigPath);
+
+  RtlInitUnicodeString (&KeyName,
+                       REG_SOFTWARE_KEY_NAME);
+  InitializeObjectAttributes(&ObjectAttributes,
+                            &KeyName,
+                            OBJ_CASE_INSENSITIVE,
+                            NULL,
+                            NULL);
 
-  Status = CmiInitializeHive(ConfigPath,
-                            REG_SOFTWARE_KEY_NAME,
-                            "Software",
-                            CmiMachineKey,
-                            SetUpBoot);
+  Status = CmiLoadHive (&ObjectAttributes,
+                       &FileName,
+                       0);
   if (!NT_SUCCESS(Status))
-  {
-    DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
-    return(Status);
-  }
+    {
+      DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
+      return(Status);
+    }
 
   /* Connect the SAM hive */
   wcscpy(EndPtr, REG_SAM_FILE_NAME);
-  DPRINT1("ConfigPath: %S\n", ConfigPath);
+  RtlInitUnicodeString (&FileName,
+                       ConfigPath);
+  DPRINT ("ConfigPath: %S\n", ConfigPath);
 
-  Status = CmiInitializeHive(ConfigPath,
-                            REG_SAM_KEY_NAME,
-                            "Sam",
-                            CmiMachineKey,
-                            SetUpBoot);
+  RtlInitUnicodeString (&KeyName,
+                       REG_SAM_KEY_NAME);
+  InitializeObjectAttributes(&ObjectAttributes,
+                            &KeyName,
+                            OBJ_CASE_INSENSITIVE,
+                            NULL,
+                            NULL);
+  Status = CmiLoadHive (&ObjectAttributes,
+                       &FileName,
+                       0);
   if (!NT_SUCCESS(Status))
-  {
-    DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
-    return(Status);
-  }
+    {
+      DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
+      return(Status);
+    }
 
   /* Connect the SECURITY hive */
   wcscpy(EndPtr, REG_SEC_FILE_NAME);
-  DPRINT1("ConfigPath: %S\n", ConfigPath);
-  Status = CmiInitializeHive(ConfigPath,
-                            REG_SEC_KEY_NAME,
-                            "Security",
-                            CmiMachineKey,
-                            SetUpBoot);
+  RtlInitUnicodeString (&FileName,
+                       ConfigPath);
+  DPRINT ("ConfigPath: %S\n", ConfigPath);
+
+  RtlInitUnicodeString (&KeyName,
+                       REG_SEC_KEY_NAME);
+  InitializeObjectAttributes(&ObjectAttributes,
+                            &KeyName,
+                            OBJ_CASE_INSENSITIVE,
+                            NULL,
+                            NULL);
+  Status = CmiLoadHive (&ObjectAttributes,
+                       &FileName,
+                       0);
   if (!NT_SUCCESS(Status))
-  {
-    DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
-    return(Status);
-  }
+    {
+      DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
+      return(Status);
+    }
 
   /* Connect the DEFAULT hive */
-  wcscpy(EndPtr, REG_USER_FILE_NAME);
-  DPRINT1("ConfigPath: %S\n", ConfigPath);
-
-  Status = CmiInitializeHive(ConfigPath,
-                            REG_USER_KEY_NAME,
-                            ".Default",
-                            CmiUserKey,
-                            SetUpBoot);
-  if (!NT_SUCCESS(Status))
-  {
-    DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
-    return(Status);
-  }
+  wcscpy(EndPtr, REG_DEFAULT_USER_FILE_NAME);
+  RtlInitUnicodeString (&FileName,
+                       ConfigPath);
+  DPRINT ("ConfigPath: %S\n", ConfigPath);
 
-  /* FIXME : initialize standards symbolic links */
+  RtlInitUnicodeString (&KeyName,
+                       REG_DEFAULT_USER_KEY_NAME);
+  InitializeObjectAttributes(&ObjectAttributes,
+                            &KeyName,
+                            OBJ_CASE_INSENSITIVE,
+                            NULL,
+                            NULL);
+  Status = CmiLoadHive (&ObjectAttributes,
+                       &FileName,
+                       0);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
+      return(Status);
+    }
 
 //  CmiCheckRegistry(TRUE);
 
@@ -945,43 +1225,41 @@ CmShutdownRegistry(VOID)
   PREGISTRY_HIVE Hive;
   PLIST_ENTRY Entry;
 
-  DPRINT1("CmShutdownRegistry() called\n");
+  DPRINT("CmShutdownRegistry() called\n");
 
   /* Stop automatic hive synchronization */
   CmiHiveSyncEnabled = FALSE;
 
+  /* Cancel pending hive synchronization */
+  if (CmiHiveSyncPending == TRUE)
+    {
+      KeCancelTimer(&CmiHiveSyncTimer);
+      CmiHiveSyncPending = FALSE;
+    }
+
   /* Acquire hive list lock exclusively */
-  ExAcquireResourceExclusiveLite(&CmiHiveListLock, TRUE);
+  KeEnterCriticalRegion();
+  ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
 
   Entry = CmiHiveListHead.Flink;
   while (Entry != &CmiHiveListHead)
     {
       Hive = CONTAINING_RECORD(Entry, REGISTRY_HIVE, HiveList);
 
-      if (IsPermanentHive(Hive))
+      if (!(IsNoFileHive(Hive) || IsNoSynchHive(Hive)))
        {
-         /* Acquire hive resource exclusively */
-         ExAcquireResourceExclusiveLite(&Hive->HiveResource,
-                                        TRUE);
-
          /* Flush non-volatile hive */
          CmiFlushRegistryHive(Hive);
-
-         /* Dereference file */
-         ObDereferenceObject(Hive->FileObject);
-         Hive->FileObject = NULL;
-
-         /* Release hive resource */
-         ExReleaseResourceLite(&Hive->HiveResource);
        }
 
       Entry = Entry->Flink;
     }
 
   /* Release hive list lock */
-  ExReleaseResourceLite(&CmiHiveListLock);
+  ExReleaseResourceLite(&CmiRegistryLock);
+  KeLeaveCriticalRegion();
 
-  DPRINT1("CmShutdownRegistry() done\n");
+  DPRINT("CmShutdownRegistry() done\n");
 }
 
 
@@ -991,39 +1269,36 @@ CmiHiveSyncRoutine(PVOID DeferredContext)
   PREGISTRY_HIVE Hive;
   PLIST_ENTRY Entry;
 
-  DPRINT1("CmiHiveSyncRoutine() called\n");
+  DPRINT("CmiHiveSyncRoutine() called\n");
 
   CmiHiveSyncPending = FALSE;
 
   /* Acquire hive list lock exclusively */
-  ExAcquireResourceExclusiveLite(&CmiHiveListLock, TRUE);
+  KeEnterCriticalRegion();
+  ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
 
   Entry = CmiHiveListHead.Flink;
   while (Entry != &CmiHiveListHead)
     {
       Hive = CONTAINING_RECORD(Entry, REGISTRY_HIVE, HiveList);
 
-      if (IsPermanentHive(Hive))
+      if (!(IsNoFileHive(Hive) || IsNoSynchHive(Hive)))
        {
-         /* Acquire hive resource exclusively */
-         ExAcquireResourceExclusiveLite(&Hive->HiveResource,
-                                        TRUE);
-
          /* Flush non-volatile hive */
          CmiFlushRegistryHive(Hive);
-
-         /* Release hive resource */
-         ExReleaseResourceLite(&Hive->HiveResource);
        }
 
       Entry = Entry->Flink;
     }
 
   /* Release hive list lock */
-  ExReleaseResourceLite(&CmiHiveListLock);
+  ExReleaseResourceLite(&CmiRegistryLock);
+  KeLeaveCriticalRegion();
 
-  DPRINT("DeferredContext %x\n", DeferredContext);
+  DPRINT("DeferredContext 0x%p\n", DeferredContext);
   ExFreePool(DeferredContext);
+
+  DPRINT("CmiHiveSyncRoutine() done\n");
 }
 
 
@@ -1047,7 +1322,7 @@ CmiHiveSyncDpcRoutine(PKDPC Dpc,
                       CmiHiveSyncRoutine,
                       WorkQueueItem);
 
-  DPRINT("DeferredContext %x\n", WorkQueueItem);
+  DPRINT("DeferredContext 0x%p\n", WorkQueueItem);
   ExQueueWorkItem(WorkQueueItem,
                  CriticalWorkQueue);
 }
@@ -1066,8 +1341,7 @@ CmiSyncHives(VOID)
 
   CmiHiveSyncPending = TRUE;
 
-
-  Timeout.QuadPart = -50000000LL;
+  Timeout.QuadPart = (LONGLONG)-50000000;
   KeSetTimer(&CmiHiveSyncTimer,
             Timeout,
             &CmiHiveSyncDpc);