forget update de.rc
[reactos.git] / reactos / ntoskrnl / cm / registry.c
index 7c4411e..c2cc4a2 100644 (file)
@@ -1,37 +1,40 @@
-/* $Id: registry.c,v 1.113 2003/10/16 14:48:22 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
  */
 
-#define NTOS_MODE_KERNEL
-#include <ntos.h>
-#include <limits.h>
-#include <string.h>
-#include <roscfg.h>
-#include <internal/ob.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
+
+
 /* 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;
@@ -56,6 +59,9 @@ CmiHiveSyncDpcRoutine(PKDPC Dpc,
                      PVOID SystemArgument1,
                      PVOID SystemArgument2);
 
+extern LIST_ENTRY CmiCallbackHead;
+extern FAST_MUTEX CmiCallbackLock;
+
 /* FUNCTIONS ****************************************************************/
 
 VOID
@@ -79,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,
@@ -117,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));
 }
 
 
@@ -151,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,
@@ -181,7 +187,7 @@ CmiCheckValues(BOOLEAN Verbose,
       Index++;
     }
 
-  assert(NT_SUCCESS(Status));
+  ASSERT(NT_SUCCESS(Status));
 }
 
 
@@ -215,7 +221,7 @@ CmiCheckByName(BOOLEAN Verbose,
                NULL,
                NULL);
 
-  Status = NtOpenKey(&Key,
+  Status = ZwOpenKey(&Key,
                KEY_ALL_ACCESS,
                &ObjectAttributes);
 
@@ -225,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);
 }
 
 
@@ -245,48 +251,165 @@ 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);
 
-VOID INIT_FUNCTION
+    }
+    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 KeyName;
   PKEY_OBJECT RootKey;
+#if 0
+  PSECURITY_CELL RootSecurityCell;
+#endif
   HANDLE RootKeyHandle;
   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 = CmiObjectSecurity;
-  CmiKeyType->QueryName = CmiObjectQueryName;
-  CmiKeyType->OkayToClose = NULL;
-  CmiKeyType->Create = CmiObjectCreate;
-  CmiKeyType->DuplicationNotify = NULL;
-  RtlInitUnicodeString(&CmiKeyType->TypeName, L"Key");
-
-  ObpCreateTypeObject (CmiKeyType);
+  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 = CmiCreateVolatileHive (&CmiVolatileHive);
-  assert(NT_SUCCESS(Status));
+  ASSERT(NT_SUCCESS(Status));
+
+  InitializeListHead(&CmiCallbackHead);
+  ExInitializeFastMutex(&CmiCallbackLock);
 
   /* Create '\Registry' key. */
   RtlInitUnicodeString(&KeyName, REG_ROOT_KEY_NAME);
@@ -300,14 +423,14 @@ CmInitializeRegistry(VOID)
                          0,
                          0,
                          (PVOID *) &RootKey);
-  assert(NT_SUCCESS(Status));
+  ASSERT(NT_SUCCESS(Status));
   Status = ObInsertObject(RootKey,
                          NULL,
-                         STANDARD_RIGHTS_REQUIRED,
+                         KEY_ALL_ACCESS,
                          0,
                          NULL,
                          &RootKeyHandle);
-  assert(NT_SUCCESS(Status));
+  ASSERT(NT_SUCCESS(Status));
   RootKey->RegistryHive = CmiVolatileHive;
   RootKey->KeyCellOffset = CmiVolatileHive->HiveHeader->RootKeyOffset;
   RootKey->KeyCell = CmiGetCell (CmiVolatileHive, RootKey->KeyCellOffset, NULL);
@@ -316,10 +439,22 @@ CmInitializeRegistry(VOID)
   RootKey->NumberOfSubKeys = 0;
   RootKey->SubKeys = NULL;
   RootKey->SizeOfSubKeys = 0;
-  Status = RtlCreateUnicodeString(&RootKey->Name, L"Registry");
-  assert(NT_SUCCESS(Status));
+  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
 
-  KeInitializeSpinLock(&CmiKeyListLock);
 
   /* Create '\Registry\Machine' key. */
   RtlInitUnicodeString(&KeyName,
@@ -329,14 +464,14 @@ CmInitializeRegistry(VOID)
                             0,
                             RootKeyHandle,
                             NULL);
