[ros-diffs] [fireball] 23336: Actually add cmlib itself

fireball at svn.reactos.org fireball at svn.reactos.org
Fri Jul 28 22:50:07 CEST 2006


Author: fireball
Date: Sat Jul 29 00:50:05 2006
New Revision: 23336

URL: http://svn.reactos.org/svn/reactos?rev=23336&view=rev
Log:
Actually add cmlib itself

Added:
    trunk/reactos/lib/cmlib/
    trunk/reactos/lib/cmlib/cmdata.h
    trunk/reactos/lib/cmlib/cminit.c
    trunk/reactos/lib/cmlib/cmlib.h
    trunk/reactos/lib/cmlib/cmlib.mak
    trunk/reactos/lib/cmlib/cmlib.rbuild
    trunk/reactos/lib/cmlib/hivebin.c
    trunk/reactos/lib/cmlib/hivecell.c
    trunk/reactos/lib/cmlib/hivedata.h
    trunk/reactos/lib/cmlib/hiveinit.c
    trunk/reactos/lib/cmlib/hivesum.c
    trunk/reactos/lib/cmlib/hivewrt.c

Added: trunk/reactos/lib/cmlib/cmdata.h
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/cmlib/cmdata.h?rev=23336&view=auto
==============================================================================
--- trunk/reactos/lib/cmlib/cmdata.h (added)
+++ trunk/reactos/lib/cmlib/cmdata.h Sat Jul 29 00:50:05 2006
@@ -1,0 +1,134 @@
+/*
+ * PROJECT:   registry manipulation library
+ * LICENSE:   GPL - See COPYING in the top level directory
+ * COPYRIGHT: Copyright 2005 Filip Navara <navaraf at reactos.org>
+ *            Copyright 2001 - 2005 Eric Kohl
+ */
+
+#ifndef CMLIB_CMDATA_H
+#define CMLIB_CMDATA_H
+
+#define  REG_INIT_BLOCK_LIST_SIZE      32
+#define  REG_INIT_HASH_TABLE_SIZE      3
+#define  REG_EXTEND_HASH_TABLE_SIZE    4
+#define  REG_VALUE_LIST_CELL_MULTIPLE  4
+
+#define  REG_KEY_CELL_ID               0x6b6e
+#define  REG_HASH_TABLE_CELL_ID        0x666c
+#define  REG_VALUE_CELL_ID             0x6b76
+#define  REG_SECURITY_CELL_ID          0x6b73
+
+#include <pshpack1.h>
+
+typedef struct _KEY_CELL
+{
+   /* Key cell identifier "kn" (0x6b6e) */
+   USHORT Id;
+
+   /* Flags */
+   USHORT Flags;
+
+   /* Time of last flush */
+   LARGE_INTEGER LastWriteTime;
+
+   /* ? */
+   ULONG UnUsed1;
+
+   /* Block offset of parent key cell */
+   HCELL_INDEX ParentKeyOffset;
+
+   /* Count of sub keys for the key in this key cell (stable & volatile) */
+   ULONG NumberOfSubKeys[HvMaxStorageType];
+
+   /* Block offset of has table for FIXME: subkeys/values? (stable & volatile) */
+   HCELL_INDEX HashTableOffset[HvMaxStorageType];
+
+   /* Count of values contained in this key cell */
+   ULONG NumberOfValues;
+
+   /* Block offset of VALUE_LIST_CELL */
+   HCELL_INDEX ValueListOffset;
+
+   /* Block offset of security cell */
+   HCELL_INDEX SecurityKeyOffset;
+
+   /* Block offset of registry key class */
+   HCELL_INDEX ClassNameOffset;
+
+   /* ? */
+   ULONG Unused4[5];
+
+   /* Size in bytes of key name */
+   USHORT NameSize;
+
+   /* Size of class name in bytes */
+   USHORT ClassSize;
+
+   /* Name of key (not zero terminated) */
+   UCHAR Name[0];
+} KEY_CELL, *PKEY_CELL;
+
+/* KEY_CELL.Flags constants */
+#define  REG_KEY_VOLATILE_CELL             0x01
+#define  REG_KEY_ROOT_CELL                 0x0C
+#define  REG_KEY_LINK_CELL                 0x10
+#define  REG_KEY_NAME_PACKED               0x20
+
+/*
+ * Hash record
+ *
+ * HashValue:
+ *	packed name: four letters of value's name
+ *	otherwise: Zero!
+ */
+typedef struct _HASH_RECORD
+{
+  HCELL_INDEX  KeyOffset;
+  ULONG  HashValue;
+} HASH_RECORD, *PHASH_RECORD;
+
+typedef struct _HASH_TABLE_CELL
+{
+  USHORT  Id;
+  USHORT  HashTableSize;
+  HASH_RECORD  Table[0];
+} HASH_TABLE_CELL, *PHASH_TABLE_CELL;
+
+typedef struct _VALUE_LIST_CELL
+{
+  HCELL_INDEX  ValueOffset[0];
+} VALUE_LIST_CELL, *PVALUE_LIST_CELL;
+
+typedef struct _VALUE_CELL
+{
+  USHORT Id;	// "kv"
+  USHORT NameSize;	// length of Name
+  ULONG  DataSize;	// length of datas in the cell pointed by DataOffset
+  HCELL_INDEX  DataOffset;// datas are here if high bit of DataSize is set
+  ULONG  DataType;
+  USHORT Flags;
+  USHORT Unused1;
+  UCHAR  Name[0]; /* warning : not zero terminated */
+} VALUE_CELL, *PVALUE_CELL;
+
+/* VALUE_CELL.Flags constants */
+#define REG_VALUE_NAME_PACKED             0x0001
+
+/* VALUE_CELL.DataSize mask constants */
+#define REG_DATA_SIZE_MASK                 0x7FFFFFFF
+#define REG_DATA_IN_OFFSET                 0x80000000
+
+typedef struct _SECURITY_CELL
+{
+  USHORT Id;	// "sk"
+  USHORT Reserved;
+  HCELL_INDEX PrevSecurityCell;
+  HCELL_INDEX NextSecurityCell;
+  ULONG RefCount;
+  ULONG SdSize;
+  UCHAR Data[0];
+} SECURITY_CELL, *PSECURITY_CELL;
+
+#include <poppack.h>
+
+#endif /* CMLIB_CMDATA_H */

Added: trunk/reactos/lib/cmlib/cminit.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/cmlib/cminit.c?rev=23336&view=auto
==============================================================================
--- trunk/reactos/lib/cmlib/cminit.c (added)
+++ trunk/reactos/lib/cmlib/cminit.c Sat Jul 29 00:50:05 2006
@@ -1,0 +1,82 @@
+/*
+ * PROJECT:   registry manipulation library
+ * LICENSE:   GPL - See COPYING in the top level directory
+ * COPYRIGHT: Copyright 2005 Filip Navara <navaraf at reactos.org>
+ *            Copyright 2001 - 2005 Eric Kohl
+ */
+
+#include "cmlib.h"
+
+BOOLEAN CMAPI
+CmCreateRootNode(
+   PREGISTRY_HIVE Hive,
+   PCWSTR Name)
+{
+   PKEY_CELL KeyCell;
+   HCELL_INDEX RootCellIndex;
+   ULONG NameSize;
+
+   NameSize = wcslen(Name) * sizeof(WCHAR);
+   RootCellIndex = HvAllocateCell(Hive, sizeof(KEY_CELL) + NameSize, HvStable);
+   if (RootCellIndex == HCELL_NULL)
+      return FALSE;
+
+   Hive->HiveHeader->RootCell = RootCellIndex;
+   Hive->HiveHeader->Checksum = HvpHiveHeaderChecksum(Hive->HiveHeader);
+
+   KeyCell = (PKEY_CELL)HvGetCell(Hive, RootCellIndex);
+   KeyCell->Id = REG_KEY_CELL_ID;
+   KeyCell->Flags = REG_KEY_ROOT_CELL;
+   KeyCell->LastWriteTime.QuadPart = 0;
+   KeyCell->ParentKeyOffset = HCELL_NULL;
+   KeyCell->NumberOfSubKeys[0] = 0;
+   KeyCell->NumberOfSubKeys[1] = 0;
+   KeyCell->HashTableOffset[0] = HCELL_NULL;
+   KeyCell->HashTableOffset[1] = HCELL_NULL;
+   KeyCell->NumberOfValues = 0;
+   KeyCell->ValueListOffset = HCELL_NULL;
+   KeyCell->SecurityKeyOffset = HCELL_NULL;
+   KeyCell->ClassNameOffset = HCELL_NULL; 
+   KeyCell->NameSize = NameSize;
+   KeyCell->ClassSize = 0;
+   memcpy(KeyCell->Name, Name, NameSize);
+
+   return TRUE;
+}
+
+static VOID CMAPI
+CmpPrepareKey(
+   PREGISTRY_HIVE RegistryHive,
+   PKEY_CELL KeyCell)
+{
+   PKEY_CELL SubKeyCell;
+   PHASH_TABLE_CELL HashCell;
+   ULONG i;
+
+   ASSERT(KeyCell->Id == REG_KEY_CELL_ID);
+
+   KeyCell->HashTableOffset[HvVolatile] = HCELL_NULL;
+   KeyCell->NumberOfSubKeys[HvVolatile] = 0;
+
+   /* Enumerate and add subkeys */
+   if (KeyCell->NumberOfSubKeys[HvStable] > 0)
+   {
+      HashCell = HvGetCell(RegistryHive, KeyCell->HashTableOffset[HvStable]);
+
+      for (i = 0; i < KeyCell->NumberOfSubKeys[HvStable]; i++)
+      {
+         SubKeyCell = HvGetCell(RegistryHive, HashCell->Table[i].KeyOffset);
+         CmpPrepareKey(RegistryHive, SubKeyCell);
+      }
+   }
+}
+
+VOID CMAPI
+CmPrepareHive(
+   PREGISTRY_HIVE RegistryHive)
+{ 
+   PKEY_CELL RootCell;
+
+   RootCell = HvGetCell(RegistryHive, RegistryHive->HiveHeader->RootCell);
+   CmpPrepareKey(RegistryHive, RootCell);
+}

