update for HEAD-2003021201
[reactos.git] / ntoskrnl / cm / regfile.c
index db89135..ea67394 100644 (file)
@@ -6,6 +6,9 @@
  * UPDATE HISTORY:
 */
 
+#ifdef WIN32_REGDBG
+#include "cm_win32.h"
+#else
 #include <ddk/ntddk.h>
 #include <ddk/ntifs.h>
 #include <roscfg.h>
 #include <internal/debug.h>
 
 #include "cm.h"
+#endif
 
-
+#define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
 
 BOOLEAN CmiDoVerify = FALSE;
 
+/* FUNCTIONS ****************************************************************/
+
 VOID
 CmiCreateDefaultHiveHeader(PHIVE_HEADER Header)
 {
@@ -62,7 +68,11 @@ CmiCreateDefaultRootKeyCell(PKEY_CELL RootKeyCell)
 {
   assert(RootKeyCell);
   RtlZeroMemory(RootKeyCell, sizeof(KEY_CELL));
+#ifdef WIN32_REGDBG
+  RootKeyCell->CellSize = -(LONG)sizeof(KEY_CELL);
+#else
   RootKeyCell->CellSize = -sizeof(KEY_CELL);
+#endif
   RootKeyCell->Id = REG_KEY_CELL_ID;
   RootKeyCell->Type = REG_ROOT_KEY_CELL_TYPE;
   ZwQuerySystemTime((PTIME) &RootKeyCell->LastWriteTime);
@@ -358,7 +368,7 @@ CmiPopulateHive(HANDLE FileHandle)
   PHBIN BinCell;
   PCHAR tBuf;
   ULONG i;
-  
+
   tBuf = (PCHAR) ExAllocatePool(NonPagedPool, REG_BLOCK_SIZE);
   if (tBuf == NULL)
     return STATUS_INSUFFICIENT_RESOURCES;
@@ -382,14 +392,14 @@ CmiPopulateHive(HANDLE FileHandle)
       FileOffset.u.LowPart   = (2 + i) * REG_BLOCK_SIZE;
 
       Status = ZwWriteFile(FileHandle,
-                   NULL,
-                   NULL,
-                   NULL,
-                   &IoStatusBlock,
-                   tBuf,
-                   REG_BLOCK_SIZE,
-                   &FileOffset,
-        NULL);
+                          NULL,
+                          NULL,
+                          NULL,
+                          &IoStatusBlock,
+                          tBuf,
+                          REG_BLOCK_SIZE,
+                          &FileOffset,
+                          NULL);
       assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status));
       if (!NT_SUCCESS(Status))
        {
@@ -413,48 +423,48 @@ CmiCreateNewRegFile(HANDLE FileHandle)
   PKEY_CELL RootKeyCell;
   NTSTATUS Status;
   PHBIN BinCell;
-  PCHAR tBuf;
-  
-  tBuf = (PCHAR) ExAllocatePool(NonPagedPool, 2 * REG_BLOCK_SIZE);
-  if (tBuf == NULL)
+  PCHAR Buffer;
+
+  Buffer = (PCHAR) ExAllocatePool(NonPagedPool, 2 * REG_BLOCK_SIZE);
+  if (Buffer == NULL)
     return STATUS_INSUFFICIENT_RESOURCES;
-    
-  HiveHeader = (PHIVE_HEADER) tBuf;
-  BinCell = (PHBIN) ((ULONG_PTR) tBuf + REG_BLOCK_SIZE);
-  RootKeyCell = (PKEY_CELL) ((ULONG_PTR) tBuf + REG_BLOCK_SIZE + REG_HBIN_DATA_OFFSET);
-  FreeCell = (PCELL_HEADER) ((ULONG_PTR) tBuf + REG_BLOCK_SIZE + REG_HBIN_DATA_OFFSET + sizeof(KEY_CELL));
+
+  HiveHeader = (PHIVE_HEADER)Buffer;
+  BinCell = (PHBIN)((ULONG_PTR)Buffer + REG_BLOCK_SIZE);
+  RootKeyCell = (PKEY_CELL)((ULONG_PTR)Buffer + REG_BLOCK_SIZE + REG_HBIN_DATA_OFFSET);
+  FreeCell = (PCELL_HEADER)((ULONG_PTR)Buffer + REG_BLOCK_SIZE + REG_HBIN_DATA_OFFSET + sizeof(KEY_CELL));
 
   CmiCreateDefaultHiveHeader(HiveHeader);
   CmiCreateDefaultBinCell(BinCell);
   CmiCreateDefaultRootKeyCell(RootKeyCell);
 
-  // First block
+  /* First block */
   BinCell->BlockOffset = 0;
 
-  // Offset to root key block
+  /* Offset to root key block */
   HiveHeader->RootKeyCell = REG_HBIN_DATA_OFFSET;
 
-  // The rest of the block is free
+  /* The rest of the block is free */
   FreeCell->CellSize = REG_BLOCK_SIZE - (REG_HBIN_DATA_OFFSET + sizeof(KEY_CELL));
 
   Status = ZwWriteFile(FileHandle,
-    NULL,
-    NULL,
-    NULL,
-    &IoStatusBlock,
-    tBuf,
-    2 * REG_BLOCK_SIZE,
-    0,
-    NULL);
+                      NULL,
+                      NULL,
+                      NULL,
+                      &IoStatusBlock,
+                      Buffer,
+                      2 * REG_BLOCK_SIZE,
+                      0,
+                      NULL);
 
-  ExFreePool(tBuf);
+  ExFreePool(Buffer);
 
   assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status));
 
 #if 1
   if (NT_SUCCESS(Status))
     {
-  CmiPopulateHive(FileHandle);
+      CmiPopulateHive(FileHandle);
     }
 #endif
 
@@ -464,8 +474,8 @@ CmiCreateNewRegFile(HANDLE FileHandle)
 
 NTSTATUS
 CmiInitPermanentRegistryHive(PREGISTRY_HIVE RegistryHive,
-  PWSTR Filename,
-  BOOLEAN CreateNew)
+                            PWSTR Filename,
+                            BOOLEAN CreateNew)
 {
   OBJECT_ATTRIBUTES ObjectAttributes;
   FILE_STANDARD_INFORMATION fsi;
@@ -475,16 +485,22 @@ CmiInitPermanentRegistryHive(PREGISTRY_HIVE RegistryHive,
   ULONG CreateDisposition;
   IO_STATUS_BLOCK IoSB;
   HANDLE FileHandle;
-  DWORD FreeOffset;
+  ULONG FreeOffset;
   NTSTATUS Status;
-  //BOOLEAN Success;
   PHBIN tmpBin;
   ULONG i, j;
+  ULONG BitmapSize;
+  PULONG BitmapBuffer;
+
+  DPRINT1("CmiInitPermanentRegistryHive(%p, %S, %d) - Entered.\n", RegistryHive, Filename, CreateNew);
 
   /* Duplicate Filename */
   Status = RtlCreateUnicodeString(&RegistryHive->Filename, Filename);
   if (!NT_SUCCESS(Status))
-    return Status;
+    {
+      DPRINT1("CmiInitPermanentRegistryHive() - Failed 1.\n");
+      return Status;
+    }
 
   InitializeObjectAttributes(&ObjectAttributes,
                             &RegistryHive->Filename,
@@ -492,76 +508,98 @@ CmiInitPermanentRegistryHive(PREGISTRY_HIVE RegistryHive,
                             NULL,
                             NULL);
 
-  if (CreateNew)
+  /*
+   * Note:
+   * This is a workaround to prevent a BSOD because of missing registry hives.
+   * The workaround is only useful for developers. An implementation for the
+   * ordinary user must bail out on missing registry hives because they are
+   * essential to booting and configuring the OS.
+   */
+#if 0
+  if (CreateNew == TRUE)
     CreateDisposition = FILE_OPEN_IF;
   else
     CreateDisposition = FILE_OPEN;
+#endif
+  CreateDisposition = FILE_OPEN_IF;
 
   Status = NtCreateFile(&FileHandle,
-               FILE_ALL_ACCESS,
-               &ObjectAttributes,
-               &IoSB,
-               NULL,
-               FILE_ATTRIBUTE_NORMAL,
-               0,
-               CreateDisposition,
-               FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
-               NULL,
-               0);
-
-  if ((CreateNew) && (IoSB.Information == FILE_CREATED))
+                       FILE_ALL_ACCESS,
+                       &ObjectAttributes,
+                       &IoSB,
+                       NULL,
+                       FILE_ATTRIBUTE_NORMAL,
+                       0,
+                       CreateDisposition,
+                       FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
+                       NULL,
+                       0);
+  if (!NT_SUCCESS(Status))
     {
-      Status = CmiCreateNewRegFile(FileHandle);
+      RtlFreeUnicodeString(&RegistryHive->Filename);
+      DPRINT1("NtCreateFile() failed (Status %lx)\n", Status);
+      return(Status);
     }
 
-  if (!NT_SUCCESS(Status))
+  /* Note: Another workaround! See the note above! */
+#if 0
+  if ((CreateNew) && (IoSB.Information == FILE_CREATED))
+#endif
+  if (IoSB.Information != FILE_OPENED)
     {
-      RtlFreeUnicodeString(&RegistryHive->Filename);
-      return Status;
+      Status = CmiCreateNewRegFile(FileHandle);
+      if (!NT_SUCCESS(Status))
+       {
+         DPRINT1("CmiCreateNewRegFile() failed (Status %lx)\n", Status);
+         RtlFreeUnicodeString(&RegistryHive->Filename);
+         return(Status);
+       }
     }
 
   Status = ObReferenceObjectByHandle(FileHandle,
-               FILE_ALL_ACCESS,
-               IoFileObjectType,
-               UserMode,
-               (PVOID*) &RegistryHive->FileObject,
-               NULL);
+                                    FILE_ALL_ACCESS,
+                                    IoFileObjectType,
+                                    UserMode,
+                                    (PVOID*)&RegistryHive->FileObject,
+                                    NULL);
 
   assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status));
 
   if (!NT_SUCCESS(Status))
     {
-      ZwClose(FileHandle);
+      NtClose(FileHandle);
       RtlFreeUnicodeString(&RegistryHive->Filename);
+      DPRINT1("CmiInitPermanentRegistryHive() - ObReferenceObjectByHandle Failed with status %x.\n", Status);
       return Status;
     }
 