-  Status = NtCreateKey(&KeyHandle,
-                      STANDARD_RIGHTS_REQUIRED,
+  Status = ZwCreateKey(&KeyHandle,
+                      KEY_ALL_ACCESS,
                       &ObjectAttributes,
                       0,
                       NULL,
                       REG_OPTION_VOLATILE,
                       NULL);
-  assert(NT_SUCCESS(Status));
+  ASSERT(NT_SUCCESS(Status));
 
   /* Create '\Registry\User' key. */
   RtlInitUnicodeString(&KeyName,
@@ -346,67 +481,124 @@ CmInitializeRegistry(VOID)
                             0,
                             RootKeyHandle,
                             NULL);
-  Status = NtCreateKey(&KeyHandle,
-                      STANDARD_RIGHTS_REQUIRED,
+  Status = ZwCreateKey(&KeyHandle,
+                      KEY_ALL_ACCESS,
                       &ObjectAttributes,
                       0,
                       NULL,
                       REG_OPTION_VOLATILE,
                       NULL);
-  assert(NT_SUCCESS(Status));
+  ASSERT(NT_SUCCESS(Status));
 }
 
 
 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();
   if (!NT_SUCCESS(Status))
+    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);
+  }
+
+  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)
     {
-      KEBUGCHECK(CONFIG_INITIALIZATION_FAILED);
+      /* 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++);
     }
-
-  /* Set PICE 'Start' value to 1, if PICE debugging is enabled */
-  PiceStart = 4;
-  p1 = (PCHAR)CommandLine;
-  while (p1 && (p2 = strchr(p1, '/')))
+  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)
     {
-      p2++;
-      if (_strnicmp(p2, "DEBUGPORT", 9) == 0)
-       {
-         p2 += 9;
-         if (*p2 == '=')
-           {
-             p2++;
-             if (_strnicmp(p2, "PICE", 4) == 0)
-               {
-                 p2 += 4;
-                 PiceStart = 1;
-               }
-           }
-       }
-      p1 = p2;
+      Status = RtlCreateRegistryKey(RTL_REGISTRY_CONTROL, L"MiniNT");
+      if (!NT_SUCCESS(Status))
+        KEBUGCHECK(CONFIG_INITIALIZATION_FAILED);
     }
 
-  Status = RtlWriteRegistryValue(RTL_REGISTRY_SERVICES,
-                                L"\\Pice",
-                                L"Start",
-                                REG_DWORD,
-                                &PiceStart,
-                                sizeof(ULONG));
+  /* 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);
-    }
+    KEBUGCHECK(CONFIG_INITIALIZATION_FAILED);
+
+  ExFreePool(SystemBootDevice);
 }
 
 
@@ -416,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;
@@ -465,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,
@@ -481,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,
@@ -495,10 +684,10 @@ 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;
 }
@@ -513,17 +702,35 @@ CmiConnectHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
   PKEY_OBJECT NewKey;
   NTSTATUS Status;
   PWSTR SubName;
+  UNICODE_STRING ObjectName;
+  OBJECT_CREATE_INFORMATION ObjectCreateInfo;
 
   DPRINT("CmiConnectHive(%p, %p) called.\n",
         KeyObjectAttributes, RegistryHive);
-
-  Status = ObFindObject(KeyObjectAttributes,
-                       (PVOID*)&ParentKey,
-                       &RemainingPath,
-                       CmiKeyType);
+     
+   /* 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);
+      return Status;
     }
 
   DPRINT ("RemainingPath %wZ\n", &RemainingPath);
@@ -531,18 +738,21 @@ CmiConnectHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
   if ((RemainingPath.Buffer == NULL) || (RemainingPath.Buffer[0] == 0))
     {
       ObDereferenceObject (ParentKey);
+      RtlFreeUnicodeString(&RemainingPath);
       return STATUS_OBJECT_NAME_COLLISION;
     }
 
-  /* If RemainingPath contains \ we must return error
-     because CmiConnectHive() can not create trees */
+  /* Ignore leading backslash */
   SubName = RemainingPath.Buffer;
   if (*SubName == L'\\')
     SubName++;
 