Added: trunk/reactos/lib/cmlib/cmlib.h
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/cmlib/cmlib.h?rev=23336&view=auto
==============================================================================
--- trunk/reactos/lib/cmlib/cmlib.h (added)
+++ trunk/reactos/lib/cmlib/cmlib.h Sat Jul 29 00:50:05 2006
@@ -1,0 +1,175 @@
+/*
+ * PROJECT:   registry manipulation library
+ * LICENSE:   GPL - See COPYING in the top level directory
+ * COPYRIGHT: Copyright 2005 Filip Navara <navaraf at reactos.org>
+ *            Copyright 2001 - 2005 Eric Kohl
+ */
+
+#ifndef CMLIB_H
+#define CMLIB_H
+
+#include <ddk/ntddk.h>
+#include "hivedata.h"
+#include "cmdata.h"
+
+#ifndef ROUND_UP
+#define ROUND_UP(a,b)        ((((a)+(b)-1)/(b))*(b))
+#define ROUND_DOWN(a,b)      (((a)/(b))*(b))
+#endif
+
+#define CMAPI
+
+typedef struct _BLOCK_LIST_ENTRY
+{
+   PHBIN Bin;
+   PVOID Block;
+} BLOCK_LIST_ENTRY, *PBLOCK_LIST_ENTRY;
+
+struct _REGISTRY_HIVE;
+
+typedef PVOID (CMAPI *PHV_ALLOCATE)(
+   ULONG Size,
+   BOOLEAN Paged);
+
+typedef VOID (CMAPI *PHV_FREE)(
+   PVOID Ptr);
+
+typedef BOOLEAN (CMAPI *PHV_FILE_READ)(
+   struct _REGISTRY_HIVE *RegistryHive,
+   ULONG FileType,
+   ULONG FileOffset,
+   PVOID Buffer,
+   ULONG BufferLength);
+
+typedef BOOLEAN (CMAPI *PHV_FILE_WRITE)(
+   struct _REGISTRY_HIVE *RegistryHive,
+   ULONG FileType,
+   ULONG FileOffset,
+   PVOID Buffer,
+   ULONG BufferLength);
+
+typedef BOOLEAN (CMAPI *PHV_FILE_SET_SIZE)(
+   struct _REGISTRY_HIVE *RegistryHive,
+   ULONG FileType,
+   ULONG FileSize);
+
+typedef BOOLEAN (CMAPI *PHV_FILE_FLUSH)(
+   struct _REGISTRY_HIVE *RegistryHive,
+   ULONG FileType);
+
+typedef struct _REGISTRY_HIVE
+{
+   PHIVE_HEADER HiveHeader;
+   BOOLEAN ReadOnly;
+   BOOLEAN Flat;
+   RTL_BITMAP DirtyBitmap;
+   struct
+   {
+      ULONG BlockListSize;
+      PBLOCK_LIST_ENTRY BlockList;
+      HCELL_INDEX FreeListOffset[24];
+   } Storage[HvMaxStorageType];
+
+   PHV_ALLOCATE Allocate;
+   PHV_FREE Free;
+   PHV_FILE_READ FileRead;
+   PHV_FILE_WRITE FileWrite;
+   PHV_FILE_SET_SIZE FileSetSize;
+   PHV_FILE_FLUSH FileFlush;
+   PVOID Opaque;
+} REGISTRY_HIVE, *PREGISTRY_HIVE;
+
+/*
+ * Public functions.
+ */
+
+#define HV_OPERATION_CREATE_HIVE    1
+#define HV_OPERATION_MEMORY         2
+#define HV_OPERATION_MEMORY_INPLACE 3
+
+NTSTATUS CMAPI
+HvInitialize(
+   PREGISTRY_HIVE *RegistryHive,
+   ULONG Operation,
+   ULONG_PTR ChunkBase,
+   SIZE_T ChunkSize,
+   PHV_ALLOCATE Allocate,
+   PHV_FREE Free,
+   PHV_FILE_READ FileRead,
+   PHV_FILE_WRITE FileWrite,
+   PHV_FILE_SET_SIZE FileSetSize,
+   PHV_FILE_FLUSH FileFlush,
+   PVOID Opaque);
+
+VOID CMAPI 
+HvFree(
+   PREGISTRY_HIVE RegistryHive);
+
+PVOID CMAPI
+HvGetCell(
+   PREGISTRY_HIVE RegistryHive,
+   HCELL_INDEX CellOffset);
+
+LONG CMAPI
+HvGetCellSize(
+   PREGISTRY_HIVE RegistryHive,
+   PVOID Cell);
+
+HCELL_INDEX CMAPI
+HvAllocateCell(
+   PREGISTRY_HIVE RegistryHive,
+   ULONG Size,
+   HV_STORAGE_TYPE Storage);
+
+HCELL_INDEX CMAPI
+HvReallocateCell(
+   PREGISTRY_HIVE RegistryHive,
+   HCELL_INDEX CellOffset,
+   ULONG Size);
+
+VOID CMAPI
+HvFreeCell(
+   PREGISTRY_HIVE RegistryHive,
+   HCELL_INDEX CellOffset);
+
+VOID CMAPI
+HvMarkCellDirty(
+   PREGISTRY_HIVE RegistryHive,
+   HCELL_INDEX CellOffset);
+
+BOOLEAN CMAPI
+HvSyncHive(
+   PREGISTRY_HIVE RegistryHive);
+
+BOOLEAN CMAPI
+HvWriteHive(
+   PREGISTRY_HIVE RegistryHive);
+
+BOOLEAN CMAPI
+CmCreateRootNode(
+   PREGISTRY_HIVE Hive,
+   PCWSTR Name);
+
+VOID CMAPI
+CmPrepareHive(
+   PREGISTRY_HIVE RegistryHive);
+
+/*
+ * Private functions.
+ */
+
+PHBIN CMAPI
+HvpAddBin(
+   PREGISTRY_HIVE RegistryHive,
+   ULONG Size,
+   HV_STORAGE_TYPE Storage);
+
+NTSTATUS CMAPI
+HvpCreateHiveFreeCellList(
+   PREGISTRY_HIVE Hive);
+
+ULONG CMAPI
+HvpHiveHeaderChecksum(
+   PHIVE_HEADER HiveHeader);
+
+#endif /* CMLIB_H */

