update for HEAD-2003091401
[reactos.git] / ntoskrnl / cm / ntfunc.c
index 91a3f95..503c944 100644 (file)
@@ -8,12 +8,13 @@
 
 /* INCLUDES *****************************************************************/
 
-#include <ddk/ntddk.h>
+#define NTOS_MODE_KERNEL
+#include <ntos.h>
 #include <roscfg.h>
 #include <internal/ob.h>
 #include <limits.h>
 #include <string.h>
-#include <internal/pool.h>
+#include <internal/se.h>
 #include <internal/registry.h>
 
 #define NDEBUG
@@ -46,14 +47,13 @@ NtCreateKey(OUT PHANDLE KeyHandle,
   NTSTATUS Status;
   PVOID Object;
   PWSTR End;
+  PWSTR Start;
 
   DPRINT("NtCreateKey (Name %wZ  KeyHandle %x  Root %x)\n",
         ObjectAttributes->ObjectName,
         KeyHandle,
         ObjectAttributes->RootDirectory);
 
-  /* FIXME: check for standard handle prefix and adjust objectAttributes accordingly */
-
   Status = ObFindObject(ObjectAttributes,
                        &Object,
                        &RemainingPath,
@@ -90,11 +90,11 @@ NtCreateKey(OUT PHANDLE KeyHandle,
 
   /* If RemainingPath contains \ we must return error
      because NtCreateKey don't create trees */
-  if (RemainingPath.Buffer[0] == '\\')
-    End = wcschr(RemainingPath.Buffer + 1, '\\');
-  else
-    End = wcschr(RemainingPath.Buffer, '\\');
+  Start = RemainingPath.Buffer;
+  if (*Start == L'\\')
+    Start++;
 
+  End = wcschr(Start, L'\\');
   if (End != NULL)
     {
       ObDereferenceObject(Object);
@@ -103,7 +103,7 @@ NtCreateKey(OUT PHANDLE KeyHandle,
 
   DPRINT("RemainingPath %S  ParentObject %x\n", RemainingPath.Buffer, Object);
 
-  Status = ObCreateObject(KeyHandle,
+  Status = ObRosCreateObject(KeyHandle,
                          DesiredAccess,
                          NULL,
                          CmiKeyType,
@@ -132,8 +132,7 @@ NtCreateKey(OUT PHANDLE KeyHandle,
   Status = CmiAddSubKey(KeyObject->RegistryHive,
                        KeyObject->ParentKey,
                        KeyObject,
-                       RemainingPath.Buffer,
-                       RemainingPath.Length,
+                       &RemainingPath,
                        TitleIndex,
                        Class,
                        CreateOptions);
@@ -147,8 +146,8 @@ NtCreateKey(OUT PHANDLE KeyHandle,
       return STATUS_UNSUCCESSFUL;
     }
 
-  KeyObject->Name = KeyObject->KeyCell->Name;
-  KeyObject->NameSize = KeyObject->KeyCell->NameSize;
+  RtlCreateUnicodeString(&KeyObject->Name,
+                        Start);
 
   if (KeyObject->RegistryHive == KeyObject->ParentKey->RegistryHive)
     {
@@ -247,16 +246,13 @@ NtDeleteKey(IN HANDLE KeyHandle)
 
 
 NTSTATUS STDCALL
-NtEnumerateKey(
-       IN      HANDLE                  KeyHandle,
-       IN      ULONG                     Index,
-       IN      KEY_INFORMATION_CLASS   KeyInformationClass,
-       OUT     PVOID                     KeyInformation,
-       IN      ULONG                     Length,
-       OUT     PULONG                  ResultLength
-       )
+NtEnumerateKey(IN HANDLE KeyHandle,
+              IN ULONG Index,
+              IN KEY_INFORMATION_CLASS KeyInformationClass,
+              OUT PVOID KeyInformation,
+              IN ULONG Length,
+              OUT PULONG ResultLength)
 {
-  NTSTATUS  Status;
   PKEY_OBJECT  KeyObject;
   PREGISTRY_HIVE  RegistryHive;
   PKEY_CELL  KeyCell, SubKeyCell;
@@ -264,7 +260,9 @@ NtEnumerateKey(
   PKEY_BASIC_INFORMATION  BasicInformation;
   PKEY_NODE_INFORMATION  NodeInformation;
   PKEY_FULL_INFORMATION  FullInformation;
-  PDATA_CELL pClassData;
+  PDATA_CELL ClassData;
+  ULONG NameSize;
+  NTSTATUS Status;
 
   DPRINT("KH %x  I %d  KIC %x KI %x  L %d  RL %x\n",
         KeyHandle,
@@ -317,7 +315,7 @@ NtEnumerateKey(
              CurKey = KeyObject->SubKeys[i];
              if (CurKey->RegistryHive == CmiVolatileHive)
                {
-                 if (Index-- == KeyObject->NumberOfSubKeys)
+                 if (Index-- == KeyCell->NumberOfSubKeys)
                    break;
                }
            }
@@ -335,9 +333,9 @@ NtEnumerateKey(
     {
       if (KeyCell->HashTableOffset == (BLOCK_OFFSET)-1)
        {
-         return(STATUS_NO_MORE_ENTRIES);
          ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
          ObDereferenceObject(KeyObject);
+         return(STATUS_NO_MORE_ENTRIES);
        }
 
       HashTableBlock = CmiGetBlock(RegistryHive, KeyCell->HashTableOffset, NULL);
@@ -364,104 +362,138 @@ NtEnumerateKey(
   Status = STATUS_SUCCESS;
   switch (KeyInformationClass)
     {
-    case KeyBasicInformation:
-      /* Check size of buffer */
-      *ResultLength = sizeof(KEY_BASIC_INFORMATION) + 
-        (SubKeyCell->NameSize ) * sizeof(WCHAR);
-      if (Length < *ResultLength)
-        {
-          Status = STATUS_BUFFER_OVERFLOW;
-        }
-      else
-        {
-          /* Fill buffer with requested info */
-          BasicInformation = (PKEY_BASIC_INFORMATION) KeyInformation;
-          BasicInformation->LastWriteTime.u.LowPart = SubKeyCell->LastWriteTime.dwLowDateTime;
-          BasicInformation->LastWriteTime.u.HighPart = SubKeyCell->LastWriteTime.dwHighDateTime;
-          BasicInformation->TitleIndex = Index;
-          BasicInformation->NameLength = SubKeyCell->NameSize * sizeof(WCHAR);
-          mbstowcs(BasicInformation->Name, 
-            SubKeyCell->Name, 
-            SubKeyCell->NameSize * 2);
-//          BasicInformation->Name[SubKeyCell->NameSize] = 0;
-        }
-      break;
-      
-    case KeyNodeInformation:
-      /* Check size of buffer */
-      *ResultLength = sizeof(KEY_NODE_INFORMATION) +
-        SubKeyCell->NameSize * sizeof(WCHAR) +
-        SubKeyCell->ClassSize;
-      if (Length < *ResultLength)
-        {
-          Status = STATUS_BUFFER_OVERFLOW;
-        }
-      else
-        {
-          /* Fill buffer with requested info */
-          NodeInformation = (PKEY_NODE_INFORMATION) KeyInformation;
-          NodeInformation->LastWriteTime.u.LowPart = SubKeyCell->LastWriteTime.dwLowDateTime;
-          NodeInformation->LastWriteTime.u.HighPart = SubKeyCell->LastWriteTime.dwHighDateTime;
-          NodeInformation->TitleIndex = Index;
-          NodeInformation->ClassOffset = sizeof(KEY_NODE_INFORMATION) + 
-            SubKeyCell->NameSize * sizeof(WCHAR);
-          NodeInformation->ClassLength = SubKeyCell->ClassSize;
-          NodeInformation->NameLength = SubKeyCell->NameSize * sizeof(WCHAR);
-          mbstowcs(NodeInformation->Name, 
-            SubKeyCell->Name,
-            SubKeyCell->NameSize * 2);
-//          NodeInformation->Name[SubKeyCell->NameSize] = 0;
-          if (SubKeyCell->ClassSize != 0)
-            {
-              pClassData=CmiGetBlock(KeyObject->RegistryHive,
-                SubKeyCell->ClassNameOffset,
-                NULL);
-              wcsncpy(NodeInformation->Name + SubKeyCell->NameSize ,
-                      (PWCHAR) pClassData->Data,
-                      SubKeyCell->ClassSize);
-            }
-        }
-      break;
-      
-    case KeyFullInformation:
-      /*  check size of buffer  */
-      *ResultLength = sizeof(KEY_FULL_INFORMATION) +
-          SubKeyCell->ClassSize;
-      if (Length < *ResultLength)
-        {
-          Status = STATUS_BUFFER_OVERFLOW;
-        }
-      else
-        {
-          /* fill buffer with requested info  */
-          FullInformation = (PKEY_FULL_INFORMATION) KeyInformation;
-          FullInformation->LastWriteTime.u.LowPart = SubKeyCell->LastWriteTime.dwLowDateTime;
-          FullInformation->LastWriteTime.u.HighPart = SubKeyCell->LastWriteTime.dwHighDateTime;
-          FullInformation->TitleIndex = Index;
-          FullInformation->ClassOffset = sizeof(KEY_FULL_INFORMATION) - 
-            sizeof(WCHAR);
-          FullInformation->ClassLength = SubKeyCell->ClassSize;
-          FullInformation->SubKeys = SubKeyCell->NumberOfSubKeys;
-          FullInformation->MaxNameLen = 
-            CmiGetMaxNameLength(RegistryHive, SubKeyCell);
-          FullInformation->MaxClassLen = 
-            CmiGetMaxClassLength(RegistryHive, SubKeyCell);
-          FullInformation->Values = SubKeyCell->NumberOfValues;
-          FullInformation->MaxValueNameLen = 
-            CmiGetMaxValueNameLength(RegistryHive, SubKeyCell);
-          FullInformation->MaxValueDataLen = 
-            CmiGetMaxValueDataLength(RegistryHive, SubKeyCell);
-          if (SubKeyCell->ClassSize != 0)
-            {
-              pClassData = CmiGetBlock(KeyObject->RegistryHive,
-                SubKeyCell->ClassNameOffset,
-                NULL);
-              wcsncpy(FullInformation->Class,
-                (PWCHAR) pClassData->Data,
-                SubKeyCell->ClassSize);
-            }
-        }
-      break;
+      case KeyBasicInformation:
+       /* Check size of buffer */
+       NameSize = SubKeyCell->NameSize;
+       if (SubKeyCell->Flags & REG_KEY_NAME_PACKED)
+         {
+           NameSize *= sizeof(WCHAR);
+         }
+       *ResultLength = sizeof(KEY_BASIC_INFORMATION) + NameSize;
+
+       if (Length < *ResultLength)
+         {
+           Status = STATUS_BUFFER_OVERFLOW;
+         }
+       else
+         {
+           /* Fill buffer with requested info */
+           BasicInformation = (PKEY_BASIC_INFORMATION) KeyInformation;
+           BasicInformation->LastWriteTime.u.LowPart = SubKeyCell->LastWriteTime.u.LowPart;
+           BasicInformation->LastWriteTime.u.HighPart = SubKeyCell->LastWriteTime.u.HighPart;
+           BasicInformation->TitleIndex = Index;
+           BasicInformation->NameLength = NameSize;
+
+           if (SubKeyCell->Flags & REG_KEY_NAME_PACKED)
+             {
+               CmiCopyPackedName(BasicInformation->Name,
+                                 SubKeyCell->Name,
+                                 SubKeyCell->NameSize);
+             }
+           else
+             {
+               RtlCopyMemory(BasicInformation->Name,
+                             SubKeyCell->Name,
+                             SubKeyCell->NameSize);
+             }
+         }
+       break;
+
+      case KeyNodeInformation:
+       /* Check size of buffer */
+       if (SubKeyCell->Flags & REG_KEY_NAME_PACKED)
+         {
+           NameSize = SubKeyCell->NameSize * sizeof(WCHAR);
+         }
+       else
+         {
+           NameSize = SubKeyCell->NameSize;
+         }
+       *ResultLength = sizeof(KEY_NODE_INFORMATION) +
+         NameSize + SubKeyCell->ClassSize;
+
+       if (Length < *ResultLength)
+         {
+           Status = STATUS_BUFFER_OVERFLOW;
+         }
+       else
+         {
+           /* Fill buffer with requested info */
+           NodeInformation = (PKEY_NODE_INFORMATION) KeyInformation;
+           NodeInformation->LastWriteTime.u.LowPart = SubKeyCell->LastWriteTime.u.LowPart;
+           NodeInformation->LastWriteTime.u.HighPart = SubKeyCell->LastWriteTime.u.HighPart;
+           NodeInformation->TitleIndex = Index;
+           NodeInformation->ClassOffset = sizeof(KEY_NODE_INFORMATION) + NameSize;
+           NodeInformation->ClassLength = SubKeyCell->ClassSize;
+           NodeInformation->NameLength = NameSize;
+
+           if (SubKeyCell->Flags & REG_KEY_NAME_PACKED)
+             {
+               CmiCopyPackedName(NodeInformation->Name,
+                                 SubKeyCell->Name,
+                                 SubKeyCell->NameSize);
+             }
+           else
+             {
+               RtlCopyMemory(NodeInformation->Name,
+                             SubKeyCell->Name,
+                             SubKeyCell->NameSize);
+             }
+
+           if (SubKeyCell->ClassSize != 0)
+             {
+               ClassData=CmiGetBlock(KeyObject->RegistryHive,
+                                     SubKeyCell->ClassNameOffset,
+                                     NULL);
+               wcsncpy(NodeInformation->Name + SubKeyCell->NameSize,
+                       (PWCHAR)ClassData->Data,
+                       SubKeyCell->ClassSize);
+             }
+         }
+       break;
+
+      case KeyFullInformation:
+       /* Check size of buffer */
+       *ResultLength = sizeof(KEY_FULL_INFORMATION) +
+         SubKeyCell->ClassSize;
+
+       if (Length < *ResultLength)
+         {
+           Status = STATUS_BUFFER_OVERFLOW;
+         }
+       else
+         {
+           /* Fill buffer with requested info */
+           FullInformation = (PKEY_FULL_INFORMATION) KeyInformation;
+           FullInformation->LastWriteTime.u.LowPart = SubKeyCell->LastWriteTime.u.LowPart;
+           FullInformation->LastWriteTime.u.HighPart = SubKeyCell->LastWriteTime.u.HighPart;
+           FullInformation->TitleIndex = Index;
+           FullInformation->ClassOffset = sizeof(KEY_FULL_INFORMATION) -
+             sizeof(WCHAR);
+           FullInformation->ClassLength = SubKeyCell->ClassSize;
+           FullInformation->SubKeys = SubKeyCell->NumberOfSubKeys;
+           FullInformation->MaxNameLen = CmiGetMaxNameLength(KeyObject);
+           FullInformation->MaxClassLen = CmiGetMaxClassLength(KeyObject);
+           FullInformation->Values = SubKeyCell->NumberOfValues;
+           FullInformation->MaxValueNameLen =
+             CmiGetMaxValueNameLength(RegistryHive, SubKeyCell);
+           FullInformation->MaxValueDataLen =
+             CmiGetMaxValueDataLength(RegistryHive, SubKeyCell);
+           if (SubKeyCell->ClassSize != 0)
+             {
+               ClassData = CmiGetBlock(KeyObject->RegistryHive,
+                                       SubKeyCell->ClassNameOffset,
+                                       NULL);
+               wcsncpy(FullInformation->Class,
+                       (PWCHAR)ClassData->Data,
+                       SubKeyCell->ClassSize);
+             }
+         }
+       break;
+
+      default:
+       DPRINT1("Not handling 0x%x\n", KeyInformationClass);
+       break;
     }
 
   ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
@@ -487,6 +519,7 @@ NtEnumerateValueKey(IN HANDLE KeyHandle,
   PKEY_CELL  KeyCell;
   PVALUE_CELL  ValueCell;
   PDATA_CELL  DataCell;
+  ULONG NameSize;
   PKEY_VALUE_BASIC_INFORMATION  ValueBasicInformation;
   PKEY_VALUE_PARTIAL_INFORMATION  ValuePartialInformation;
   PKEY_VALUE_FULL_INFORMATION  ValueFullInformation;
@@ -539,16 +572,12 @@ NtEnumerateValueKey(IN HANDLE KeyHandle,
       switch (KeyValueInformationClass)
         {
         case KeyValueBasicInformation:
-          if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
+         NameSize = ValueCell->NameSize;
+         if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
             {
-              *ResultLength = sizeof(KEY_VALUE_BASIC_INFORMATION) + 
-                (ValueCell->NameSize + 1) * sizeof(WCHAR);
-            }
-          else
-            {
-              *ResultLength = sizeof(KEY_VALUE_BASIC_INFORMATION) + 
-                ValueCell->NameSize + sizeof(WCHAR);
-            }
+             NameSize *= sizeof(WCHAR);
+           }
+          *ResultLength = sizeof(KEY_VALUE_BASIC_INFORMATION) + NameSize;
           if (Length < *ResultLength)
             {
               Status = STATUS_BUFFER_OVERFLOW;
@@ -559,23 +588,18 @@ NtEnumerateValueKey(IN HANDLE KeyHandle,
                 KeyValueInformation;
               ValueBasicInformation->TitleIndex = 0;
               ValueBasicInformation->Type = ValueCell->DataType;
+             ValueBasicInformation->NameLength = NameSize;
               if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
                 {
-                  ValueBasicInformation->NameLength =
-                    (ValueCell->NameSize + 1) * sizeof(WCHAR);
                   CmiCopyPackedName(ValueBasicInformation->Name,
                                     ValueCell->Name,
                                     ValueCell->NameSize);
-                  ValueBasicInformation->Name[ValueCell->NameSize] = 0;
                 }
               else
                 {
-                  ValueBasicInformation->NameLength =
-                    ValueCell->NameSize + sizeof(WCHAR);
                   RtlCopyMemory(ValueBasicInformation->Name,
                                 ValueCell->Name,
-                                ValueCell->NameSize * sizeof(WCHAR));
-                  ValueBasicInformation->Name[ValueCell->NameSize / sizeof(WCHAR)] = 0;
+                                NameSize);
                 }
             }
           break;
@@ -612,18 +636,13 @@ NtEnumerateValueKey(IN HANDLE KeyHandle,
           break;
 
         case KeyValueFullInformation:
+         NameSize = ValueCell->NameSize;
           if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
             {
-              *ResultLength = sizeof(KEY_VALUE_FULL_INFORMATION) + 
-                (ValueCell->NameSize + 1) * sizeof(WCHAR) +
-                (ValueCell->DataSize & LONG_MAX);
-            }
-          else
-            {
-              *ResultLength = sizeof(KEY_VALUE_FULL_INFORMATION) + 
-                ValueCell->NameSize + sizeof(WCHAR) +
-                (ValueCell->DataSize & LONG_MAX);
-            }
+             NameSize *= sizeof(WCHAR);
+           }
+          *ResultLength = sizeof(KEY_VALUE_FULL_INFORMATION) + 
+             NameSize + (ValueCell->DataSize & LONG_MAX);
           if (Length < *ResultLength)
             {
               Status = STATUS_BUFFER_OVERFLOW;
@@ -634,24 +653,18 @@ NtEnumerateValueKey(IN HANDLE KeyHandle,
                 KeyValueInformation;
               ValueFullInformation->TitleIndex = 0;
               ValueFullInformation->Type = ValueCell->DataType;
+              ValueFullInformation->NameLength = NameSize;
               if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
                 {
-                  ValueFullInformation->NameLength =
-                    (ValueCell->NameSize + 1) * sizeof(WCHAR);
-
                   CmiCopyPackedName(ValueFullInformation->Name,
                                    ValueCell->Name,
                                    ValueCell->NameSize);
-                  ValueFullInformation->Name[ValueCell->NameSize] = 0;
                 }
               else
                 {
-                  ValueFullInformation->NameLength =
-                    ValueCell->NameSize + sizeof(WCHAR);
                   RtlCopyMemory(ValueFullInformation->Name,
                                ValueCell->Name,
                                ValueCell->NameSize);
-                  ValueFullInformation->Name[ValueCell->NameSize / sizeof(WCHAR)] = 0;
                 }
               ValueFullInformation->DataOffset = 
                 (ULONG)ValueFullInformation->Name - (ULONG)ValueFullInformation +
@@ -676,6 +689,10 @@ NtEnumerateValueKey(IN HANDLE KeyHandle,
                 }
             }
           break;
+
+          default:
+            DPRINT1("Not handling 0x%x\n", KeyValueInformationClass);
+               break;
         }
     }
   else
@@ -719,7 +736,7 @@ NtFlushKey(IN HANDLE KeyHandle)
   ExAcquireResourceExclusiveLite(&RegistryHive->HiveResource,
                                 TRUE);
 
-  if (IsVolatileHive(RegistryHive))
+  if (IsNoFileHive(RegistryHive))
     {
       Status = STATUS_SUCCESS;
     }
@@ -806,12 +823,12 @@ NtQueryKey(IN HANDLE KeyHandle,
   PKEY_NODE_INFORMATION NodeInformation;
   PKEY_FULL_INFORMATION FullInformation;
   PREGISTRY_HIVE RegistryHive;
-  PDATA_CELL pClassData;
+  PDATA_CELL ClassData;
   PKEY_OBJECT KeyObject;
   PKEY_CELL KeyCell;
   NTSTATUS Status;
 
-  DPRINT("KH %x  KIC %x  KI %x  L %d  RL %x\n",
+  DPRINT("NtQueryKey(KH %x  KIC %x  KI %x  L %d  RL %x)\n",
         KeyHandle,
         KeyInformationClass,
         KeyInformation,
@@ -842,104 +859,125 @@ NtQueryKey(IN HANDLE KeyHandle,
   Status = STATUS_SUCCESS;
   switch (KeyInformationClass)
     {
-    case KeyBasicInformation:
-      /* Check size of buffer */
-      if (Length < sizeof(KEY_BASIC_INFORMATION) + 
-          KeyObject->NameSize * sizeof(WCHAR))
-        {
-          Status = STATUS_BUFFER_OVERFLOW;
-        }
-      else
-        {
-          /* Fill buffer with requested info */
-          BasicInformation = (PKEY_BASIC_INFORMATION) KeyInformation;
-          BasicInformation->LastWriteTime.u.LowPart = KeyCell->LastWriteTime.dwLowDateTime;
-          BasicInformation->LastWriteTime.u.HighPart = KeyCell->LastWriteTime.dwHighDateTime;
-          BasicInformation->TitleIndex = 0;
-          BasicInformation->NameLength = (KeyObject->NameSize) * sizeof(WCHAR);
-          mbstowcs(BasicInformation->Name,
-            KeyObject->Name, 
-            KeyObject->NameSize*sizeof(WCHAR));
-          *ResultLength = sizeof(KEY_BASIC_INFORMATION) + 
-            KeyObject->NameSize * sizeof(WCHAR);
-        }
-      break;
-
-    case KeyNodeInformation:
-      /* Check size of buffer */
-      if (Length < sizeof(KEY_NODE_INFORMATION)
-         + KeyObject->NameSize * sizeof(WCHAR)
-         + KeyCell->ClassSize)
-        {
-          Status = STATUS_BUFFER_OVERFLOW;
-        }
-      else
-        {
-          /* Fill buffer with requested info */
-          NodeInformation = (PKEY_NODE_INFORMATION) KeyInformation;
-          NodeInformation->LastWriteTime.u.LowPart = KeyCell->LastWriteTime.dwLowDateTime;
-          NodeInformation->LastWriteTime.u.HighPart = KeyCell->LastWriteTime.dwHighDateTime;
-          NodeInformation->TitleIndex = 0;
-          NodeInformation->ClassOffset = sizeof(KEY_NODE_INFORMATION) + 
-            KeyObject->NameSize * sizeof(WCHAR);
-          NodeInformation->ClassLength = KeyCell->ClassSize;
-          NodeInformation->NameLength = KeyObject->NameSize * sizeof(WCHAR);
-          mbstowcs(NodeInformation->Name,
-            KeyObject->Name,
-            KeyObject->NameSize * sizeof(WCHAR));
-
-          if (KeyCell->ClassSize != 0)
-            {
-              pClassData = CmiGetBlock(KeyObject->RegistryHive,
-                KeyCell->ClassNameOffset,
-                NULL);
-              wcsncpy(NodeInformation->Name + KeyObject->NameSize * sizeof(WCHAR),
-                (PWCHAR)pClassData->Data,
-                KeyCell->ClassSize);
-            }
-          *ResultLength = sizeof(KEY_NODE_INFORMATION)
-            + KeyObject->NameSize * sizeof(WCHAR)
-            + KeyCell->ClassSize;
-        }
-      break;
-
-    case KeyFullInformation:
-      /* Check size of buffer */
-      if (Length < sizeof(KEY_FULL_INFORMATION) + KeyCell->ClassSize)
-        {
-          Status = STATUS_BUFFER_OVERFLOW;
-        }
-      else
-        {
-          /* Fill buffer with requested info */
-          FullInformation = (PKEY_FULL_INFORMATION) KeyInformation;
-          FullInformation->LastWriteTime.u.LowPart = KeyCell->LastWriteTime.dwLowDateTime;
-          FullInformation->LastWriteTime.u.HighPart = KeyCell->LastWriteTime.dwHighDateTime;
-          FullInformation->TitleIndex = 0;
-          FullInformation->ClassOffset = sizeof(KEY_FULL_INFORMATION) - sizeof(WCHAR);
-          FullInformation->ClassLength = KeyCell->ClassSize;
-          FullInformation->SubKeys = KeyCell->NumberOfSubKeys;
-          FullInformation->MaxNameLen =
-            CmiGetMaxNameLength(RegistryHive, KeyCell);
-          FullInformation->MaxClassLen =
-            CmiGetMaxClassLength(RegistryHive, KeyCell);
-          FullInformation->Values = KeyCell->NumberOfValues;
-          FullInformation->MaxValueNameLen =
-            CmiGetMaxValueNameLength(RegistryHive, KeyCell);
-          FullInformation->MaxValueDataLen = 
-            CmiGetMaxValueDataLength(RegistryHive, KeyCell);
-          if (KeyCell->ClassSize != 0)
-            {
-              pClassData=CmiGetBlock(KeyObject->RegistryHive,
-                KeyCell->ClassNameOffset,
-                NULL);
-              wcsncpy(FullInformation->Class,
-                (PWCHAR)pClassData->Data,
-                KeyCell->ClassSize);
-            }
-          *ResultLength = sizeof(KEY_FULL_INFORMATION) + KeyCell->ClassSize;
-        }
-      break;
+      case KeyBasicInformation:
+       /* Check size of buffer */
+       *ResultLength = sizeof(KEY_BASIC_INFORMATION) +
+         KeyObject->Name.Length;
+
+       if (Length < *ResultLength)
+         {
+           Status = STATUS_BUFFER_OVERFLOW;
+         }
+       else
+         {
+           /* Fill buffer with requested info */
+           BasicInformation = (PKEY_BASIC_INFORMATION) KeyInformation;
+           BasicInformation->LastWriteTime.u.LowPart = KeyCell->LastWriteTime.u.LowPart;
+           BasicInformation->LastWriteTime.u.HighPart = KeyCell->LastWriteTime.u.HighPart;
+           BasicInformation->TitleIndex = 0;
+           BasicInformation->NameLength = KeyObject->Name.Length;
+
+           if (KeyCell->Flags & REG_KEY_NAME_PACKED)
+             {
+               CmiCopyPackedName(BasicInformation->Name,
+                                 KeyCell->Name,
+                                 KeyCell->NameSize);
+             }
+           else
+             {
+               RtlCopyMemory(BasicInformation->Name,
+                             KeyCell->Name,
+                             KeyCell->NameSize);
+             }
+         }
+       break;
+
+      case KeyNodeInformation:
+       /* Check size of buffer */
+       *ResultLength = sizeof(KEY_NODE_INFORMATION) +
+         KeyObject->Name.Length + KeyCell->ClassSize;
+
+       if (Length < *ResultLength)
+         {
+           Status = STATUS_BUFFER_OVERFLOW;
+         }
+       else
+         {
+           /* Fill buffer with requested info */
+           NodeInformation = (PKEY_NODE_INFORMATION) KeyInformation;
+           NodeInformation->LastWriteTime.u.LowPart = KeyCell->LastWriteTime.u.LowPart;
+           NodeInformation->LastWriteTime.u.HighPart = KeyCell->LastWriteTime.u.HighPart;
+           NodeInformation->TitleIndex = 0;
+           NodeInformation->ClassOffset = sizeof(KEY_NODE_INFORMATION) +
+             KeyObject->Name.Length;
+           NodeInformation->ClassLength = KeyCell->ClassSize;
+           NodeInformation->NameLength = KeyObject->Name.Length;
+
+           if (KeyCell->Flags & REG_KEY_NAME_PACKED)
+             {
+               CmiCopyPackedName(NodeInformation->Name,
+                                 KeyCell->Name,
+                                 KeyCell->NameSize);
+             }
+           else
+             {
+               RtlCopyMemory(NodeInformation->Name,
+                             KeyCell->Name,
+                             KeyCell->NameSize);
+             }
+
+           if (KeyCell->ClassSize != 0)
+             {
+               ClassData = CmiGetBlock(KeyObject->RegistryHive,
+                                       KeyCell->ClassNameOffset,
+                                       NULL);
+               wcsncpy(NodeInformation->Name + KeyObject->Name.Length,
+                       (PWCHAR)ClassData->Data,
+                       KeyCell->ClassSize);
+             }
+         }
+       break;
+
+      case KeyFullInformation:
+       /* Check size of buffer */
+       *ResultLength = sizeof(KEY_FULL_INFORMATION) +
+         KeyCell->ClassSize;
+
+       if (Length < *ResultLength)
+         {
+           Status = STATUS_BUFFER_OVERFLOW;
+         }
+       else
+         {
+           /* Fill buffer with requested info */
+           FullInformation = (PKEY_FULL_INFORMATION) KeyInformation;
+           FullInformation->LastWriteTime.u.LowPart = KeyCell->LastWriteTime.u.LowPart;
+           FullInformation->LastWriteTime.u.HighPart = KeyCell->LastWriteTime.u.HighPart;
+           FullInformation->TitleIndex = 0;
+           FullInformation->ClassOffset = sizeof(KEY_FULL_INFORMATION) - sizeof(WCHAR);
+           FullInformation->ClassLength = KeyCell->ClassSize;
+           FullInformation->SubKeys = KeyCell->NumberOfSubKeys;
+           FullInformation->MaxNameLen = CmiGetMaxNameLength(KeyObject);
+           FullInformation->MaxClassLen = CmiGetMaxClassLength(KeyObject);
+           FullInformation->Values = KeyCell->NumberOfValues;
+           FullInformation->MaxValueNameLen =
+             CmiGetMaxValueNameLength(RegistryHive, KeyCell);
+           FullInformation->MaxValueDataLen =
+             CmiGetMaxValueDataLength(RegistryHive, KeyCell);
+           if (KeyCell->ClassSize != 0)
+             {
+               ClassData=CmiGetBlock(KeyObject->RegistryHive,
+                                     KeyCell->ClassNameOffset,
+                                     NULL);
+               wcsncpy(FullInformation->Class,
+                       (PWCHAR)ClassData->Data,
+                       KeyCell->ClassSize);
+             }
+         }
+       break;
+  default:
+    DPRINT1("Not handling 0x%x\n", KeyInformationClass);
+       break;
     }
 
   ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
@@ -958,6 +996,7 @@ NtQueryValueKey(IN HANDLE KeyHandle,
        OUT PULONG ResultLength)
 {
   NTSTATUS  Status;
+  ULONG NameSize;
   PKEY_OBJECT  KeyObject;
   PREGISTRY_HIVE  RegistryHive;
   PKEY_CELL  KeyCell;
@@ -1011,16 +1050,12 @@ NtQueryValueKey(IN HANDLE KeyHandle,
       switch (KeyValueInformationClass)
         {
         case KeyValueBasicInformation:
+         NameSize = ValueCell->NameSize;
           if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
             {
-              *ResultLength = sizeof(KEY_VALUE_BASIC_INFORMATION) + 
-                (ValueCell->NameSize + 1) * sizeof(WCHAR);
-            }
-          else
-            {
-              *ResultLength = sizeof(KEY_VALUE_BASIC_INFORMATION) + 
-                ValueCell->NameSize + sizeof(WCHAR);
-            }
+             NameSize *= sizeof(WCHAR);
+           }
+          *ResultLength = sizeof(KEY_VALUE_BASIC_INFORMATION) + NameSize;
           if (Length < *ResultLength)
             {
               Status = STATUS_BUFFER_TOO_SMALL;
@@ -1031,23 +1066,18 @@ NtQueryValueKey(IN HANDLE KeyHandle,
                 KeyValueInformation;
               ValueBasicInformation->TitleIndex = 0;
               ValueBasicInformation->Type = ValueCell->DataType;
+              ValueBasicInformation->NameLength = NameSize;
               if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
                 {
-                  ValueBasicInformation->NameLength =
-                    (ValueCell->NameSize + 1) * sizeof(WCHAR);
                   CmiCopyPackedName(ValueBasicInformation->Name,
                                     ValueCell->Name,
                                     ValueCell->NameSize);
-                  ValueBasicInformation->Name[ValueCell->NameSize] = 0;
                 }
               else
                 {
-                  ValueBasicInformation->NameLength =
-                    ValueCell->NameSize + sizeof(WCHAR);
                   RtlCopyMemory(ValueBasicInformation->Name,
                                 ValueCell->Name,
                                 ValueCell->NameSize * sizeof(WCHAR));
-                  ValueBasicInformation->Name[ValueCell->NameSize / sizeof(WCHAR)] = 0;
                 }
             }
           break;
@@ -1083,18 +1113,13 @@ NtQueryValueKey(IN HANDLE KeyHandle,
           break;
 
         case KeyValueFullInformation:
+         NameSize = ValueCell->NameSize;
           if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
             {
-              *ResultLength = sizeof(KEY_VALUE_FULL_INFORMATION) + 
-                (ValueCell->NameSize + 1) * sizeof(WCHAR) +
-                (ValueCell->DataSize & LONG_MAX);
-            }
-          else
-            {
-              *ResultLength = sizeof(KEY_VALUE_FULL_INFORMATION) + 
-                ValueCell->NameSize + sizeof(WCHAR) +
-                (ValueCell->DataSize & LONG_MAX);
-            }
+             NameSize *= sizeof(WCHAR);
+           }
+          *ResultLength = sizeof(KEY_VALUE_FULL_INFORMATION) + 
+            NameSize + (ValueCell->DataSize & LONG_MAX);
           if (Length < *ResultLength)
             {
               Status = STATUS_BUFFER_TOO_SMALL;
@@ -1105,23 +1130,18 @@ NtQueryValueKey(IN HANDLE KeyHandle,
                 KeyValueInformation;
               ValueFullInformation->TitleIndex = 0;
               ValueFullInformation->Type = ValueCell->DataType;
+              ValueFullInformation->NameLength = NameSize;
               if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
                 {
-                  ValueFullInformation->NameLength =
-                    (ValueCell->NameSize + 1) * sizeof(WCHAR);
                   CmiCopyPackedName(ValueFullInformation->Name,
                                     ValueCell->Name,
                                     ValueCell->NameSize);
-                  ValueFullInformation->Name[ValueCell->NameSize] = 0;
                 }
               else
                 {
-                  ValueFullInformation->NameLength =
-                    ValueCell->NameSize + sizeof(WCHAR);
                   RtlCopyMemory(ValueFullInformation->Name,
                                 ValueCell->Name,
                                 ValueCell->NameSize);
-                  ValueFullInformation->Name[ValueCell->NameSize / sizeof(WCHAR)] = 0;
                 }
               ValueFullInformation->DataOffset = 
                 (ULONG)ValueFullInformation->Name - (ULONG)ValueFullInformation +
@@ -1146,6 +1166,9 @@ NtQueryValueKey(IN HANDLE KeyHandle,
                 }
             }
           break;
+          default:
+            DPRINT1("Not handling 0x%x\n", KeyValueInformationClass);
+               break;
         }
     }
   else
@@ -1271,9 +1294,9 @@ NtSetValueKey(IN HANDLE KeyHandle,
       ValueCell->DataType = Type;
 
       /* Update time of heap */
-      if (!IsVolatileHive(RegistryHive))
+      if (!IsNoFileHive(RegistryHive))
        {
-         NtQuerySystemTime((PTIME) &pBin->DateModified);
+         NtQuerySystemTime(&pBin->DateModified);
        }
       CmiMarkBlockDirty(RegistryHive, ValueCell->DataOffset);
     }
@@ -1321,14 +1344,14 @@ NtSetValueKey(IN HANDLE KeyHandle,
   if ((_wcsicmp(ValueName->Buffer, L"SymbolicLinkValue") == 0) &&
       (Type == REG_LINK))
     {
-      KeyCell->Type = REG_LINK_KEY_CELL_TYPE;
+      KeyCell->Flags |= REG_KEY_LINK_CELL;
       CmiMarkBlockDirty(RegistryHive, KeyObject->BlockOffset);
     }
 
   /* Update time of heap */
-  if (!IsVolatileHive(RegistryHive) && CmiGetBlock(RegistryHive, VBOffset, &pBin))
+  if (!IsNoFileHive(RegistryHive) && CmiGetBlock(RegistryHive, VBOffset, &pBin))
     {
-      NtQuerySystemTime((PTIME) &pBin->DateModified);
+      NtQuerySystemTime(&pBin->DateModified);
     }
 
   ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
@@ -1343,8 +1366,8 @@ NtSetValueKey(IN HANDLE KeyHandle,
 
 
 NTSTATUS STDCALL
-NtDeleteValueKey(IN HANDLE KeyHandle,
-                IN PUNICODE_STRING ValueName)
+NtDeleteValueKey (IN HANDLE KeyHandle,
+                 IN PUNICODE_STRING ValueName)
 {
   PKEY_OBJECT KeyObject;
   NTSTATUS Status;
@@ -1381,16 +1404,19 @@ NtDeleteValueKey(IN HANDLE KeyHandle,
   return Status;
 }
 
+
 /*
  * NOTE:
  * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
  * KeyObjectAttributes->Name specifies the name of the key to load.
  */
 NTSTATUS STDCALL
-NtLoadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
-         IN POBJECT_ATTRIBUTES FileObjectAttributes)
+NtLoadKey (IN POBJECT_ATTRIBUTES KeyObjectAttributes,
+          IN POBJECT_ATTRIBUTES FileObjectAttributes)
 {
-  return NtLoadKey2(KeyObjectAttributes, FileObjectAttributes, 0);
+  return NtLoadKey2 (KeyObjectAttributes,
+                    FileObjectAttributes,
+                    0);
 }
 
 
@@ -1398,41 +1424,139 @@ NtLoadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
  * NOTE:
  * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
  * KeyObjectAttributes->Name specifies the name of the key to load.
+ * Flags can be 0 or REG_NO_LAZY_FLUSH.
  */
 NTSTATUS STDCALL
-NtLoadKey2(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
-          IN POBJECT_ATTRIBUTES FileObjectAttributes,
-          IN ULONG Flags)
+NtLoadKey2 (IN POBJECT_ATTRIBUTES KeyObjectAttributes,
+           IN POBJECT_ATTRIBUTES FileObjectAttributes,
+           IN ULONG Flags)
 {
-  UNIMPLEMENTED;
-  return STATUS_NOT_IMPLEMENTED;
+  POBJECT_NAME_INFORMATION NameInfo;
+  PUNICODE_STRING NamePointer;
+  PUCHAR Buffer;
+  ULONG BufferSize;
+  ULONG Length;
+  NTSTATUS Status;
+
+  DPRINT ("NtLoadKey2() called\n");
+
+#if 0
+  if (!SeSinglePrivilegeCheck (SeRestorePrivilege, KeGetPreviousMode ()))
+    return STATUS_PRIVILEGE_NOT_HELD;
+#endif
+
+  if (FileObjectAttributes->RootDirectory != NULL)
+    {
+      BufferSize =
+       sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR);
+      Buffer = ExAllocatePool (NonPagedPool,
+                              BufferSize);
+      if (Buffer == NULL)
+       return STATUS_INSUFFICIENT_RESOURCES;
+
+      Status = NtQueryObject (FileObjectAttributes->RootDirectory,
+                             ObjectNameInformation,
+                             Buffer,
+                             BufferSize,
+                             &Length);
+      if (!NT_SUCCESS(Status))
+       {
+         DPRINT1 ("NtQueryObject() failed (Status %lx)\n", Status);
+         ExFreePool (Buffer);
+         return Status;
+       }
+
+      NameInfo = (POBJECT_NAME_INFORMATION)Buffer;
+      DPRINT ("ObjectPath: '%wZ'  Length %hu\n",
+             &NameInfo->Name, NameInfo->Name.Length);
+
+      NameInfo->Name.MaximumLength = MAX_PATH * sizeof(WCHAR);
+      if (FileObjectAttributes->ObjectName->Buffer[0] != L'\\')
+       {
+         RtlAppendUnicodeToString (&NameInfo->Name,
+                                   L"\\");
+         DPRINT ("ObjectPath: '%wZ'  Length %hu\n",
+                 &NameInfo->Name, NameInfo->Name.Length);
+       }
+      RtlAppendUnicodeStringToString (&NameInfo->Name,
+                                     FileObjectAttributes->ObjectName);
+
+      DPRINT ("ObjectPath: '%wZ'  Length %hu\n",
+             &NameInfo->Name, NameInfo->Name.Length);
+      NamePointer = &NameInfo->Name;
+    }
+  else
+    {
+      if (FileObjectAttributes->ObjectName->Buffer[0] == L'\\')
+       {
+         Buffer = NULL;
+         NamePointer = FileObjectAttributes->ObjectName;
+       }
+      else
+       {
+         BufferSize =
+           sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR);
+         Buffer = ExAllocatePool (NonPagedPool,
+                                  BufferSize);
+         if (Buffer == NULL)
+           return STATUS_INSUFFICIENT_RESOURCES;
+
+         NameInfo = (POBJECT_NAME_INFORMATION)Buffer;
+         NameInfo->Name.MaximumLength = MAX_PATH * sizeof(WCHAR);
+         NameInfo->Name.Length = 0;
+         NameInfo->Name.Buffer = (PWSTR)((ULONG_PTR)Buffer + sizeof(OBJECT_NAME_INFORMATION));
+         NameInfo->Name.Buffer[0] = 0;
+
+         RtlAppendUnicodeToString (&NameInfo->Name,
+                                   L"\\");
+         RtlAppendUnicodeStringToString (&NameInfo->Name,
+                                         FileObjectAttributes->ObjectName);
+
+         NamePointer = &NameInfo->Name;
+       }
+    }
+
+  DPRINT ("Full name: '%wZ'\n", NamePointer);
+
+  Status = CmiLoadHive (KeyObjectAttributes,
+                       NamePointer,
+                       Flags);
+  if (!NT_SUCCESS (Status))
+    {
+      DPRINT1 ("CmiLoadHive() failed (Status %lx)\n", Status);
+    }
+
+  if (Buffer != NULL)
+    ExFreePool (Buffer);
+
+  return Status;
 }
 
 
 NTSTATUS STDCALL
-NtNotifyChangeKey(
-       IN      HANDLE  KeyHandle,
-       IN      HANDLE  Event,
-       IN      PIO_APC_ROUTINE  ApcRoutine  OPTIONAL,
-       IN      PVOID  ApcContext  OPTIONAL,
-       OUT     PIO_STATUS_BLOCK  IoStatusBlock,
-       IN      ULONG  CompletionFilter,
-       IN      BOOLEAN  Asynchroneous,
-       OUT     PVOID  ChangeBuffer,
-       IN      ULONG  Length,
-       IN      BOOLEAN  WatchSubtree)
+NtNotifyChangeKey (IN HANDLE KeyHandle,
+                  IN HANDLE Event,
+                  IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
+                  IN PVOID ApcContext OPTIONAL,
+                  OUT PIO_STATUS_BLOCK IoStatusBlock,
+                  IN ULONG CompletionFilter,
+                  IN BOOLEAN Asynchroneous,
+                  OUT PVOID ChangeBuffer,
+                  IN ULONG Length,
+                  IN BOOLEAN WatchSubtree)
 {
        UNIMPLEMENTED;
+       return(STATUS_NOT_IMPLEMENTED);
 }
 
 
 NTSTATUS STDCALL
-NtQueryMultipleValueKey(IN HANDLE KeyHandle,
-                       IN OUT PKEY_VALUE_ENTRY ValueList,
-                       IN ULONG NumberOfValues,
-                       OUT PVOID Buffer,
-                       IN OUT PULONG Length,
-                       OUT PULONG ReturnLength)
+NtQueryMultipleValueKey (IN HANDLE KeyHandle,
+                        IN OUT PKEY_VALUE_ENTRY ValueList,
+                        IN ULONG NumberOfValues,
+                        OUT PVOID Buffer,
+                        IN OUT PULONG Length,
+                        OUT PULONG ReturnLength)
 {
   PREGISTRY_HIVE RegistryHive;
   PVALUE_CELL ValueCell;
@@ -1538,49 +1662,120 @@ NtQueryMultipleValueKey(IN HANDLE KeyHandle,
 
   DPRINT("Return Status 0x%X\n", Status);
 
-  return(Status);
+  return Status;
 }
 
 
 NTSTATUS STDCALL
-NtReplaceKey(
-       IN      POBJECT_ATTRIBUTES      ObjectAttributes,
-       IN      HANDLE  Key,
-       IN      POBJECT_ATTRIBUTES      ReplacedObjectAttributes
-       )
+NtReplaceKey (IN POBJECT_ATTRIBUTES ObjectAttributes,
+             IN HANDLE Key,
+             IN POBJECT_ATTRIBUTES ReplacedObjectAttributes)
 {
        UNIMPLEMENTED;
+       return(STATUS_NOT_IMPLEMENTED);
 }
 
 
 NTSTATUS STDCALL
-NtRestoreKey(
-       IN      HANDLE  KeyHandle,
-       IN      HANDLE  FileHandle,
-       IN      ULONG   RestoreFlags
-       )
+NtRestoreKey (IN HANDLE KeyHandle,
+             IN HANDLE FileHandle,
+             IN ULONG RestoreFlags)
 {
        UNIMPLEMENTED;
+       return(STATUS_NOT_IMPLEMENTED);
 }
 
 
 NTSTATUS STDCALL
-NtSaveKey(
-       IN      HANDLE  KeyHandle,
-       IN      HANDLE  FileHandle)
+NtSaveKey (IN HANDLE KeyHandle,
+          IN HANDLE FileHandle)
 {
-       UNIMPLEMENTED;
+  PREGISTRY_HIVE TempHive;
+  PKEY_OBJECT KeyObject;
+  NTSTATUS Status;
+
+  DPRINT ("NtSaveKey() called\n");
+
+#if 0
+  if (!SeSinglePrivilegeCheck (SeBackupPrivilege, KeGetPreviousMode ()))
+    return STATUS_PRIVILEGE_NOT_HELD;
+#endif
+
+  Status = ObReferenceObjectByHandle (KeyHandle,
+                                     0,
+                                     CmiKeyType,
+                                     KeGetPreviousMode(),
+                                     (PVOID *)&KeyObject,
+                                     NULL);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1 ("ObReferenceObjectByHandle() failed (Status %lx)\n", Status);
+      return Status;
+    }
+
+  /* Acquire hive lock exclucively */
+  ExAcquireResourceExclusiveLite (&KeyObject->RegistryHive->HiveResource,
+                                 TRUE);
+
+  /* Refuse to save a volatile key */
+  if (KeyObject->RegistryHive == CmiVolatileHive)
+    {
+      DPRINT1 ("Cannot save a volatile key\n");
+      ExReleaseResourceLite (&KeyObject->RegistryHive->HiveResource);
+      ObDereferenceObject (KeyObject);
+      return STATUS_ACCESS_DENIED;
+    }
+
+  Status = CmiCreateTempHive(&TempHive);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1 ("CmiCreateTempHive() failed (Status %lx)\n", Status);
+      ExReleaseResourceLite (&KeyObject->RegistryHive->HiveResource);
+      ObDereferenceObject (KeyObject);
+      return(Status);
+    }
+
+  Status = CmiCopyKey (TempHive,
+                      NULL,
+                      KeyObject->RegistryHive,
+                      KeyObject->KeyCell);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1 ("CmiCopyKey() failed (Status %lx)\n", Status);
+      CmiRemoveRegistryHive (TempHive);
+      ExReleaseResourceLite (&KeyObject->RegistryHive->HiveResource);
+      ObDereferenceObject (KeyObject);
+      return(Status);
+    }
+
+  Status = CmiSaveTempHive (TempHive,
+                           FileHandle);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1 ("CmiSaveTempHive() failed (Status %lx)\n", Status);
+    }
+
+  CmiRemoveRegistryHive (TempHive);
+
+  /* Release hive lock */
+  ExReleaseResourceLite(&KeyObject->RegistryHive->HiveResource);
+
+  ObDereferenceObject (KeyObject);
+
+  DPRINT ("NtSaveKey() done\n");
+
+  return STATUS_SUCCESS;
 }
 
 
 NTSTATUS STDCALL
-NtSetInformationKey(
-       IN      HANDLE  KeyHandle,
-       IN      CINT    KeyInformationClass,
-       IN      PVOID    KeyInformation,
-       IN      ULONG    KeyInformationLength)
+NtSetInformationKey (IN HANDLE KeyHandle,
+                    IN CINT KeyInformationClass,
+                    IN PVOID KeyInformation,
+                    IN ULONG KeyInformationLength)
 {
-  UNIMPLEMENTED;
+       UNIMPLEMENTED;
+       return(STATUS_NOT_IMPLEMENTED);
 }
 
 
@@ -1590,27 +1785,64 @@ NtSetInformationKey(
  * KeyObjectAttributes->Name specifies the name of the key to unload.
  */
 NTSTATUS STDCALL
-NtUnloadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes)
+NtUnloadKey (IN POBJECT_ATTRIBUTES KeyObjectAttributes)
 {
-  UNIMPLEMENTED;
+  PREGISTRY_HIVE RegistryHive;
+  NTSTATUS Status;
+
+  DPRINT ("NtUnloadKey() called\n");
+
+#if 0
+  if (!SeSinglePrivilegeCheck (SeRestorePrivilege, KeGetPreviousMode ()))
+    return STATUS_PRIVILEGE_NOT_HELD;
+#endif
+
+  Status = CmiDisconnectHive (KeyObjectAttributes,
+                             &RegistryHive);
+  if (!NT_SUCCESS (Status))
+    {
+      DPRINT1 ("CmiDisconnectHive() failed (Status %lx)\n", Status);
+      return Status;
+    }
+
+  DPRINT ("RegistryHive %p\n", RegistryHive);
+
+  /* Acquire hive list lock exclusively */
+  ExAcquireResourceExclusiveLite (&CmiHiveListLock,
+                                 TRUE);
+
+#if 0
+  /* Flush hive */
+  if (!IsNoFileHive (RegistryHive))
+    CmiFlushRegistryHive (RegistryHive);
+#endif
+
+  /* Release hive list lock */
+  ExReleaseResourceLite (&CmiHiveListLock);
+
+  CmiRemoveRegistryHive (RegistryHive);
+
+  DPRINT ("NtUnloadKey() done\n");
+
+  return STATUS_SUCCESS;
 }
 
 
 NTSTATUS STDCALL
-NtInitializeRegistry(IN BOOLEAN SetUpBoot)
+NtInitializeRegistry (IN BOOLEAN SetUpBoot)
 {
-  NTSTATUS Status = STATUS_ACCESS_DENIED;
+  NTSTATUS Status;
 
-  if (CmiRegistryInitialized == FALSE)
-    {
-      /* FIXME: save boot log file */
+  if (CmiRegistryInitialized == TRUE)
+    return STATUS_ACCESS_DENIED;
 
-      Status = CmiInitHives(SetUpBoot);
+  /* FIXME: save boot log file */
 
-      CmiRegistryInitialized = TRUE;
-    }
+  Status = CmiInitHives (SetUpBoot);
 
-  return(Status);
+  CmiRegistryInitialized = TRUE;
+
+  return Status;
 }
 
 /* EOF */