mirror of
https://github.com/reactos/reactos.git
synced 2024-10-15 13:45:58 +00:00
Actually add cmlib itself
svn path=/trunk/; revision=23336
This commit is contained in:
parent
d01cb10386
commit
793b990edb
134
reactos/lib/cmlib/cmdata.h
Normal file
134
reactos/lib/cmlib/cmdata.h
Normal 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 */
|
82
reactos/lib/cmlib/cminit.c
Normal file
82
reactos/lib/cmlib/cminit.c
Normal 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
175
reactos/lib/cmlib/cmlib.h
Normal 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 */
|
55
reactos/lib/cmlib/cmlib.mak
Normal file
55
reactos/lib/cmlib/cmlib.mak
Normal 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
|
14
reactos/lib/cmlib/cmlib.rbuild
Normal file
14
reactos/lib/cmlib/cmlib.rbuild
Normal 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>
|
98
reactos/lib/cmlib/hivebin.c
Normal file
98
reactos/lib/cmlib/hivebin.c
Normal 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;
|
||||||
|
}
|
429
reactos/lib/cmlib/hivecell.c
Normal file
429
reactos/lib/cmlib/hivecell.c
Normal 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);
|
||||||
|
}
|
138
reactos/lib/cmlib/hivedata.h
Normal file
138
reactos/lib/cmlib/hivedata.h
Normal 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 */
|
377
reactos/lib/cmlib/hiveinit.c
Normal file
377
reactos/lib/cmlib/hiveinit.c
Normal 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 */
|
32
reactos/lib/cmlib/hivesum.c
Normal file
32
reactos/lib/cmlib/hivesum.c
Normal 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
277
reactos/lib/cmlib/hivewrt.c
Normal 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;
|
||||||
|
}
|
Loading…
Reference in a new issue