Added: trunk/reactos/lib/cmlib/cmlib.mak
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/cmlib/cmlib.mak?rev=23336&view=auto
==============================================================================
--- trunk/reactos/lib/cmlib/cmlib.mak (added)
+++ trunk/reactos/lib/cmlib/cmlib.mak Sat Jul 29 00:50:05 2006
@@ -1,0 +1,55 @@
+CMLIB_BASE = $(LIB_BASE_)cmlib
+CMLIB_BASE_ = $(CMLIB_BASE)$(SEP)
+CMLIB_INT = $(INTERMEDIATE_)$(CMLIB_BASE)_host
+CMLIB_INT_ = $(INTERMEDIATE_)$(CMLIB_BASE)_host$(SEP)
+CMLIB_OUT = $(OUTPUT_)$(CMLIB_BASE)_host
+CMLIB_OUT_ = $(OUTPUT_)$(CMLIB_BASE)_host$(SEP)
+
+$(CMLIB_INT): | $(LIB_INT)
+	$(ECHO_MKDIR)
+	${mkdir} $@
+
+ifneq ($(INTERMEDIATE),$(OUTPUT))
+$(CMLIB_OUT): | $(OUTPUT_)$(LIB_BASE)
+	$(ECHO_MKDIR)
+	${mkdir} $@
+endif
+
+CMLIB_HOST_TARGET = \
+	$(CMLIB_OUT)$(SEP)cmlib.a
+
+CMLIB_HOST_SOURCES = $(addprefix $(CMLIB_BASE_), \
+	hivebin.c \
+	hivecell.c \
+	hiveinit.c \
+	)
+
+CMLIB_HOST_OBJECTS = \
+	$(subst $(CMLIB_BASE), $(CMLIB_INT), $(CMLIB_HOST_SOURCES:.c=.o))
+
+CMLIB_HOST_CFLAGS = -O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+  -DCMLIB_HOST -D_M_IX86 -I$(CMLIB_BASE) -Iinclude/reactos -DDBG
+
+$(CMLIB_HOST_TARGET): $(CMLIB_HOST_OBJECTS) | $(CMLIB_OUT)
+	$(ECHO_AR)
+	$(host_ar) -r $@ $(CMLIB_HOST_OBJECTS)
+
+$(CMLIB_INT_)hivebin.o: $(CMLIB_BASE_)hivebin.c | $(CMLIB_INT)
+	$(ECHO_CC)
+	${host_gcc} $(CMLIB_HOST_CFLAGS) -c $< -o $@
+
+$(CMLIB_INT_)hivecell.o: $(CMLIB_BASE_)hivecell.c | $(CMLIB_INT)
+	$(ECHO_CC)
+	${host_gcc} $(CMLIB_HOST_CFLAGS) -c $< -o $@
+
+$(CMLIB_INT_)hiveinit.o: $(CMLIB_BASE_)hiveinit.c | $(CMLIB_INT)
+	$(ECHO_CC)
+	${host_gcc} $(CMLIB_HOST_CFLAGS) -c $< -o $@
+
+.PHONY: cmlib_host
+cmlib_host: $(CMLIB_HOST_TARGET)
+
+.PHONY: cmlib_host_clean
+cmlib_host_clean:
+	-@$(rm) $(CMLIB_HOST_TARGET) $(CMLIB_HOST_OBJECTS) 2>$(NUL)
+clean: cmlib_host_clean

Added: trunk/reactos/lib/cmlib/cmlib.rbuild
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/cmlib/cmlib.rbuild?rev=23336&view=auto
==============================================================================
--- trunk/reactos/lib/cmlib/cmlib.rbuild (added)
+++ trunk/reactos/lib/cmlib/cmlib.rbuild Sat Jul 29 00:50:05 2006
@@ -1,0 +1,14 @@
+<module name="cmlib" type="staticlibrary">
+	<include base="cmlib">.</include>
+	<define name="__NO_CTYPE_INLINES" />
+	<define name="_NTOSKRNL_" />
+	<define name="_NTSYSTEM_" />
+	<define name="NASSERT" />
+	<pch>cmlib.h</pch>
+	<file>cminit.c</file>
+	<file>hivebin.c</file>
+	<file>hivecell.c</file>
+	<file>hiveinit.c</file>
+	<file>hivesum.c</file>
+	<file>hivewrt.c</file>
+</module>

Added: trunk/reactos/lib/cmlib/hivebin.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/cmlib/hivebin.c?rev=23336&view=auto
==============================================================================
--- trunk/reactos/lib/cmlib/hivebin.c (added)
+++ trunk/reactos/lib/cmlib/hivebin.c Sat Jul 29 00:50:05 2006
@@ -1,0 +1,98 @@
+/*
+ * PROJECT:   registry manipulation library
+ * LICENSE:   GPL - See COPYING in the top level directory
+ * COPYRIGHT: Copyright 2005 Filip Navara <navaraf at reactos.org>
+ *            Copyright 2005 Hartmut Birr
+ *            Copyright 2001 - 2005 Eric Kohl
+ */
+
+#include "cmlib.h"
+
+PHBIN CMAPI
+HvpAddBin(
+   PREGISTRY_HIVE RegistryHive,
+   ULONG Size,
+   HV_STORAGE_TYPE Storage)
+{
+   PBLOCK_LIST_ENTRY BlockList;
+   PHBIN Bin;
+   ULONG BinSize;
+   ULONG i;
+   ULONG BitmapSize;
+   ULONG BlockCount;
+   ULONG OldBlockListSize;
+   PCELL_HEADER Block;
+
+   BinSize = ROUND_UP(Size + sizeof(HBIN), HV_BLOCK_SIZE);
+   BlockCount = BinSize / HV_BLOCK_SIZE;
+
+   Bin = RegistryHive->Allocate(BinSize, TRUE);
+   if (Bin == NULL)
+      return NULL;
+   RtlZeroMemory(Bin, sizeof(HBIN));
+
+   Bin->Signature = HV_BIN_SIGNATURE;
+   Bin->BinOffset = RegistryHive->Storage[Storage].BlockListSize *
+                    HV_BLOCK_SIZE;
+   Bin->BinSize = BinSize;
+
+   /* Allocate new block list */
+   OldBlockListSize = RegistryHive->Storage[Storage].BlockListSize;
+   BlockList = RegistryHive->Allocate(sizeof(BLOCK_LIST_ENTRY) *
+                                      (OldBlockListSize + BlockCount), TRUE);
+   if (BlockList == NULL)
+   {
+      RegistryHive->Free(Bin);
+      return NULL;
+   }
+
+   if (OldBlockListSize > 0)
+   {
+      RtlCopyMemory(BlockList, RegistryHive->Storage[Storage].BlockList,
+                    OldBlockListSize * sizeof(BLOCK_LIST_ENTRY));
+      RegistryHive->Free(RegistryHive->Storage[Storage].BlockList);
+   }
+
+   RegistryHive->Storage[Storage].BlockList = BlockList;
+   RegistryHive->Storage[Storage].BlockListSize += BlockCount;
+  
+   for (i = 0; i < BlockCount; i++)
+   {
+      RegistryHive->Storage[Storage].BlockList[OldBlockListSize + i].Block =
+         (PVOID)((ULONG_PTR)Bin + (i * HV_BLOCK_SIZE));
+      RegistryHive->Storage[Storage].BlockList[OldBlockListSize + i].Bin = Bin;
+   }
+
+   /* Initialize a free block in this heap. */
+   Block = (PCELL_HEADER)(Bin + 1);
+   Block->CellSize = BinSize - sizeof(HBIN);
+
+   if (Storage == HvStable)
+   {
+      /* Calculate bitmap size in bytes (always a multiple of 32 bits). */
+      BitmapSize = ROUND_UP(RegistryHive->Storage[HvStable].BlockListSize,
+                            sizeof(ULONG) * 8) / 8;
+
+      /* Grow bitmap if necessary. */
+      if (BitmapSize > RegistryHive->DirtyBitmap.SizeOfBitMap / 8)
+      {
+         PULONG BitmapBuffer;
+
+         BitmapBuffer = RegistryHive->Allocate(BitmapSize, TRUE);
+         RtlZeroMemory(BitmapBuffer, BitmapSize);
+         RtlCopyMemory(BitmapBuffer,
+   		    RegistryHive->DirtyBitmap.Buffer,
+   		    RegistryHive->DirtyBitmap.SizeOfBitMap / 8);
+         RegistryHive->Free(RegistryHive->DirtyBitmap.Buffer);
+         RtlInitializeBitMap(&RegistryHive->DirtyBitmap, BitmapBuffer,
+                             BitmapSize * 8);
+      }
+
+      /* Mark new bin dirty. */
+      RtlSetBits(&RegistryHive->DirtyBitmap,
+                 Bin->BinOffset / HV_BLOCK_SIZE,
+                 BlockCount);
+   }
+
+   return Bin;
+}

