- CmiAddValueToKey(): Double the size of the value list cell when it is completely...
[reactos.git] / reactos / ntoskrnl / cm / regfile.c
index acd33a7..bebaf3b 100644 (file)
@@ -6,13 +6,7 @@
  * UPDATE HISTORY:
 */
 
-#include <ddk/ntddk.h>
-#include <string.h>
-#include <roscfg.h>
-#include <internal/ob.h>
-#include <ntos/minmax.h>
-#include <reactos/bugcodes.h>
-
+#include <ntoskrnl.h>
 #define NDEBUG
 #include <internal/debug.h>
 
@@ -58,14 +52,14 @@ CmiCreateDefaultHiveHeader(PHIVE_HEADER Header)
 
 
 VOID
-CmiCreateDefaultBinCell(PHBIN BinCell)
+CmiCreateDefaultBinHeader(PHBIN BinHeader)
 {
-  assert(BinCell);
-  RtlZeroMemory(BinCell, sizeof(HBIN));
-  BinCell->BlockId = REG_BIN_ID;
-  BinCell->DateModified.u.LowPart = 0;
-  BinCell->DateModified.u.HighPart = 0;
-  BinCell->BlockSize = REG_BLOCK_SIZE;
+  assert(BinHeader);
+  RtlZeroMemory(BinHeader, sizeof(HBIN));
+  BinHeader->HeaderId = REG_BIN_ID;
+  BinHeader->DateModified.u.LowPart = 0;
+  BinHeader->DateModified.u.HighPart = 0;
+  BinHeader->BinSize = REG_BLOCK_SIZE;
 }
 
 
@@ -91,30 +85,30 @@ CmiCreateDefaultRootKeyCell(PKEY_CELL RootKeyCell)
 
 
 VOID
