Actually add cmlib itself

svn path=/trunk/; revision=23336
This commit is contained in:
Aleksey Bragin 2006-07-28 20:50:05 +00:00
parent d01cb10386
commit 793b990edb
11 changed files with 1811 additions and 0 deletions

134
reactos/lib/cmlib/cmdata.h Normal file
View file

@ -0,0 +1,134 @@
/*
* PROJECT: registry manipulation library
* LICENSE: GPL - See COPYING in the top level directory
* COPYRIGHT: Copyright 2005 Filip Navara <navaraf@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 */

View file

@ -0,0 +1,82 @@
/*
* PROJECT: registry manipulation library
* LICENSE: GPL - See COPYING in the top level directory
* COPYRIGHT: Copyright 2005 Filip Navara <navaraf@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);
}

175
reactos/lib/cmlib/cmlib.h Normal file
View file

@ -0,0 +1,175 @@
/*
* PROJECT: registry manipulation library
* LICENSE: GPL - See COPYING in the top level directory
* COPYRIGHT: Copyright 2005 Filip Navara <navaraf@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 */

View file

@ -0,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

View file

@ -0,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>

View file

@ -0,0 +1,98 @@
/*
* PROJECT: registry manipulation library
* LICENSE: GPL - See COPYING in the top level directory
* COPYRIGHT: Copyright 2005 Filip Navara <navaraf@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;
}

View file

@ -0,0 +1,429 @@
/*
* PROJECT: registry manipulation library
* LICENSE: GPL - See COPYING in the top level directory
* COPYRIGHT: Copyright 2005 Filip Navara <navaraf@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);
}

View file

@ -0,0 +1,138 @@
/*
* PROJECT: registry manipulation library
* LICENSE: GPL - See COPYING in the top level directory
* COPYRIGHT: Copyright 2005 Filip Navara <navaraf@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 */

View file

@ -0,0 +1,377 @@
/*
* PROJECT: registry manipulation library
* LICENSE: GPL - See COPYING in the top level directory
* COPYRIGHT: Copyright 2005 Filip Navara <navaraf@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 */

View file

@ -0,0 +1,32 @@
/*
* PROJECT: registry manipulation library
* LICENSE: GPL - See COPYING in the top level directory
* COPYRIGHT: Copyright 2005 Filip Navara <navaraf@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;
}

277
reactos/lib/cmlib/hivewrt.c Normal file
View file

@ -0,0 +1,277 @@
/*
* PROJECT: registry manipulation library
* LICENSE: GPL - See COPYING in the top level directory
* COPYRIGHT: Copyright 2005 Filip Navara <navaraf@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;
}