Added: trunk/reactos/lib/cmlib/hivecell.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/cmlib/hivecell.c?rev=23336&view=auto
==============================================================================
--- trunk/reactos/lib/cmlib/hivecell.c (added)
+++ trunk/reactos/lib/cmlib/hivecell.c Sat Jul 29 00:50:05 2006
@@ -1,0 +1,429 @@
+/*
+ * PROJECT:   registry manipulation library
+ * LICENSE:   GPL - See COPYING in the top level directory
+ * COPYRIGHT: Copyright 2005 Filip Navara <navaraf at reactos.org>
+ *            Copyright 2001 - 2005 Eric Kohl
+ */
+
+#include "cmlib.h"
+#define NDEBUG
+#include <debug.h>
+
+static PCELL_HEADER __inline CMAPI
+HvpGetCellHeader(
+   PREGISTRY_HIVE RegistryHive,
+   HCELL_INDEX CellIndex)
+{
+   PVOID Block;
+
+   ASSERT(CellIndex != HCELL_NULL);
+   if (!RegistryHive->Flat)
+   {
+      ULONG CellType;
+      ULONG CellBlock;
+      ULONG CellOffset;
+
+      CellType = (CellIndex & HCELL_TYPE_MASK) >> HCELL_TYPE_SHIFT;
+      CellBlock = (CellIndex & HCELL_BLOCK_MASK) >> HCELL_BLOCK_SHIFT;
+      CellOffset = (CellIndex & HCELL_OFFSET_MASK) >> HCELL_OFFSET_SHIFT;
+      ASSERT(CellBlock < RegistryHive->Storage[CellType].BlockListSize);
+      Block = RegistryHive->Storage[CellType].BlockList[CellBlock].Block;
+      ASSERT(Block != NULL);
+      return (PVOID)((ULONG_PTR)Block + CellOffset);
+   }
+   else
+   {
+      ASSERT((CellIndex & HCELL_TYPE_MASK) == HvStable);
+      return (PVOID)((ULONG_PTR)RegistryHive->HiveHeader + HV_BLOCK_SIZE +
+                     CellIndex);
+   }
+}
+
+PVOID CMAPI
+HvGetCell(
+   PREGISTRY_HIVE RegistryHive,
+   HCELL_INDEX CellIndex)
+{
+   return (PVOID)(HvpGetCellHeader(RegistryHive, CellIndex) + 1);
+}
+
+static LONG __inline CMAPI
+HvpGetCellFullSize(
+   PREGISTRY_HIVE RegistryHive,
+   PVOID Cell)
+{
+   return ((PCELL_HEADER)Cell - 1)->CellSize;
+}
+
+LONG CMAPI
+HvGetCellSize(
+   PREGISTRY_HIVE RegistryHive,
+   PVOID Cell)
+{
+   PCELL_HEADER CellHeader;
+
+   CellHeader = (PCELL_HEADER)Cell - 1;
+   if (CellHeader->CellSize < 0)
+      return CellHeader->CellSize + sizeof(CELL_HEADER);
+   else
+      return CellHeader->CellSize - sizeof(CELL_HEADER);
+}
+
+VOID CMAPI
+HvMarkCellDirty(
+   PREGISTRY_HIVE RegistryHive,
+   HCELL_INDEX CellIndex)
+{
+   LONG CellSize;
+   ULONG CellBlock;
+   ULONG CellLastBlock;
+
+   ASSERT(RegistryHive->ReadOnly == FALSE);
+
+   if ((CellIndex & HCELL_TYPE_MASK) >> HCELL_TYPE_SHIFT != HvStable)
+      return;
+
+   CellBlock = (CellIndex & HCELL_BLOCK_MASK) >> HCELL_BLOCK_SHIFT;
+   CellLastBlock = ((CellIndex + HV_BLOCK_SIZE - 1) & HCELL_BLOCK_MASK) >> HCELL_BLOCK_SHIFT;
+
+   CellSize = HvpGetCellFullSize(RegistryHive, HvGetCell(RegistryHive, CellIndex));
+   if (CellSize < 0)
+      CellSize = -CellSize;
+
+   RtlSetBits(&RegistryHive->DirtyBitmap,
+              CellBlock, CellLastBlock - CellBlock);
+}
+
+static ULONG __inline CMAPI
+HvpComputeFreeListIndex(
+   ULONG Size)
+{
+   ULONG Index;
+   static CCHAR FindFirstSet[256] = {
+      0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
+      4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+      5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+      5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+      6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+      6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+      6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+      6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+      7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7};
+
+   Index = (Size >> 3) - 1;
+   if (Index >= 16)
+   {
+      if (Index > 255)
+         Index = 23;
+      else
+         Index = FindFirstSet[Index] + 7;
+   }
+
+   return Index;
+}
+
+static NTSTATUS CMAPI
+HvpAddFree(
+   PREGISTRY_HIVE RegistryHive,
+   PCELL_HEADER FreeBlock,
+   HCELL_INDEX FreeIndex)
+{
+   PHCELL_INDEX FreeBlockData;
+   HV_STORAGE_TYPE Storage;
+   ULONG Index;
+
+   ASSERT(RegistryHive != NULL);
+   ASSERT(FreeBlock != NULL);
+
+   Storage = (FreeIndex & HCELL_TYPE_MASK) >> HCELL_TYPE_SHIFT;
+   Index = HvpComputeFreeListIndex(FreeBlock->CellSize);
+
+   FreeBlockData = (PHCELL_INDEX)(FreeBlock + 1);
+   *FreeBlockData = RegistryHive->Storage[Storage].FreeListOffset[Index];
+   RegistryHive->Storage[Storage].FreeListOffset[Index] = FreeIndex;
+
+   /* FIXME: Eventually get rid of free bins. */
+
+   return STATUS_SUCCESS;
+}
+
+static VOID CMAPI
+HvpRemoveFree(
+   PREGISTRY_HIVE RegistryHive,
+   PCELL_HEADER CellBlock,
+   HCELL_INDEX CellIndex)
+{
+   PHCELL_INDEX FreeCellData;
+   PHCELL_INDEX pFreeCellOffset;
+   HV_STORAGE_TYPE Storage;
+   ULONG Index;
+
+   ASSERT(RegistryHive->ReadOnly == FALSE);
+
+   Storage = (CellIndex & HCELL_TYPE_MASK) >> HCELL_TYPE_SHIFT;
+   Index = HvpComputeFreeListIndex(CellBlock->CellSize);
+
+   pFreeCellOffset = &RegistryHive->Storage[Storage].FreeListOffset[Index];
+   while (*pFreeCellOffset != HCELL_NULL)
+   {
+      FreeCellData = (PHCELL_INDEX)HvGetCell(RegistryHive, *pFreeCellOffset);
+      if (*pFreeCellOffset == CellIndex)
+      {
+         *pFreeCellOffset = *FreeCellData;
+         return;
+      }
+      pFreeCellOffset = FreeCellData;
+   }
+
+   ASSERT(FALSE);
+}
+
+static HCELL_INDEX CMAPI
+HvpFindFree(
+   PREGISTRY_HIVE RegistryHive,
+   ULONG Size,
+   HV_STORAGE_TYPE Storage)
+{
+   PHCELL_INDEX FreeCellData;
+   HCELL_INDEX FreeCellOffset;
+   PHCELL_INDEX pFreeCellOffset;
+   ULONG Index;
+
+   for (Index = HvpComputeFreeListIndex(Size); Index < 24; Index++)
+   {
+      pFreeCellOffset = &RegistryHive->Storage[Storage].FreeListOffset[Index];
+      while (*pFreeCellOffset != HCELL_NULL)
+      {
+         FreeCellData = (PHCELL_INDEX)HvGetCell(RegistryHive, *pFreeCellOffset);
+         if (HvpGetCellFullSize(RegistryHive, FreeCellData) >= Size)
+         {
+            FreeCellOffset = *pFreeCellOffset;
+            *pFreeCellOffset = *FreeCellData;
+            return FreeCellOffset;
+         }
+         pFreeCellOffset = FreeCellData;
+      }
+   }
+
+   return HCELL_NULL;
+}
+
+NTSTATUS CMAPI
+HvpCreateHiveFreeCellList(
+   PREGISTRY_HIVE Hive)
+{
+   HCELL_INDEX BlockOffset;
+   PCELL_HEADER FreeBlock;
+   ULONG BlockIndex;
+   ULONG FreeOffset;
+   PHBIN Bin;
+   NTSTATUS Status;
+   ULONG Index;
+
+   /* Initialize the free cell list */
+   for (Index = 0; Index < 24; Index++)
+   {
+      Hive->Storage[HvStable].FreeListOffset[Index] = HCELL_NULL;
+      Hive->Storage[HvVolatile].FreeListOffset[Index] = HCELL_NULL;
+   }
+
+   BlockOffset = 0;
+   BlockIndex = 0;
+   while (BlockIndex < Hive->Storage[HvStable].BlockListSize)
+   {
+      Bin = Hive->Storage[HvStable].BlockList[BlockIndex].Bin;
+
+      /* Search free blocks and add to list */
+      FreeOffset = sizeof(HBIN);
+      while (FreeOffset < Bin->BinSize)
+      {
+         FreeBlock = (PCELL_HEADER)((ULONG_PTR)Bin + FreeOffset);
+         if (FreeBlock->CellSize > 0)
+         {
+            Status = HvpAddFree(Hive, FreeBlock, Bin->BinOffset + FreeOffset);
+            if (!NT_SUCCESS(Status))
+               return Status;
+
+            FreeOffset += FreeBlock->CellSize;
+         }
+         else
+         {
+            FreeOffset -= FreeBlock->CellSize;
+         }
+      }
+
+      BlockIndex += Bin->BinSize / HV_BLOCK_SIZE;
+      BlockOffset += Bin->BinSize;
+   }
+
+   return STATUS_SUCCESS;
+}
+
+HCELL_INDEX CMAPI
+HvAllocateCell(
+   PREGISTRY_HIVE RegistryHive,
+   ULONG Size,
+   HV_STORAGE_TYPE Storage)
+{
+   PCELL_HEADER FreeCell;
+   HCELL_INDEX FreeCellOffset;
+   PCELL_HEADER NewCell;
+   PHBIN Bin;
+
+   ASSERT(RegistryHive->ReadOnly == FALSE);
+
+   /* Round to 16 bytes multiple. */
+   Size = ROUND_UP(Size + sizeof(CELL_HEADER), 16);
+
+   /* First search in free blocks. */
+   FreeCellOffset = HvpFindFree(RegistryHive, Size, Storage);
+
+   /* If no free cell was found we need to extend the hive file. */
+   if (FreeCellOffset == HCELL_NULL)
+   {
+      Bin = HvpAddBin(RegistryHive, Size, Storage);
+      if (Bin == NULL)
+         return HCELL_NULL;
+      FreeCellOffset = Bin->BinOffset + sizeof(HBIN);
+      FreeCellOffset |= Storage << HCELL_TYPE_SHIFT;
+   }
+
+   FreeCell = HvpGetCellHeader(RegistryHive, FreeCellOffset);
+
+   /* Split the block in two parts */
+   /* FIXME: There is some minimal cell size that we must respect. */
+   if (FreeCell->CellSize > Size + sizeof(HCELL_INDEX))
+   {
+      NewCell = (PCELL_HEADER)((ULONG_PTR)FreeCell + Size);
+      NewCell->CellSize = FreeCell->CellSize - Size;
+      FreeCell->CellSize = Size;
+      HvpAddFree(RegistryHive, NewCell, FreeCellOffset + Size);
+      if (Storage == HvStable)
+         HvMarkCellDirty(RegistryHive, FreeCellOffset + Size);
+   }
+
+   if (Storage == HvStable)
+      HvMarkCellDirty(RegistryHive, FreeCellOffset);
+   FreeCell->CellSize = -FreeCell->CellSize;
+   RtlZeroMemory(FreeCell + 1, Size - sizeof(CELL_HEADER));
+
+   return FreeCellOffset;
+}
+
+HCELL_INDEX CMAPI
+HvReallocateCell(
+   PREGISTRY_HIVE RegistryHive,
+   HCELL_INDEX CellIndex,
+   ULONG Size)
+{
+   PVOID OldCell;
+   PVOID NewCell;
+   LONG OldCellSize;
+   HCELL_INDEX NewCellIndex;
+   HV_STORAGE_TYPE Storage;
+
+   ASSERT(CellIndex != HCELL_NULL);
+
+   Storage = (CellIndex & HCELL_TYPE_MASK) >> HCELL_TYPE_SHIFT;
+
+   OldCell = HvGetCell(RegistryHive, CellIndex);
+   OldCellSize = HvGetCellSize(RegistryHive, OldCell);
+   ASSERT(OldCellSize < 0);
+  
+   /*
+    * If new data size is larger than the current, destroy current
+    * data block and allocate a new one.
+    *
+    * FIXME: Merge with adjacent free cell if possible.
+    * FIXME: Implement shrinking.
+    */
+   if (Size > -OldCellSize)
+   {
+      NewCellIndex = HvAllocateCell(RegistryHive, Size, Storage);
+      if (NewCellIndex == HCELL_NULL)
+         return HCELL_NULL;
+
+      NewCell = HvGetCell(RegistryHive, NewCellIndex);
+      RtlCopyMemory(NewCell, OldCell, -OldCellSize);
+      
+      HvFreeCell(RegistryHive, CellIndex);
+
+      return NewCellIndex;
+   }
+
+   return CellIndex;
+}
+
+VOID CMAPI
+HvFreeCell(
+   PREGISTRY_HIVE RegistryHive,
+   HCELL_INDEX CellIndex)
+{
+   PCELL_HEADER Free;
+   PCELL_HEADER Neighbor;
+   PHBIN Bin;
+   ULONG CellType;
+   ULONG CellBlock;
+
+   ASSERT(RegistryHive->ReadOnly == FALSE);
+   
+   Free = HvpGetCellHeader(RegistryHive, CellIndex);
+
+   ASSERT(Free->CellSize < 0);   
+   
+   Free->CellSize = -Free->CellSize;
+
+   CellType = (CellIndex & HCELL_TYPE_MASK) >> HCELL_TYPE_SHIFT;
+   CellBlock = (CellIndex & HCELL_BLOCK_MASK) >> HCELL_BLOCK_SHIFT;
+
+   /* FIXME: Merge free blocks */
+   Bin = RegistryHive->Storage[CellType].BlockList[CellBlock].Bin;
+
+   if ((CellIndex & ~HCELL_TYPE_MASK) + Free->CellSize <
+       Bin->BinOffset + Bin->BinSize)
+   {
+      Neighbor = (PCELL_HEADER)((ULONG_PTR)Free + Free->CellSize);
+      if (Neighbor->CellSize > 0)
+      {
+         HvpRemoveFree(RegistryHive, Neighbor,
+                       ((HCELL_INDEX)Neighbor - (HCELL_INDEX)Bin +
+                       Bin->BinOffset) | (CellIndex & HCELL_TYPE_MASK));
+         Free->CellSize += Neighbor->CellSize;
+      }
+   }
+
+   Neighbor = (PCELL_HEADER)(Bin + 1);
+   while (Neighbor < Free)
+   {
+      if (Neighbor->CellSize > 0)
+      {
+         if ((ULONG_PTR)Neighbor + Neighbor->CellSize == (ULONG_PTR)Free)
+         {
+            Neighbor->CellSize += Free->CellSize;
+            if (CellType == HvStable)
+               HvMarkCellDirty(RegistryHive,
+                               (HCELL_INDEX)Neighbor - (HCELL_INDEX)Bin +
+                               Bin->BinOffset);
+            return;
+         }
+         Neighbor = (PCELL_HEADER)((ULONG_PTR)Neighbor + Neighbor->CellSize);
+      }
+      else
+      {
+         Neighbor = (PCELL_HEADER)((ULONG_PTR)Neighbor - Neighbor->CellSize);
+      }
+   }
+
+   /* Add block to the list of free blocks */
+   HvpAddFree(RegistryHive, Free, CellIndex);
+
+   if (CellType == HvStable)
+      HvMarkCellDirty(RegistryHive, CellIndex);
+}