+  /* 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;
     }
 
@@ -558,34 +768,54 @@ CmiConnectHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
                          0,
                          0,
                          (PVOID*)&NewKey);
+                            
   if (!NT_SUCCESS(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->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(ULONG));
-
-  if ((NewKey->SubKeys == NULL) && (NewKey->KeyCell->NumberOfSubKeys != 0))
+  InsertTailList(&CmiKeyObjectListHead, &NewKey->ListEntry);
+  if (NewKey->KeyCell->NumberOfSubKeys != 0)
     {
-      DPRINT("NumberOfSubKeys %d\n", NewKey->KeyCell->NumberOfSubKeys);
-      ObDereferenceObject (NewKey);
-      ObDereferenceObject (ParentKey);
-      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;
     }
 
-  Status = RtlCreateUnicodeString(&NewKey->Name,
-                                 SubName);
+  DPRINT ("SubName %S\n", SubName);
+
+  Status = RtlpCreateUnicodeString(&NewKey->Name,
+              SubName, NonPagedPool);
+  RtlFreeUnicodeString(&RemainingPath);
   if (!NT_SUCCESS(Status))
     {
-      DPRINT1("RtlCreateUnicodeString() failed (Status %lx)\n", Status);
+      DPRINT1("RtlpCreateUnicodeString() failed (Status %lx)\n", Status);
       if (NewKey->SubKeys != NULL)
        {
          ExFreePool (NewKey->SubKeys);
@@ -614,6 +844,8 @@ CmiDisconnectHive (IN POBJECT_ATTRIBUTES KeyObjectAttributes,
   PREGISTRY_HIVE Hive;
   HANDLE KeyHandle;
   NTSTATUS Status;
+  PLIST_ENTRY CurrentEntry;
+  PKEY_OBJECT CurrentKey;
 
   DPRINT("CmiDisconnectHive() called\n");
 
@@ -638,7 +870,7 @@ CmiDisconnectHive (IN POBJECT_ATTRIBUTES KeyObjectAttributes,
                                      KernelMode,
                                      (PVOID*)&KeyObject,
                                      NULL);
-  NtClose (KeyHandle);
+  ZwClose (KeyHandle);
   if (!NT_SUCCESS(Status))
     {
       DPRINT1 ("ObReferenceObjectByName() failed (Status %lx)\n", Status);
@@ -653,16 +885,40 @@ CmiDisconnectHive (IN POBJECT_ATTRIBUTES KeyObjectAttributes,
       return STATUS_INVALID_PARAMETER;
     }
 
+  /* Acquire registry lock exclusively */
+  KeEnterCriticalRegion();
+  ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
+
+  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\n");
+      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;
     }
 
   Hive = KeyObject->RegistryHive;
-  CmiRemoveKeyFromList (KeyObject);
 
   /* Dereference KeyObject twice to delete it */
   ObDereferenceObject (KeyObject);