+  /* Read hive header */
   FileOffset.u.HighPart = 0;
   FileOffset.u.LowPart = 0;
-  Status = ZwReadFile(FileHandle,
-                     0,
+  DPRINT("    Attempting to ZwReadFile(%d) for %d bytes into %p\n", FileHandle, sizeof(HIVE_HEADER), RegistryHive->HiveHeader);
+  Status = NtReadFile(FileHandle,
                      0,
                      0,
                      0,
+                     &IoSB,
                      RegistryHive->HiveHeader,
                      sizeof(HIVE_HEADER),
                      &FileOffset,
                      0);
-
   assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status));
-
   if (!NT_SUCCESS(Status))
     {
       ObDereferenceObject(RegistryHive->FileObject);
       RtlFreeUnicodeString(&RegistryHive->Filename);
+      DPRINT("CmiInitPermanentRegistryHive() - Failed 4.\n");
       return Status;
     }
 
-  Status = ZwQueryInformationFile(FileHandle,
-    &IoSB,
-    &fsi,
-    sizeof(fsi),
-    FileStandardInformation);
+  Status = NtQueryInformationFile(FileHandle,
+                                 &IoSB,
+                                 &fsi,
+                                 sizeof(fsi),
+                                 FileStandardInformation);
 
   assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status));
 