Added: trunk/reactos/lib/cmlib/hivedata.h
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/cmlib/hivedata.h?rev=23336&view=auto
==============================================================================
--- trunk/reactos/lib/cmlib/hivedata.h (added)
+++ trunk/reactos/lib/cmlib/hivedata.h Sat Jul 29 00:50:05 2006
@@ -1,0 +1,138 @@
+/*
+ * PROJECT:   registry manipulation library
+ * LICENSE:   GPL - See COPYING in the top level directory
+ * COPYRIGHT: Copyright 2005 Filip Navara <navaraf at reactos.org>
+ *            Copyright 2001 - 2005 Eric Kohl
+ */
+
+#ifndef CMLIB_HIVEDATA_H
+#define CMLIB_HIVEDATA_H
+
+#define HV_BLOCK_SIZE                  4096
+#define HV_LOG_HEADER_SIZE             FIELD_OFFSET(HIVE_HEADER, Reserved2)
+#define HV_SIGNATURE                   0x66676572
+#define HV_BIN_SIGNATURE               0x6e696268
+
+#define HV_MAJOR_VER                   1
+#define HV_MINOR_VER                   3
+#define HV_FORMAT_MEMORY               1
+
+#define HV_TYPE_PRIMARY                0
+#define HV_TYPE_ALTERNATE              1
+#define HV_TYPE_LOG                    2
+#define HV_TYPE_EXTERNAL               3
+#define HV_TYPE_MAX                    4
+
+/**
+ * @name HCELL_INDEX
+ *
+ * A handle to cell index. The highest bit specifies the cell storage and
+ * the other bits specify index into the hive file. The value HCELL_NULL
+ * (-1) is reserved for marking invalid cells.
+ */
+
+typedef ULONG HCELL_INDEX, *PHCELL_INDEX;
+
+#define HCELL_NULL                     ((HCELL_INDEX)-1)
+#define HCELL_TYPE_MASK                0x80000000
+#define HCELL_BLOCK_MASK               0x7ffff000
+#define HCELL_OFFSET_MASK              0x00000fff
+#define HCELL_TYPE_SHIFT               31
+#define HCELL_BLOCK_SHIFT              12
+#define HCELL_OFFSET_SHIFT             0
+
+#include <pshpack1.h>
+
+/**
+ * @name HIVE_HEADER
+ *
+ * On-disk header for registry hive file.
+ */
+
+typedef struct _HIVE_HEADER
+{
+   /* Hive identifier "regf" (0x66676572) */
+   ULONG Signature;
+
+   /* Update counter */
+   ULONG Sequence1;
+
+   /* Update counter */
+   ULONG Sequence2;
+   
+   /* When this hive file was last modified */
+   LARGE_INTEGER TimeStamp;
+
+   /* Registry format major version (1) */
+   ULONG Major;
+
+   /* Registry format minor version (3)
+      Version 3 added fast indexes, version 5 has large value optimizations */
+   ULONG Minor;
+
+   /* Registry file type (0 - Primary, 1 - Log) */
+   ULONG Type;
+
+   /* Registry format (1 is the only defined value so far) */
+   ULONG Format;
+
+   /* Offset into file from the byte after the end of the base block.
+      If the hive is volatile, this is the actual pointer to the KEY_CELL */
+   HCELL_INDEX RootCell;
+
+   /* Size of each hive block ? */
+   ULONG Length;
+
+   /* (1?) */
+   ULONG Cluster;
+
+   /* Name of hive file */
+   WCHAR FileName[32];
+
+   ULONG Reserved1[99];
+
+   /* Checksum of first 0x200 bytes */
+   ULONG Checksum;
+
+   ULONG Reserved2[0x380];
+} HIVE_HEADER, *PHIVE_HEADER;
+
+typedef struct _BIN_HEADER
+{
+   /* Bin identifier "hbin" (0x6E696268) */
+   ULONG Signature;
+
+   /* Block offset of this bin */
+   HCELL_INDEX BinOffset;
+
+   /* Size in bytes, multiple of the block size (4KB) */
+   ULONG BinSize;
+
+   ULONG Reserved[2];
+
+   /* When this bin was last modified */
+   LARGE_INTEGER DateModified;
+
+   /* ? (In-memory only) */
+   ULONG MemAlloc;
+} HBIN, *PHBIN;
+
+typedef struct _CELL_HEADER
+{
+   /* <0 if used, >0 if free */
+   LONG CellSize;
+} CELL_HEADER, *PCELL_HEADER;
+
+#include <poppack.h>
+
+#define IsFreeCell(Cell)(Cell->CellSize >= 0)
+#define IsUsedCell(Cell)(Cell->CellSize < 0)
+
+typedef enum _HV_STORAGE_TYPE
+{
+   HvStable = 0,
+   HvVolatile,
+   HvMaxStorageType
+} HV_STORAGE_TYPE;
+
+#endif /* CMLIB_HIVEDATA_H */