@@ -670,6 +926,10 @@ CmiDisconnectHive (IN POBJECT_ATTRIBUTES KeyObjectAttributes,
 
   *RegistryHive = Hive;
 
+  /* Release registry lock */
+  ExReleaseResourceLite (&CmiRegistryLock);
+  KeLeaveCriticalRegion();
+
   DPRINT ("CmiDisconnectHive() done\n");
 
   return STATUS_SUCCESS;
@@ -680,21 +940,21 @@ static NTSTATUS
 CmiInitControlSetLink (VOID)
 {
   OBJECT_ATTRIBUTES ObjectAttributes;
-  UNICODE_STRING ControlSetKeyName;
-  UNICODE_STRING ControlSetLinkName;
-  UNICODE_STRING ControlSetValueName;
+  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 */
-  RtlInitUnicodeStringFromLiteral (&ControlSetKeyName,
-                                  L"\\Registry\\Machine\\SYSTEM\\ControlSet001");
   InitializeObjectAttributes (&ObjectAttributes,
                              &ControlSetKeyName,
                              OBJ_CASE_INSENSITIVE,
                              NULL,
                              NULL);
-  Status = NtCreateKey (&KeyHandle,
+  Status = ZwCreateKey (&KeyHandle,
                        KEY_ALL_ACCESS,
                        &ObjectAttributes,
                        0,
@@ -703,20 +963,18 @@ CmiInitControlSetLink (VOID)
                        NULL);
   if (!NT_SUCCESS(Status))
     {
-      DPRINT1 ("NtCreateKey() failed (Status %lx)\n", Status);
+      DPRINT1 ("ZwCreateKey() failed (Status %lx)\n", Status);
       return Status;
     }
-  NtClose (KeyHandle);
+  ZwClose (KeyHandle);
 
   /* Link 'CurrentControlSet' to 'ControlSet001' key */
-  RtlInitUnicodeStringFromLiteral (&ControlSetLinkName,
-                                  L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet");
   InitializeObjectAttributes (&ObjectAttributes,
                              &ControlSetLinkName,
                              OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_OPENLINK,
                              NULL,
                              NULL);
-  Status = NtCreateKey (&KeyHandle,
+  Status = ZwCreateKey (&KeyHandle,
                        KEY_ALL_ACCESS | KEY_CREATE_LINK,
                        &ObjectAttributes,
                        0,
@@ -725,13 +983,11 @@ CmiInitControlSetLink (VOID)
                        NULL);
   if (!NT_SUCCESS(Status))
     {
-      DPRINT1 ("NtCreateKey() failed (Status %lx)\n", Status);
+      DPRINT1 ("ZwCreateKey() failed (Status %lx)\n", Status);
       return Status;
     }
 
-  RtlInitUnicodeStringFromLiteral (&ControlSetValueName,
-                                  L"SymbolicLinkValue");
-  Status = NtSetValueKey (KeyHandle,
+  Status = ZwSetValueKey (KeyHandle,
                          &ControlSetValueName,
                          0,
                          REG_LINK,
@@ -739,9 +995,9 @@ CmiInitControlSetLink (VOID)
                          ControlSetKeyName.Length);
   if (!NT_SUCCESS(Status))
     {
-      DPRINT1 ("NtSetValueKey() failed (Status %lx)\n", Status);
+      DPRINT1 ("ZwSetValueKey() failed (Status %lx)\n", Status);
     }
-  NtClose (KeyHandle);
+  ZwClose (KeyHandle);
 
   return STATUS_SUCCESS;
 }
@@ -753,8 +1009,8 @@ CmiInitHives(BOOLEAN SetupBoot)
   PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
   OBJECT_ATTRIBUTES ObjectAttributes;
   UNICODE_STRING FileName;
-  UNICODE_STRING KeyName;
-  UNICODE_STRING ValueName;
+  UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE");
+  UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"InstallPath");
   HANDLE KeyHandle;
 
   NTSTATUS Status;
@@ -770,41 +1026,36 @@ CmiInitHives(BOOLEAN SetupBoot)
 
   if (SetupBoot == TRUE)
     {
-      RtlInitUnicodeStringFromLiteral(&KeyName,
-                                     L"\\Registry\\Machine\\HARDWARE");
       InitializeObjectAttributes(&ObjectAttributes,
                                 &KeyName,
                                 OBJ_CASE_INSENSITIVE,
                                 NULL,
                                 NULL);
-      Status =  NtOpenKey(&KeyHandle,
+      Status =  ZwOpenKey(&KeyHandle,
                          KEY_ALL_ACCESS,
                          &ObjectAttributes);
       if (!NT_SUCCESS(Status))
        {
-         DPRINT1("NtOpenKey() failed (Status %lx)\n", 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)
        {
-         NtClose(KeyHandle);
+         ZwClose(KeyHandle);
          return(STATUS_INSUFFICIENT_RESOURCES);
        }
 
-      Status = NtQueryValueKey(KeyHandle,
+      Status = ZwQueryValueKey(KeyHandle,
                               &ValueName,
                               KeyValuePartialInformation,
                               ValueInfo,
                               BufferSize,
                               &ResultSize);
-      NtClose(KeyHandle);
+      ZwClose(KeyHandle);
       if (!NT_SUCCESS(Status))
        {
          ExFreePool(ValueInfo);
@@ -974,7 +1225,7 @@ CmShutdownRegistry(VOID)
   PREGISTRY_HIVE Hive;
   PLIST_ENTRY Entry;
 
-  DPRINT1("CmShutdownRegistry() called\n");
+  DPRINT("CmShutdownRegistry() called\n");
 
   /* Stop automatic hive synchronization */
   CmiHiveSyncEnabled = FALSE;
@@ -987,7 +1238,8 @@ CmShutdownRegistry(VOID)
     }
 
   /* Acquire hive list lock exclusively */
-  ExAcquireResourceExclusiveLite(&CmiHiveListLock, TRUE);
+  KeEnterCriticalRegion();
+  ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
 
   Entry = CmiHiveListHead.Flink;
   while (Entry != &CmiHiveListHead)
@@ -996,24 +1248,18 @@ CmShutdownRegistry(VOID)
 
       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();
 
-  DPRINT1("CmShutdownRegistry() done\n");
+  DPRINT("CmShutdownRegistry() done\n");
 }
 
 
@@ -1028,7 +1274,8 @@ CmiHiveSyncRoutine(PVOID DeferredContext)
   CmiHiveSyncPending = FALSE;
 
   /* Acquire hive list lock exclusively */
-  ExAcquireResourceExclusiveLite(&CmiHiveListLock, TRUE);
+  KeEnterCriticalRegion();
+  ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
 
   Entry = CmiHiveListHead.Flink;
   while (Entry != &CmiHiveListHead)
@@ -1037,24 +1284,18 @@ CmiHiveSyncRoutine(PVOID DeferredContext)
 
       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");
@@ -1081,7 +1322,7 @@ CmiHiveSyncDpcRoutine(PKDPC Dpc,
                       CmiHiveSyncRoutine,
                       WorkQueueItem);
 
-  DPRINT("DeferredContext %x\n", WorkQueueItem);
+  DPRINT("DeferredContext 0x%p\n", WorkQueueItem);
   ExQueueWorkItem(WorkQueueItem,
                  CriticalWorkQueue);
 }
@@ -1100,8 +1341,7 @@ CmiSyncHives(VOID)
 
   CmiHiveSyncPending = TRUE;
 
-
-  Timeout.QuadPart = -50000000LL;
+  Timeout.QuadPart = (LONGLONG)-50000000;
   KeSetTimer(&CmiHiveSyncTimer,
             Timeout,
             &CmiHiveSyncDpc);