@@ -569,15 +607,32 @@ CmiInitPermanentRegistryHive(PREGISTRY_HIVE RegistryHive,
     {
       ObDereferenceObject(RegistryHive->FileObject);
       RtlFreeUnicodeString(&RegistryHive->Filename);
+      DPRINT("CmiInitPermanentRegistryHive() - Failed 5.\n");
       return Status;
     }
+
 #if 0
   /* We have a reference to the file object so we don't need the handle anymore */
   ZwClose(FileHandle);
 #endif
 
   RegistryHive->FileSize = fsi.EndOfFile.u.LowPart;
+#ifdef WIN32_REGDBG
+//  assert(RegistryHive->FileSize);
+  if (RegistryHive->FileSize)
+  {
+    RegistryHive->BlockListSize = (RegistryHive->FileSize / 4096) - 1;
+  }
+  else
+  {
+    ObDereferenceObject(RegistryHive->FileObject);
+    RtlFreeUnicodeString(&RegistryHive->Filename);
+    DPRINT("CmiInitPermanentRegistryHive() - Failed, zero length hive file.\n");
+    return STATUS_INSUFFICIENT_RESOURCES;
+  }
+#else
   RegistryHive->BlockListSize = (RegistryHive->FileSize / 4096) - 1;
+#endif
 
   DPRINT("Space needed for block list describing hive: 0x%x\n",
     sizeof(PHBIN *) * RegistryHive->BlockListSize);
@@ -590,6 +645,7 @@ CmiInitPermanentRegistryHive(PREGISTRY_HIVE RegistryHive,
       ExFreePool(RegistryHive->BlockList);
       ObDereferenceObject(RegistryHive->FileObject);
       RtlFreeUnicodeString(&RegistryHive->Filename);
+      DPRINT("CmiInitPermanentRegistryHive() - Failed 6.\n");
       return STATUS_INSUFFICIENT_RESOURCES;
     }
 
@@ -611,6 +667,7 @@ CmiInitPermanentRegistryHive(PREGISTRY_HIVE RegistryHive,
       ExFreePool(RegistryHive->BlockList);
       ObDereferenceObject(RegistryHive->FileObject);
       RtlFreeUnicodeString(&RegistryHive->Filename);
+      DPRINT("CmiInitPermanentRegistryHive() - Failed 7.\n");
       return Status;
     }
 
@@ -618,30 +675,36 @@ CmiInitPermanentRegistryHive(PREGISTRY_HIVE RegistryHive,
 
   RegistryHive->BlockList[0] = ExAllocatePool(PagedPool,
          RegistryHive->FileSize - 4096);
+#ifdef WIN32_REGDBG
+  RtlZeroMemory(RegistryHive->BlockList[0], RegistryHive->FileSize - 4096);
+#endif
 
   if (RegistryHive->BlockList[0] == NULL)
     {
       ExFreePool(RegistryHive->BlockList);
       ObDereferenceObject(RegistryHive->FileObject);
       RtlFreeUnicodeString(&RegistryHive->Filename);
+      DPRINT("CmiInitPermanentRegistryHive() - Failed 8.\n");
       return STATUS_INSUFFICIENT_RESOURCES;
     }
 
   FileOffset.u.HighPart = 0;
   FileOffset.u.LowPart = 4096;
 
-  Status = ZwReadFile(FileHandle,
-               0,
-    0,
-    0,
-    0,
-               (PVOID) RegistryHive->BlockList[0],
-               RegistryHive->FileSize - 4096,
-               &FileOffset,
-    0);
+  DPRINT("    Attempting to ZwReadFile(%d) for %d bytes into %p\n", FileHandle, RegistryHive->FileSize - 4096, (PVOID)RegistryHive->BlockList[0]);
+  Status = NtReadFile(FileHandle,
+                     0,
+                     0,
+                     0,
+                     &IoSB,
+                     (PVOID) RegistryHive->BlockList[0],
+                     RegistryHive->FileSize - 4096,
+                     &FileOffset,
+                     0);
 
   assertmsg(NT_SUCCESS(Status), ("Status: 0x%X\n", Status));
 
+  NtClose(FileHandle);
 #endif
 
   RegistryHive->FreeListSize = 0;
@@ -656,7 +719,8 @@ CmiInitPermanentRegistryHive(PREGISTRY_HIVE RegistryHive,
       if (tmpBin->BlockId != REG_BIN_ID)
        {
          DPRINT("Bad BlockId %x, offset %x\n", tmpBin->BlockId, BlockOffset);
-         KeBugCheck(0);
+         //KeBugCheck(0);
+         return STATUS_INSUFFICIENT_RESOURCES;
        }
 
       assertmsg((tmpBin->BlockSize % 4096) == 0, ("BlockSize (0x%.08x) must be multiplum of 4K\n", tmpBin->BlockSize));
@@ -697,7 +761,23 @@ CmiInitPermanentRegistryHive(PREGISTRY_HIVE RegistryHive,
       BlockOffset += tmpBin->BlockSize;
     }
 
-  return STATUS_SUCCESS;
+  /* Create block bitmap and clear all bits */
+
+  /* Calculate bitmap size in bytes (always a multiple of 32 bits) */
+  BitmapSize = ROUND_UP(RegistryHive->BlockListSize, sizeof(ULONG) * 8) / 8;
+  DPRINT1("RegistryHive->BlockListSize: %lu\n", RegistryHive->BlockListSize);
+  DPRINT1("BitmapSize:  %lu Bytes  %lu Bits\n", BitmapSize, BitmapSize * 8);
+  BitmapBuffer = (PULONG)ExAllocatePool(PagedPool,
+                                       BitmapSize);
+  RtlInitializeBitMap(&RegistryHive->DirtyBitMap,
+                     BitmapBuffer,
+                     BitmapSize * 8);
+  RtlClearAllBits(&RegistryHive->DirtyBitMap);
+  RegistryHive->HiveDirty = FALSE;
+
+  DPRINT1("CmiInitPermanentRegistryHive(%p, %S, %d) - Finished.\n", RegistryHive, Filename, CreateNew);
+
+  return(STATUS_SUCCESS);
 }
 
 
@@ -737,7 +817,7 @@ CmiCreateRegistryHive(PWSTR Filename,
 
   Hive = ExAllocatePool(NonPagedPool, sizeof(REGISTRY_HIVE));
   if (Hive == NULL)
-    return STATUS_INSUFFICIENT_RESOURCES;
+    return(STATUS_INSUFFICIENT_RESOURCES);
 
   DPRINT("Hive %x\n", Hive);
 
@@ -749,7 +829,7 @@ CmiCreateRegistryHive(PWSTR Filename,
   if (Hive->HiveHeader == NULL)
     {
       ExFreePool(Hive);
-      return STATUS_INSUFFICIENT_RESOURCES;
+      return(STATUS_INSUFFICIENT_RESOURCES);
     }
 
   if (Filename != NULL)
@@ -768,11 +848,156 @@ CmiCreateRegistryHive(PWSTR Filename,
       return(Status);
     }
 
-  KeInitializeSemaphore(&Hive->RegSem, 1, 1);
+  ExInitializeResourceLite(&Hive->HiveResource);
+
+  /* Acquire hive list lock exclusively */
+  ExAcquireResourceExclusiveLite(&CmiHiveListLock, TRUE);
+
+  /* Add the new hive to the hive list */
+  InsertHeadList(&CmiHiveListHead, &Hive->HiveList);
+
+  /* Release hive list lock */
+  ExReleaseResourceLite(&CmiHiveListLock);
+
   VERIFY_REGISTRY_HIVE(Hive);
 
   *RegistryHive = Hive;
 
+  DPRINT("CmiCreateRegistryHive(Filename %S) - Finished.\n", Filename);
+
+  return(STATUS_SUCCESS);
+}
+
+
+NTSTATUS
+CmiRemoveRegistryHive(PREGISTRY_HIVE RegistryHive)
+{
+  /* Acquire hive list lock exclusively */
+  ExAcquireResourceExclusiveLite(&CmiHiveListLock, TRUE);
+
+  /* Remove hive from hive list */
+  RemoveEntryList(&RegistryHive->HiveList);
+
+  /* Release hive list lock */
+  ExReleaseResourceLite(&CmiHiveListLock);
+
+
+  /* FIXME: Remove attached keys and values */
+
+
+  /* Release hive header */
+  ExFreePool(RegistryHive->HiveHeader);
+
+  /* Release hive */
+  ExFreePool(RegistryHive);
+
+  return(STATUS_SUCCESS);
+}
+
+
+NTSTATUS
+CmiFlushRegistryHive(PREGISTRY_HIVE RegistryHive)
+{
+  ULONG BlockIndex;
+  ULONG BlockOffset;
+  PVOID BlockPtr;
+  LARGE_INTEGER FileOffset;
+  OBJECT_ATTRIBUTES ObjectAttributes;
+  IO_STATUS_BLOCK IoStatusBlock;
+  HANDLE FileHandle;
+  NTSTATUS Status;
+
+
+
+
+  DPRINT("CmiFlushRegistryHive() called\n");
+
+  if (RegistryHive->HiveDirty == FALSE)
+    {
+      return(STATUS_SUCCESS);
+    }
+
+  DPRINT1("Hive '%wZ' is dirty\n", &RegistryHive->Filename);
+
+
+  /* Open hive for writing */
+  InitializeObjectAttributes(&ObjectAttributes,
+                            &RegistryHive->Filename,
+                            0,
+                            NULL,
+                            NULL);
+
+  Status = NtCreateFile(&FileHandle,
+                       FILE_ALL_ACCESS,
+                       &ObjectAttributes,
+                       &IoStatusBlock,
+                       NULL,
+                       FILE_ATTRIBUTE_NORMAL,
+                       0,
+                       FILE_OPEN,
+                       FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
+                       NULL,
+                       0);
+  if (!NT_SUCCESS(Status))
+    {
+      DPRINT1("NtCreateFile() failed (Status %lx)\n", Status);
+      return(Status);
+    }
+
+
+
+  BlockIndex = 0;
+  while (TRUE)
+    {
+      BlockIndex = RtlFindSetBitsAndClear(&RegistryHive->DirtyBitMap,
+                                         1,
+                                         BlockIndex);
+      if (BlockIndex == (ULONG)-1)
+       {
+         DPRINT("No more set bits\n");
+         break;
+       }
+
+      DPRINT1("Block %lu is dirty\n", BlockIndex);
+
+      BlockOffset = RegistryHive->BlockList[BlockIndex]->BlockOffset;
+      DPRINT1("Block offset %lx\n", BlockOffset);
+
+      BlockPtr = RegistryHive->BlockList[BlockIndex] + ((BlockIndex * 4096) - BlockOffset);
+      DPRINT1("BlockPtr %p\n", BlockPtr);
+
+      FileOffset.QuadPart = (ULONGLONG)(BlockIndex + 1) * 4096ULL;
+      DPRINT1("File offset %I64x\n", FileOffset.QuadPart);
+
+
+      /* Write hive block */
+      Status = NtWriteFile(FileHandle,
+                          NULL,
+                          NULL,
+                          NULL,
+                          &IoStatusBlock,
+                          BlockPtr,
+                          REG_BLOCK_SIZE,
+                          &FileOffset,
+                          NULL);
+      if (!NT_SUCCESS(Status))
+       {
+         DPRINT1("NtWriteFile() failed (Status %lx)\n", Status);
+         NtClose(FileHandle);
+         return(Status);
+       }
+
+
+    }
+
+  NtClose(FileHandle);
+
+
+  /* Clear dirty flag */
+  RegistryHive->HiveDirty = FALSE;
+
+  DPRINT("CmiFlushRegistryHive() done\n");
+
   return(STATUS_SUCCESS);
 }
 
@@ -898,7 +1123,7 @@ CmiGetMaxValueDataLength(PREGISTRY_HIVE RegistryHive,
 {
   PVALUE_LIST_CELL ValueListCell;
   PVALUE_CELL CurValueCell;
-  ULONG MaxValueData;
+  LONG MaxValueData;
   ULONG i;
 
   VERIFY_KEY_CELL(KeyCell);
@@ -944,7 +1169,7 @@ CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive,
 
   VERIFY_KEY_CELL(KeyCell);
 
-  DPRINT("Scanning for sub key %s\n", KeyName);
+  //DPRINT("Scanning for sub key %s\n", KeyName);
 
   assert(RegistryHive);
 
@@ -963,7 +1188,7 @@ CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive,
       if (Attributes & OBJ_CASE_INSENSITIVE)
         {
           if ((HashBlock->Table[i].KeyOffset != 0) &&
-              (HashBlock->Table[i].KeyOffset != -1) &&
+              (HashBlock->Table[i].KeyOffset != (ULONG_PTR)-1) &&
               (_strnicmp(KeyName, (PCHAR) &HashBlock->Table[i].HashValue, 4) == 0))
             {
               CurSubKeyCell = CmiGetBlock(RegistryHive, 
@@ -985,7 +1210,7 @@ CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive,
       else
         {
           if (HashBlock->Table[i].KeyOffset != 0 &&
-              HashBlock->Table[i].KeyOffset != -1 &&
+              HashBlock->Table[i].KeyOffset != (ULONG_PTR) -1 &&
               !strncmp(KeyName, (PCHAR) &HashBlock->Table[i].HashValue, 4))
             {
               CurSubKeyCell = CmiGetBlock(RegistryHive,
@@ -1013,13 +1238,13 @@ CmiScanForSubKey(IN PREGISTRY_HIVE RegistryHive,
 
 NTSTATUS
 CmiAddSubKey(PREGISTRY_HIVE RegistryHive,
-       PKEY_OBJECT Parent,
-       PKEY_OBJECT SubKey,
-       PWSTR NewSubKeyName,
-       USHORT NewSubKeyNameSize,
-       ULONG TitleIndex,
-       PUNICODE_STRING Class,
-       ULONG CreateOptions)
+            PKEY_OBJECT Parent,
+            PKEY_OBJECT SubKey,
+            PWSTR NewSubKeyName,
+            USHORT NewSubKeyNameSize,
+            ULONG TitleIndex,
+            PUNICODE_STRING Class,
+            ULONG CreateOptions)
 {
   PHASH_TABLE_CELL NewHashBlock;
   PHASH_TABLE_CELL HashBlock;
@@ -1057,33 +1282,33 @@ CmiAddSubKey(PREGISTRY_HIVE RegistryHive,
     }
   else
     {
-           NewKeyCell->Id = REG_KEY_CELL_ID;
-           NewKeyCell->Type = REG_KEY_CELL_TYPE;
-           ZwQuerySystemTime((PTIME) &NewKeyCell->LastWriteTime);
-           NewKeyCell->ParentKeyOffset = -1;
-           NewKeyCell->NumberOfSubKeys = 0;
-           NewKeyCell->HashTableOffset = -1;
-           NewKeyCell->NumberOfValues = 0;
-           NewKeyCell->ValuesOffset = -1;
-           NewKeyCell->SecurityKeyOffset = -1;
-           NewKeyCell->NameSize = NameSize;
-           wcstombs(NewKeyCell->Name, NewSubKeyName, NameSize);
-           NewKeyCell->ClassNameOffset = -1;
+      NewKeyCell->Id = REG_KEY_CELL_ID;
+      NewKeyCell->Type = REG_KEY_CELL_TYPE;
+      ZwQuerySystemTime((PTIME) &NewKeyCell->LastWriteTime);
+      NewKeyCell->ParentKeyOffset = -1;
+      NewKeyCell->NumberOfSubKeys = 0;
+      NewKeyCell->HashTableOffset = -1;
+      NewKeyCell->NumberOfValues = 0;
+      NewKeyCell->ValuesOffset = -1;
+      NewKeyCell->SecurityKeyOffset = -1;
+      NewKeyCell->NameSize = NameSize;
+      wcstombs(NewKeyCell->Name, NewSubKeyName, NameSize);
+      NewKeyCell->ClassNameOffset = -1;
 
       VERIFY_KEY_CELL(NewKeyCell);
 
-           if (Class)
-                   {
-                     PDATA_CELL pClass;
-
-                     NewKeyCell->ClassSize = Class->Length + sizeof(WCHAR);
-                     Status = CmiAllocateBlock(RegistryHive,
-                                         (PVOID) &pClass,
-                                         NewKeyCell->ClassSize,
-                                         &NewKeyCell->ClassNameOffset);
-                     wcsncpy((PWSTR) pClass->Data, Class->Buffer, Class->Length);
-                     ((PWSTR) (pClass->Data))[Class->Length] = 0;
-                   }
+      if (Class)
+       {
+         PDATA_CELL pClass;
+
+         NewKeyCell->ClassSize = Class->Length + sizeof(WCHAR);
+         Status = CmiAllocateBlock(RegistryHive,
+                                   (PVOID) &pClass,
+                                   NewKeyCell->ClassSize,
+                                   &NewKeyCell->ClassNameOffset);
+         wcsncpy((PWSTR) pClass->Data, Class->Buffer, Class->Length);
+         ((PWSTR) (pClass->Data))[Class->Length] = 0;
+       }
     }
 
   if (!NT_SUCCESS(Status))
@@ -1096,72 +1321,148 @@ CmiAddSubKey(PREGISTRY_HIVE RegistryHive,
 
   /* Don't modify hash table if key is volatile and parent is not */
   if (IsVolatileHive(RegistryHive) && (!IsVolatileHive(Parent->RegistryHive)))
-         {
-           return Status;
-         }
+    {
+      return(Status);
+    }
 
-  if (KeyCell->HashTableOffset == -1)
+  if (KeyCell->HashTableOffset == (ULONG_PTR) -1)
     {
       Status = CmiAllocateHashTableBlock(RegistryHive,
-        &HashBlock,
-                               &KeyCell->HashTableOffset,
-        REG_INIT_HASH_TABLE_SIZE);
-
+                                        &HashBlock,
+                                        &KeyCell->HashTableOffset,
+                                        REG_INIT_HASH_TABLE_SIZE);
       if (!NT_SUCCESS(Status))
-        {
-          return Status;
-        }
+       {
+         return(Status);
+       }
     }
   else
     {
       HashBlock = CmiGetBlock(RegistryHive, KeyCell->HashTableOffset, NULL);
       if (((KeyCell->NumberOfSubKeys + 1) >= HashBlock->HashTableSize))
-        {
-          BLOCK_OFFSET HTOffset;
-
-          /* Reallocate the hash table block */
-          Status = CmiAllocateHashTableBlock(RegistryHive,
-            &NewHashBlock,
-                                         &HTOffset,
-            HashBlock->HashTableSize +
-            REG_EXTEND_HASH_TABLE_SIZE);
-
-          if (!NT_SUCCESS(Status))
-            {
-              return Status;
-            }
+       {
+         BLOCK_OFFSET HTOffset;
+
+         /* Reallocate the hash table block */
+         Status = CmiAllocateHashTableBlock(RegistryHive,
+                                            &NewHashBlock,
+                                            &HTOffset,
+                                            HashBlock->HashTableSize +
+                                              REG_EXTEND_HASH_TABLE_SIZE);
+         if (!NT_SUCCESS(Status))
+           {
+             return Status;
+           }
 
-          RtlZeroMemory(&NewHashBlock->Table[0],
-            sizeof(NewHashBlock->Table[0]) * NewHashBlock->HashTableSize);
-          RtlCopyMemory(&NewHashBlock->Table[0],
-            &HashBlock->Table[0],
-            sizeof(NewHashBlock->Table[0]) * HashBlock->HashTableSize);
-          CmiDestroyBlock(RegistryHive, HashBlock, KeyCell->HashTableOffset);
-               KeyCell->HashTableOffset = HTOffset;
-          HashBlock = NewHashBlock;
-        }
+         RtlZeroMemory(&NewHashBlock->Table[0],
+                       sizeof(NewHashBlock->Table[0]) * NewHashBlock->HashTableSize);
+         RtlCopyMemory(&NewHashBlock->Table[0],
+                       &HashBlock->Table[0],
+                       sizeof(NewHashBlock->Table[0]) * HashBlock->HashTableSize);
+         CmiDestroyBlock(RegistryHive,
+                         HashBlock,
+                         KeyCell->HashTableOffset);
+         KeyCell->HashTableOffset = HTOffset;
+         HashBlock = NewHashBlock;
+       }
     }
 
-  Status = CmiAddKeyToHashTable(RegistryHive, HashBlock, NewKeyCell, NKBOffset);
+  Status = CmiAddKeyToHashTable(RegistryHive,
+                               HashBlock,
+                               NewKeyCell,
+                               NKBOffset);
   if (NT_SUCCESS(Status))
     {
       KeyCell->NumberOfSubKeys++;
     }
-  
-  return Status;
+
+  return(Status);
+}
+
+
+NTSTATUS
+CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive,
+               PKEY_OBJECT ParentKey,
+               PKEY_OBJECT SubKey)
+{
+  PHASH_TABLE_CELL HashBlock;
+
+  DPRINT1("CmiRemoveSubKey() called\n");
+
+  /* Remove the key from the parent key's hash block */
+  if (ParentKey->KeyCell->HashTableOffset != -1)
+    {
+      DPRINT1("ParentKey HashTableOffset %lx\n", ParentKey->KeyCell->HashTableOffset)
+      HashBlock = CmiGetBlock(RegistryHive,
+                             ParentKey->KeyCell->HashTableOffset,
+                             NULL);
+      DPRINT1("ParentKey HashBlock %p\n", HashBlock)
+      if (HashBlock != NULL)
+       {
+         CmiRemoveKeyFromHashTable(RegistryHive,
+                                   HashBlock,
+                                   SubKey->BlockOffset);
+         CmiMarkBlockDirty(RegistryHive,
+                           ParentKey->KeyCell->HashTableOffset);
+       }
+    }
+
+  /* Remove the key's hash block */
+  if (SubKey->KeyCell->HashTableOffset != -1)
+    {
+      DPRINT1("SubKey HashTableOffset %lx\n", SubKey->KeyCell->HashTableOffset)
+      HashBlock = CmiGetBlock(RegistryHive,
+                             SubKey->KeyCell->HashTableOffset,
+                             NULL);
+      DPRINT1("SubKey HashBlock %p\n", HashBlock)
+      if (HashBlock != NULL)
+       {
+         CmiDestroyBlock(RegistryHive,
+                         HashBlock,
+                         SubKey->KeyCell->HashTableOffset);
+         SubKey->KeyCell->HashTableOffset = -1;
+       }
+    }
+
+  /* Decrement the number of the parent key's sub keys */
+  if (ParentKey != NULL)
+    {
+      DPRINT1("ParentKey %p\n", ParentKey)
+      ParentKey->KeyCell->NumberOfSubKeys--;
+      NtQuerySystemTime((PTIME)&ParentKey->KeyCell->LastWriteTime);
+      CmiMarkBlockDirty(RegistryHive,
+                       ParentKey->BlockOffset);
+
+      /* Remove the parent key's hash table */
+      if (ParentKey->KeyCell->NumberOfSubKeys == 0)
+       {
+         DPRINT1("FIXME: Remove parent key hash table\n")
+
+       }
+    }
+
+  /* Destroy key cell */
+  CmiDestroyBlock(RegistryHive,
+                 SubKey->KeyCell,
+                 SubKey->BlockOffset);
+  SubKey->BlockOffset = -1;
+  SubKey->KeyCell = NULL;
+
+  /* FIXME: Merge free blocks within the Bin */
+
+  return(STATUS_SUCCESS);
 }
 
 
 NTSTATUS
 CmiScanKeyForValue(IN PREGISTRY_HIVE RegistryHive,
        IN PKEY_CELL KeyCell,
-       IN PCHAR ValueName,
+       IN PUNICODE_STRING ValueName,
        OUT PVALUE_CELL *ValueCell,
        OUT BLOCK_OFFSET *VBOffset)
 {
   PVALUE_LIST_CELL ValueListCell;
   PVALUE_CELL CurValueCell;
-  ULONG Length;
   ULONG i;
 
   ValueListCell = CmiGetBlock(RegistryHive, KeyCell->ValuesOffset, NULL);
@@ -1179,26 +1480,26 @@ CmiScanKeyForValue(IN PREGISTRY_HIVE RegistryHive,
   for (i = 0; i < KeyCell->NumberOfValues; i++)
     {
       CurValueCell = CmiGetBlock(RegistryHive,
-        ValueListCell->Values[i],
-        NULL);
-      /* FIXME: perhaps we must not ignore case if NtCreateKey has not been */
-      /*        called with OBJ_CASE_INSENSITIVE flag ? */
-      Length = strlen(ValueName);
+                                ValueListCell->Values[i],
+                                NULL);
+
       if ((CurValueCell != NULL) &&
-          (CurValueCell->NameSize == Length) &&
-          (_strnicmp(CurValueCell->Name, ValueName, Length) == 0))
+         CmiComparePackedNames(ValueName,
+                               CurValueCell->Name,
+                               CurValueCell->NameSize,
+                               CurValueCell->Flags & REG_VALUE_NAME_PACKED))
         {
           *ValueCell = CurValueCell;
-               if (VBOffset)
+          if (VBOffset)
             *VBOffset = ValueListCell->Values[i];
-          DPRINT("Found value %s\n", ValueName);
+          //DPRINT("Found value %s\n", ValueName);
           break;
         }
       CmiReleaseBlock(RegistryHive, CurValueCell);
     }
 
   CmiReleaseBlock(RegistryHive, ValueListCell);
-  
+
   return STATUS_SUCCESS;
 }
 
@@ -1211,7 +1512,7 @@ CmiGetValueFromKeyByIndex(IN PREGISTRY_HIVE RegistryHive,
 {
   PVALUE_LIST_CELL ValueListCell;
   PVALUE_CELL CurValueCell;
+
   ValueListCell = CmiGetBlock(RegistryHive, KeyCell->ValuesOffset, NULL);
 
   *ValueCell = NULL;
@@ -1239,7 +1540,7 @@ CmiGetValueFromKeyByIndex(IN PREGISTRY_HIVE RegistryHive,
 
   CmiReleaseBlock(RegistryHive, CurValueCell);
   CmiReleaseBlock(RegistryHive, ValueListCell);
-  
+
   return STATUS_SUCCESS;
 }
 
@@ -1247,7 +1548,7 @@ CmiGetValueFromKeyByIndex(IN PREGISTRY_HIVE RegistryHive,
 NTSTATUS
 CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive,
        IN PKEY_CELL KeyCell,
-       IN PCHAR ValueNameBuf,
+       IN PUNICODE_STRING ValueName,
        OUT PVALUE_CELL *pValueCell,
        OUT BLOCK_OFFSET *pVBOffset)
 {
@@ -1261,7 +1562,7 @@ CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive,
   Status = CmiAllocateValueCell(RegistryHive,
                &NewValueCell,
                &VBOffset,
-               ValueNameBuf);
+               ValueName);
   *pVBOffset = VBOffset;
 
   if (!NT_SUCCESS(Status))
@@ -1286,7 +1587,7 @@ CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive,
       KeyCell->ValuesOffset = VLBOffset;
     }
   else if ((KeyCell->NumberOfValues
-               >= ((LONG) (ValueListCell->CellSize - 4)) / (LONG) sizeof(BLOCK_OFFSET)))
+               >= (ULONG) ((LONG) (ValueListCell->CellSize - 4)) / (LONG) sizeof(BLOCK_OFFSET)))
     {
       Status = CmiAllocateBlock(RegistryHive,
              (PVOID) &NewValueListCell,
@@ -1325,7 +1626,8 @@ CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive,
 NTSTATUS
 CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive,
                      IN PKEY_CELL KeyCell,
-                     IN PCHAR ValueName)
+                     IN BLOCK_OFFSET KeyCellOffset,
+                     IN PUNICODE_STRING ValueName)
 {
   PVALUE_LIST_CELL ValueListCell;
   PVALUE_CELL CurValueCell;
@@ -1343,9 +1645,12 @@ CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive,
   for (i = 0; i < KeyCell->NumberOfValues; i++)
     {
       CurValueCell = CmiGetBlock(RegistryHive, ValueListCell->Values[i], NULL);
+
       if ((CurValueCell != NULL) &&
-          (CurValueCell->NameSize == strlen(ValueName)) &&
-          (memcmp(CurValueCell->Name, ValueName, strlen(ValueName)) == 0))
+         CmiComparePackedNames(ValueName,
+                               CurValueCell->Name,
+                               CurValueCell->NameSize,
+                               CurValueCell->Flags & REG_VALUE_NAME_PACKED))
         {
           if ((KeyCell->NumberOfValues - 1) < i)
             {
@@ -1367,6 +1672,21 @@ CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive,
 
   CmiReleaseBlock(RegistryHive, ValueListCell);
 
+  if (KeyCell->NumberOfValues == 0)
+    {
+      CmiDestroyBlock(RegistryHive,
+                     ValueListCell,
+                     KeyCell->ValuesOffset);
+    }
+  else
+    {
+      CmiMarkBlockDirty(RegistryHive,
+                       KeyCell->ValuesOffset);
+    }
+
+  CmiMarkBlockDirty(RegistryHive,
+                   KeyCellOffset);
+
   return STATUS_SUCCESS;
 }
 
@@ -1386,9 +1706,9 @@ CmiAllocateHashTableBlock(IN PREGISTRY_HIVE RegistryHive,
   NewHashSize = sizeof(HASH_TABLE_CELL) + 
     (HashTableSize - 1) * sizeof(HASH_RECORD);
   Status = CmiAllocateBlock(RegistryHive,
-               (PVOID*) &NewHashBlock,
-               NewHashSize,
-    HBOffset);
+                           (PVOID*) &NewHashBlock,
+                           NewHashSize,
+                           HBOffset);
 
   if ((NewHashBlock == NULL) || (!NT_SUCCESS(Status)))
     {
@@ -1454,23 +1774,49 @@ CmiAddKeyToHashTable(PREGISTRY_HIVE RegistryHive,
 
 
 NTSTATUS
+CmiRemoveKeyFromHashTable(PREGISTRY_HIVE RegistryHive,
+                         PHASH_TABLE_CELL HashBlock,
+                         BLOCK_OFFSET NKBOffset)
+{
+  ULONG i;
+
+  for (i = 0; i < HashBlock->HashTableSize; i++)
+    {
+      if (HashBlock->Table[i].KeyOffset == NKBOffset)
+       {
+         HashBlock->Table[i].KeyOffset = 0;
+         RtlZeroMemory(&HashBlock->Table[i].HashValue, 4);
+         return STATUS_SUCCESS;
+       }
+    }
+
+  return STATUS_UNSUCCESSFUL;
+}
+
+
+NTSTATUS
 CmiAllocateValueCell(PREGISTRY_HIVE RegistryHive,
   PVALUE_CELL *ValueCell,
   BLOCK_OFFSET *VBOffset,
-  IN PCHAR ValueNameBuf)
+  IN PUNICODE_STRING ValueName)
 {
   PVALUE_CELL NewValueCell;
-  ULONG NewValueSize;
   NTSTATUS Status;
+  BOOLEAN Packable;
+  ULONG NameSize;
+  ULONG i;
 
   Status = STATUS_SUCCESS;
 
-  NewValueSize = sizeof(VALUE_CELL) + strlen(ValueNameBuf);
-  Status = CmiAllocateBlock(RegistryHive,
-    (PVOID*) &NewValueCell,
-    NewValueSize,
-    VBOffset);
+  NameSize = CmiGetPackedNameLength(ValueName,
+                                   &Packable);
+
+  DPRINT("ValueName->Length %lu  NameSize %lu\n", ValueName->Length, NameSize);
 
+  Status = CmiAllocateBlock(RegistryHive,
+                           (PVOID*) &NewValueCell,
+                           sizeof(VALUE_CELL) + NameSize,
+                           VBOffset);
   if ((NewValueCell == NULL) || (!NT_SUCCESS(Status)))
     {
       Status = STATUS_INSUFFICIENT_RESOURCES;
@@ -1478,8 +1824,22 @@ CmiAllocateValueCell(PREGISTRY_HIVE RegistryHive,
   else
     {
       NewValueCell->Id = REG_VALUE_CELL_ID;
-      NewValueCell->NameSize = strlen(ValueNameBuf);
-      memcpy(NewValueCell->Name, ValueNameBuf, strlen(ValueNameBuf));
+      NewValueCell->NameSize = NameSize;
+      if (Packable)
+       {
+         /* Pack the value name */
+         for (i = 0; i < NameSize; i++)
+           NewValueCell->Name[i] = (CHAR)ValueName->Buffer[i];
+         NewValueCell->Flags |= REG_VALUE_NAME_PACKED;
+       }
+      else
+       {
+         /* Copy the value name */
+         RtlCopyMemory(NewValueCell->Name,
+                       ValueName->Buffer,
+                       NameSize);
+         NewValueCell->Flags = 0;
+       }
       NewValueCell->DataType = 0;
       NewValueCell->DataSize = 0;
       NewValueCell->DataOffset = 0xffffffff;
@@ -1501,8 +1861,8 @@ CmiDestroyValueCell(PREGISTRY_HIVE RegistryHive,
 
   VERIFY_VALUE_CELL(ValueCell);
 
-  /* First, release datas: */
-  if (ValueCell->DataSize > 0)
+  /* First, release data: */
+  if (ValueCell->DataSize > 4)
     {
       pBlock = CmiGetBlock(RegistryHive, ValueCell->DataOffset, &pBin);
       Status = CmiDestroyBlock(RegistryHive, pBlock, ValueCell->DataOffset);
@@ -1574,6 +1934,17 @@ CmiAddBin(PREGISTRY_HIVE RegistryHive,
   /* Initialize a free block in this heap : */
   tmpBlock = (PCELL_HEADER)((ULONG_PTR) tmpBin + REG_HBIN_DATA_OFFSET);
   tmpBlock->CellSize = (REG_BLOCK_SIZE - REG_HBIN_DATA_OFFSET);
+
+  /* Grow bitmap if necessary */
+  if (IsVolatileHive(RegistryHive) &&
+      (RegistryHive->BlockListSize % (sizeof(ULONG) * 8) == 0))
+    {
+      DPRINT1("Grow hive bitmap - BlockListSize %lu\n", RegistryHive->BlockListSize);
+
+      /* FIXME */
+
+    }
+
   *NewBlock = (PVOID) tmpBlock;
 
   if (NewBlockOffset)
@@ -1587,9 +1958,9 @@ CmiAddBin(PREGISTRY_HIVE RegistryHive,
 
 NTSTATUS
 CmiAllocateBlock(PREGISTRY_HIVE RegistryHive,
-       PVOID *Block,
-       LONG BlockSize,
-  BLOCK_OFFSET * pBlockOffset)
+                PVOID *Block,
+                LONG BlockSize,
+                BLOCK_OFFSET * pBlockOffset)
 {
   PCELL_HEADER NewBlock;
   NTSTATUS Status;
@@ -1605,86 +1976,92 @@ CmiAllocateBlock(PREGISTRY_HIVE RegistryHive,
     {
       NewBlock = ExAllocatePool(NonPagedPool, BlockSize);
 
-           if (NewBlock == NULL)
-                   {
-                     Status = STATUS_INSUFFICIENT_RESOURCES;
-                   }
-           else
-                   {
-                     RtlZeroMemory(NewBlock, BlockSize);
-                     NewBlock->CellSize = BlockSize;
-                     CmiLockBlock(RegistryHive, NewBlock);
-                     *Block = NewBlock;
-                     if (pBlockOffset)
-            *pBlockOffset = (BLOCK_OFFSET) NewBlock;
-                   }
+      if (NewBlock == NULL)
+       {
+         Status = STATUS_INSUFFICIENT_RESOURCES;
+       }
+      else
+       {
+         RtlZeroMemory(NewBlock, BlockSize);
+         NewBlock->CellSize = BlockSize;
+         CmiLockBlock(RegistryHive, NewBlock);
+         *Block = NewBlock;
+         if (pBlockOffset)
+           *pBlockOffset = (BLOCK_OFFSET) NewBlock;
+       }
     }
   else
     {
-           ULONG i;
-
-           /* first search in free blocks */
-           NewBlock = NULL;
-           for (i = 0; i < RegistryHive->FreeListSize; i++)
-                   {
-                     if (RegistryHive->FreeList[i]->CellSize >= BlockSize)
-                             {
-              PVOID Temp;
-                                                       NewBlock = RegistryHive->FreeList[i];
-
-                                                       if (pBlockOffset)
-                                       *pBlockOffset = RegistryHive->FreeListOffset[i];
-
-                                /* Update time of heap */
-               Temp = CmiGetBlock(RegistryHive, RegistryHive->FreeListOffset[i], &pBin);
-
-                                if (Temp)
-                                  ZwQuerySystemTime((PTIME) &pBin->DateModified);
-
-                                if ((i + 1) < RegistryHive->FreeListSize)
-                 {
-                                    RtlMoveMemory(&RegistryHive->FreeList[i],
-                     &RegistryHive->FreeList[i + 1],
-                                            sizeof(RegistryHive->FreeList[0])
-                       * (RegistryHive->FreeListSize - i - 1));
-                                    RtlMoveMemory(&RegistryHive->FreeListOffset[i],
-                                            &RegistryHive->FreeListOffset[i + 1],
-                                            sizeof(RegistryHive->FreeListOffset[0])
-                       * (RegistryHive->FreeListSize - i - 1));
-                 }
-                                RegistryHive->FreeListSize--;
-                                break;
-                             }
-                   }
-
-           /* Need to extend hive file : */
-           if (NewBlock == NULL)
-                   {
-                     /* Add a new block */
-                     Status = CmiAddBin(RegistryHive, (PVOID *) &NewBlock , pBlockOffset);
-                   }
-
-           if (NT_SUCCESS(Status))
-                   {
-                     *Block = NewBlock;
-
-                     /* Split the block in two parts */
-                     if (NewBlock->CellSize > BlockSize)
-                             {
-                                                       NewBlock = (PCELL_HEADER) ((ULONG_PTR) NewBlock+BlockSize);
-                                                       NewBlock->CellSize = ((PCELL_HEADER) (*Block))->CellSize - BlockSize;
-                                                       CmiAddFree(RegistryHive, NewBlock, *pBlockOffset + BlockSize);
-                             }
-                     else if (NewBlock->CellSize < BlockSize)
-            {
-                               return STATUS_UNSUCCESSFUL;
-            }
-                     RtlZeroMemory(*Block, BlockSize);
-                     ((PCELL_HEADER) (*Block))->CellSize = -BlockSize;
-                     CmiLockBlock(RegistryHive, *Block);
-                   }
-         }
-  return  Status;
+      ULONG i;
+
+      /* first search in free blocks */
+      NewBlock = NULL;
+      for (i = 0; i < RegistryHive->FreeListSize; i++)
+       {
+         if (RegistryHive->FreeList[i]->CellSize >= BlockSize)
+           {
+             PVOID Temp;
+
+             NewBlock = RegistryHive->FreeList[i];
+             if (pBlockOffset)
+               *pBlockOffset = RegistryHive->FreeListOffset[i];
+
+             /* Update time of heap */
+             Temp = CmiGetBlock(RegistryHive, RegistryHive->FreeListOffset[i], &pBin);
+
+             if (Temp)
+               {
+                 ZwQuerySystemTime((PTIME) &pBin->DateModified);
+                 CmiMarkBlockDirty(RegistryHive, RegistryHive->FreeListOffset[i]);
+               }
+
+             if ((i + 1) < RegistryHive->FreeListSize)
+               {
+                 RtlMoveMemory(&RegistryHive->FreeList[i],
+                               &RegistryHive->FreeList[i + 1],
+                               sizeof(RegistryHive->FreeList[0])
+                                 * (RegistryHive->FreeListSize - i - 1));
+                 RtlMoveMemory(&RegistryHive->FreeListOffset[i],
+                               &RegistryHive->FreeListOffset[i + 1],
+                               sizeof(RegistryHive->FreeListOffset[0])
+                                 * (RegistryHive->FreeListSize - i - 1));
+               }
+             RegistryHive->FreeListSize--;
+             break;
+           }
+       }
+
+      /* Need to extend hive file : */
+      if (NewBlock == NULL)
+       {
+         /* Add a new block */
+         Status = CmiAddBin(RegistryHive, (PVOID *) &NewBlock , pBlockOffset);
+       }
+
+      if (NT_SUCCESS(Status))
+       {
+         *Block = NewBlock;
+
+         /* Split the block in two parts */
+         if (NewBlock->CellSize > BlockSize)
+           {
+             NewBlock = (PCELL_HEADER) ((ULONG_PTR) NewBlock+BlockSize);
+             NewBlock->CellSize = ((PCELL_HEADER) (*Block))->CellSize - BlockSize;
+             CmiAddFree(RegistryHive, NewBlock, *pBlockOffset + BlockSize);
+             CmiMarkBlockDirty(RegistryHive, *pBlockOffset + BlockSize);
+           }
+         else if (NewBlock->CellSize < BlockSize)
+           {
+             return(STATUS_UNSUCCESSFUL);
+           }
+
+         RtlZeroMemory(*Block, BlockSize);
+         ((PCELL_HEADER) (*Block))->CellSize = -BlockSize;
+         CmiLockBlock(RegistryHive, *Block);
+       }
+    }
+
+  return(Status);
 }
 
 
@@ -1699,27 +2076,33 @@ CmiDestroyBlock(PREGISTRY_HIVE RegistryHive,
   Status = STATUS_SUCCESS;
 
   if (IsVolatileHive(RegistryHive))
-         {
-           CmiReleaseBlock(RegistryHive, Block);
-           ExFreePool(Block);
-         }
+    {
+      CmiReleaseBlock(RegistryHive, Block);
+      ExFreePool(Block);
+    }
   else
-         {
-           PCELL_HEADER pFree = Block;
+    {
+      PCELL_HEADER pFree = Block;
 
-           if (pFree->CellSize < 0)
-             pFree->CellSize = -pFree->CellSize;
+      if (pFree->CellSize < 0)
+        pFree->CellSize = -pFree->CellSize;
 
-           CmiAddFree(RegistryHive, Block, Offset);
-           CmiReleaseBlock(RegistryHive, Block);
+      /* Clear block (except the block size) */
+      RtlZeroMemory(((PVOID)pFree) + sizeof(ULONG),
+                   pFree->CellSize - sizeof(ULONG));
 
-           /* Update time of heap */
-           if (IsPermanentHive(RegistryHive) && CmiGetBlock(RegistryHive, Offset,&pBin))
-             ZwQuerySystemTime((PTIME) &pBin->DateModified);
+      CmiAddFree(RegistryHive, Block, Offset);
+      CmiReleaseBlock(RegistryHive, Block);
 
-             /* FIXME: Set first dword to block_offset of another free block ? */
-             /* FIXME: Concatenate with previous and next block if free */
-         }
+      /* Update time of heap */
+      if (IsPermanentHive(RegistryHive) && CmiGetBlock(RegistryHive, Offset,&pBin))
+       ZwQuerySystemTime((PTIME) &pBin->DateModified);
+
+      CmiMarkBlockDirty(RegistryHive, Offset);
+
+      /* FIXME: Set first dword to block_offset of another free block ? */
+      /* FIXME: Concatenate with previous and next block if free */
+    }
 
   return Status;
 }
@@ -1743,98 +2126,100 @@ CmiAddFree(PREGISTRY_HIVE RegistryHive,
     FreeBlock, FreeOffset);
 DPRINT("\n");
   if ((RegistryHive->FreeListSize + 1) > RegistryHive->FreeListMax)
-         {
+    {
 DPRINT("\n");
-           tmpList = ExAllocatePool(PagedPool,
+      tmpList = ExAllocatePool(PagedPool,
                          sizeof(PCELL_HEADER) * (RegistryHive->FreeListMax + 32));
 DPRINT("\n");
 
-           if (tmpList == NULL)
-        return STATUS_INSUFFICIENT_RESOURCES;
+      if (tmpList == NULL)
+       return STATUS_INSUFFICIENT_RESOURCES;
 DPRINT("\n");
 
-           tmpListOffset = ExAllocatePool(PagedPool,
+      tmpListOffset = ExAllocatePool(PagedPool,
                          sizeof(BLOCK_OFFSET *) * (RegistryHive->FreeListMax + 32));
 DPRINT("\n");
 
-           if (tmpListOffset == NULL)
-        {
-          ExFreePool(tmpList);
-          return STATUS_INSUFFICIENT_RESOURCES;
-        }
+      if (tmpListOffset == NULL)
+       {
+         ExFreePool(tmpList);
+         return STATUS_INSUFFICIENT_RESOURCES;
+       }
 DPRINT("\n");
 
-           if (RegistryHive->FreeListMax)
-           {
+      if (RegistryHive->FreeListMax)
+       {
 DPRINT("\n");
-        RtlMoveMemory(tmpList, RegistryHive->FreeList,
-          sizeof(PCELL_HEADER) * (RegistryHive->FreeListMax));
+         RtlMoveMemory(tmpList,
+                       RegistryHive->FreeList,
+                       sizeof(PCELL_HEADER) * (RegistryHive->FreeListMax));
 DPRINT("\n");
-        RtlMoveMemory(tmpListOffset, RegistryHive->FreeListOffset,
-          sizeof(BLOCK_OFFSET *) * (RegistryHive->FreeListMax));
+         RtlMoveMemory(tmpListOffset,
+                       RegistryHive->FreeListOffset,
+                       sizeof(BLOCK_OFFSET *) * (RegistryHive->FreeListMax));
 DPRINT("\n");
-                   ExFreePool(RegistryHive->FreeList);
+         ExFreePool(RegistryHive->FreeList);
 DPRINT("\n");
-                   ExFreePool(RegistryHive->FreeListOffset);
+         ExFreePool(RegistryHive->FreeListOffset);
 DPRINT("\n");
-      }
+       }
 DPRINT("\n");
-           RegistryHive->FreeList = tmpList;
-           RegistryHive->FreeListOffset = tmpListOffset;
-           RegistryHive->FreeListMax += 32;
+      RegistryHive->FreeList = tmpList;
+      RegistryHive->FreeListOffset = tmpListOffset;
+      RegistryHive->FreeListMax += 32;
 DPRINT("\n");
-         }
+    }
 DPRINT("\n");
 
-         /* Add new offset to free list, maintaining list in ascending order */
-         if ((RegistryHive->FreeListSize == 0)
-            || (RegistryHive->FreeListOffset[RegistryHive->FreeListSize-1] < FreeOffset))
-                 {
+  /* Add new offset to free list, maintaining list in ascending order */
+  if ((RegistryHive->FreeListSize == 0)
+     || (RegistryHive->FreeListOffset[RegistryHive->FreeListSize-1] < FreeOffset))
+    {
+DPRINT("\n");
+      /* Add to end of list */
+      RegistryHive->FreeList[RegistryHive->FreeListSize] = FreeBlock;
+      RegistryHive->FreeListOffset[RegistryHive->FreeListSize++] = FreeOffset;
+    }
+  else if (RegistryHive->FreeListOffset[0] > FreeOffset)
+    {
 DPRINT("\n");
-                   /* Add to end of list */
-                   RegistryHive->FreeList[RegistryHive->FreeListSize] = FreeBlock;
-                   RegistryHive->FreeListOffset[RegistryHive->FreeListSize++] = FreeOffset;
-                 }
-         else if (RegistryHive->FreeListOffset[0] > FreeOffset)
-                 {
+      /* Add to begin of list */
+      RtlMoveMemory(&RegistryHive->FreeList[1],
+                   &RegistryHive->FreeList[0],
+                   sizeof(RegistryHive->FreeList[0]) * RegistryHive->FreeListSize);
+      RtlMoveMemory(&RegistryHive->FreeListOffset[1],
+                   &RegistryHive->FreeListOffset[0],
+                   sizeof(RegistryHive->FreeListOffset[0]) * RegistryHive->FreeListSize);
+      RegistryHive->FreeList[0] = FreeBlock;
+      RegistryHive->FreeListOffset[0] = FreeOffset;
+      RegistryHive->FreeListSize++;
+    }
+  else
+    {
 DPRINT("\n");
-                   /* Add to begin of list */
-                   RtlMoveMemory(&RegistryHive->FreeList[1],
-          &RegistryHive->FreeList[0],
-                           sizeof(RegistryHive->FreeList[0]) * RegistryHive->FreeListSize);
-                   RtlMoveMemory(&RegistryHive->FreeListOffset[1],
-          &RegistryHive->FreeListOffset[0],
-                           sizeof(RegistryHive->FreeListOffset[0]) * RegistryHive->FreeListSize);
-                   RegistryHive->FreeList[0] = FreeBlock;
-                   RegistryHive->FreeListOffset[0] = FreeOffset;
-                   RegistryHive->FreeListSize++;
-                 }
+      /* Search where to insert */
+      minInd = 0;
+      maxInd = RegistryHive->FreeListSize - 1;
+      while ((maxInd - minInd) > 1)
+       {
+         medInd = (minInd + maxInd) / 2;
+         if (RegistryHive->FreeListOffset[medInd] > FreeOffset)
+           maxInd = medInd;
          else
-         {
-DPRINT("\n");
-           /* Search where to insert */
-           minInd = 0;
-           maxInd = RegistryHive->FreeListSize - 1;
-           while ((maxInd - minInd) > 1)
-                   {
-                     medInd = (minInd + maxInd) / 2;
-                     if (RegistryHive->FreeListOffset[medInd] > FreeOffset)
-                       maxInd = medInd;
-                     else
-                       minInd = medInd;
-                   }
-
-           /* Insert before maxInd */
-           RtlMoveMemory(&RegistryHive->FreeList[maxInd+1],
-        &RegistryHive->FreeList[maxInd],
+           minInd = medInd;
+       }
+
+      /* Insert before maxInd */
+      RtlMoveMemory(&RegistryHive->FreeList[maxInd+1],
+                   &RegistryHive->FreeList[maxInd],
                    sizeof(RegistryHive->FreeList[0]) * (RegistryHive->FreeListSize - minInd));
-           RtlMoveMemory(&RegistryHive->FreeListOffset[maxInd + 1],
+      RtlMoveMemory(&RegistryHive->FreeListOffset[maxInd + 1],
                    &RegistryHive->FreeListOffset[maxInd],
                    sizeof(RegistryHive->FreeListOffset[0]) * (RegistryHive->FreeListSize-minInd));
-           RegistryHive->FreeList[maxInd] = FreeBlock;
-           RegistryHive->FreeListOffset[maxInd] = FreeOffset;
-           RegistryHive->FreeListSize++;
-         }
+      RegistryHive->FreeList[maxInd] = FreeBlock;
+      RegistryHive->FreeListOffset[maxInd] = FreeOffset;
+      RegistryHive->FreeListSize++;
+    }
 DPRINT("\n");
 
   return STATUS_SUCCESS;
@@ -1843,13 +2228,13 @@ DPRINT("\n");
 
 PVOID
 CmiGetBlock(PREGISTRY_HIVE RegistryHive,
-       BLOCK_OFFSET BlockOffset,
-       PHBIN * ppBin)
+           BLOCK_OFFSET BlockOffset,
+           PHBIN * ppBin)
 {
   if (ppBin)
     *ppBin = NULL;
 
-  if ((BlockOffset == 0) || (BlockOffset == -1))
+  if ((BlockOffset == 0) || (BlockOffset == (ULONG_PTR) -1))
     return NULL;
 
   if (IsVolatileHive(RegistryHive))
@@ -1869,24 +2254,19 @@ CmiGetBlock(PREGISTRY_HIVE RegistryHive,
 
 
 VOID
-CmiPrepareForWrite(PREGISTRY_HIVE RegistryHive,
-  PHBIN pBin)
+CmiLockBlock(PREGISTRY_HIVE RegistryHive,
+            PVOID Block)
 {
-  if (IsVolatileHive(RegistryHive))
-    {
-      /* No need to do anything special for volatile hives */
-      return;
-    }
-  else
+  if (IsPermanentHive(RegistryHive))
     {
-      
+      /* FIXME: Implement */
     }
 }
 
 
 VOID
-CmiLockBlock(PREGISTRY_HIVE RegistryHive,
-  PVOID Block)
+CmiReleaseBlock(PREGISTRY_HIVE RegistryHive,
+               PVOID Block)
 {
   if (IsPermanentHive(RegistryHive))
     {
@@ -1896,11 +2276,96 @@ CmiLockBlock(PREGISTRY_HIVE RegistryHive,
 
 
 VOID
-CmiReleaseBlock(PREGISTRY_HIVE RegistryHive,
-  PVOID Block)
+CmiMarkBlockDirty(PREGISTRY_HIVE RegistryHive,
+                 BLOCK_OFFSET BlockOffset)
 {
-  if (IsPermanentHive(RegistryHive))
+  ULONG Index;
+
+  if (IsVolatileHive(RegistryHive))
+      return;
+
+  Index = (ULONG)BlockOffset / 4096;
+
+  DPRINT1("CmiMarkBlockDirty(Offset 0x%lx)  Index %lu\n",
+         (ULONG)BlockOffset, Index);
+
+  RegistryHive->HiveDirty = TRUE;
+  RtlSetBits(&RegistryHive->DirtyBitMap,
+            Index,
+            1);
+}
+
+
+ULONG
+CmiGetPackedNameLength(IN PUNICODE_STRING Name,
+                      OUT PBOOLEAN Packable)
+{
+  ULONG i;
+
+  if (Packable != NULL)
+    *Packable = TRUE;
+
+  for (i = 0; i < Name->Length; i++)
     {
-      /* FIXME: Implement */
+      if (Name->Buffer[i] > 0xFF)
+       {
+         if (Packable != NULL)
+           *Packable = FALSE;
+         return(Name->Length);
+       }
+    }
+
+  return(Name->Length / sizeof(WCHAR));
+}
+
+
+BOOLEAN
+CmiComparePackedNames(IN PUNICODE_STRING Name,
+                     IN PCHAR NameBuffer,
+                     IN USHORT NameBufferSize,
+                     IN BOOLEAN NamePacked)
+{
+  PWCHAR UNameBuffer;
+  ULONG i;
+
+  if (NamePacked == TRUE)
+    {
+      if (Name->Length != NameBufferSize * sizeof(WCHAR))
+       return(FALSE);
+
+      for (i = 0; i < Name->Length / sizeof(WCHAR); i++)
+       {
+         if (RtlUpcaseUnicodeChar(Name->Buffer[i]) != RtlUpcaseUnicodeChar((WCHAR)NameBuffer[i]))
+           return(FALSE);
+       }
+    }
+  else
+    {
+      if (Name->Length != NameBufferSize)
+       return(FALSE);
+
+      UNameBuffer = (PWCHAR)NameBuffer;
+
+      for (i = 0; i < Name->Length / sizeof(WCHAR); i++)
+       {
+         if (RtlUpcaseUnicodeChar(Name->Buffer[i]) != RtlUpcaseUnicodeChar(UNameBuffer[i]))
+           return(FALSE);
+       }
     }
+
+  return(TRUE);
 }
+
+
+VOID
+CmiCopyPackedName(PWCHAR NameBuffer,
+                 PCHAR PackedNameBuffer,
+                 ULONG PackedNameSize)
+{
+  ULONG i;
+
+  for (i = 0; i < PackedNameSize; i++)
+    NameBuffer[i] = (WCHAR)PackedNameBuffer[i];
+}
+
+/* EOF */