Added: trunk/reactos/lib/cmlib/hiveinit.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/cmlib/hiveinit.c?rev=23336&view=auto
==============================================================================
--- trunk/reactos/lib/cmlib/hiveinit.c (added)
+++ trunk/reactos/lib/cmlib/hiveinit.c Sat Jul 29 00:50:05 2006
@@ -1,0 +1,377 @@
+/*
+ * PROJECT:   registry manipulation library
+ * LICENSE:   GPL - See COPYING in the top level directory
+ * COPYRIGHT: Copyright 2005 Filip Navara <navaraf at reactos.org>
+ *            Copyright 2001 - 2005 Eric Kohl
+ */
+
+#include "cmlib.h"
+#define NDEBUG
+#include <debug.h>
+
+/**
+ * @name HvpVerifyHiveHeader
+ *
+ * Internal function to verify that a hive header has valid format.
+ */
+
+BOOLEAN CMAPI
+HvpVerifyHiveHeader(
+   PHIVE_HEADER HiveHeader)
+{
+   if (HiveHeader->Signature != HV_SIGNATURE ||
+       HiveHeader->Major != HV_MAJOR_VER ||
+       HiveHeader->Minor > HV_MINOR_VER ||
+       HiveHeader->Type != HV_TYPE_PRIMARY ||
+       HiveHeader->Format != HV_FORMAT_MEMORY ||
+       HiveHeader->Cluster != 1 ||
+       HiveHeader->Sequence1 != HiveHeader->Sequence2 ||
+       HvpHiveHeaderChecksum(HiveHeader) != HiveHeader->Checksum)
+   {
+      return FALSE;
+   }
+
+   return TRUE;
+}
+
+/**
+ * @name HvpFreeHiveBins
+ *
+ * Internal function to free all bin storage associated with hive
+ * descriptor.
+ */
+
+VOID CMAPI
+HvpFreeHiveBins(
+   PREGISTRY_HIVE Hive)
+{        	
+   ULONG i;
+   PHBIN Bin;
+   ULONG Storage;
+
+   for (Storage = HvStable; Storage < HvMaxStorageType; Storage++)
+   {
+      Bin = NULL;
+      for (i = 0; i < Hive->Storage[Storage].BlockListSize; i++)
+      {
+         if (Hive->Storage[Storage].BlockList[i].Bin == NULL)
+            continue;
+         if (Hive->Storage[Storage].BlockList[i].Bin != Bin)
+         {
+            Bin = Hive->Storage[Storage].BlockList[i].Bin;
+            Hive->Free(Hive->Storage[Storage].BlockList[i].Bin);
+         }
+         Hive->Storage[Storage].BlockList[i].Bin = NULL;
+         Hive->Storage[Storage].BlockList[i].Block = NULL;
+      }
+
+      if (Hive->Storage[Storage].BlockListSize)
+         Hive->Free(Hive->Storage[Storage].BlockList);
+   }
+}
+
+/**
+ * @name HvpCreateHive
+ *
+ * Internal helper function to initalize hive descriptor structure for
+ * newly created hive.
+ *
+ * @see HvInitialize
+ */
+
+NTSTATUS CMAPI
+HvpCreateHive(
+   PREGISTRY_HIVE RegistryHive)
+{
+   PHIVE_HEADER HiveHeader;
+   ULONG Index;
+
+   HiveHeader = RegistryHive->Allocate(sizeof(HIVE_HEADER), FALSE);
+   if (HiveHeader == NULL)
+      return STATUS_NO_MEMORY;
+   RtlZeroMemory(HiveHeader, sizeof(HIVE_HEADER));
+   HiveHeader->Signature = HV_SIGNATURE;
+   HiveHeader->Major = HV_MAJOR_VER;
+   HiveHeader->Minor = HV_MINOR_VER;
+   HiveHeader->Type = HV_TYPE_PRIMARY;
+   HiveHeader->Format = HV_FORMAT_MEMORY;
+   HiveHeader->Cluster = 1;
+   HiveHeader->RootCell = HCELL_NULL;
+   HiveHeader->Length = HV_BLOCK_SIZE;
+   HiveHeader->Sequence1 = 1;
+   HiveHeader->Sequence2 = 1;
+   /* FIXME: Fill in the file name */
+   HiveHeader->Checksum = HvpHiveHeaderChecksum(HiveHeader);
+
+   RegistryHive->HiveHeader = HiveHeader;
+   for (Index = 0; Index < 24; Index++)
+   {
+      RegistryHive->Storage[HvStable].FreeListOffset[Index] = HCELL_NULL;
+      RegistryHive->Storage[HvVolatile].FreeListOffset[Index] = HCELL_NULL;
+   }
+   RtlInitializeBitMap(&RegistryHive->DirtyBitmap, NULL, 0);
+
+   return STATUS_SUCCESS;
+}
+
+/**
+ * @name HvpInitializeMemoryHive
+ *
+ * Internal helper function to initalize hive descriptor structure for
+ * a hive stored in memory. The data of the hive are copied and it is
+ * prepared for read/write access.
+ *
+ * @see HvInitialize
+ */
+
+NTSTATUS CMAPI
+HvpInitializeMemoryHive(
+   PREGISTRY_HIVE Hive,
+   ULONG_PTR ChunkBase,
+   SIZE_T ChunkSize)
+{
+   SIZE_T BlockIndex;
+   PHBIN Bin, NewBin;
+   ULONG i;
+   ULONG BitmapSize;
+   PULONG BitmapBuffer;
+   
+   if (ChunkSize < sizeof(HIVE_HEADER) ||
+       !HvpVerifyHiveHeader((PHIVE_HEADER)ChunkBase))
+   {
+      return STATUS_REGISTRY_CORRUPT;
+   }
+
+   Hive->HiveHeader = Hive->Allocate(sizeof(HIVE_HEADER), FALSE);
+   if (Hive->HiveHeader == NULL)
+   {
+      return STATUS_NO_MEMORY;
+   }
+   RtlCopyMemory(Hive->HiveHeader, (PVOID)ChunkBase, sizeof(HIVE_HEADER));
+
+   /*
+    * Build a block list from the in-memory chunk and copy the data as
+    * we go.
+    */
+   
+   Hive->Storage[HvStable].BlockListSize = (ChunkSize / HV_BLOCK_SIZE) - 1;
+   Hive->Storage[HvStable].BlockList =
+      Hive->Allocate(Hive->Storage[HvStable].BlockListSize *
+                     sizeof(BLOCK_LIST_ENTRY), FALSE);
+   if (Hive->Storage[HvStable].BlockList == NULL)
+   {
+      DPRINT1("Allocating block list failed\n");
+      Hive->Free(Hive->HiveHeader);
+      return STATUS_NO_MEMORY;
+   }
+
+   for (BlockIndex = 0; BlockIndex < Hive->Storage[HvStable].BlockListSize; )
+   {
+      Bin = (PHBIN)((ULONG_PTR)ChunkBase + (BlockIndex + 1) * HV_BLOCK_SIZE);
+      if (Bin->Signature != HV_BIN_SIGNATURE ||
+          (Bin->BinSize % HV_BLOCK_SIZE) != 0)
+      {
+         Hive->Free(Hive->HiveHeader);
+         Hive->Free(Hive->Storage[HvStable].BlockList);
+         return STATUS_REGISTRY_CORRUPT;
+      }
+
+      NewBin = Hive->Allocate(Bin->BinSize, TRUE);
+      if (NewBin == NULL)
+      {
+         Hive->Free(Hive->HiveHeader);
+         Hive->Free(Hive->Storage[HvStable].BlockList);
+         return STATUS_NO_MEMORY;
+      }
+
+      Hive->Storage[HvStable].BlockList[BlockIndex].Bin = NewBin;
+      Hive->Storage[HvStable].BlockList[BlockIndex].Block = NewBin;
+
+      RtlCopyMemory(NewBin, Bin, Bin->BinSize);
+
+      if (Bin->BinSize > HV_BLOCK_SIZE)
+      {
+         for (i = 1; i < Bin->BinSize / HV_BLOCK_SIZE; i++)
+         {
+            Hive->Storage[HvStable].BlockList[BlockIndex + i].Bin = NewBin;
+            Hive->Storage[HvStable].BlockList[BlockIndex + i].Block =
+               (PVOID)((ULONG_PTR)NewBin + (i * HV_BLOCK_SIZE));
+         }
+      }
+
+      BlockIndex += Bin->BinSize / HV_BLOCK_SIZE;
+   }
+
+   if (HvpCreateHiveFreeCellList(Hive))
+   {
+      HvpFreeHiveBins(Hive);
+      Hive->Free(Hive->HiveHeader);
+      return STATUS_NO_MEMORY;
+   }
+
+   BitmapSize = ROUND_UP(Hive->Storage[HvStable].BlockListSize,
+                         sizeof(ULONG) * 8) / 8;
+   BitmapBuffer = (PULONG)Hive->Allocate(BitmapSize, TRUE);
+   if (BitmapBuffer == NULL)
+   {
+      HvpFreeHiveBins(Hive);
+      Hive->Free(Hive->HiveHeader);
+      return STATUS_NO_MEMORY;
+   }
+
+   RtlInitializeBitMap(&Hive->DirtyBitmap, BitmapBuffer, BitmapSize * 8);
+   RtlClearAllBits(&Hive->DirtyBitmap);
+
+   return STATUS_SUCCESS;
+}
+
+/**
+ * @name HvpInitializeMemoryInplaceHive
+ *
+ * Internal helper function to initalize hive descriptor structure for
+ * a hive stored in memory. The in-memory data of the hive are directly
+ * used and it is read-only accessible.
+ *
+ * @see HvInitialize
+ */
+
+NTSTATUS CMAPI
+HvpInitializeMemoryInplaceHive(
+   PREGISTRY_HIVE Hive,
+   ULONG_PTR ChunkBase,
+   SIZE_T ChunkSize)
+{
+   if (ChunkSize < sizeof(HIVE_HEADER) ||
+       !HvpVerifyHiveHeader((PHIVE_HEADER)ChunkBase))
+   {
+      return STATUS_REGISTRY_CORRUPT;
+   }
+
+   Hive->HiveHeader = (PHIVE_HEADER)ChunkBase;
+   Hive->ReadOnly = TRUE;
+   Hive->Flat = TRUE;
+
+   return STATUS_SUCCESS;
+}
+
+/**
+ * @name HvInitialize
+ *
+ * Allocate a new hive descriptor structure and intialize it.
+ *
+ * @param RegistryHive
+ *        Output variable to store pointer to the hive descriptor.
+ * @param Operation
+ *        - HV_OPERATION_CREATE_HIVE
+ *          Create a new hive for read/write access.
+ *        - HV_OPERATION_MEMORY
+ *          Load and copy in-memory hive for read/write access. The
+ *          pointer to data passed to this routine can be freed after
+ *          the function is executed.
+ *        - HV_OPERATION_MEMORY_INPLACE
+ *          Load an in-memory hive for read-only access. The pointer
+ *          to data passed to this routine MUSTN'T be freed until
+ *          HvFree is called.
+ * @param ChunkBase
+ *        Pointer to hive data.
+ * @param ChunkSize
+ *        Size of passed hive data.
+ *
+ * @return
+ *    STATUS_NO_MEMORY - A memory allocation failed.
+ *    STATUS_REGISTRY_CORRUPT - Registry corruption was detected.
+ *    STATUS_SUCCESS
+ *        
+ * @see HvFree
+ */
+
+NTSTATUS CMAPI
+HvInitialize(
+   PREGISTRY_HIVE *RegistryHive,
+   ULONG Operation,
+   ULONG_PTR ChunkBase,
+   SIZE_T ChunkSize,
+   PHV_ALLOCATE Allocate,
+   PHV_FREE Free,
+   PHV_FILE_READ FileRead,
+   PHV_FILE_WRITE FileWrite,
+   PHV_FILE_SET_SIZE FileSetSize,
+   PHV_FILE_FLUSH FileFlush,
+   PVOID Opaque)
+{
+   NTSTATUS Status;
+   PREGISTRY_HIVE Hive;
+
+   /*
+    * Create a new hive structure that will hold all the maintenance data.
+    */
+
+   Hive = Allocate(sizeof(REGISTRY_HIVE), TRUE);
+   if (Hive == NULL)
+      return STATUS_NO_MEMORY;
+   RtlZeroMemory(Hive, sizeof(REGISTRY_HIVE));
+
+   Hive->Allocate = Allocate;
+   Hive->Free = Free;
+   Hive->FileRead = FileRead;
+   Hive->FileWrite = FileWrite;
+   Hive->FileSetSize = FileSetSize;
+   Hive->FileFlush = FileFlush;
+   Hive->Opaque = Opaque;
+
+   switch (Operation)
+   {
+      case HV_OPERATION_CREATE_HIVE:
+         Status = HvpCreateHive(Hive);
+         break;
+
+      case HV_OPERATION_MEMORY:
+         Status = HvpInitializeMemoryHive(Hive, ChunkBase, ChunkSize);
+         break;
+
+      case HV_OPERATION_MEMORY_INPLACE:
+         Status = HvpInitializeMemoryInplaceHive(Hive, ChunkBase, ChunkSize);
+         break;
+
+      default:
+         /* FIXME: A better return status value is needed */
+         Status = STATUS_NOT_IMPLEMENTED;
+         ASSERT(FALSE);
+   }
+
+   if (!NT_SUCCESS(Status))
+   {
+      Hive->Free(Hive);
+      return Status;
+   }
+
+   *RegistryHive = Hive;
+   
+   return Status;
+}
+
+/**
+ * @name HvFree
+ *
+ * Free all stroage and handles associated with hive descriptor.
+ */
+
+VOID CMAPI 
+HvFree(
+   PREGISTRY_HIVE RegistryHive)
+{
+   if (!RegistryHive->ReadOnly)
+   {
+      /* Release hive bitmap */
+      if (RegistryHive->DirtyBitmap.Buffer)
+      {
+         RegistryHive->Free(RegistryHive->DirtyBitmap.Buffer);
+      }
+
+      HvpFreeHiveBins(RegistryHive);
+   }
+
+   RegistryHive->Free(RegistryHive);
+}
+
+/* EOF */