-CmiVerifyBinCell(PHBIN BinCell)
+CmiVerifyBinHeader(PHBIN BinHeader)
 {
   if (CmiDoVerify)
     {
 
-  assert(BinCell);
+  assert(BinHeader);
 
-  if (BinCell->BlockId != REG_BIN_ID)
+  if (BinHeader->HeaderId != REG_BIN_ID)
     {
-      DbgPrint("BlockId is %.08x (should be %.08x)\n",
-        BinCell->BlockId, REG_BIN_ID);
-      assert(BinCell->BlockId == REG_BIN_ID);
+      DbgPrint("Bin header ID is %.08x (should be %.08x)\n",
+        BinHeader->HeaderId, REG_BIN_ID);
+      assert(BinHeader->HeaderId == REG_BIN_ID);
     }
 
-  //BinCell->DateModified.dwLowDateTime
+  //BinHeader->DateModified.dwLowDateTime
 
-  //BinCell->DateModified.dwHighDateTime
+  //BinHeader->DateModified.dwHighDateTime
 
   
-  if (BinCell->BlockSize != REG_BLOCK_SIZE)
+  if (BinHeader->BinSize != REG_BLOCK_SIZE)
     {
-      DbgPrint("BlockSize is %.08x (should be %.08x)\n",
-        BinCell->BlockSize, REG_BLOCK_SIZE);
-      assert(BinCell->BlockSize == REG_BLOCK_SIZE);
+      DbgPrint("BinSize is %.08x (should be a multiple of %.08x)\n",
+        BinHeader->BinSize, REG_BLOCK_SIZE);
+      assert(BinHeader->BinSize % REG_BLOCK_SIZE == 0);
     }
 
     }
@@ -362,24 +356,27 @@ CmiCreateNewRegFile(HANDLE FileHandle)
   PHIVE_HEADER HiveHeader;
   PKEY_CELL RootKeyCell;
   NTSTATUS Status;
-  PHBIN BinCell;
+  PHBIN BinHeader;
   PCHAR Buffer;
 
   Buffer = (PCHAR) ExAllocatePool(NonPagedPool, 2 * REG_BLOCK_SIZE);
   if (Buffer == NULL)
     return STATUS_INSUFFICIENT_RESOURCES;
 
+  RtlZeroMemory (Buffer,
+                2 * REG_BLOCK_SIZE);
+
   HiveHeader = (PHIVE_HEADER)Buffer;
-  BinCell = (PHBIN)((ULONG_PTR)Buffer + REG_BLOCK_SIZE);
+  BinHeader = (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);
+  CmiCreateDefaultBinHeader(BinHeader);
   CmiCreateDefaultRootKeyCell(RootKeyCell);
 
   /* First block */
-  BinCell->BlockOffset = 0;
+  BinHeader->BinOffset = 0;
 
   /* Offset to root key block */
   HiveHeader->RootKeyOffset = REG_HBIN_DATA_OFFSET;
@@ -436,7 +433,7 @@ CmiCheckAndFixHive(PREGISTRY_HIVE RegistryHive)
   /* Try to open the hive file */
   InitializeObjectAttributes(&ObjectAttributes,
                             &RegistryHive->HiveFileName,
-                            0,
+                            OBJ_CASE_INSENSITIVE,
                             NULL,
                             NULL);
 
@@ -464,7 +461,7 @@ CmiCheckAndFixHive(PREGISTRY_HIVE RegistryHive)
   /* Try to open the log file */
   InitializeObjectAttributes(&ObjectAttributes,
                             &RegistryHive->LogFileName,
-                            0,
+                            OBJ_CASE_INSENSITIVE,
                             NULL,
                             NULL);
 
@@ -601,11 +598,11 @@ CmiCheckAndFixHive(PREGISTRY_HIVE RegistryHive)
       FileSize = fsi.EndOfFile.u.LowPart;
 
       /* Calculate bitmap and block size */
-      BitmapSize = ROUND_UP((FileSize / 4096) - 1, sizeof(ULONG) * 8) / 8;
+      BitmapSize = ROUND_UP((FileSize / REG_BLOCK_SIZE) - 1, sizeof(ULONG) * 8) / 8;
       BufferSize = sizeof(HIVE_HEADER) +
                          sizeof(ULONG) +
                          BitmapSize;
-      BufferSize = ROUND_UP(BufferSize, 4096);
+      BufferSize = ROUND_UP(BufferSize, REG_BLOCK_SIZE);
 
       /* Reallocate log header block */
       ExFreePool(LogHeader);
@@ -637,7 +634,7 @@ CmiCheckAndFixHive(PREGISTRY_HIVE RegistryHive)
 
       /* Initialize bitmap */
       RtlInitializeBitMap(&BlockBitMap,
-                         (PVOID)((ULONG)LogHeader + 4096 + sizeof(ULONG)),
+                         (PVOID)((ULONG_PTR)LogHeader + REG_BLOCK_SIZE + sizeof(ULONG)),
                          BitmapSize * 8);
 
       /* FIXME: Update dirty blocks */
@@ -683,40 +680,43 @@ CmiImportHiveBins(PREGISTRY_HIVE Hive,
     {
       Bin = (PHBIN)((ULONG_PTR)ChunkPtr + BlockOffset);
 
-      if (Bin->BlockId != REG_BIN_ID)
+      if (Bin->HeaderId != REG_BIN_ID)
        {
-         DPRINT1 ("Bad BlockId %x, offset %x\n", Bin->BlockId, BlockOffset);
+         DPRINT1 ("Bad bin header id %x, offset %x\n", Bin->HeaderId, BlockOffset);
          return STATUS_REGISTRY_CORRUPT;
        }
 
-      assertmsg((Bin->BlockSize % 4096) == 0,
-               ("BlockSize (0x%.08x) must be multiple of 4K\n",
-               Bin->BlockSize));
+      assertmsg((Bin->BinSize % REG_BLOCK_SIZE) == 0,
+               ("Bin size (0x%.08x) must be multiple of 4K\n",
+               Bin->BinSize));
 
       /* Allocate the hive block */
-      Hive->BlockList[BlockIndex] = ExAllocatePool (PagedPool,
-                                                   Bin->BlockSize);
-      if (Hive->BlockList[BlockIndex] == NULL)
+      Hive->BlockList[BlockIndex].Bin = ExAllocatePool (PagedPool,
+                                                       Bin->BinSize);
+      if (Hive->BlockList[BlockIndex].Bin == NULL)
        {
          DPRINT1 ("ExAllocatePool() failed\n");
          return STATUS_INSUFFICIENT_RESOURCES;
        }
+      Hive->BlockList[BlockIndex].Block = (PVOID)Hive->BlockList[BlockIndex].Bin;
 
       /* Import the Bin */
-      RtlCopyMemory (Hive->BlockList[BlockIndex],
+      RtlCopyMemory (Hive->BlockList[BlockIndex].Bin,
                     Bin,
-                    Bin->BlockSize);
+                    Bin->BinSize);
 
-      if (Bin->BlockSize > 4096)
+      if (Bin->BinSize > REG_BLOCK_SIZE)
        {
-         for (j = 1; j < Bin->BlockSize / 4096; j++)
+         for (j = 1; j < Bin->BinSize / REG_BLOCK_SIZE; j++)
            {
-             Hive->BlockList[BlockIndex + j] = Hive->BlockList[BlockIndex];
+             Hive->BlockList[BlockIndex + j].Bin = Hive->BlockList[BlockIndex].Bin;
+             Hive->BlockList[BlockIndex + j].Block =
+               (PVOID)((ULONG_PTR)Hive->BlockList[BlockIndex].Bin + (j * REG_BLOCK_SIZE));
            }
        }
 
-      BlockIndex += Bin->BlockSize / 4096;
-      BlockOffset += Bin->BlockSize;
+      BlockIndex += Bin->BinSize / REG_BLOCK_SIZE;
+      BlockOffset += Bin->BinSize;
     }
 
   return STATUS_SUCCESS;
@@ -732,15 +732,16 @@ CmiFreeHiveBins (PREGISTRY_HIVE Hive)
   Bin = NULL;
   for (i = 0; i < Hive->BlockListSize; i++)
     {
-      if (Hive->BlockList[i] == NULL)
+      if (Hive->BlockList[i].Bin == NULL)
        continue;
 
-      if (Hive->BlockList[i] != Bin)
+      if (Hive->BlockList[i].Bin != Bin)
        {
-         Bin = Hive->BlockList[i];
-         ExFreePool (Hive->BlockList[i]);
+         Bin = Hive->BlockList[i].Bin;
+         ExFreePool (Hive->BlockList[i].Bin);
        }
-      Hive->BlockList[i] = NULL;
+      Hive->BlockList[i].Bin = NULL;
+      Hive->BlockList[i].Block = NULL;
     }
 }
 
@@ -765,18 +766,18 @@ CmiCreateHiveFreeCellList(PREGISTRY_HIVE Hive)
   BlockIndex = 0;
   while (BlockIndex < Hive->BlockListSize)
     {
-      Bin = Hive->BlockList[BlockIndex];
+      Bin = Hive->BlockList[BlockIndex].Bin;
 
       /* Search free blocks and add to list */
       FreeOffset = REG_HBIN_DATA_OFFSET;
-      while (FreeOffset < Bin->BlockSize)
+      while (FreeOffset < Bin->BinSize)
        {
          FreeBlock = (PCELL_HEADER) ((ULONG_PTR) Bin + FreeOffset);
          if (FreeBlock->CellSize > 0)
            {
              Status = CmiAddFree(Hive,
                                  FreeBlock,
-                                 Bin->BlockOffset + FreeOffset,
+                                 Bin->BinOffset + FreeOffset,
                                  FALSE);
 
              if (!NT_SUCCESS(Status))
@@ -792,8 +793,8 @@ CmiCreateHiveFreeCellList(PREGISTRY_HIVE Hive)
            }
        }
 
-      BlockIndex += Bin->BlockSize / 4096;
-      BlockOffset += Bin->BlockSize;
+      BlockIndex += Bin->BinSize / REG_BLOCK_SIZE;
+      BlockOffset += Bin->BinSize;
     }
 
   return STATUS_SUCCESS;
@@ -851,7 +852,7 @@ CmiInitNonVolatileRegistryHive (PREGISTRY_HIVE RegistryHive,
   ULONG CreateDisposition;
   IO_STATUS_BLOCK IoSB;
   HANDLE FileHandle;
-  HANDLE SectionHandle;
+  PSECTION_OBJECT SectionObject;
   PUCHAR ViewBase;
   ULONG ViewSize;
   NTSTATUS Status;
@@ -898,7 +899,7 @@ CmiInitNonVolatileRegistryHive (PREGISTRY_HIVE RegistryHive,
 
   InitializeObjectAttributes(&ObjectAttributes,
                             &RegistryHive->HiveFileName,
-                            0,
+                            OBJ_CASE_INSENSITIVE,
                             NULL,
                             NULL);
 
@@ -936,17 +937,17 @@ CmiInitNonVolatileRegistryHive (PREGISTRY_HIVE RegistryHive,
     }
 
   /* Create the hive section */
-  Status = NtCreateSection(&SectionHandle,
+  Status = MmCreateSection(&SectionObject,
                           SECTION_ALL_ACCESS,
                           NULL,
                           NULL,
                           PAGE_READWRITE,
                           SEC_COMMIT,
-                          FileHandle);
-  NtClose(FileHandle);
+                          FileHandle,
+                          NULL);
   if (!NT_SUCCESS(Status))
     {
-      DPRINT1("NtCreateSection() failed (Status %lx)\n", Status);
+      DPRINT1("MmCreateSection() failed (Status %lx)\n", Status);
       RtlFreeUnicodeString(&RegistryHive->HiveFileName);
       RtlFreeUnicodeString(&RegistryHive->LogFileName);
       return(Status);
@@ -955,8 +956,8 @@ CmiInitNonVolatileRegistryHive (PREGISTRY_HIVE RegistryHive,
   /* Map the hive file */
   ViewBase = NULL;
   ViewSize = 0;
-  Status = NtMapViewOfSection(SectionHandle,
-                             NtCurrentProcess(),
+  Status = MmMapViewOfSection(SectionObject,
+                             PsGetCurrentProcess(),
                              (PVOID*)&ViewBase,
                              0,
                              ViewSize,
@@ -967,10 +968,11 @@ CmiInitNonVolatileRegistryHive (PREGISTRY_HIVE RegistryHive,
                              PAGE_READWRITE);
   if (!NT_SUCCESS(Status))
     {
-      DPRINT1("MmMapViewInSystemSpace() failed (Status %lx)\n", Status);
-      NtClose(SectionHandle);
+      DPRINT1("MmMapViewOfSection() failed (Status %lx)\n", Status);
+      ObDereferenceObject(SectionObject);
       RtlFreeUnicodeString(&RegistryHive->HiveFileName);
       RtlFreeUnicodeString(&RegistryHive->LogFileName);
+      NtClose(FileHandle);
       return(Status);
     }
   DPRINT("ViewBase %p  ViewSize %lx\n", ViewBase, ViewSize);
@@ -980,41 +982,48 @@ CmiInitNonVolatileRegistryHive (PREGISTRY_HIVE RegistryHive,
                 ViewBase,
                 sizeof(HIVE_HEADER));
   RegistryHive->FileSize = ViewSize;
-  RegistryHive->BlockListSize = (RegistryHive->FileSize / 4096) - 1;
+  RegistryHive->BlockListSize = (RegistryHive->FileSize / REG_BLOCK_SIZE) - 1;
   RegistryHive->UpdateCounter = RegistryHive->HiveHeader->UpdateCounter1;
 
   /* Allocate hive block list */
   RegistryHive->BlockList = ExAllocatePool(NonPagedPool,
-         sizeof(PHBIN *) * RegistryHive->BlockListSize);
+                                          RegistryHive->BlockListSize * sizeof(BLOCK_LIST_ENTRY));
   if (RegistryHive->BlockList == NULL)
     {
       DPRINT1("Failed to allocate the hive block list\n");
-      NtUnmapViewOfSection(NtCurrentProcess(),
+      MmUnmapViewOfSection(PsGetCurrentProcess(),
                           ViewBase);
-      NtClose(SectionHandle);
+      ObDereferenceObject(SectionObject);
       RtlFreeUnicodeString(&RegistryHive->HiveFileName);
       RtlFreeUnicodeString(&RegistryHive->LogFileName);
+      NtClose(FileHandle);
       return STATUS_INSUFFICIENT_RESOURCES;
     }
+  RtlZeroMemory (RegistryHive->BlockList,
+                RegistryHive->BlockListSize * sizeof(BLOCK_LIST_ENTRY));
 
   /* Import the hive bins */
   Status = CmiImportHiveBins (RegistryHive,
-                             ViewBase + 4096);
+                             ViewBase + REG_BLOCK_SIZE);
   if (!NT_SUCCESS(Status))
     {
       ExFreePool(RegistryHive->BlockList);
-      NtUnmapViewOfSection(NtCurrentProcess(),
+      MmUnmapViewOfSection(PsGetCurrentProcess(),
                           ViewBase);
-      NtClose(SectionHandle);
+      ObDereferenceObject(SectionObject);
       RtlFreeUnicodeString(&RegistryHive->HiveFileName);
       RtlFreeUnicodeString(&RegistryHive->LogFileName);
+      NtClose(FileHandle);
       return Status;
     }
 
   /* Unmap and dereference the hive section */
-  NtUnmapViewOfSection(NtCurrentProcess(),
-                      ViewBase);
-  NtClose(SectionHandle);
+  MmUnmapViewOfSection(PsGetCurrentProcess(),
+                       ViewBase);
+  ObDereferenceObject(SectionObject);
+
+  /* Close the hive file */
+  NtClose(FileHandle);
 
   /* Initialize the free cell list */
   Status = CmiCreateHiveFreeCellList (RegistryHive);
@@ -1042,7 +1051,7 @@ CmiInitNonVolatileRegistryHive (PREGISTRY_HIVE RegistryHive,
   DPRINT("CmiInitNonVolatileRegistryHive(%p, %S) - Finished.\n",
         RegistryHive, Filename);
 
-  return(STATUS_SUCCESS);
+  return STATUS_SUCCESS;
 }
 
 
@@ -1071,6 +1080,8 @@ CmiCreateVolatileHive(PREGISTRY_HIVE *RegistryHive)
       ExFreePool (Hive);
       return STATUS_INSUFFICIENT_RESOURCES;
     }
+  RtlZeroMemory (Hive->HiveHeader,
+                sizeof(HIVE_HEADER));
 
   Hive->Flags = (HIVE_NO_FILE | HIVE_POINTER);
 
@@ -1114,7 +1125,7 @@ CmiCreateVolatileHive(PREGISTRY_HIVE *RegistryHive)
 NTSTATUS
 CmiCreateTempHive(PREGISTRY_HIVE *RegistryHive)
 {
-  PHBIN BinCell;
+  PHBIN BinHeader;
   PCELL_HEADER FreeCell;
   PREGISTRY_HIVE Hive;
   NTSTATUS Status;
@@ -1159,7 +1170,7 @@ CmiCreateTempHive(PREGISTRY_HIVE *RegistryHive)
 
   /* Allocate hive block list */
   Hive->BlockList = ExAllocatePool (NonPagedPool,
-                                   sizeof(PHBIN *));
+                                   sizeof(PBLOCK_LIST_ENTRY));
   if (Hive->BlockList == NULL)
     {
       DPRINT1 ("Failed to allocate hive block list\n");
@@ -1169,9 +1180,9 @@ CmiCreateTempHive(PREGISTRY_HIVE *RegistryHive)
     }
 
   /* Allocate first Bin */
-  Hive->BlockList[0] = ExAllocatePool (NonPagedPool,
-                                      REG_BLOCK_SIZE);
-  if (Hive->BlockList[0] == NULL)
+  Hive->BlockList[0].Bin = ExAllocatePool (NonPagedPool,
+                                          REG_BLOCK_SIZE);
+  if (Hive->BlockList[0].Bin == NULL)
     {
       DPRINT1 ("Failed to allocate first bin\n");
       ExFreePool(Hive->BlockList);
@@ -1179,19 +1190,20 @@ CmiCreateTempHive(PREGISTRY_HIVE *RegistryHive)
       ExFreePool(Hive);
       return STATUS_INSUFFICIENT_RESOURCES;
     }
+  Hive->BlockList[0].Block = (PVOID)Hive->BlockList[0].Bin;
 
   Hive->FileSize = 2* REG_BLOCK_SIZE;
   Hive->BlockListSize = 1;
   Hive->UpdateCounter = Hive->HiveHeader->UpdateCounter1;
 
 
-  BinCell = (PHBIN)Hive->BlockList[0];
-  FreeCell = (PCELL_HEADER)((ULONG_PTR)BinCell + REG_HBIN_DATA_OFFSET);
+  BinHeader = Hive->BlockList[0].Bin;
+  FreeCell = (PCELL_HEADER)((ULONG_PTR)BinHeader + REG_HBIN_DATA_OFFSET);
 
-  CmiCreateDefaultBinCell (BinCell);
+  CmiCreateDefaultBinHeader (BinHeader);
 
   /* First block */
-  BinCell->BlockOffset = 0;
+  BinHeader->BinOffset = 0;
 
   /* Offset to root key block */
   Hive->HiveHeader->RootKeyOffset = (BLOCK_OFFSET)-1;
@@ -1201,10 +1213,10 @@ CmiCreateTempHive(PREGISTRY_HIVE *RegistryHive)
 
   /* Create the free cell list */
   Status = CmiCreateHiveFreeCellList (Hive);
-  if (Hive->BlockList[0] == NULL)
+  if (Hive->BlockList[0].Bin == NULL)
     {
       DPRINT1 ("CmiCreateHiveFreeCellList() failed (Status %lx)\n", Status);
-      ExFreePool(Hive->BlockList[0]);
+      ExFreePool(Hive->BlockList[0].Bin);
       ExFreePool(Hive->BlockList);
       ExFreePool(Hive->HiveHeader);
       ExFreePool(Hive);
@@ -1270,6 +1282,9 @@ CmiLoadHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
       return STATUS_INSUFFICIENT_RESOURCES;
     }
 
+  RtlZeroMemory (Hive->HiveHeader,
+                sizeof(HIVE_HEADER));
+
   Status = CmiInitNonVolatileRegistryHive (Hive,
                                           FileName->Buffer);
   if (!NT_SUCCESS (Status))
@@ -1391,21 +1406,24 @@ CmiStartLogUpdate(PREGISTRY_HIVE RegistryHive)
   BufferSize = sizeof(HIVE_HEADER) +
               sizeof(ULONG) +
               BitmapSize;
-  BufferSize = ROUND_UP(BufferSize, 4096);
+  BufferSize = ROUND_UP(BufferSize, REG_BLOCK_SIZE);
 
   DPRINT("Bitmap size %lu  buffer size: %lu\n", BitmapSize, BufferSize);
 
-  Buffer = (PUCHAR)ExAllocatePool(NonPagedPool, BufferSize);
+  Buffer = (PUCHAR)ExAllocatePool(NonPagedPool,
+                                 BufferSize);
   if (Buffer == NULL)
     {
       DPRINT("ExAllocatePool() failed\n");
       return(STATUS_INSUFFICIENT_RESOURCES);
     }
+  RtlZeroMemory (Buffer,
+                BufferSize);
 
   /* Open log file for writing */
   InitializeObjectAttributes(&ObjectAttributes,
                             &RegistryHive->LogFileName,
-                            0,
+                            OBJ_CASE_INSENSITIVE,
                             NULL,
                             NULL);
 
@@ -1446,11 +1464,7 @@ CmiStartLogUpdate(PREGISTRY_HIVE RegistryHive)
                BitmapSize);
 
   /* Write hive block and block bitmap */
-#if defined(__GNUC__)
-  FileOffset.QuadPart = 0ULL;
-#else
-  FileOffset.QuadPart = 0;
-#endif
+  FileOffset.QuadPart = (ULONGLONG)0;
   Status = NtWriteFile(FileHandle,
                       NULL,
                       NULL,
@@ -1487,7 +1501,7 @@ CmiStartLogUpdate(PREGISTRY_HIVE RegistryHive)
 
       DPRINT("Block %lu is dirty\n", BlockIndex);
 
-      BlockPtr = RegistryHive->BlockList[BlockIndex];
+      BlockPtr = RegistryHive->BlockList[BlockIndex].Block;
       DPRINT("BlockPtr %p\n", BlockPtr);
       DPRINT("File offset %I64x\n", FileOffset.QuadPart);
 
@@ -1509,11 +1523,7 @@ CmiStartLogUpdate(PREGISTRY_HIVE RegistryHive)
        }
 
       BlockIndex++;
-#if defined(__GNUC__)
-      FileOffset.QuadPart += 4096ULL;
-#else
-      FileOffset.QuadPart += 4096;
-#endif
+      FileOffset.QuadPart += (ULONGLONG)REG_BLOCK_SIZE;
     }
 
   /* Truncate log file */
@@ -1576,7 +1586,7 @@ CmiFinishLogUpdate(PREGISTRY_HIVE RegistryHive)
   BufferSize = sizeof(HIVE_HEADER) +
               sizeof(ULONG) +
               BitmapSize;
-  BufferSize = ROUND_UP(BufferSize, 4096);
+  BufferSize = ROUND_UP(BufferSize, REG_BLOCK_SIZE);
 
   DPRINT("Bitmap size %lu  buffer size: %lu\n", BitmapSize, BufferSize);
 
@@ -1590,7 +1600,7 @@ CmiFinishLogUpdate(PREGISTRY_HIVE RegistryHive)
   /* Open log file for writing */
   InitializeObjectAttributes(&ObjectAttributes,
                             &RegistryHive->LogFileName,
-                            0,
+                            OBJ_CASE_INSENSITIVE,
                             NULL,
                             NULL);
 
@@ -1632,11 +1642,7 @@ CmiFinishLogUpdate(PREGISTRY_HIVE RegistryHive)
                BitmapSize);
 
   /* Write hive block and block bitmap */
-#if defined(__GNUC__)
-  FileOffset.QuadPart = 0ULL;
-#else
-  FileOffset.QuadPart = 0;
-#endif
+  FileOffset.QuadPart = (ULONGLONG)0;
   Status = NtWriteFile(FileHandle,
                       NULL,
                       NULL,
@@ -1688,14 +1694,14 @@ CmiCleanupLogUpdate(PREGISTRY_HIVE RegistryHive)
   BufferSize = sizeof(HIVE_HEADER) +
               sizeof(ULONG) +
               BitmapSize;
-  BufferSize = ROUND_UP(BufferSize, 4096);
+  BufferSize = ROUND_UP(BufferSize, REG_BLOCK_SIZE);
 
   DPRINT("Bitmap size %lu  buffer size: %lu\n", BitmapSize, BufferSize);
 
   /* Open log file for writing */
   InitializeObjectAttributes(&ObjectAttributes,
                             &RegistryHive->LogFileName,
-                            0,
+                            OBJ_CASE_INSENSITIVE,
                             NULL,
                             NULL);
 
@@ -1773,7 +1779,7 @@ CmiStartHiveUpdate(PREGISTRY_HIVE RegistryHive)
   /* Open hive for writing */
   InitializeObjectAttributes(&ObjectAttributes,
                             &RegistryHive->HiveFileName,
-                            0,
+                            OBJ_CASE_INSENSITIVE,
                             NULL,
                             NULL);
 
@@ -1799,11 +1805,7 @@ CmiStartHiveUpdate(PREGISTRY_HIVE RegistryHive)
   RegistryHive->HiveHeader->Checksum = CmiCalcChecksum((PULONG)RegistryHive->HiveHeader);
 
   /* Write hive block */
-#if defined(__GNUC__)
-  FileOffset.QuadPart = 0ULL;
-#else
-  FileOffset.QuadPart = 0;
-#endif
+  FileOffset.QuadPart = (ULONGLONG)0;
   Status = NtWriteFile(FileHandle,
                       NULL,
                       NULL,
@@ -1836,15 +1838,11 @@ CmiStartHiveUpdate(PREGISTRY_HIVE RegistryHive)
 
       DPRINT("Block %lu is dirty\n", BlockIndex);
 
-      BlockPtr = RegistryHive->BlockList[BlockIndex];
-      DPRINT("BlockPtr %p\n", BlockPtr);
+      BlockPtr = RegistryHive->BlockList[BlockIndex].Block;
+      DPRINT("  BlockPtr %p\n", BlockPtr);
 
-#if defined(__GNUC__)
-      FileOffset.QuadPart = (ULONGLONG)(BlockIndex + 1) * 4096ULL;
-#else
-      FileOffset.QuadPart = (ULONGLONG)(BlockIndex + 1) * 4096;
-#endif
-      DPRINT("File offset %I64x\n", FileOffset.QuadPart);
+      FileOffset.QuadPart = (ULONGLONG)(BlockIndex + 1) * (ULONGLONG)REG_BLOCK_SIZE;
+      DPRINT("  File offset %I64x\n", FileOffset.QuadPart);
 
       /* Write hive block */
       Status = NtWriteFile(FileHandle,
@@ -1892,7 +1890,7 @@ CmiFinishHiveUpdate(PREGISTRY_HIVE RegistryHive)
 
   InitializeObjectAttributes(&ObjectAttributes,
                             &RegistryHive->HiveFileName,
-                            0,
+                            OBJ_CASE_INSENSITIVE,
                             NULL,
                             NULL);
 
@@ -1919,11 +1917,7 @@ CmiFinishHiveUpdate(PREGISTRY_HIVE RegistryHive)
   RegistryHive->HiveHeader->Checksum = CmiCalcChecksum((PULONG)RegistryHive->HiveHeader);
 
   /* Write hive block */
-#if defined(__GNUC__)
-  FileOffset.QuadPart = 0ULL;
-#else
-  FileOffset.QuadPart = 0;
-#endif
+  FileOffset.QuadPart = (ULONGLONG)0;
   Status = NtWriteFile(FileHandle,
                       NULL,
                       NULL,
@@ -2026,6 +2020,36 @@ CmiFlushRegistryHive(PREGISTRY_HIVE RegistryHive)
 }
 
 
+ULONG
+CmiGetNumberOfSubKeys(PKEY_OBJECT KeyObject)
+{
+  PKEY_OBJECT CurKey;
+  PKEY_CELL KeyCell;
+  ULONG SubKeyCount;
+  ULONG i;
+
+  VERIFY_KEY_OBJECT(KeyObject);
+
+  KeyCell = KeyObject->KeyCell;
+  VERIFY_KEY_CELL(KeyCell);
+
+  SubKeyCount = (KeyCell == NULL) ? 0 : KeyCell->NumberOfSubKeys;
+
+  /* Search for volatile or 'foreign' keys */
+  for (i = 0; i < KeyObject->NumberOfSubKeys; i++)
+    {
+      CurKey = KeyObject->SubKeys[i];
+      if (CurKey->RegistryHive == CmiVolatileHive ||
+         CurKey->RegistryHive != KeyObject->RegistryHive)
+       {
+         SubKeyCount++;
+       }
+    }
+
+  return SubKeyCount;
+}
+
+
 ULONG
 CmiGetMaxNameLength(PKEY_OBJECT KeyObject)
 {
@@ -2053,8 +2077,8 @@ CmiGetMaxNameLength(PKEY_OBJECT KeyObject)
   else
     {
       for (i = 0; i < HashBlock->HashTableSize; i++)
-        {
-          if (HashBlock->Table[i].KeyOffset != 0)
+       {
+         if (HashBlock->Table[i].KeyOffset != 0)
            {
              CurSubKeyCell = CmiGetCell (KeyObject->RegistryHive,
                                          HashBlock->Table[i].KeyOffset,
@@ -2064,45 +2088,60 @@ CmiGetMaxNameLength(PKEY_OBJECT KeyObject)
                  DPRINT("CmiGetBlock() failed\n");
                  continue;
                }
-              NameSize = CurSubKeyCell->NameSize;
+
+             NameSize = CurSubKeyCell->NameSize;
              if (CurSubKeyCell->Flags & REG_KEY_NAME_PACKED)
                {
                  NameSize *= sizeof(WCHAR);
                }
-             if (MaxName < NameSize)
+
+             if (NameSize > MaxName)
                {
                  MaxName = NameSize;
                }
            }
        }
     }
-  if (KeyObject->RegistryHive != CmiVolatileHive)
+
+  DPRINT ("KeyObject->NumberOfSubKeys %d\n", KeyObject->NumberOfSubKeys);
+  for (i = 0; i < KeyObject->NumberOfSubKeys; i++)
     {
-      DPRINT("KeyObject->NumberOfSubKeys %d\n", KeyObject->NumberOfSubKeys);
-      for (i = 0; i < KeyObject->NumberOfSubKeys; i++)
-        {
-         CurKey = KeyObject->SubKeys[i];
-         if (CurKey->RegistryHive == CmiVolatileHive)
+      CurKey = KeyObject->SubKeys[i];
+      if (CurKey->RegistryHive == CmiVolatileHive ||
+         CurKey->RegistryHive != KeyObject->RegistryHive)
+       {
+         CurSubKeyCell = CurKey->KeyCell;
+         if (CurSubKeyCell == NULL)
            {
-             CurSubKeyCell = CurKey->KeyCell;
-             if (CurSubKeyCell == NULL)
-               {
-                  DPRINT("CmiGetBlock() failed\n");
-                 continue;
-               }
-              NameSize = CurSubKeyCell->NameSize;
+             DPRINT("CmiGetBlock() failed\n");
+             continue;
+           }
+
+         if ((CurSubKeyCell->Flags & REG_KEY_ROOT_CELL) == REG_KEY_ROOT_CELL)
+           {
+             /* Use name of the key object */
+             NameSize = CurKey->Name.Length;
+           }
+         else
+           {
+             /* Use name of the key cell */
+             NameSize = CurSubKeyCell->NameSize;
              if (CurSubKeyCell->Flags & REG_KEY_NAME_PACKED)
-               {
-                 NameSize *= sizeof(WCHAR);
-               }
-             if (MaxName < NameSize)
-               {
-                 MaxName = NameSize;
-               }
+               {
+                 NameSize *= sizeof(WCHAR);
+               }
+           }
+         DPRINT ("NameSize %lu\n", NameSize);
+
+         if (NameSize > MaxName)
+           {
+             MaxName = NameSize;
            }
        }
     }
 
+  DPRINT ("MaxName %lu\n", MaxName);
+
   return MaxName;
 }
 
@@ -2133,8 +2172,8 @@ CmiGetMaxClassLength(PKEY_OBJECT  KeyObject)
   else
     {
       for (i = 0; i < HashBlock->HashTableSize; i++)
-        {
-          if (HashBlock->Table[i].KeyOffset != 0)
+       {
+         if (HashBlock->Table[i].KeyOffset != 0)
            {
              CurSubKeyCell = CmiGetCell (KeyObject->RegistryHive,
                                          HashBlock->Table[i].KeyOffset,
@@ -2152,24 +2191,24 @@ CmiGetMaxClassLength(PKEY_OBJECT  KeyObject)
            }
        }
     }
-  if (KeyObject->RegistryHive != CmiVolatileHive)
+
+  DPRINT("KeyObject->NumberOfSubKeys %d\n", KeyObject->NumberOfSubKeys);
+  for (i = 0; i < KeyObject->NumberOfSubKeys; i++)
     {
-      DPRINT("KeyObject->NumberOfSubKeys %d\n", KeyObject->NumberOfSubKeys);
-      for (i = 0; i < KeyObject->NumberOfSubKeys; i++)
-        {
-         CurKey = KeyObject->SubKeys[i];
-         if (CurKey->RegistryHive == CmiVolatileHive)
+      CurKey = KeyObject->SubKeys[i];
+      if (CurKey->RegistryHive == CmiVolatileHive ||
+         CurKey->RegistryHive != KeyObject->RegistryHive)
+       {
+         CurSubKeyCell = CurKey->KeyCell;
+         if (CurSubKeyCell == NULL)
            {
-             CurSubKeyCell = CurKey->KeyCell;
-             if (CurSubKeyCell == NULL)
-               {
-                  DPRINT("CmiGetBlock() failed\n");
-                 continue;
-               }
-             if (MaxClass < CurSubKeyCell->ClassSize)
-               {
-                 MaxClass = CurSubKeyCell->ClassSize;
-               }
+             DPRINT("CmiGetBlock() failed\n");
+             continue;
+           }
+
+         if (MaxClass < CurSubKeyCell->ClassSize)
+           {
+             MaxClass = CurSubKeyCell->ClassSize;
            }
        }
     }
@@ -2211,15 +2250,15 @@ CmiGetMaxValueNameLength(PREGISTRY_HIVE RegistryHive,
        }
 
       if (CurValueCell != NULL)
-        {
+       {
          Size = CurValueCell->NameSize;
          if (CurValueCell->Flags & REG_VALUE_NAME_PACKED)
            {
              Size *= sizeof(WCHAR);
            }
-          if (MaxValueName < Size)
-            {
-              MaxValueName = Size;
+         if (MaxValueName < Size)
+           {
+             MaxValueName = Size;
            }
         }
     }
@@ -2572,43 +2611,43 @@ CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive,
          return STATUS_UNSUCCESSFUL;
        }
 
-      if (ValueList != NULL)
+      /* Enumerate all values */
+      for (i = 0; i < SubKey->KeyCell->NumberOfValues; i++)
        {
-         /* Enumerate all values */
-         for (i = 0; i < SubKey->KeyCell->NumberOfValues; i++)
+         /* Get pointer to value cell */
+         ValueCell = CmiGetCell(RegistryHive,
+                                ValueList->ValueOffset[i],
+                                NULL);
+         if (ValueCell == NULL)
            {
-             /* Get pointer to value cell */
-             ValueCell = CmiGetCell (RegistryHive,
-                                     ValueList->ValueOffset[i],
-                                     NULL);
-             if (ValueCell != NULL)
+             DPRINT("CmiGetCell() failed\n");
+             return STATUS_UNSUCCESSFUL;
+           }
+
+         if (ValueCell->DataSize > sizeof(BLOCK_OFFSET))
+           {
+             DataCell = CmiGetCell (RegistryHive,
+                                    ValueCell->DataOffset,
+                                    NULL);
+             if (DataCell == NULL)
+               {
+                 DPRINT("CmiGetCell() failed\n");
+                 return STATUS_UNSUCCESSFUL;
+               }
+
+             if (DataCell != NULL)
                {
-                 if (ValueCell->DataSize > sizeof(BLOCK_OFFSET))
-                   {
-                     DataCell = CmiGetCell (RegistryHive,
-                                            ValueCell->DataOffset,
-                                            NULL);
-                     if (DataCell == NULL)
-                       {
-                         DPRINT("CmiGetCell() failed\n");
-                         return STATUS_UNSUCCESSFUL;
-                       }
-
-                     if (DataCell != NULL)
-                       {
-                         /* Destroy data cell */
-                         CmiDestroyCell (RegistryHive,
-                                         DataCell,
-                                         ValueCell->DataOffset);
-                       }
-                   }
-
-                 /* Destroy value cell */
+                 /* Destroy data cell */
                  CmiDestroyCell (RegistryHive,
-                                 ValueCell,
-                                 ValueList->ValueOffset[i]);
+                                 DataCell,
+                                 ValueCell->DataOffset);
                }
            }
+
+         /* Destroy value cell */
+         CmiDestroyCell (RegistryHive,
+                         ValueCell,
+                         ValueList->ValueOffset[i]);
        }
 
       /* Destroy value list cell */
@@ -2618,6 +2657,9 @@ CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive,
 
       SubKey->KeyCell->NumberOfValues = 0;
       SubKey->KeyCell->ValueListOffset = (BLOCK_OFFSET)-1;
+
+      CmiMarkBlockDirty(RegistryHive,
+                       SubKey->KeyCellOffset);
     }
 
   /* Remove the key from the parent key's hash block */
@@ -2705,7 +2747,9 @@ CmiRemoveSubKey(PREGISTRY_HIVE RegistryHive,
   SubKey->KeyCell = NULL;
   SubKey->KeyCellOffset = (BLOCK_OFFSET)-1;
 
-  return(STATUS_SUCCESS);
+  DPRINT("CmiRemoveSubKey() done\n");
+
+  return STATUS_SUCCESS;
 }
 
 
@@ -2714,18 +2758,20 @@ CmiScanKeyForValue(IN PREGISTRY_HIVE RegistryHive,
                   IN PKEY_CELL KeyCell,
                   IN PUNICODE_STRING ValueName,
                   OUT PVALUE_CELL *ValueCell,
-                  OUT BLOCK_OFFSET *VBOffset)
+                  OUT BLOCK_OFFSET *ValueCellOffset)
 {
   PVALUE_LIST_CELL ValueListCell;
   PVALUE_CELL CurValueCell;
   ULONG i;
 
   *ValueCell = NULL;
+  if (ValueCellOffset != NULL)
+    *ValueCellOffset = (BLOCK_OFFSET)-1;
 
   /* The key does not have any values */
   if (KeyCell->ValueListOffset == (BLOCK_OFFSET)-1)
     {
-      return STATUS_SUCCESS;
+      return STATUS_OBJECT_NAME_NOT_FOUND;
     }
 
   ValueListCell = CmiGetCell (RegistryHive, KeyCell->ValueListOffset, NULL);
@@ -2755,14 +2801,14 @@ CmiScanKeyForValue(IN PREGISTRY_HIVE RegistryHive,
                                (BOOLEAN)((CurValueCell->Flags & REG_VALUE_NAME_PACKED) ? TRUE : FALSE)))
        {
          *ValueCell = CurValueCell;
-         if (VBOffset)
-           *VBOffset = ValueListCell->ValueOffset[i];
+         if (ValueCellOffset != NULL)
+           *ValueCellOffset = ValueListCell->ValueOffset[i];
          //DPRINT("Found value %s\n", ValueName);
-         break;
+         return STATUS_SUCCESS;
        }
     }
 
-  return STATUS_SUCCESS;
+  return STATUS_OBJECT_NAME_NOT_FOUND;
 }
 
 
@@ -2816,31 +2862,23 @@ CmiGetValueFromKeyByIndex(IN PREGISTRY_HIVE RegistryHive,
 NTSTATUS
 CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive,
                 IN PKEY_CELL KeyCell,
+                IN BLOCK_OFFSET KeyCellOffset,
                 IN PUNICODE_STRING ValueName,
                 OUT PVALUE_CELL *pValueCell,
-                OUT BLOCK_OFFSET *pVBOffset)
+                OUT BLOCK_OFFSET *pValueCellOffset)
 {
   PVALUE_LIST_CELL NewValueListCell;
   PVALUE_LIST_CELL ValueListCell;
   PVALUE_CELL NewValueCell;
-  BLOCK_OFFSET VLBOffset;
-  BLOCK_OFFSET VBOffset;
+  BLOCK_OFFSET NewValueListCellOffset;
+  BLOCK_OFFSET ValueListCellOffset;
+  BLOCK_OFFSET NewValueCellOffset;
   ULONG CellSize;
   NTSTATUS Status;
 
-  Status = CmiAllocateValueCell(RegistryHive,
-                               &NewValueCell,
-                               &VBOffset,
-                               ValueName);
-  if (!NT_SUCCESS(Status))
-    {
-      return Status;
-    }
-
   DPRINT("KeyCell->ValuesOffset %lu\n", (ULONG)KeyCell->ValueListOffset);
 
   ValueListCell = CmiGetCell (RegistryHive, KeyCell->ValueListOffset, NULL);
-
   if (ValueListCell == NULL)
     {
       CellSize = sizeof(VALUE_LIST_CELL) +
@@ -2848,27 +2886,30 @@ CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive,
       Status = CmiAllocateCell (RegistryHive,
                                CellSize,
                                (PVOID) &ValueListCell,
-                               &VLBOffset);
-
+                               &ValueListCellOffset);
       if (!NT_SUCCESS(Status))
        {
-         CmiDestroyValueCell(RegistryHive, NewValueCell, VBOffset);
          return Status;
        }
-      KeyCell->ValueListOffset = VLBOffset;
+
+      KeyCell->ValueListOffset = ValueListCellOffset;
+      CmiMarkBlockDirty(RegistryHive, KeyCellOffset);
+      CmiMarkBlockDirty(RegistryHive, ValueListCellOffset);
     }
   else if (KeyCell->NumberOfValues >= 
           (((ULONG)ABS_VALUE(ValueListCell->CellSize) - sizeof(VALUE_LIST_CELL)) / sizeof(BLOCK_OFFSET)))
     {
+#if 0
       CellSize = sizeof(VALUE_LIST_CELL) +
                 ((KeyCell->NumberOfValues + REG_VALUE_LIST_CELL_MULTIPLE) * sizeof(BLOCK_OFFSET));
+#endif
+      CellSize = 2 * (ULONG)ABS_VALUE(ValueListCell->CellSize);
       Status = CmiAllocateCell (RegistryHive,
                                CellSize,
                                (PVOID) &NewValueListCell,
-                               &VLBOffset);
+                               &NewValueListCellOffset);
       if (!NT_SUCCESS(Status))
        {
-         CmiDestroyValueCell(RegistryHive, NewValueCell, VBOffset);
          return Status;
        }
 
@@ -2876,8 +2917,12 @@ CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive,
                    &ValueListCell->ValueOffset[0],
                    sizeof(BLOCK_OFFSET) * KeyCell->NumberOfValues);
       CmiDestroyCell (RegistryHive, ValueListCell, KeyCell->ValueListOffset);
-      KeyCell->ValueListOffset = VLBOffset;
+      CmiMarkBlockDirty (RegistryHive, KeyCell->ValueListOffset);
+
+      KeyCell->ValueListOffset = NewValueListCellOffset;
       ValueListCell = NewValueListCell;
+      CmiMarkBlockDirty (RegistryHive, KeyCellOffset);
+      CmiMarkBlockDirty (RegistryHive, NewValueListCellOffset);
     }
 
   DPRINT("KeyCell->NumberOfValues %lu, ValueListCell->CellSize %lu (%lu %lx)\n",
@@ -2886,11 +2931,24 @@ CmiAddValueToKey(IN PREGISTRY_HIVE RegistryHive,
         ((ULONG)ABS_VALUE(ValueListCell->CellSize) - sizeof(VALUE_LIST_CELL)) / sizeof(BLOCK_OFFSET),
         ((ULONG)ABS_VALUE(ValueListCell->CellSize) - sizeof(VALUE_LIST_CELL)) / sizeof(BLOCK_OFFSET));
 
-  ValueListCell->ValueOffset[KeyCell->NumberOfValues] = VBOffset;
+  Status = CmiAllocateValueCell(RegistryHive,
+                               &NewValueCell,
+                               &NewValueCellOffset,
+                               ValueName);
+  if (!NT_SUCCESS(Status))
+    {
+      return Status;
+    }
+
+  ValueListCell->ValueOffset[KeyCell->NumberOfValues] = NewValueCellOffset;
   KeyCell->NumberOfValues++;
 
+  CmiMarkBlockDirty(RegistryHive, KeyCellOffset);
+  CmiMarkBlockDirty(RegistryHive, KeyCell->ValueListOffset);
+  CmiMarkBlockDirty(RegistryHive, NewValueCellOffset);
+
   *pValueCell = NewValueCell;
-  *pVBOffset = VBOffset;
+  *pValueCellOffset = NewValueCellOffset;
 
   return STATUS_SUCCESS;
 }
@@ -2904,13 +2962,13 @@ CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive,
 {
   PVALUE_LIST_CELL ValueListCell;
   PVALUE_CELL CurValueCell;
-  ULONG  i;
+  ULONG i;
+  NTSTATUS Status;
 
   ValueListCell = CmiGetCell (RegistryHive, KeyCell->ValueListOffset, NULL);
-
   if (ValueListCell == NULL)
     {
-      DPRINT("CmiGetBlock() failed\n");
+      DPRINT1("CmiGetBlock() failed\n");
       return STATUS_SUCCESS;
     }
 
@@ -2921,50 +2979,58 @@ CmiDeleteValueFromKey(IN PREGISTRY_HIVE RegistryHive,
       CurValueCell = CmiGetCell (RegistryHive, ValueListCell->ValueOffset[i], NULL);
       if (CurValueCell == NULL)
        {
-         DPRINT("CmiGetBlock() failed\n");
+         DPRINT1("CmiGetBlock() failed\n");
          return STATUS_UNSUCCESSFUL;
        }
 
-      if ((CurValueCell != NULL) &&
-         CmiComparePackedNames(ValueName,
+      if (CmiComparePackedNames(ValueName,
                                CurValueCell->Name,
                                CurValueCell->NameSize,
                                (BOOLEAN)((CurValueCell->Flags & REG_VALUE_NAME_PACKED) ? TRUE : FALSE)))
        {
-         CmiDestroyValueCell(RegistryHive, CurValueCell, ValueListCell->ValueOffset[i]);
+         Status = CmiDestroyValueCell(RegistryHive,
+                                      CurValueCell,
+                                      ValueListCell->ValueOffset[i]);
+         if (CurValueCell == NULL)
+           {
+             DPRINT1("CmiDestroyValueCell() failed\n");
+             return Status;
+           }
 
-         if ((KeyCell->NumberOfValues - 1) < i)
+         if (i < (KeyCell->NumberOfValues - 1))
            {
-             RtlCopyMemory(&ValueListCell->ValueOffset[i],
+             RtlMoveMemory(&ValueListCell->ValueOffset[i],
                            &ValueListCell->ValueOffset[i + 1],
                            sizeof(BLOCK_OFFSET) * (KeyCell->NumberOfValues - 1 - i));
            }
+         ValueListCell->ValueOffset[KeyCell->NumberOfValues - 1] = 0;
+
+
+         KeyCell->NumberOfValues--;
+
+         if (KeyCell->NumberOfValues == 0)
+           {
+             CmiDestroyCell(RegistryHive,
+                            ValueListCell,
+                            KeyCell->ValueListOffset);
+             KeyCell->ValueListOffset = -1;
+           }
          else
            {
-             RtlZeroMemory(&ValueListCell->ValueOffset[i], sizeof(BLOCK_OFFSET));
+             CmiMarkBlockDirty(RegistryHive,
+                               KeyCell->ValueListOffset);
            }
 
-         KeyCell->NumberOfValues -= 1;
-         break;
-       }
-    }
+         CmiMarkBlockDirty(RegistryHive,
+                           KeyCellOffset);
 
-  if (KeyCell->NumberOfValues == 0)
-    {
-      CmiDestroyCell (RegistryHive,
-                     ValueListCell,
-                     KeyCell->ValueListOffset);
-    }
-  else
-    {
-      CmiMarkBlockDirty(RegistryHive,
-                       KeyCell->ValueListOffset);
+         return STATUS_SUCCESS;
+       }
     }
 
-  CmiMarkBlockDirty(RegistryHive,
-                   KeyCellOffset);
+  DPRINT("Couldn't find the desired value\n");
 
-  return STATUS_SUCCESS;
+  return STATUS_OBJECT_NAME_NOT_FOUND;
 }
 
 
@@ -2993,7 +3059,7 @@ CmiAllocateHashTableCell (IN PREGISTRY_HIVE RegistryHive,
     }
   else
     {
-         assert(SubKeyCount <= 0xffff); /* should really be USHORT_MAX or similar */
+      assert(SubKeyCount <= 0xffff); /* should really be USHORT_MAX or similar */
       NewHashBlock->Id = REG_HASH_TABLE_CELL_ID;
       NewHashBlock->HashTableSize = (USHORT)SubKeyCount;
       *HashBlock = NewHashBlock;
@@ -3108,7 +3174,7 @@ CmiAllocateValueCell(PREGISTRY_HIVE RegistryHive,
     }
   else
     {
-         assert(NameSize <= 0xffff); /* should really be USHORT_MAX or similar */
+      assert(NameSize <= 0xffff); /* should really be USHORT_MAX or similar */
       NewValueCell->Id = REG_VALUE_CELL_ID;
       NewValueCell->NameSize = (USHORT)NameSize;
       if (Packable)
@@ -3139,44 +3205,45 @@ CmiAllocateValueCell(PREGISTRY_HIVE RegistryHive,
 NTSTATUS
 CmiDestroyValueCell(PREGISTRY_HIVE RegistryHive,
                    PVALUE_CELL ValueCell,
-                   BLOCK_OFFSET VBOffset)
+                   BLOCK_OFFSET ValueCellOffset)
 {
   NTSTATUS Status;
-  PVOID pBlock;
-  PHBIN pBin;
+  PVOID DataCell;
+  PHBIN Bin;
 
-  DPRINT("CmiDestroyValueCell(Cell %p  Offset %lx)\n", ValueCell, VBOffset);
+  DPRINT("CmiDestroyValueCell(Cell %p  Offset %lx)\n",
+        ValueCell, ValueCellOffset);
 
   VERIFY_VALUE_CELL(ValueCell);
 
   /* Destroy the data cell */
   if (ValueCell->DataSize > sizeof(BLOCK_OFFSET))
     {
-      pBlock = CmiGetCell (RegistryHive, ValueCell->DataOffset, &pBin);
-      if (pBlock == NULL)
+      DataCell = CmiGetCell (RegistryHive, ValueCell->DataOffset, &Bin);
+      if (DataCell == NULL)
        {
-         DPRINT("CmiGetBlock() failed\n");
+         DPRINT("CmiGetCell() failed\n");
          return STATUS_UNSUCCESSFUL;
        }
 
-      Status = CmiDestroyCell (RegistryHive, pBlock, ValueCell->DataOffset);
+      Status = CmiDestroyCell (RegistryHive, DataCell, ValueCell->DataOffset);
       if (!NT_SUCCESS(Status))
        {
-         return  Status;
+         return Status;
        }
 
       /* Update time of heap */
       if (!IsNoFileHive(RegistryHive))
-       NtQuerySystemTime(&pBin->DateModified);
+       NtQuerySystemTime(&Bin->DateModified);
     }
 
   /* Destroy the value cell */
-  Status = CmiDestroyCell (RegistryHive, ValueCell, VBOffset);
+  Status = CmiDestroyCell (RegistryHive, ValueCell, ValueCellOffset);
 
   /* Update time of heap */
-  if (!IsNoFileHive(RegistryHive) && CmiGetCell (RegistryHive, VBOffset, &pBin))
+  if (!IsNoFileHive(RegistryHive) && CmiGetCell (RegistryHive, ValueCellOffset, &Bin))
     {
-      NtQuerySystemTime(&pBin->DateModified);
+      NtQuerySystemTime(&Bin->DateModified);
     }
 
   return Status;
@@ -3185,31 +3252,41 @@ CmiDestroyValueCell(PREGISTRY_HIVE RegistryHive,
 
 NTSTATUS
 CmiAddBin(PREGISTRY_HIVE RegistryHive,
+         ULONG BlockCount,
          PVOID *NewBlock,
          BLOCK_OFFSET *NewBlockOffset)
 {
+  PBLOCK_LIST_ENTRY BlockList;
   PCELL_HEADER tmpBlock;
-  PHBIN * tmpBlockList;
   PHBIN tmpBin;
+  ULONG BinSize;
+  ULONG i;
 
-  tmpBin = ExAllocatePool(PagedPool, REG_BLOCK_SIZE);
+  DPRINT ("CmiAddBin (BlockCount %lu)\n", BlockCount);
+
+  BinSize = BlockCount * REG_BLOCK_SIZE;
+  tmpBin = ExAllocatePool(PagedPool, BinSize);
   if (tmpBin == NULL)
     {
       return STATUS_INSUFFICIENT_RESOURCES;
     }
+  RtlZeroMemory (tmpBin,
+                BinSize);
 
-  tmpBin->BlockId = REG_BIN_ID;
-  tmpBin->BlockOffset = RegistryHive->FileSize - REG_BLOCK_SIZE;
-  RegistryHive->FileSize += REG_BLOCK_SIZE;
-  tmpBin->BlockSize = REG_BLOCK_SIZE;
+  tmpBin->HeaderId = REG_BIN_ID;
+  tmpBin->BinOffset = RegistryHive->FileSize - REG_BLOCK_SIZE;
+  RegistryHive->FileSize += BinSize;
+  tmpBin->BinSize = BinSize;
   tmpBin->Unused1 = 0;
-  ZwQuerySystemTime(&tmpBin->DateModified);
+  NtQuerySystemTime(&tmpBin->DateModified);
   tmpBin->Unused2 = 0;
 
-  /* Increase size of list of blocks */
-  tmpBlockList = ExAllocatePool(NonPagedPool,
-         sizeof(PHBIN *) * (RegistryHive->BlockListSize + 1));
-  if (tmpBlockList == NULL)
+  DPRINT ("  BinOffset %lx  BinSize %lx\n", tmpBin->BinOffset,tmpBin->BinSize);
+
+  /* Allocate new block list */
+  BlockList = ExAllocatePool(NonPagedPool,
+                            sizeof(BLOCK_LIST_ENTRY) * (RegistryHive->BlockListSize + BlockCount));
+  if (BlockList == NULL)
     {
       ExFreePool(tmpBin);
       return STATUS_INSUFFICIENT_RESOURCES;
@@ -3217,19 +3294,24 @@ CmiAddBin(PREGISTRY_HIVE RegistryHive,
 
   if (RegistryHive->BlockListSize > 0)
     {
-      RtlCopyMemory (tmpBlockList,
+      RtlCopyMemory (BlockList,
                     RegistryHive->BlockList,
-                    sizeof(PHBIN *)*(RegistryHive->BlockListSize));
+                    sizeof(BLOCK_LIST_ENTRY) * RegistryHive->BlockListSize);
       ExFreePool(RegistryHive->BlockList);
     }
 
-  RegistryHive->BlockList = tmpBlockList;
-  RegistryHive->BlockList[RegistryHive->BlockListSize] = tmpBin;
-  RegistryHive->BlockListSize++;
+  RegistryHive->BlockList = BlockList;
+  for (i = 0; i < BlockCount; i++)
+    {
+      RegistryHive->BlockList[RegistryHive->BlockListSize + i].Block =
+       (PVOID)((ULONG_PTR)tmpBin + (i * REG_BLOCK_SIZE));
+      RegistryHive->BlockList[RegistryHive->BlockListSize + i].Bin = tmpBin;
+    }
+  RegistryHive->BlockListSize += BlockCount;
 
   /* 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);
+  tmpBlock->CellSize = (BinSize - REG_HBIN_DATA_OFFSET);
 
   /* Grow bitmap if necessary */
   if (IsNoFileHive(RegistryHive) &&
@@ -3260,11 +3342,11 @@ CmiAddBin(PREGISTRY_HIVE RegistryHive,
   *NewBlock = (PVOID) tmpBlock;
 
   if (NewBlockOffset)
-    *NewBlockOffset = tmpBin->BlockOffset + REG_HBIN_DATA_OFFSET;
+    *NewBlockOffset = tmpBin->BinOffset + REG_HBIN_DATA_OFFSET;
 
   /* Mark new bin dirty */
   CmiMarkBinDirty(RegistryHive,
-                 tmpBin->BlockOffset);
+                 tmpBin->BinOffset);
 
   return STATUS_SUCCESS;
 }
@@ -3277,12 +3359,10 @@ CmiAllocateCell (PREGISTRY_HIVE RegistryHive,
                 BLOCK_OFFSET *CellOffset)
 {
   PCELL_HEADER NewCell;
-  NTSTATUS Status;
-  PHBIN pBin;
+  PHBIN Bin;
   ULONG i;
   PVOID Temp;
-
-  Status = STATUS_SUCCESS;
+  NTSTATUS Status;
 
   /* Round to 16 bytes multiple */
   CellSize = ROUND_UP(CellSize, 16);
@@ -3291,20 +3371,18 @@ CmiAllocateCell (PREGISTRY_HIVE RegistryHive,
   if (IsPointerHive(RegistryHive))
     {
       NewCell = ExAllocatePool(NonPagedPool, CellSize);
-
       if (NewCell == NULL)
        {
-         Status = STATUS_INSUFFICIENT_RESOURCES;
+         return STATUS_INSUFFICIENT_RESOURCES;
        }
-      else
-       {
-         RtlZeroMemory(NewCell, CellSize);
-         NewCell->CellSize = -CellSize;
 
-         *Cell = NewCell;
-         if (CellOffset != NULL)
-           *CellOffset = (BLOCK_OFFSET) NewCell;
-       }
+      RtlZeroMemory (NewCell,
+                    CellSize);
+      NewCell->CellSize = -CellSize;
+
+      *Cell = NewCell;
+      if (CellOffset != NULL)
+       *CellOffset = (BLOCK_OFFSET) NewCell;
     }
   else
     {
@@ -3319,18 +3397,17 @@ CmiAllocateCell (PREGISTRY_HIVE RegistryHive,
                *CellOffset = RegistryHive->FreeListOffset[i];
 
              /* Update time of heap */
-             Temp = CmiGetCell (RegistryHive, RegistryHive->FreeListOffset[i], &pBin);
+             Temp = CmiGetCell (RegistryHive,
+                                RegistryHive->FreeListOffset[i],
+                                &Bin);
              if (Temp == NULL)
                {
                  DPRINT("CmiGetBlock() failed\n");
                  return STATUS_UNSUCCESSFUL;
                }
 
-             if (Temp)
-               {
-                 NtQuerySystemTime(&pBin->DateModified);
-                 CmiMarkBlockDirty(RegistryHive, RegistryHive->FreeListOffset[i]);
-               }
+             NtQuerySystemTime(&Bin->DateModified);
+             CmiMarkBlockDirty(RegistryHive, RegistryHive->FreeListOffset[i]);
 
              if ((i + 1) < RegistryHive->FreeListSize)
                {
@@ -3352,36 +3429,39 @@ CmiAllocateCell (PREGISTRY_HIVE RegistryHive,
       if (NewCell == NULL)
        {
          /* Add a new bin */
-         Status = CmiAddBin(RegistryHive, (PVOID *) &NewCell , CellOffset);
+         Status = CmiAddBin(RegistryHive,
+                            ((CellSize + sizeof(HBIN) - 1) / REG_BLOCK_SIZE) + 1,
+                            (PVOID *)&NewCell,
+                            CellOffset);
+         if (!NT_SUCCESS(Status))
+           return Status;
        }
 
-      if (NT_SUCCESS(Status))
-       {
-         *Cell = NewCell;
-
-         /* Split the block in two parts */
-         if (NewCell->CellSize > CellSize)
-           {
-             NewCell = (PCELL_HEADER) ((ULONG_PTR) NewCell + CellSize);
-             NewCell->CellSize = ((PCELL_HEADER) (*Cell))->CellSize - CellSize;
-             CmiAddFree(RegistryHive,
-                        NewCell,
-                        *CellOffset + CellSize,
-                        TRUE);
-             CmiMarkBlockDirty(RegistryHive,
-                               *CellOffset + CellSize);
-           }
-         else if (NewCell->CellSize < CellSize)
-           {
-             return(STATUS_UNSUCCESSFUL);
-           }
+      *Cell = NewCell;
 
-         RtlZeroMemory(*Cell, CellSize);
-         ((PCELL_HEADER) (*Cell))->CellSize = -CellSize;
+      /* Split the block in two parts */
+      if (NewCell->CellSize > CellSize)
+       {
+         NewCell = (PCELL_HEADER) ((ULONG_PTR) NewCell + CellSize);
+         NewCell->CellSize = ((PCELL_HEADER) (*Cell))->CellSize - CellSize;
+         CmiAddFree(RegistryHive,
+                    NewCell,
+                    *CellOffset + CellSize,
+                    TRUE);
+         CmiMarkBlockDirty(RegistryHive,
+                           *CellOffset + CellSize);
+       }
+      else if (NewCell->CellSize < CellSize)
+       {
+         return STATUS_UNSUCCESSFUL;
        }
+
+      RtlZeroMemory(*Cell,
+                   CellSize);
+      ((PCELL_HEADER) (*Cell))->CellSize = -CellSize;
     }
 
-  return(Status);
+  return STATUS_SUCCESS;
 }
 
 
@@ -3427,13 +3507,13 @@ CmiDestroyCell (PREGISTRY_HIVE RegistryHive,
 PVOID
 CmiGetCell (PREGISTRY_HIVE RegistryHive,
            BLOCK_OFFSET CellOffset,
-           PHBIN * ppBin)
+           PHBIN *Bin)
 {
   PHBIN pBin;
 
-  if (ppBin)
+  if (Bin != NULL)
     {
-      *ppBin = NULL;
+      *Bin = NULL;
     }
 
   if (CellOffset == (BLOCK_OFFSET)-1)
@@ -3446,25 +3526,25 @@ CmiGetCell (PREGISTRY_HIVE RegistryHive,
       return (PVOID)CellOffset;
     }
 
-  if (CellOffset > RegistryHive->BlockListSize * 4096)
+  if (CellOffset > RegistryHive->BlockListSize * REG_BLOCK_SIZE)
     {
       DPRINT1("CellOffset exceeds valid range (%lu > %lu)\n",
-             CellOffset, RegistryHive->BlockListSize * 4096);
+             CellOffset, RegistryHive->BlockListSize * REG_BLOCK_SIZE);
       return NULL;
     }
 
-  pBin = RegistryHive->BlockList[CellOffset / 4096];
+  pBin = RegistryHive->BlockList[CellOffset / REG_BLOCK_SIZE].Bin;
   if (pBin == NULL)
     {
       return NULL;
     }
 
-  if (ppBin)
+  if (Bin != NULL)
     {
-      *ppBin = pBin;
+      *Bin = pBin;
     }
 
-  return((PVOID)((ULONG_PTR)pBin + (CellOffset - pBin->BlockOffset)));
+  return((PVOID)((ULONG_PTR)pBin + (CellOffset - pBin->BinOffset)));
 }
 
 
@@ -3490,8 +3570,8 @@ CmiMergeFree(PREGISTRY_HIVE RegistryHive,
   if (Bin == NULL)
     return(FALSE);
 
-  BinOffset = Bin->BlockOffset;
-  BinSize = Bin->BlockSize;
+  BinOffset = Bin->BinOffset;
+  BinSize = Bin->BinSize;
   DPRINT("Bin %p  Offset %lx  Size %lx\n", Bin, BinOffset, BinSize);
 
   for (i = 0; i < RegistryHive->FreeListSize; i++)
@@ -3687,7 +3767,7 @@ CmiMarkBlockDirty(PREGISTRY_HIVE RegistryHive,
 
   DPRINT("CmiMarkBlockDirty(Offset 0x%lx)\n", (ULONG)BlockOffset);
 
-  BlockNumber = (ULONG)BlockOffset / 4096;
+  BlockNumber = (ULONG)BlockOffset / REG_BLOCK_SIZE;
 
   Cell = CmiGetCell (RegistryHive,
                     BlockOffset,
@@ -3697,7 +3777,8 @@ CmiMarkBlockDirty(PREGISTRY_HIVE RegistryHive,
   if (CellSize < 0)
     CellSize = -CellSize;
 
-  BlockCount = (ROUND_UP(BlockOffset + CellSize, 4096) - ROUND_DOWN(BlockOffset, 4096)) / 4096;
+  BlockCount = (ROUND_UP(BlockOffset + CellSize, REG_BLOCK_SIZE) -
+               ROUND_DOWN(BlockOffset, REG_BLOCK_SIZE)) / REG_BLOCK_SIZE;
 
   DPRINT("  BlockNumber %lu  Size %lu (%s)  BlockCount %lu\n",
         BlockNumber,
@@ -3725,15 +3806,15 @@ CmiMarkBinDirty(PREGISTRY_HIVE RegistryHive,
 
   DPRINT("CmiMarkBinDirty(Offset 0x%lx)\n", (ULONG)BinOffset);
 
-  BlockNumber = (ULONG)BinOffset / 4096;
+  BlockNumber = (ULONG)BinOffset / REG_BLOCK_SIZE;
 
-  Bin = RegistryHive->BlockList[BlockNumber];
+  Bin = RegistryHive->BlockList[BlockNumber].Bin;
 
-  BlockCount = Bin->BlockSize / 4096;
+  BlockCount = Bin->BinSize / REG_BLOCK_SIZE;
 
-  DPRINT("  BlockNumber %lu  Size %lu  BlockCount %lu\n",
+  DPRINT("  BlockNumber %lu  BinSize %lu  BlockCount %lu\n",
         BlockNumber,
-        Bin->BlockSize,
+        Bin->BinSize,
         BlockCount);
 
   RegistryHive->HiveDirty = TRUE;
@@ -4189,11 +4270,7 @@ CmiSaveTempHive (PREGISTRY_HIVE Hive,
   Hive->HiveHeader->Checksum = CmiCalcChecksum ((PULONG)Hive->HiveHeader);
 
   /* Write hive block */
-#if defined(__GNUC__)
-  FileOffset.QuadPart = 0ULL;
-#else
-  FileOffset.QuadPart = 0;
-#endif
+  FileOffset.QuadPart = (ULONGLONG)0;
   Status = NtWriteFile (FileHandle,
                        NULL,
                        NULL,
@@ -4212,14 +4289,10 @@ CmiSaveTempHive (PREGISTRY_HIVE Hive,
   DPRINT ("Saving %lu blocks\n", Hive->BlockListSize);
   for (BlockIndex = 0; BlockIndex < Hive->BlockListSize; BlockIndex++)
     {
-      BlockPtr = Hive->BlockList[BlockIndex];
+      BlockPtr = Hive->BlockList[BlockIndex].Block;
       DPRINT ("BlockPtr %p\n", BlockPtr);
 
-#if defined(__GNUC__)
-      FileOffset.QuadPart = (ULONGLONG)(BlockIndex + 1) * 4096ULL;
-#else
-      FileOffset.QuadPart = (ULONGLONG)(BlockIndex + 1) * 4096;
-#endif
+      FileOffset.QuadPart = (ULONGLONG)(BlockIndex + 1) * (ULONGLONG)REG_BLOCK_SIZE;
       DPRINT ("File offset %I64x\n", FileOffset.QuadPart);
 
       /* Write hive block */