Added: trunk/reactos/lib/cmlib/hivesum.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/cmlib/hivesum.c?rev=23336&view=auto
==============================================================================
--- trunk/reactos/lib/cmlib/hivesum.c (added)
+++ trunk/reactos/lib/cmlib/hivesum.c Sat Jul 29 00:50:05 2006
@@ -1,0 +1,32 @@
+/*
+ * PROJECT:   registry manipulation library
+ * LICENSE:   GPL - See COPYING in the top level directory
+ * COPYRIGHT: Copyright 2005 Filip Navara <navaraf at reactos.org>
+ *            Copyright 2001 - 2005 Eric Kohl
+ */
+
+#include "cmlib.h"
+
+/**
+ * @name HvpHiveHeaderChecksum
+ *
+ * Compute checksum of hive header and return it.
+ */
+
+ULONG CMAPI
+HvpHiveHeaderChecksum(
+   PHIVE_HEADER HiveHeader)
+{
+   PULONG Buffer = (PULONG)HiveHeader;
+   ULONG Sum = 0;
+   ULONG i;
+
+   for (i = 0; i < 127; i++)
+      Sum ^= Buffer[i];
+   if (Sum == (ULONG)-1)
+      Sum = (ULONG)-2;
+   if (Sum == 0)
+      Sum = 1;
+
+   return Sum;
+}

Added: trunk/reactos/lib/cmlib/hivewrt.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/cmlib/hivewrt.c?rev=23336&view=auto
==============================================================================
--- trunk/reactos/lib/cmlib/hivewrt.c (added)
+++ trunk/reactos/lib/cmlib/hivewrt.c Sat Jul 29 00:50:05 2006
@@ -1,0 +1,277 @@
+/*
+ * PROJECT:   registry manipulation library
+ * LICENSE:   GPL - See COPYING in the top level directory
+ * COPYRIGHT: Copyright 2005 Filip Navara <navaraf at reactos.org>
+ *            Copyright 2001 - 2005 Eric Kohl
+ */
+
+#include "cmlib.h"
+#define NDEBUG
+#include <debug.h>
+
+static BOOLEAN CMAPI
+HvpWriteLog(
+   PREGISTRY_HIVE RegistryHive)
+{
+   ULONG FileOffset;
+   ULONG BufferSize;
+   ULONG BitmapSize;
+   PUCHAR Buffer;
+   PUCHAR Ptr;
+   ULONG BlockIndex;
+   ULONG LastIndex;
+   PVOID BlockPtr;
+   BOOLEAN Success;
+   
+   ASSERT(RegistryHive->ReadOnly == FALSE);
+   
+   DPRINT("HvpWriteLog called\n");
+
+   if (RegistryHive->HiveHeader->Sequence1 !=
+       RegistryHive->HiveHeader->Sequence2)
+   {
+      return FALSE;
+   }
+
+   BitmapSize = RegistryHive->DirtyBitmap.SizeOfBitMap;
+   BufferSize = HV_LOG_HEADER_SIZE + sizeof(ULONG) + BitmapSize;
+   BufferSize = ROUND_UP(BufferSize, HV_BLOCK_SIZE);
+
+   DPRINT("Bitmap size %lu  buffer size: %lu\n", BitmapSize, BufferSize);
+
+   Buffer = RegistryHive->Allocate(BufferSize, TRUE);
+   if (Buffer == NULL)
+   {
+      return FALSE;
+   }
+
+   /* Update first update counter and checksum */
+   RegistryHive->HiveHeader->Type = HV_TYPE_LOG;
+   RegistryHive->HiveHeader->Sequence1++;
+   RegistryHive->HiveHeader->Checksum =
+      HvpHiveHeaderChecksum(RegistryHive->HiveHeader);
+
+   /* Copy hive header */
+   RtlCopyMemory(Buffer, RegistryHive->HiveHeader, HV_LOG_HEADER_SIZE);
+   Ptr = Buffer + HV_LOG_HEADER_SIZE;
+   RtlCopyMemory(Ptr, "DIRT", 4);
+   Ptr += 4;
+   RtlCopyMemory(Ptr, RegistryHive->DirtyBitmap.Buffer, BitmapSize);
+
+   /* Write hive block and block bitmap */
+   Success = RegistryHive->FileWrite(RegistryHive, HV_TYPE_LOG,
+                                     0, Buffer, BufferSize);
+   if (!Success)
+   {
+      return FALSE;
+   }
+
+   RegistryHive->Free(Buffer);
+
+   /* Write dirty blocks */
+   FileOffset = BufferSize;
+   BlockIndex = 0;
+   while (BlockIndex < RegistryHive->Storage[HvStable].BlockListSize)
+   {
+      LastIndex = BlockIndex;
+      BlockIndex = RtlFindSetBits(&RegistryHive->DirtyBitmap, 1, BlockIndex);
+      if (BlockIndex == ~0 || BlockIndex < LastIndex)
+      {
+         break;
+      }
+
+      BlockPtr = RegistryHive->Storage[HvStable].BlockList[BlockIndex].Block;
+
+      /* Write hive block */
+      Success = RegistryHive->FileWrite(RegistryHive, HV_TYPE_LOG,
+                                        FileOffset, BlockPtr,
+                                        HV_BLOCK_SIZE);
+      if (!Success)
+      {
+         return FALSE;
+      }
+
+      BlockIndex++;
+      FileOffset += HV_BLOCK_SIZE;
+    }
+
+   Success = RegistryHive->FileSetSize(RegistryHive, HV_TYPE_LOG, FileOffset);
+   if (!Success)
+   {
+      DPRINT("FileSetSize failed\n");
+      return FALSE;
+    }
+
+   /* Flush the log file */
+   Success = RegistryHive->FileFlush(RegistryHive, HV_TYPE_LOG);
+   if (!Success)
+   {
+      DPRINT("FileFlush failed\n");
+   }
+
+   /* Update first and second update counter and checksum. */
+   RegistryHive->HiveHeader->Sequence2++;
+   RegistryHive->HiveHeader->Checksum =
+      HvpHiveHeaderChecksum(RegistryHive->HiveHeader);
+
+   /* Write hive header again with updated sequence counter. */
+   Success = RegistryHive->FileWrite(RegistryHive, HV_TYPE_LOG,
+                                     0, RegistryHive->HiveHeader,
+                                     HV_LOG_HEADER_SIZE);
+   if (!Success)
+   {
+      return FALSE;
+   }
+
+   /* Flush the log file */
+   Success = RegistryHive->FileFlush(RegistryHive, HV_TYPE_LOG);
+   if (!Success)
+   {
+      DPRINT("FileFlush failed\n");
+   }
+
+   return TRUE;
+}
+
+static BOOLEAN CMAPI
+HvpWriteHive(
+   PREGISTRY_HIVE RegistryHive,
+   BOOLEAN OnlyDirty)
+{
+   ULONG FileOffset;
+   ULONG BlockIndex;
+   ULONG LastIndex;
+   PVOID BlockPtr;
+   BOOLEAN Success;
+
+   ASSERT(RegistryHive->ReadOnly == FALSE);
+   
+   DPRINT("HvpWriteHive called\n");
+
+   if (RegistryHive->HiveHeader->Sequence1 !=
+       RegistryHive->HiveHeader->Sequence2)
+   {
+      return FALSE;
+   }
+
+   /* Update first update counter and checksum */
+   RegistryHive->HiveHeader->Type = HV_TYPE_PRIMARY;
+   RegistryHive->HiveHeader->Sequence1++;
+   RegistryHive->HiveHeader->Checksum =
+      HvpHiveHeaderChecksum(RegistryHive->HiveHeader);
+
+   /* Write hive block */
+   Success = RegistryHive->FileWrite(RegistryHive, HV_TYPE_PRIMARY,
+                                     0, RegistryHive->HiveHeader,
+                                     sizeof(HIVE_HEADER));
+   if (!Success)
+   {
+      return FALSE;
+   }
+
+   BlockIndex = 0;
+   while (BlockIndex < RegistryHive->Storage[HvStable].BlockListSize)
+   {
+      if (OnlyDirty)
+      {
+         LastIndex = BlockIndex;
+         BlockIndex = RtlFindSetBits(&RegistryHive->DirtyBitmap, 1, BlockIndex);
+         if (BlockIndex == ~0 || BlockIndex < LastIndex)
+         {
+            break;
+         }
+      }
+
+      BlockPtr = RegistryHive->Storage[HvStable].BlockList[BlockIndex].Block;
+      FileOffset = (ULONGLONG)(BlockIndex + 1) * (ULONGLONG)HV_BLOCK_SIZE;
+
+      /* Write hive block */
+      Success = RegistryHive->FileWrite(RegistryHive, HV_TYPE_PRIMARY,
+                                        FileOffset, BlockPtr,
+                                        HV_BLOCK_SIZE);
+      if (!Success)
+      {
+         return FALSE;
+      }
+
+      BlockIndex++;
+   }
+
+   Success = RegistryHive->FileFlush(RegistryHive, HV_TYPE_PRIMARY);
+   if (!Success)
+   {
+      DPRINT("FileFlush failed\n");
+   }
+
+   /* Update second update counter and checksum */
+   RegistryHive->HiveHeader->Sequence2++;
+   RegistryHive->HiveHeader->Checksum =
+      HvpHiveHeaderChecksum(RegistryHive->HiveHeader);
+
+   /* Write hive block */
+   Success = RegistryHive->FileWrite(RegistryHive, HV_TYPE_PRIMARY,
+                                     0, RegistryHive->HiveHeader,
+                                     sizeof(HIVE_HEADER));
+   if (!Success)
+   {
+      return FALSE;
+   }
+
+   Success = RegistryHive->FileFlush(RegistryHive, HV_TYPE_PRIMARY);
+   if (!Success)
+   {
+      DPRINT("FileFlush failed\n");
+   }
+
+   return TRUE;
+}
+
+BOOLEAN CMAPI
+HvSyncHive(
+   PREGISTRY_HIVE RegistryHive)
+{
+   ASSERT(RegistryHive->ReadOnly == FALSE);
+
+   if (RtlFindSetBits(&RegistryHive->DirtyBitmap, 1, 0) == ~0)
+   {
+      return TRUE;
+   }
+
+   /* Update hive header modification time */
+   KeQuerySystemTime(&RegistryHive->HiveHeader->TimeStamp);
+
+   /* Update log file */
+   if (!HvpWriteLog(RegistryHive))
+   {
+      return FALSE;
+   }
+
+   /* Update hive file */
+   if (!HvpWriteHive(RegistryHive, TRUE))
+   {
+      return FALSE;
+   }
+
+   /* Clear dirty bitmap. */
+   RtlClearAllBits(&RegistryHive->DirtyBitmap);
+
+   return TRUE;
+}
+
+BOOLEAN CMAPI
+HvWriteHive(
+   PREGISTRY_HIVE RegistryHive)
+{
+   ASSERT(RegistryHive->ReadOnly == FALSE);
+
+   /* Update hive header modification time */
+   KeQuerySystemTime(&RegistryHive->HiveHeader->TimeStamp);
+
+   /* Update hive file */
+   if (!HvpWriteHive(RegistryHive, FALSE))
+   {
+      return FALSE;
+   }
+
+   return TRUE;
+}




More information about the Ros-diffs mailing list