Create a branch for cmake bringup.

svn path=/branches/cmake-bringup/; revision=48236
This commit is contained in:
Amine Khaldi 2010-07-24 18:52:44 +00:00
parent a28e798006
commit c424146e2c
20602 changed files with 0 additions and 1140137 deletions

210
lib/cmlib/cmdata.h Normal file
View file

@ -0,0 +1,210 @@
/*
* 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
*/
#pragma once
#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
//
// Key Types
//
#define CM_KEY_INDEX_ROOT 0x6972
#define CM_KEY_INDEX_LEAF 0x696c
#define CM_KEY_FAST_LEAF 0x666c
#define CM_KEY_HASH_LEAF 0x686c
//
// Key Signatures
//
#define CM_KEY_NODE_SIGNATURE 0x6B6E
#define CM_LINK_NODE_SIGNATURE 0x6B6C
#define CM_KEY_VALUE_SIGNATURE 0x6B76
//
// CM_KEY_NODE Flags
//
#define KEY_IS_VOLATILE 0x01
#define KEY_HIVE_EXIT 0x02
#define KEY_HIVE_ENTRY 0x04
#define KEY_NO_DELETE 0x08
#define KEY_SYM_LINK 0x10
#define KEY_COMP_NAME 0x20
#define KEY_PREFEF_HANDLE 0x40
#define KEY_VIRT_MIRRORED 0x80
#define KEY_VIRT_TARGET 0x100
#define KEY_VIRTUAL_STORE 0x200
//
// CM_KEY_VALUE Flags
//
#define VALUE_COMP_NAME 0x0001
#ifdef CMLIB_HOST
#include <host/pshpack1.h>
#else
#include <pshpack1.h>
#endif
//
// For memory-mapped Hives
//
typedef struct _CM_VIEW_OF_FILE
{
LIST_ENTRY LRUViewList;
LIST_ENTRY PinViewList;
ULONG FileOffset;
ULONG Size;
PULONG ViewAddress;
PVOID Bcb;
ULONG UseCount;
} CM_VIEW_OF_FILE, *PCM_VIEW_OF_FILE;
//
// Children of Key Notes
//
typedef struct _CHILD_LIST
{
ULONG Count;
HCELL_INDEX List;
} CHILD_LIST, *PCHILD_LIST;
//
// Node Key Reference to Parents
//
typedef struct _CM_KEY_REFERENCE
{
HCELL_INDEX KeyCell;
PHHIVE KeyHive;
} CM_KEY_REFERENCE, *PCM_KEY_REFERENCE;
//
// Node Key
//
typedef struct _CM_KEY_NODE
{
USHORT Signature;
USHORT Flags;
LARGE_INTEGER LastWriteTime;
ULONG Spare;
HCELL_INDEX Parent;
ULONG SubKeyCounts[HTYPE_COUNT];
union
{
struct
{
HCELL_INDEX SubKeyLists[HTYPE_COUNT];
CHILD_LIST ValueList;
};
CM_KEY_REFERENCE ChildHiveReference;
};
HCELL_INDEX Security;
HCELL_INDEX Class;
ULONG MaxNameLen;
ULONG MaxClassLen;
ULONG MaxValueNameLen;
ULONG MaxValueDataLen;
ULONG WorkVar;
USHORT NameLength;
USHORT ClassLength;
WCHAR Name[ANYSIZE_ARRAY];
} CM_KEY_NODE, *PCM_KEY_NODE;
//
// Value List
//
typedef struct _VALUE_LIST_CELL
{
HCELL_INDEX ValueOffset[ANYSIZE_ARRAY];
} VALUE_LIST_CELL, *PVALUE_LIST_CELL;
//
// Value Key
//
typedef struct _CM_KEY_VALUE
{
USHORT Signature;
USHORT NameLength;
ULONG DataLength;
HCELL_INDEX Data;
ULONG Type;
USHORT Flags;
USHORT Unused1;
WCHAR Name[ANYSIZE_ARRAY];
} CM_KEY_VALUE, *PCM_KEY_VALUE;
//
// Security Key
//
typedef struct _CM_KEY_SECURITY
{
USHORT Signature;
USHORT Reserved;
HCELL_INDEX Flink;
HCELL_INDEX Blink;
ULONG ReferenceCount;
ULONG DescriptorLength;
//SECURITY_DESCRIPTOR_RELATIVE Descriptor;
UCHAR Data[ANYSIZE_ARRAY];
} CM_KEY_SECURITY, *PCM_KEY_SECURITY;
#ifdef CMLIB_HOST
#include <host/poppack.h>
#else
#include <poppack.h>
#endif
//
// Generic Index Entry
//
typedef struct _CM_INDEX
{
HCELL_INDEX Cell;
union
{
UCHAR NameHint[4];
ULONG HashKey;
};
} CM_INDEX, *PCM_INDEX;
//
// Key Index
//
typedef struct _CM_KEY_INDEX
{
USHORT Signature;
USHORT Count;
HCELL_INDEX List[ANYSIZE_ARRAY];
} CM_KEY_INDEX, *PCM_KEY_INDEX;
//
// Fast/Hash Key Index
//
typedef struct _CM_KEY_FAST_INDEX
{
USHORT Signature;
USHORT Count;
CM_INDEX List[ANYSIZE_ARRAY];
} CM_KEY_FAST_INDEX, *PCM_KEY_FAST_INDEX;
//
// Cell Data
//
typedef struct _CELL_DATA
{
union
{
CM_KEY_NODE KeyNode;
CM_KEY_VALUE KeyValue;
CM_KEY_SECURITY KeySecurity;
CM_KEY_INDEX KeyIndex;
HCELL_INDEX KeyList[ANYSIZE_ARRAY];
WCHAR KeyString[ANYSIZE_ARRAY];
} u;
} CELL_DATA, *PCELL_DATA;

136
lib/cmlib/cminit.c Normal file
View file

@ -0,0 +1,136 @@
/*
* 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>
ULONG CmlibTraceLevel = 0;
BOOLEAN CMAPI
CmCreateRootNode(
PHHIVE Hive,
PCWSTR Name)
{
PCM_KEY_NODE KeyCell;
HCELL_INDEX RootCellIndex;
SIZE_T NameSize;
/* Allocate the cell */
NameSize = strlenW(Name) * sizeof(WCHAR);
RootCellIndex = HvAllocateCell(Hive,
FIELD_OFFSET(CM_KEY_NODE, Name) + NameSize,
Stable,
HCELL_NIL);
if (RootCellIndex == HCELL_NIL) return FALSE;
/* Seutp the base block */
Hive->BaseBlock->RootCell = RootCellIndex;
Hive->BaseBlock->CheckSum = HvpHiveHeaderChecksum(Hive->BaseBlock);
/* Get the key cell */
KeyCell = (PCM_KEY_NODE)HvGetCell(Hive, RootCellIndex);
if (!KeyCell) return FALSE;
/* Setup the cell */
KeyCell->Signature = (USHORT)CM_KEY_NODE_SIGNATURE;
KeyCell->Flags = KEY_HIVE_ENTRY | KEY_NO_DELETE;
KeyCell->LastWriteTime.QuadPart = 0;
KeyCell->Parent = HCELL_NIL;
KeyCell->SubKeyCounts[Stable] = 0;
KeyCell->SubKeyCounts[Volatile] = 0;
KeyCell->SubKeyLists[Stable] = HCELL_NIL;
KeyCell->SubKeyLists[Volatile] = HCELL_NIL;
KeyCell->ValueList.Count = 0;
KeyCell->ValueList.List = HCELL_NIL;
KeyCell->Security = HCELL_NIL;
KeyCell->Class = HCELL_NIL;
KeyCell->ClassLength = 0;
KeyCell->MaxNameLen = 0;
KeyCell->MaxClassLen = 0;
KeyCell->MaxValueNameLen = 0;
KeyCell->MaxValueDataLen = 0;
/* Write the name */
KeyCell->NameLength = (USHORT)NameSize;
memcpy(KeyCell->Name, Name, NameSize);
/* Return success */
HvReleaseCell(Hive, RootCellIndex);
return TRUE;
}
static VOID CMAPI
CmpPrepareKey(
PHHIVE RegistryHive,
PCM_KEY_NODE KeyCell);
static VOID CMAPI
CmpPrepareIndexOfKeys(
PHHIVE RegistryHive,
PCM_KEY_INDEX IndexCell)
{
ULONG i;
if (IndexCell->Signature == CM_KEY_INDEX_ROOT ||
IndexCell->Signature == CM_KEY_INDEX_LEAF)
{
for (i = 0; i < IndexCell->Count; i++)
{
PCM_KEY_INDEX SubIndexCell = HvGetCell(RegistryHive, IndexCell->List[i]);
if (SubIndexCell->Signature == CM_KEY_NODE_SIGNATURE)
CmpPrepareKey(RegistryHive, (PCM_KEY_NODE)SubIndexCell);
else
CmpPrepareIndexOfKeys(RegistryHive, SubIndexCell);
}
}
else if (IndexCell->Signature == CM_KEY_FAST_LEAF ||
IndexCell->Signature == CM_KEY_HASH_LEAF)
{
PCM_KEY_FAST_INDEX HashCell = (PCM_KEY_FAST_INDEX)IndexCell;
for (i = 0; i < HashCell->Count; i++)
{
PCM_KEY_NODE SubKeyCell = HvGetCell(RegistryHive, HashCell->List[i].Cell);
CmpPrepareKey(RegistryHive, SubKeyCell);
}
}
else
{
DPRINT1("IndexCell->Signature %x\n", IndexCell->Signature);
ASSERT(FALSE);
}
}
static VOID CMAPI
CmpPrepareKey(
PHHIVE RegistryHive,
PCM_KEY_NODE KeyCell)
{
PCM_KEY_INDEX IndexCell;
ASSERT(KeyCell->Signature == CM_KEY_NODE_SIGNATURE);
KeyCell->SubKeyLists[Volatile] = HCELL_NIL;
KeyCell->SubKeyCounts[Volatile] = 0;
/* Enumerate and add subkeys */
if (KeyCell->SubKeyCounts[Stable] > 0)
{
IndexCell = HvGetCell(RegistryHive, KeyCell->SubKeyLists[Stable]);
CmpPrepareIndexOfKeys(RegistryHive, IndexCell);
}
}
VOID CMAPI
CmPrepareHive(
PHHIVE RegistryHive)
{
PCM_KEY_NODE RootCell;
RootCell = HvGetCell(RegistryHive, RegistryHive->BaseBlock->RootCell);
CmpPrepareKey(RegistryHive, RootCell);
}

346
lib/cmlib/cmlib.h Normal file
View file

@ -0,0 +1,346 @@
/*
* 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
*/
#pragma once
//
// Debug support switch
//
#define _CMLIB_DEBUG_ 1
#ifdef CMLIB_HOST
#include <wine/unicode.h>
#include <host/typedefs.h>
#include <stdio.h>
#include <string.h>
// Definitions copied from <ntstatus.h>
// We only want to include host headers, so we define them manually
#define STATUS_SUCCESS ((NTSTATUS)0x00000000)
#define STATUS_NOT_IMPLEMENTED ((NTSTATUS)0xC0000002)
#define STATUS_NO_MEMORY ((NTSTATUS)0xC0000017)
#define STATUS_INSUFFICIENT_RESOURCES ((NTSTATUS)0xC000009A)
#define STATUS_REGISTRY_CORRUPT ((NTSTATUS)0xC000014C)
#define STATUS_NOT_REGISTRY_FILE ((NTSTATUS)0xC000015C)
#define STATUS_REGISTRY_RECOVERED ((NTSTATUS)0x40000009)
#define REG_OPTION_VOLATILE 1
#define OBJ_CASE_INSENSITIVE 0x00000040L
#define USHORT_MAX USHRT_MAX
VOID NTAPI
KeQuerySystemTime(
OUT PLARGE_INTEGER CurrentTime);
VOID NTAPI
RtlInitializeBitMap(
IN PRTL_BITMAP BitMapHeader,
IN PULONG BitMapBuffer,
IN ULONG SizeOfBitMap);
ULONG NTAPI
RtlFindSetBits(
IN PRTL_BITMAP BitMapHeader,
IN ULONG NumberToFind,
IN ULONG HintIndex);
VOID NTAPI
RtlSetBits(
IN PRTL_BITMAP BitMapHeader,
IN ULONG StartingIndex,
IN ULONG NumberToSet);
VOID NTAPI
RtlClearAllBits(
IN PRTL_BITMAP BitMapHeader);
#define RtlCheckBit(BMH,BP) (((((PLONG)(BMH)->Buffer)[(BP) / 32]) >> ((BP) % 32)) & 0x1)
#define UNREFERENCED_PARAMETER(P) {(P)=(P);}
#define PKTHREAD PVOID
#define PKGUARDED_MUTEX PVOID
#define PERESOURCE PVOID
#define PFILE_OBJECT PVOID
#define PKEVENT PVOID
#define PWORK_QUEUE_ITEM PVOID
#define EX_PUSH_LOCK PULONG_PTR
/* For <host/wcsfuncs.h> */
#define USE_HOST_WCSFUNCS
#define CMLTRACE(x, ...)
#else
//
// Debug/Tracing support
//
#if _CMLIB_DEBUG_
#ifdef NEW_DEBUG_SYSTEM_IMPLEMENTED // enable when Debug Filters are implemented
#define CMLTRACE DbgPrintEx
#else
#define CMLTRACE(x, ...) \
if (x & CmlibTraceLevel) DbgPrint(__VA_ARGS__)
#endif
#else
#define CMLTRACE(x, ...) DPRINT(__VA_ARGS__)
#endif
#include <ntdef.h>
#undef DECLSPEC_IMPORT
#define DECLSPEC_IMPORT
#include <ntddk.h>
#endif
#include <host/wcsfuncs.h>
//
// These define the Debug Masks Supported
//
#define CMLIB_HCELL_DEBUG 0x01
#ifndef ROUND_UP
#define ROUND_UP(a,b) ((((a)+(b)-1)/(b))*(b))
#define ROUND_DOWN(a,b) (((a)/(b))*(b))
#endif
//
// PAGE_SIZE definition
//
#ifndef PAGE_SIZE
#if defined(TARGET_i386) || defined(TARGET_amd64) || defined(TARGET_arm)
#define PAGE_SIZE 0x1000
#else
#error Local PAGE_SIZE definition required when built as host
#endif
#endif
#define TAG_CM 0x68742020
#define CMAPI NTAPI
#include <wchar.h>
#include "hivedata.h"
#include "cmdata.h"
#if defined(_TYPEDEFS_HOST_H) || defined(__FREELDR_H)
#define PCM_KEY_SECURITY_CACHE_ENTRY PVOID
#define PCM_KEY_CONTROL_BLOCK PVOID
#define CMP_SECURITY_HASH_LISTS 64
#define PCM_CELL_REMAP_BLOCK PVOID
//
// Use Count Log and Entry
//
typedef struct _CM_USE_COUNT_LOG_ENTRY
{
HCELL_INDEX Cell;
PVOID Stack[7];
} CM_USE_COUNT_LOG_ENTRY, *PCM_USE_COUNT_LOG_ENTRY;
typedef struct _CM_USE_COUNT_LOG
{
USHORT Next;
USHORT Size;
CM_USE_COUNT_LOG_ENTRY Log[32];
} CM_USE_COUNT_LOG, *PCM_USE_COUNT_LOG;
//
// Configuration Manager Hive Structure
//
typedef struct _CMHIVE
{
HHIVE Hive;
HANDLE FileHandles[3];
LIST_ENTRY NotifyList;
LIST_ENTRY HiveList;
EX_PUSH_LOCK HiveLock;
PKTHREAD HiveLockOwner;
PKGUARDED_MUTEX ViewLock;
PKTHREAD ViewLockOwner;
EX_PUSH_LOCK WriterLock;
PKTHREAD WriterLockOwner;
PERESOURCE FlusherLock;
EX_PUSH_LOCK SecurityLock;
PKTHREAD HiveSecurityLockOwner;
LIST_ENTRY LRUViewListHead;
LIST_ENTRY PinViewListHead;
PFILE_OBJECT FileObject;
UNICODE_STRING FileFullPath;
UNICODE_STRING FileUserName;
USHORT MappedViews;
USHORT PinnedViews;
ULONG UseCount;
ULONG SecurityCount;
ULONG SecurityCacheSize;
LONG SecurityHitHint;
PCM_KEY_SECURITY_CACHE_ENTRY SecurityCache;
LIST_ENTRY SecurityHash[CMP_SECURITY_HASH_LISTS];
PKEVENT UnloadEvent;
PCM_KEY_CONTROL_BLOCK RootKcb;
BOOLEAN Frozen;
PWORK_QUEUE_ITEM UnloadWorkItem;
BOOLEAN GrowOnlyMode;
ULONG GrowOffset;
LIST_ENTRY KcbConvertListHead;
LIST_ENTRY KnodeConvertListHead;
PCM_CELL_REMAP_BLOCK CellRemapArray;
CM_USE_COUNT_LOG UseCountLog;
CM_USE_COUNT_LOG LockHiveLog;
ULONG Flags;
LIST_ENTRY TrustClassEntry;
ULONG FlushCount;
BOOLEAN HiveIsLoading;
PKTHREAD CreatorOwner;
} CMHIVE, *PCMHIVE;
#endif
typedef struct _HV_HIVE_CELL_PAIR
{
PHHIVE Hive;
HCELL_INDEX Cell;
} HV_HIVE_CELL_PAIR, *PHV_HIVE_CELL_PAIR;
#define STATIC_CELL_PAIR_COUNT 4
typedef struct _HV_TRACK_CELL_REF
{
USHORT Count;
USHORT Max;
PHV_HIVE_CELL_PAIR CellArray;
HV_HIVE_CELL_PAIR StaticArray[STATIC_CELL_PAIR_COUNT];
USHORT StaticCount;
} HV_TRACK_CELL_REF, *PHV_TRACK_CELL_REF;
extern ULONG CmlibTraceLevel;
/*
* Public functions.
*/
NTSTATUS CMAPI
HvInitialize(
PHHIVE RegistryHive,
ULONG Operation,
ULONG HiveType,
ULONG HiveFlags,
PVOID HiveData OPTIONAL,
PALLOCATE_ROUTINE Allocate,
PFREE_ROUTINE Free,
PFILE_SET_SIZE_ROUTINE FileSetSize,
PFILE_WRITE_ROUTINE FileWrite,
PFILE_READ_ROUTINE FileRead,
PFILE_FLUSH_ROUTINE FileFlush,
ULONG Cluster OPTIONAL,
PUNICODE_STRING FileName);
VOID CMAPI
HvFree(
PHHIVE RegistryHive);
PVOID CMAPI
HvGetCell(
PHHIVE RegistryHive,
HCELL_INDEX CellOffset);
#define HvReleaseCell(h, c) \
if (h->ReleaseCellRoutine) h->ReleaseCellRoutine(h, c)
LONG CMAPI
HvGetCellSize(
PHHIVE RegistryHive,
PVOID Cell);
HCELL_INDEX CMAPI
HvAllocateCell(
PHHIVE RegistryHive,
SIZE_T Size,
HSTORAGE_TYPE Storage,
IN HCELL_INDEX Vicinity);
BOOLEAN CMAPI
HvIsCellAllocated(
IN PHHIVE RegistryHive,
IN HCELL_INDEX CellIndex
);
HCELL_INDEX CMAPI
HvReallocateCell(
PHHIVE RegistryHive,
HCELL_INDEX CellOffset,
ULONG Size);
VOID CMAPI
HvFreeCell(
PHHIVE RegistryHive,
HCELL_INDEX CellOffset);
BOOLEAN CMAPI
HvMarkCellDirty(
PHHIVE RegistryHive,
HCELL_INDEX CellOffset,
BOOLEAN HoldingLock);
BOOLEAN CMAPI
HvIsCellDirty(
IN PHHIVE Hive,
IN HCELL_INDEX Cell
);
BOOLEAN
CMAPI
HvHiveWillShrink(
IN PHHIVE RegistryHive
);
BOOLEAN CMAPI
HvSyncHive(
PHHIVE RegistryHive);
BOOLEAN CMAPI
HvWriteHive(
PHHIVE RegistryHive);
BOOLEAN CMAPI
CmCreateRootNode(
PHHIVE Hive,
PCWSTR Name);
VOID CMAPI
CmPrepareHive(
PHHIVE RegistryHive);
BOOLEAN
CMAPI
HvTrackCellRef(
PHV_TRACK_CELL_REF CellRef,
PHHIVE Hive,
HCELL_INDEX Cell
);
VOID
CMAPI
HvReleaseFreeCellRefArray(
PHV_TRACK_CELL_REF CellRef
);
/*
* Private functions.
*/
PHBIN CMAPI
HvpAddBin(
PHHIVE RegistryHive,
ULONG Size,
HSTORAGE_TYPE Storage);
NTSTATUS CMAPI
HvpCreateHiveFreeCellList(
PHHIVE Hive);
ULONG CMAPI
HvpHiveHeaderChecksum(
PHBASE_BLOCK HiveHeader);

36
lib/cmlib/cmlib.rbuild Normal file
View file

@ -0,0 +1,36 @@
<?xml version="1.0"?>
<!DOCTYPE module SYSTEM "../../tools/rbuild/project.dtd">
<group>
<module name="cmlib" type="staticlibrary">
<include base="cmlib">.</include>
<define name="_NTOSKRNL_" />
<define name="_NTSYSTEM_" />
<define name="NASSERT" />
<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>
<module name="cmlibhost" type="hoststaticlibrary">
<define name="WINE_UNICODE_API">" "</define>
<include base="unicode" />
<include base="cmlibhost">.</include>
<define name="__NO_CTYPE_INLINES" />
<define name="_NTOSKRNL_" />
<define name="_NTSYSTEM_" />
<define name="NASSERT" />
<group compilerset="gcc">
<compilerflag>-Wwrite-strings</compilerflag>
<compilerflag>-Wpointer-arith</compilerflag>
</group>
<define name="CMLIB_HOST" />
<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>
</group>

104
lib/cmlib/hivebin.c Normal file
View file

@ -0,0 +1,104 @@
/*
* 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(
PHHIVE RegistryHive,
ULONG Size,
HSTORAGE_TYPE Storage)
{
PHMAP_ENTRY BlockList;
PHBIN Bin;
SIZE_T BinSize;
ULONG i;
ULONG BitmapSize;
ULONG BlockCount;
ULONG OldBlockListSize;
PHCELL Block;
BinSize = ROUND_UP(Size + sizeof(HBIN), HV_BLOCK_SIZE);
BlockCount = (ULONG)(BinSize / HV_BLOCK_SIZE);
Bin = RegistryHive->Allocate(BinSize, TRUE, TAG_CM);
if (Bin == NULL)
return NULL;
RtlZeroMemory(Bin, BinSize);
Bin->Signature = HV_BIN_SIGNATURE;
Bin->FileOffset = RegistryHive->Storage[Storage].Length *
HV_BLOCK_SIZE;
Bin->Size = (ULONG)BinSize;
/* Allocate new block list */
OldBlockListSize = RegistryHive->Storage[Storage].Length;
BlockList = RegistryHive->Allocate(sizeof(HMAP_ENTRY) *
(OldBlockListSize + BlockCount),
TRUE,
TAG_CM);
if (BlockList == NULL)
{
RegistryHive->Free(Bin, 0);
return NULL;
}
if (OldBlockListSize > 0)
{
RtlCopyMemory(BlockList, RegistryHive->Storage[Storage].BlockList,
OldBlockListSize * sizeof(HMAP_ENTRY));
RegistryHive->Free(RegistryHive->Storage[Storage].BlockList, 0);
}
RegistryHive->Storage[Storage].BlockList = BlockList;
RegistryHive->Storage[Storage].Length += BlockCount;
for (i = 0; i < BlockCount; i++)
{
RegistryHive->Storage[Storage].BlockList[OldBlockListSize + i].BlockAddress =
((ULONG_PTR)Bin + (i * HV_BLOCK_SIZE));
RegistryHive->Storage[Storage].BlockList[OldBlockListSize + i].BinAddress = (ULONG_PTR)Bin;
}
/* Initialize a free block in this heap. */
Block = (PHCELL)(Bin + 1);
Block->Size = (LONG)(BinSize - sizeof(HBIN));
if (Storage == Stable)
{
/* Calculate bitmap size in bytes (always a multiple of 32 bits). */
BitmapSize = ROUND_UP(RegistryHive->Storage[Stable].Length,
sizeof(ULONG) * 8) / 8;
/* Grow bitmap if necessary. */
if (BitmapSize > RegistryHive->DirtyVector.SizeOfBitMap / 8)
{
PULONG BitmapBuffer;
BitmapBuffer = RegistryHive->Allocate(BitmapSize, TRUE, TAG_CM);
RtlZeroMemory(BitmapBuffer, BitmapSize);
if (RegistryHive->DirtyVector.SizeOfBitMap > 0)
{
ASSERT(RegistryHive->DirtyVector.Buffer);
RtlCopyMemory(BitmapBuffer,
RegistryHive->DirtyVector.Buffer,
RegistryHive->DirtyVector.SizeOfBitMap / 8);
RegistryHive->Free(RegistryHive->DirtyVector.Buffer, 0);
}
RtlInitializeBitMap(&RegistryHive->DirtyVector, BitmapBuffer,
BitmapSize * 8);
}
/* Mark new bin dirty. */
RtlSetBits(&RegistryHive->DirtyVector,
Bin->FileOffset / HV_BLOCK_SIZE,
BlockCount);
}
return Bin;
}

580
lib/cmlib/hivecell.c Normal file
View file

@ -0,0 +1,580 @@
/*
* 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 __inline PHCELL CMAPI
HvpGetCellHeader(
PHHIVE RegistryHive,
HCELL_INDEX CellIndex)
{
PVOID Block;
CMLTRACE(CMLIB_HCELL_DEBUG, "%s - Hive %p, CellIndex %08lx\n",
__FUNCTION__, RegistryHive, CellIndex);
ASSERT(CellIndex != HCELL_NIL);
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].Length);
Block = (PVOID)RegistryHive->Storage[CellType].BlockList[CellBlock].BlockAddress;
ASSERT(Block != NULL);
return (PVOID)((ULONG_PTR)Block + CellOffset);
}
else
{
ASSERT((CellIndex & HCELL_TYPE_MASK) == Stable);
return (PVOID)((ULONG_PTR)RegistryHive->BaseBlock + HV_BLOCK_SIZE +
CellIndex);
}
}
BOOLEAN CMAPI
HvIsCellAllocated(IN PHHIVE RegistryHive,
IN HCELL_INDEX CellIndex)
{
ULONG Type, Block;
/* If it's a flat hive, the cell is always allocated */
if (RegistryHive->Flat)
return TRUE;
/* Otherwise, get the type and make sure it's valid */
Type = HvGetCellType(CellIndex);
Block = HvGetCellBlock(CellIndex);
if (Block >= RegistryHive->Storage[Type].Length)
return FALSE;
/* Try to get the cell block */
if (RegistryHive->Storage[Type].BlockList[Block].BlockAddress)
return TRUE;
/* No valid block, fail */
return FALSE;
}
PVOID CMAPI
HvGetCell(
PHHIVE RegistryHive,
HCELL_INDEX CellIndex)
{
return (PVOID)(HvpGetCellHeader(RegistryHive, CellIndex) + 1);
}
static __inline LONG CMAPI
HvpGetCellFullSize(
PHHIVE RegistryHive,
PVOID Cell)
{
UNREFERENCED_PARAMETER(RegistryHive);
return ((PHCELL)Cell - 1)->Size;
}
LONG CMAPI
HvGetCellSize(IN PHHIVE Hive,
IN PVOID Address)
{
PHCELL CellHeader;
LONG Size;
UNREFERENCED_PARAMETER(Hive);
CellHeader = (PHCELL)Address - 1;
Size = CellHeader->Size * -1;
Size -= sizeof(HCELL);
return Size;
}
BOOLEAN CMAPI
HvMarkCellDirty(
PHHIVE RegistryHive,
HCELL_INDEX CellIndex,
BOOLEAN HoldingLock)
{
ULONG CellBlock;
ULONG CellLastBlock;
ASSERT(RegistryHive->ReadOnly == FALSE);
CMLTRACE(CMLIB_HCELL_DEBUG, "%s - Hive %p, CellIndex %08lx, HoldingLock %b\n",
__FUNCTION__, RegistryHive, CellIndex, HoldingLock);
if ((CellIndex & HCELL_TYPE_MASK) >> HCELL_TYPE_SHIFT != Stable)
return TRUE;
CellBlock = (CellIndex & HCELL_BLOCK_MASK) >> HCELL_BLOCK_SHIFT;
CellLastBlock = ((CellIndex + HV_BLOCK_SIZE - 1) & HCELL_BLOCK_MASK) >> HCELL_BLOCK_SHIFT;
RtlSetBits(&RegistryHive->DirtyVector,
CellBlock, CellLastBlock - CellBlock);
return TRUE;
}
BOOLEAN CMAPI
HvIsCellDirty(IN PHHIVE Hive,
IN HCELL_INDEX Cell)
{
BOOLEAN IsDirty = FALSE;
/* Sanity checks */
ASSERT(Hive->ReadOnly == FALSE);
/* Volatile cells are always "dirty" */
if (HvGetCellType(Cell) == Volatile)
return TRUE;
/* Check if the dirty bit is set */
if (RtlCheckBit(&Hive->DirtyVector, Cell / HV_BLOCK_SIZE))
IsDirty = TRUE;
/* Return result as boolean*/
return IsDirty;
}
static __inline ULONG 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(
PHHIVE RegistryHive,
PHCELL FreeBlock,
HCELL_INDEX FreeIndex)
{
PHCELL_INDEX FreeBlockData;
HSTORAGE_TYPE Storage;
ULONG Index;
ASSERT(RegistryHive != NULL);
ASSERT(FreeBlock != NULL);
Storage = (FreeIndex & HCELL_TYPE_MASK) >> HCELL_TYPE_SHIFT;
Index = HvpComputeFreeListIndex((ULONG)FreeBlock->Size);
FreeBlockData = (PHCELL_INDEX)(FreeBlock + 1);
*FreeBlockData = RegistryHive->Storage[Storage].FreeDisplay[Index];
RegistryHive->Storage[Storage].FreeDisplay[Index] = FreeIndex;
/* FIXME: Eventually get rid of free bins. */
return STATUS_SUCCESS;
}
static VOID CMAPI
HvpRemoveFree(
PHHIVE RegistryHive,
PHCELL CellBlock,
HCELL_INDEX CellIndex)
{
PHCELL_INDEX FreeCellData;
PHCELL_INDEX pFreeCellOffset;
HSTORAGE_TYPE Storage;
ULONG Index, FreeListIndex;
ASSERT(RegistryHive->ReadOnly == FALSE);
Storage = (CellIndex & HCELL_TYPE_MASK) >> HCELL_TYPE_SHIFT;
Index = HvpComputeFreeListIndex((ULONG)CellBlock->Size);
pFreeCellOffset = &RegistryHive->Storage[Storage].FreeDisplay[Index];
while (*pFreeCellOffset != HCELL_NIL)
{
FreeCellData = (PHCELL_INDEX)HvGetCell(RegistryHive, *pFreeCellOffset);
if (*pFreeCellOffset == CellIndex)
{
*pFreeCellOffset = *FreeCellData;
return;
}
pFreeCellOffset = FreeCellData;
}
/* Something bad happened, print a useful trace info and bugcheck */
CMLTRACE(CMLIB_HCELL_DEBUG, "-- beginning of HvpRemoveFree trace --\n");
CMLTRACE(CMLIB_HCELL_DEBUG, "block we are about to free: %08x\n", CellIndex);
CMLTRACE(CMLIB_HCELL_DEBUG, "chosen free list index: %d\n", Index);
for (FreeListIndex = 0; FreeListIndex < 24; FreeListIndex++)
{
CMLTRACE(CMLIB_HCELL_DEBUG, "free list [%d]: ", FreeListIndex);
pFreeCellOffset = &RegistryHive->Storage[Storage].FreeDisplay[FreeListIndex];
while (*pFreeCellOffset != HCELL_NIL)
{
CMLTRACE(CMLIB_HCELL_DEBUG, "%08x ", *pFreeCellOffset);
FreeCellData = (PHCELL_INDEX)HvGetCell(RegistryHive, *pFreeCellOffset);
pFreeCellOffset = FreeCellData;
}
CMLTRACE(CMLIB_HCELL_DEBUG, "\n");
}
CMLTRACE(CMLIB_HCELL_DEBUG, "-- end of HvpRemoveFree trace --\n");
ASSERT(FALSE);
}
static HCELL_INDEX CMAPI
HvpFindFree(
PHHIVE RegistryHive,
ULONG Size,
HSTORAGE_TYPE Storage)
{
PHCELL_INDEX FreeCellData;
HCELL_INDEX FreeCellOffset;
PHCELL_INDEX pFreeCellOffset;
ULONG Index;
for (Index = HvpComputeFreeListIndex(Size); Index < 24; Index++)
{
pFreeCellOffset = &RegistryHive->Storage[Storage].FreeDisplay[Index];
while (*pFreeCellOffset != HCELL_NIL)
{
FreeCellData = (PHCELL_INDEX)HvGetCell(RegistryHive, *pFreeCellOffset);
if ((ULONG)HvpGetCellFullSize(RegistryHive, FreeCellData) >= Size)
{
FreeCellOffset = *pFreeCellOffset;
*pFreeCellOffset = *FreeCellData;
return FreeCellOffset;
}
pFreeCellOffset = FreeCellData;
}
}
return HCELL_NIL;
}
NTSTATUS CMAPI
HvpCreateHiveFreeCellList(
PHHIVE Hive)
{
HCELL_INDEX BlockOffset;
PHCELL FreeBlock;
ULONG BlockIndex;
ULONG FreeOffset;
PHBIN Bin;
NTSTATUS Status;
ULONG Index;
/* Initialize the free cell list */
for (Index = 0; Index < 24; Index++)
{
Hive->Storage[Stable].FreeDisplay[Index] = HCELL_NIL;
Hive->Storage[Volatile].FreeDisplay[Index] = HCELL_NIL;
}
BlockOffset = 0;
BlockIndex = 0;
while (BlockIndex < Hive->Storage[Stable].Length)
{
Bin = (PHBIN)Hive->Storage[Stable].BlockList[BlockIndex].BinAddress;
/* Search free blocks and add to list */
FreeOffset = sizeof(HBIN);
while (FreeOffset < Bin->Size)
{
FreeBlock = (PHCELL)((ULONG_PTR)Bin + FreeOffset);
if (FreeBlock->Size > 0)
{
Status = HvpAddFree(Hive, FreeBlock, Bin->FileOffset + FreeOffset);
if (!NT_SUCCESS(Status))
return Status;
FreeOffset += FreeBlock->Size;
}
else
{
FreeOffset -= FreeBlock->Size;
}
}
BlockIndex += Bin->Size / HV_BLOCK_SIZE;
BlockOffset += Bin->Size;
}
return STATUS_SUCCESS;
}
HCELL_INDEX CMAPI
HvAllocateCell(
PHHIVE RegistryHive,
SIZE_T Size,
HSTORAGE_TYPE Storage,
HCELL_INDEX Vicinity)
{
PHCELL FreeCell;
HCELL_INDEX FreeCellOffset;
PHCELL NewCell;
PHBIN Bin;
ASSERT(RegistryHive->ReadOnly == FALSE);
CMLTRACE(CMLIB_HCELL_DEBUG, "%s - Hive %p, Size %x, %s, Vicinity %08lx\n",
__FUNCTION__, RegistryHive, Size, (Storage == 0) ? "Stable" : "Volatile", Vicinity);
/* Round to 16 bytes multiple. */
Size = ROUND_UP(Size + sizeof(HCELL), 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_NIL)
{
Bin = HvpAddBin(RegistryHive, Size, Storage);
if (Bin == NULL)
return HCELL_NIL;
FreeCellOffset = Bin->FileOffset + sizeof(HBIN);
FreeCellOffset |= Storage << HCELL_TYPE_SHIFT;
}
FreeCell = HvpGetCellHeader(RegistryHive, FreeCellOffset);
/* Split the block in two parts */
/* The free block that is created has to be at least
sizeof(HCELL) + sizeof(HCELL_INDEX) big, so that free
cell list code can work. Moreover we round cell sizes
to 16 bytes, so creating a smaller block would result in
a cell that would never be allocated. */
if ((ULONG)FreeCell->Size > Size + 16)
{
NewCell = (PHCELL)((ULONG_PTR)FreeCell + Size);
NewCell->Size = FreeCell->Size - Size;
FreeCell->Size = Size;
HvpAddFree(RegistryHive, NewCell, FreeCellOffset + Size);
if (Storage == Stable)
HvMarkCellDirty(RegistryHive, FreeCellOffset + Size, FALSE);
}
if (Storage == Stable)
HvMarkCellDirty(RegistryHive, FreeCellOffset, FALSE);
FreeCell->Size = -FreeCell->Size;
RtlZeroMemory(FreeCell + 1, Size - sizeof(HCELL));
CMLTRACE(CMLIB_HCELL_DEBUG, "%s - CellIndex %08lx\n",
__FUNCTION__, FreeCellOffset);
return FreeCellOffset;
}
HCELL_INDEX CMAPI
HvReallocateCell(
PHHIVE RegistryHive,
HCELL_INDEX CellIndex,
ULONG Size)
{
PVOID OldCell;
PVOID NewCell;
LONG OldCellSize;
HCELL_INDEX NewCellIndex;
HSTORAGE_TYPE Storage;
ASSERT(CellIndex != HCELL_NIL);
CMLTRACE(CMLIB_HCELL_DEBUG, "%s - Hive %p, CellIndex %08lx, Size %x\n",
__FUNCTION__, RegistryHive, CellIndex, Size);
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 > (ULONG)OldCellSize)
{
NewCellIndex = HvAllocateCell(RegistryHive, Size, Storage, HCELL_NIL);
if (NewCellIndex == HCELL_NIL)
return HCELL_NIL;
NewCell = HvGetCell(RegistryHive, NewCellIndex);
RtlCopyMemory(NewCell, OldCell, (SIZE_T)OldCellSize);
HvFreeCell(RegistryHive, CellIndex);
return NewCellIndex;
}
return CellIndex;
}
VOID CMAPI
HvFreeCell(
PHHIVE RegistryHive,
HCELL_INDEX CellIndex)
{
PHCELL Free;
PHCELL Neighbor;
PHBIN Bin;
ULONG CellType;
ULONG CellBlock;
ASSERT(RegistryHive->ReadOnly == FALSE);
CMLTRACE(CMLIB_HCELL_DEBUG, "%s - Hive %p, CellIndex %08lx\n",
__FUNCTION__, RegistryHive, CellIndex);
Free = HvpGetCellHeader(RegistryHive, CellIndex);
ASSERT(Free->Size < 0);
Free->Size = -Free->Size;
CellType = (CellIndex & HCELL_TYPE_MASK) >> HCELL_TYPE_SHIFT;
CellBlock = (CellIndex & HCELL_BLOCK_MASK) >> HCELL_BLOCK_SHIFT;
/* FIXME: Merge free blocks */
Bin = (PHBIN)RegistryHive->Storage[CellType].BlockList[CellBlock].BinAddress;
if ((CellIndex & ~HCELL_TYPE_MASK) + Free->Size <
Bin->FileOffset + Bin->Size)
{
Neighbor = (PHCELL)((ULONG_PTR)Free + Free->Size);
if (Neighbor->Size > 0)
{
HvpRemoveFree(RegistryHive, Neighbor,
((HCELL_INDEX)((ULONG_PTR)Neighbor - (ULONG_PTR)Bin +
Bin->FileOffset)) | (CellIndex & HCELL_TYPE_MASK));
Free->Size += Neighbor->Size;
}
}
Neighbor = (PHCELL)(Bin + 1);
while (Neighbor < Free)
{
if (Neighbor->Size > 0)
{
if ((ULONG_PTR)Neighbor + Neighbor->Size == (ULONG_PTR)Free)
{
HCELL_INDEX NeighborCellIndex =
(HCELL_INDEX)((ULONG_PTR)Neighbor - (ULONG_PTR)Bin +
Bin->FileOffset) | (CellIndex & HCELL_TYPE_MASK);
if (HvpComputeFreeListIndex(Neighbor->Size) !=
HvpComputeFreeListIndex(Neighbor->Size + Free->Size))
{
HvpRemoveFree(RegistryHive, Neighbor, NeighborCellIndex);
Neighbor->Size += Free->Size;
HvpAddFree(RegistryHive, Neighbor, NeighborCellIndex);
}
else
Neighbor->Size += Free->Size;
if (CellType == Stable)
HvMarkCellDirty(RegistryHive, NeighborCellIndex, FALSE);
return;
}
Neighbor = (PHCELL)((ULONG_PTR)Neighbor + Neighbor->Size);
}
else
{
Neighbor = (PHCELL)((ULONG_PTR)Neighbor - Neighbor->Size);
}
}
/* Add block to the list of free blocks */
HvpAddFree(RegistryHive, Free, CellIndex);
if (CellType == Stable)
HvMarkCellDirty(RegistryHive, CellIndex, FALSE);
}
BOOLEAN
CMAPI
HvTrackCellRef(PHV_TRACK_CELL_REF CellRef,
PHHIVE Hive,
HCELL_INDEX Cell)
{
/* Sanity checks */
ASSERT(CellRef);
ASSERT(Hive );
ASSERT(Cell != HCELL_NIL);
/* Less than 4? */
if (CellRef->StaticCount < STATIC_CELL_PAIR_COUNT)
{
/* Add reference */
CellRef->StaticArray[CellRef->StaticCount].Hive = Hive;
CellRef->StaticArray[CellRef->StaticCount].Cell = Cell;
CellRef->StaticCount++;
return TRUE;
}
/* FIXME: TODO */
DPRINT1("ERROR: Too many references\n");
while (TRUE);
return FALSE;
}
VOID
CMAPI
HvReleaseFreeCellRefArray(PHV_TRACK_CELL_REF CellRef)
{
ULONG i;
ASSERT(CellRef);
/* Any references? */
if (CellRef->StaticCount > 0)
{
/* Sanity check */
ASSERT(CellRef->StaticCount <= STATIC_CELL_PAIR_COUNT);
/* Loop them */
for (i = 0; i < CellRef->StaticCount;i++)
{
/* Release them */
HvReleaseCell(CellRef->StaticArray[i].Hive,
CellRef->StaticArray[i].Cell);
}
/* Free again */
CellRef->StaticCount = 0;
}
}

306
lib/cmlib/hivedata.h Normal file
View file

@ -0,0 +1,306 @@
/*
* 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
*/
#pragma once
//
// Hive operations
//
#define HINIT_CREATE 0
#define HINIT_MEMORY 1
#define HINIT_FILE 2
#define HINIT_MEMORY_INPLACE 3
#define HINIT_FLAT 4
#define HINIT_MAPFILE 5
//
// Hive flags
//
#define HIVE_VOLATILE 1
#define HIVE_NOLAZYFLUSH 2
#define HIVE_HAS_BEEN_REPLACED 4
#define HIVE_HAS_BEEN_FREED 8
#define HIVE_UNKNOWN 0x10
#define HIVE_IS_UNLOADING 0x20
//
// Hive types
//
#define HFILE_TYPE_PRIMARY 0
#define HFILE_TYPE_ALTERNATE 1
#define HFILE_TYPE_LOG 2
#define HFILE_TYPE_EXTERNAL 3
#define HFILE_TYPE_MAX 4
//
// Hive sizes
//
#define HBLOCK_SIZE 0x1000
#define HSECTOR_SIZE 0x200
#define HSECTOR_COUNT 8
#define HV_BLOCK_SIZE 4096
#define HV_LOG_HEADER_SIZE FIELD_OFFSET(HBASE_BLOCK, Reserved2)
#define HV_SIGNATURE 0x66676572
#define HV_BIN_SIGNATURE 0x6e696268
//
// Hive versions
//
#define HSYS_MAJOR 1
#define HSYS_MINOR 3
#define HSYS_WHISTLER_BETA1 4
#define HSYS_WHISTLER 5
#define HSYS_MINOR_SUPPORTED HSYS_WHISTLER
//
// Hive formats
//
#define HBASE_FORMAT_MEMORY 1
//
// Hive storage
//
#define HTYPE_COUNT 2
/**
* @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;
//
// Cell Magic Values
//
#define HCELL_NIL MAXULONG
#define HCELL_CACHED 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
#define HvGetCellType(Cell) \
((ULONG)((Cell & HCELL_TYPE_MASK) >> HCELL_TYPE_SHIFT))
#define HvGetCellBlock(Cell) \
((ULONG)((Cell & HCELL_BLOCK_MASK) >> HCELL_BLOCK_SHIFT))
typedef enum
{
Stable = 0,
Volatile = 1
} HSTORAGE_TYPE;
#ifdef CMLIB_HOST
#include <host/pshpack1.h>
#else
#include <pshpack1.h>
#endif
/**
* @name HBASE_BLOCK
*
* On-disk header for registry hive file.
*/
typedef struct _HBASE_BLOCK
{
/* 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 CM_KEY_NODE */
HCELL_INDEX RootCell;
/* Size of each hive block ? */
ULONG Length;
/* (1?) */
ULONG Cluster;
/* Name of hive file */
CHAR FileName[64];
ULONG Reserved1[99];
/* Checksum of first 0x200 bytes */
ULONG CheckSum;
ULONG Reserved2[0x37E];
ULONG BootType;
ULONG BootRecover;
} HBASE_BLOCK, *PHBASE_BLOCK;
typedef struct _HBIN
{
/* Bin identifier "hbin" (0x6E696268) */
ULONG Signature;
/* Block offset of this bin */
HCELL_INDEX FileOffset;
/* Size in bytes, multiple of the block size (4KB) */
ULONG Size;
ULONG Reserved1[2];
/* When this bin was last modified */
LARGE_INTEGER TimeStamp;
/* ? (In-memory only) */
ULONG Spare;
} HBIN, *PHBIN;
typedef struct _HCELL
{
/* <0 if used, >0 if free */
LONG Size;
} HCELL, *PHCELL;
#ifdef CMLIB_HOST
#include <host/poppack.h>
#else
#include <poppack.h>
#endif
struct _HHIVE;
typedef struct _CELL_DATA* (CMAPI *PGET_CELL_ROUTINE)(
struct _HHIVE *Hive,
HCELL_INDEX Cell);
typedef VOID (CMAPI *PRELEASE_CELL_ROUTINE)(
struct _HHIVE *Hive,
HCELL_INDEX Cell);
typedef PVOID (CMAPI *PALLOCATE_ROUTINE)(
SIZE_T Size,
BOOLEAN Paged,
ULONG Tag);
typedef VOID (CMAPI *PFREE_ROUTINE)(
PVOID Ptr,
ULONG Quota);
typedef BOOLEAN (CMAPI *PFILE_READ_ROUTINE)(
struct _HHIVE *RegistryHive,
ULONG FileType,
PULONG FileOffset,
PVOID Buffer,
SIZE_T BufferLength);
typedef BOOLEAN (CMAPI *PFILE_WRITE_ROUTINE)(
struct _HHIVE *RegistryHive,
ULONG FileType,
PULONG FileOffset,
PVOID Buffer,
SIZE_T BufferLength);
typedef BOOLEAN (CMAPI *PFILE_SET_SIZE_ROUTINE)(
struct _HHIVE *RegistryHive,
ULONG FileType,
ULONG FileSize,
ULONG OldfileSize);
typedef BOOLEAN (CMAPI *PFILE_FLUSH_ROUTINE)(
struct _HHIVE *RegistryHive,
ULONG FileType,
PLARGE_INTEGER FileOffset,
ULONG Length
);
typedef struct _HMAP_ENTRY
{
ULONG_PTR BlockAddress;
ULONG_PTR BinAddress;
struct _CM_VIEW_OF_FILE *CmView;
ULONG MemAlloc;
} HMAP_ENTRY, *PHMAP_ENTRY;
typedef struct _HMAP_TABLE
{
HMAP_ENTRY Table[512];
} HMAP_TABLE, *PHMAP_TABLE;
typedef struct _HMAP_DIRECTORY
{
PHMAP_TABLE Directory[2048];
} HMAP_DIRECTORY, *PHMAP_DIRECTORY;
typedef struct _DUAL
{
ULONG Length;
PHMAP_DIRECTORY Map;
PHMAP_ENTRY BlockList; // PHMAP_TABLE SmallDir;
ULONG Guard;
HCELL_INDEX FreeDisplay[24]; //FREE_DISPLAY FreeDisplay[24];
ULONG FreeSummary;
LIST_ENTRY FreeBins;
} DUAL, *PDUAL;
typedef struct _HHIVE
{
ULONG Signature;
PGET_CELL_ROUTINE GetCellRoutine;
PRELEASE_CELL_ROUTINE ReleaseCellRoutine;
PALLOCATE_ROUTINE Allocate;
PFREE_ROUTINE Free;
PFILE_READ_ROUTINE FileRead;
PFILE_WRITE_ROUTINE FileWrite;
PFILE_SET_SIZE_ROUTINE FileSetSize;
PFILE_FLUSH_ROUTINE FileFlush;
PHBASE_BLOCK BaseBlock;
RTL_BITMAP DirtyVector;
ULONG DirtyCount;
ULONG DirtyAlloc;
ULONG BaseBlockAlloc;
ULONG Cluster;
BOOLEAN Flat;
BOOLEAN ReadOnly;
BOOLEAN Log;
BOOLEAN DirtyFlag;
ULONG HvBinHeadersUse;
ULONG HvFreeCellsUse;
ULONG HvUsedcellsUse;
ULONG CmUsedCellsUse;
ULONG HiveFlags;
ULONG LogSize;
ULONG RefreshCount;
ULONG StorageTypeCount;
ULONG Version;
DUAL Storage[HTYPE_COUNT];
} HHIVE, *PHHIVE;
#define IsFreeCell(Cell)(Cell->Size >= 0)
#define IsUsedCell(Cell)(Cell->Size < 0)

535
lib/cmlib/hiveinit.c Normal file
View file

@ -0,0 +1,535 @@
/*
* 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(
PHBASE_BLOCK BaseBlock)
{
if (BaseBlock->Signature != HV_SIGNATURE ||
BaseBlock->Major != HSYS_MAJOR ||
BaseBlock->Minor < HSYS_MINOR ||
BaseBlock->Type != HFILE_TYPE_PRIMARY ||
BaseBlock->Format != HBASE_FORMAT_MEMORY ||
BaseBlock->Cluster != 1 ||
BaseBlock->Sequence1 != BaseBlock->Sequence2 ||
HvpHiveHeaderChecksum(BaseBlock) != BaseBlock->CheckSum)
{
DPRINT1("Verify Hive Header failed: \n");
DPRINT1(" Signature: 0x%x and not 0x%x, Major: 0x%x and not 0x%x\n",
BaseBlock->Signature, HV_SIGNATURE, BaseBlock->Major, HSYS_MAJOR);
DPRINT1(" Minor: 0x%x is not >= 0x%x, Type: 0x%x and not 0x%x\n",
BaseBlock->Minor, HSYS_MINOR, BaseBlock->Type, HFILE_TYPE_PRIMARY);
DPRINT1(" Format: 0x%x and not 0x%x, Cluster: 0x%x and not 1\n",
BaseBlock->Format, HBASE_FORMAT_MEMORY, BaseBlock->Cluster);
DPRINT1(" Sequence: 0x%x and not 0x%x, Checksum: 0x%x and not 0x%x\n",
BaseBlock->Sequence1, BaseBlock->Sequence2,
HvpHiveHeaderChecksum(BaseBlock), BaseBlock->CheckSum);
return FALSE;
}
return TRUE;
}
/**
* @name HvpFreeHiveBins
*
* Internal function to free all bin storage associated with hive
* descriptor.
*/
VOID CMAPI
HvpFreeHiveBins(
PHHIVE Hive)
{
ULONG i;
PHBIN Bin;
ULONG Storage;
for (Storage = Stable; Storage < HTYPE_COUNT; Storage++)
{
Bin = NULL;
for (i = 0; i < Hive->Storage[Storage].Length; i++)
{
if (Hive->Storage[Storage].BlockList[i].BinAddress == (ULONG_PTR)NULL)
continue;
if (Hive->Storage[Storage].BlockList[i].BinAddress != (ULONG_PTR)Bin)
{
Bin = (PHBIN)Hive->Storage[Storage].BlockList[i].BinAddress;
Hive->Free((PHBIN)Hive->Storage[Storage].BlockList[i].BinAddress, 0);
}
Hive->Storage[Storage].BlockList[i].BinAddress = (ULONG_PTR)NULL;
Hive->Storage[Storage].BlockList[i].BlockAddress = (ULONG_PTR)NULL;
}
if (Hive->Storage[Storage].Length)
Hive->Free(Hive->Storage[Storage].BlockList, 0);
}
}
/**
* @name HvpCreateHive
*
* Internal helper function to initalize hive descriptor structure for
* newly created hive.
*
* @see HvInitialize
*/
NTSTATUS CMAPI
HvpCreateHive(
PHHIVE RegistryHive)
{
PHBASE_BLOCK BaseBlock;
ULONG Index;
BaseBlock = RegistryHive->Allocate(sizeof(HBASE_BLOCK), FALSE, TAG_CM);
if (BaseBlock == NULL)
return STATUS_NO_MEMORY;
RtlZeroMemory(BaseBlock, sizeof(HBASE_BLOCK));
BaseBlock->Signature = HV_SIGNATURE;
BaseBlock->Major = HSYS_MAJOR;
BaseBlock->Minor = HSYS_MINOR;
BaseBlock->Type = HFILE_TYPE_PRIMARY;
BaseBlock->Format = HBASE_FORMAT_MEMORY;
BaseBlock->Cluster = 1;
BaseBlock->RootCell = HCELL_NIL;
BaseBlock->Length = HV_BLOCK_SIZE;
BaseBlock->Sequence1 = 1;
BaseBlock->Sequence2 = 1;
/* FIXME: Fill in the file name */
BaseBlock->CheckSum = HvpHiveHeaderChecksum(BaseBlock);
RegistryHive->BaseBlock = BaseBlock;
for (Index = 0; Index < 24; Index++)
{
RegistryHive->Storage[Stable].FreeDisplay[Index] = HCELL_NIL;
RegistryHive->Storage[Volatile].FreeDisplay[Index] = HCELL_NIL;
}
RtlInitializeBitMap(&RegistryHive->DirtyVector, 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(
PHHIVE Hive,
PVOID ChunkBase)
{
SIZE_T BlockIndex;
PHBIN Bin, NewBin;
ULONG i;
ULONG BitmapSize;
PULONG BitmapBuffer;
SIZE_T ChunkSize;
//
// This hack is similar in magnitude to the US's National Debt
//
ChunkSize = ((PHBASE_BLOCK)ChunkBase)->Length;
((PHBASE_BLOCK)ChunkBase)->Length = HV_BLOCK_SIZE;
DPRINT("ChunkSize: %lx\n", ChunkSize);
if (ChunkSize < sizeof(HBASE_BLOCK) ||
!HvpVerifyHiveHeader((PHBASE_BLOCK)ChunkBase))
{
DPRINT1("Registry is corrupt: ChunkSize %lu < sizeof(HBASE_BLOCK) %lu, "
"or HvpVerifyHiveHeader() failed\n", ChunkSize, (SIZE_T)sizeof(HBASE_BLOCK));
return STATUS_REGISTRY_CORRUPT;
}
Hive->BaseBlock = Hive->Allocate(sizeof(HBASE_BLOCK), FALSE, TAG_CM);
if (Hive->BaseBlock == NULL)
{
return STATUS_NO_MEMORY;
}
RtlCopyMemory(Hive->BaseBlock, ChunkBase, sizeof(HBASE_BLOCK));
/*
* Build a block list from the in-memory chunk and copy the data as
* we go.
*/
Hive->Storage[Stable].Length = (ULONG)(ChunkSize / HV_BLOCK_SIZE) - 1;
Hive->Storage[Stable].BlockList =
Hive->Allocate(Hive->Storage[Stable].Length *
sizeof(HMAP_ENTRY), FALSE, TAG_CM);
if (Hive->Storage[Stable].BlockList == NULL)
{
DPRINT1("Allocating block list failed\n");
Hive->Free(Hive->BaseBlock, 0);
return STATUS_NO_MEMORY;
}
for (BlockIndex = 0; BlockIndex < Hive->Storage[Stable].Length; )
{
Bin = (PHBIN)((ULONG_PTR)ChunkBase + (BlockIndex + 1) * HV_BLOCK_SIZE);
if (Bin->Signature != HV_BIN_SIGNATURE ||
(Bin->Size % HV_BLOCK_SIZE) != 0)
{
Hive->Free(Hive->BaseBlock, 0);
Hive->Free(Hive->Storage[Stable].BlockList, 0);
return STATUS_REGISTRY_CORRUPT;
}
NewBin = Hive->Allocate(Bin->Size, TRUE, TAG_CM);
if (NewBin == NULL)
{
Hive->Free(Hive->BaseBlock, 0);
Hive->Free(Hive->Storage[Stable].BlockList, 0);
return STATUS_NO_MEMORY;
}
Hive->Storage[Stable].BlockList[BlockIndex].BinAddress = (ULONG_PTR)NewBin;
Hive->Storage[Stable].BlockList[BlockIndex].BlockAddress = (ULONG_PTR)NewBin;
RtlCopyMemory(NewBin, Bin, Bin->Size);
if (Bin->Size > HV_BLOCK_SIZE)
{
for (i = 1; i < Bin->Size / HV_BLOCK_SIZE; i++)
{
Hive->Storage[Stable].BlockList[BlockIndex + i].BinAddress = (ULONG_PTR)NewBin;
Hive->Storage[Stable].BlockList[BlockIndex + i].BlockAddress =
((ULONG_PTR)NewBin + (i * HV_BLOCK_SIZE));
}
}
BlockIndex += Bin->Size / HV_BLOCK_SIZE;
}
if (HvpCreateHiveFreeCellList(Hive))
{
HvpFreeHiveBins(Hive);
Hive->Free(Hive->BaseBlock, 0);
return STATUS_NO_MEMORY;
}
BitmapSize = ROUND_UP(Hive->Storage[Stable].Length,
sizeof(ULONG) * 8) / 8;
BitmapBuffer = (PULONG)Hive->Allocate(BitmapSize, TRUE, TAG_CM);
if (BitmapBuffer == NULL)
{
HvpFreeHiveBins(Hive);
Hive->Free(Hive->BaseBlock, 0);
return STATUS_NO_MEMORY;
}
RtlInitializeBitMap(&Hive->DirtyVector, BitmapBuffer, BitmapSize * 8);
RtlClearAllBits(&Hive->DirtyVector);
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(
PHHIVE Hive,
PVOID ChunkBase)
{
if (!HvpVerifyHiveHeader((PHBASE_BLOCK)ChunkBase))
{
return STATUS_REGISTRY_CORRUPT;
}
Hive->BaseBlock = (PHBASE_BLOCK)ChunkBase;
Hive->ReadOnly = TRUE;
Hive->Flat = TRUE;
return STATUS_SUCCESS;
}
typedef enum _RESULT
{
NotHive,
Fail,
NoMemory,
HiveSuccess,
RecoverHeader,
RecoverData,
SelfHeal
} RESULT;
RESULT CMAPI
HvpGetHiveHeader(IN PHHIVE Hive,
IN PHBASE_BLOCK *HiveBaseBlock,
IN PLARGE_INTEGER TimeStamp)
{
PHBASE_BLOCK BaseBlock;
ULONG Alignment;
ULONG Result;
ULONG Offset = 0;
ASSERT(sizeof(HBASE_BLOCK) >= (HV_BLOCK_SIZE * Hive->Cluster));
/* Assume failure and allocate the buffer */
*HiveBaseBlock = 0;
BaseBlock = Hive->Allocate(sizeof(HBASE_BLOCK), TRUE, TAG_CM);
if (!BaseBlock) return NoMemory;
/* Check for, and enforce, alignment */
Alignment = Hive->Cluster * HV_BLOCK_SIZE -1;
if ((ULONG_PTR)BaseBlock & Alignment)
{
/* Free the old header */
Hive->Free(BaseBlock, 0);
BaseBlock = Hive->Allocate(PAGE_SIZE, TRUE, TAG_CM);
if (!BaseBlock) return NoMemory;
//BaseBlock->Length = PAGE_SIZE; ??
}
/* Clear it */
RtlZeroMemory(BaseBlock, sizeof(HBASE_BLOCK));
/* Now read it from disk */
Result = Hive->FileRead(Hive,
HFILE_TYPE_PRIMARY,
&Offset,
BaseBlock,
Hive->Cluster * HV_BLOCK_SIZE);
/* Couldn't read: assume it's not a hive */
if (!Result) return NotHive;
/* Do validation */
if (!HvpVerifyHiveHeader(BaseBlock)) return NotHive;
/* Return information */
*HiveBaseBlock = BaseBlock;
*TimeStamp = BaseBlock->TimeStamp;
return HiveSuccess;
}
NTSTATUS CMAPI
HvLoadHive(IN PHHIVE Hive,
IN ULONG FileSize)
{
PHBASE_BLOCK BaseBlock = NULL;
ULONG Result;
LARGE_INTEGER TimeStamp;
ULONG Offset = 0;
PVOID HiveData;
/* Get the hive header */
Result = HvpGetHiveHeader(Hive, &BaseBlock, &TimeStamp);
switch (Result)
{
/* Out of memory */
case NoMemory:
/* Fail */
return STATUS_INSUFFICIENT_RESOURCES;
/* Not a hive */
case NotHive:
/* Fail */
return STATUS_NOT_REGISTRY_FILE;
/* Has recovery data */
case RecoverData:
case RecoverHeader:
/* Fail */
return STATUS_REGISTRY_CORRUPT;
}
/* Set default boot type */
BaseBlock->BootType = 0;
/* Setup hive data */
Hive->BaseBlock = BaseBlock;
Hive->Version = Hive->BaseBlock->Minor;
/* Allocate a buffer large enough to hold the hive */
HiveData = Hive->Allocate(FileSize, TRUE, TAG_CM);
if (!HiveData) return STATUS_INSUFFICIENT_RESOURCES;
/* Now read the whole hive */
Result = Hive->FileRead(Hive,
HFILE_TYPE_PRIMARY,
&Offset,
HiveData,
FileSize);
if (!Result) return STATUS_NOT_REGISTRY_FILE;
/* Apply "US National Debt" hack */
((PHBASE_BLOCK)HiveData)->Length = FileSize;
/* Free our base block... it's usless in this implementation */
Hive->Free(BaseBlock, 0);
/* Initialize the hive directly from memory */
return HvpInitializeMemoryHive(Hive, HiveData);
}
/**
* @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(
PHHIVE RegistryHive,
ULONG Operation,
ULONG HiveType,
ULONG HiveFlags,
PVOID HiveData OPTIONAL,
PALLOCATE_ROUTINE Allocate,
PFREE_ROUTINE Free,
PFILE_SET_SIZE_ROUTINE FileSetSize,
PFILE_WRITE_ROUTINE FileWrite,
PFILE_READ_ROUTINE FileRead,
PFILE_FLUSH_ROUTINE FileFlush,
ULONG Cluster OPTIONAL,
PUNICODE_STRING FileName)
{
NTSTATUS Status;
PHHIVE Hive = RegistryHive;
UNREFERENCED_PARAMETER(HiveType);
UNREFERENCED_PARAMETER(FileName);
/*
* Create a new hive structure that will hold all the maintenance data.
*/
RtlZeroMemory(Hive, sizeof(HHIVE));
Hive->Allocate = Allocate;
Hive->Free = Free;
Hive->FileRead = FileRead;
Hive->FileWrite = FileWrite;
Hive->FileSetSize = FileSetSize;
Hive->FileFlush = FileFlush;
Hive->StorageTypeCount = HTYPE_COUNT;
Hive->Cluster = 1;
Hive->Version = HSYS_MINOR;
Hive->HiveFlags = HiveFlags &~ HIVE_NOLAZYFLUSH;
switch (Operation)
{
case HINIT_CREATE:
Status = HvpCreateHive(Hive);
break;
case HINIT_MEMORY:
Status = HvpInitializeMemoryHive(Hive, HiveData);
break;
case HINIT_FLAT:
Status = HvpInitializeMemoryInplaceHive(Hive, HiveData);
break;
case HINIT_FILE:
/* Hack of doom: Cluster is actually the file size. */
Status = HvLoadHive(Hive, Cluster);
if ((Status != STATUS_SUCCESS) &&
(Status != STATUS_REGISTRY_RECOVERED))
{
/* Unrecoverable failure */
return Status;
}
/* Check for previous damage */
if (Status == STATUS_REGISTRY_RECOVERED) ASSERT(FALSE);
break;
default:
/* FIXME: A better return status value is needed */
Status = STATUS_NOT_IMPLEMENTED;
ASSERT(FALSE);
}
if (!NT_SUCCESS(Status))
return Status;
if (Operation != HINIT_CREATE) CmPrepareHive(Hive);
return Status;
}
/**
* @name HvFree
*
* Free all stroage and handles associated with hive descriptor.
*/
VOID CMAPI
HvFree(
PHHIVE RegistryHive)
{
if (!RegistryHive->ReadOnly)
{
/* Release hive bitmap */
if (RegistryHive->DirtyVector.Buffer)
{
RegistryHive->Free(RegistryHive->DirtyVector.Buffer, 0);
}
HvpFreeHiveBins(RegistryHive);
}
RegistryHive->Free(RegistryHive, 0);
}
/* EOF */

32
lib/cmlib/hivesum.c Normal file
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(
PHBASE_BLOCK 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;
}

292
lib/cmlib/hivewrt.c Normal file
View file

@ -0,0 +1,292 @@
/*
* 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(
PHHIVE RegistryHive)
{
ULONG FileOffset;
SIZE_T BufferSize;
SIZE_T BitmapSize;
PUCHAR Buffer;
PUCHAR Ptr;
ULONG BlockIndex;
ULONG LastIndex;
PVOID BlockPtr;
BOOLEAN Success;
UNIMPLEMENTED;
return TRUE;
ASSERT(RegistryHive->ReadOnly == FALSE);
DPRINT("HvpWriteLog called\n");
if (RegistryHive->BaseBlock->Sequence1 !=
RegistryHive->BaseBlock->Sequence2)
{
return FALSE;
}
BitmapSize = RegistryHive->DirtyVector.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, TAG_CM);
if (Buffer == NULL)
{
return FALSE;
}
/* Update first update counter and CheckSum */
RegistryHive->BaseBlock->Type = HFILE_TYPE_LOG;
RegistryHive->BaseBlock->Sequence1++;
RegistryHive->BaseBlock->CheckSum =
HvpHiveHeaderChecksum(RegistryHive->BaseBlock);
/* Copy hive header */
RtlCopyMemory(Buffer, RegistryHive->BaseBlock, HV_LOG_HEADER_SIZE);
Ptr = Buffer + HV_LOG_HEADER_SIZE;
RtlCopyMemory(Ptr, "DIRT", 4);
Ptr += 4;
RtlCopyMemory(Ptr, RegistryHive->DirtyVector.Buffer, BitmapSize);
/* Write hive block and block bitmap */
FileOffset = 0;
Success = RegistryHive->FileWrite(RegistryHive, HFILE_TYPE_LOG,
&FileOffset, Buffer, BufferSize);
RegistryHive->Free(Buffer, 0);
if (!Success)
{
return FALSE;
}
/* Write dirty blocks */
FileOffset = BufferSize;
BlockIndex = 0;
while (BlockIndex < RegistryHive->Storage[Stable].Length)
{
LastIndex = BlockIndex;
BlockIndex = RtlFindSetBits(&RegistryHive->DirtyVector, 1, BlockIndex);
if (BlockIndex == ~0U || BlockIndex < LastIndex)
{
break;
}
BlockPtr = (PVOID)RegistryHive->Storage[Stable].BlockList[BlockIndex].BlockAddress;
/* Write hive block */
Success = RegistryHive->FileWrite(RegistryHive, HFILE_TYPE_LOG,
&FileOffset, BlockPtr,
HV_BLOCK_SIZE);
if (!Success)
{
return FALSE;
}
BlockIndex++;
FileOffset += HV_BLOCK_SIZE;
}
Success = RegistryHive->FileSetSize(RegistryHive, HFILE_TYPE_LOG, FileOffset, FileOffset);
if (!Success)
{
DPRINT("FileSetSize failed\n");
return FALSE;
}
/* Flush the log file */
Success = RegistryHive->FileFlush(RegistryHive, HFILE_TYPE_LOG, NULL, 0);
if (!Success)
{
DPRINT("FileFlush failed\n");
}
/* Update first and second update counter and CheckSum. */
RegistryHive->BaseBlock->Sequence2++;
RegistryHive->BaseBlock->CheckSum =
HvpHiveHeaderChecksum(RegistryHive->BaseBlock);
/* Write hive header again with updated sequence counter. */
FileOffset = 0;
Success = RegistryHive->FileWrite(RegistryHive, HFILE_TYPE_LOG,
&FileOffset, RegistryHive->BaseBlock,
HV_LOG_HEADER_SIZE);
if (!Success)
{
return FALSE;
}
/* Flush the log file */
Success = RegistryHive->FileFlush(RegistryHive, HFILE_TYPE_LOG, NULL, 0);
if (!Success)
{
DPRINT("FileFlush failed\n");
}
return TRUE;
}
static BOOLEAN CMAPI
HvpWriteHive(
PHHIVE RegistryHive,
BOOLEAN OnlyDirty)
{
ULONG FileOffset;
ULONG BlockIndex;
ULONG LastIndex;
PVOID BlockPtr;
BOOLEAN Success;
ASSERT(RegistryHive->ReadOnly == FALSE);
DPRINT("HvpWriteHive called\n");
if (RegistryHive->BaseBlock->Sequence1 !=
RegistryHive->BaseBlock->Sequence2)
{
return FALSE;
}
/* Update first update counter and CheckSum */
RegistryHive->BaseBlock->Type = HFILE_TYPE_PRIMARY;
RegistryHive->BaseBlock->Sequence1++;
RegistryHive->BaseBlock->CheckSum =
HvpHiveHeaderChecksum(RegistryHive->BaseBlock);
/* Write hive block */
FileOffset = 0;
Success = RegistryHive->FileWrite(RegistryHive, HFILE_TYPE_PRIMARY,
&FileOffset, RegistryHive->BaseBlock,
sizeof(HBASE_BLOCK));
if (!Success)
{
return FALSE;
}
BlockIndex = 0;
while (BlockIndex < RegistryHive->Storage[Stable].Length)
{
if (OnlyDirty)
{
LastIndex = BlockIndex;
BlockIndex = RtlFindSetBits(&RegistryHive->DirtyVector, 1, BlockIndex);
if (BlockIndex == ~0U || BlockIndex < LastIndex)
{
break;
}
}
BlockPtr = (PVOID)RegistryHive->Storage[Stable].BlockList[BlockIndex].BlockAddress;
FileOffset = (BlockIndex + 1) * HV_BLOCK_SIZE;
/* Write hive block */
Success = RegistryHive->FileWrite(RegistryHive, HFILE_TYPE_PRIMARY,
&FileOffset, BlockPtr,
HV_BLOCK_SIZE);
if (!Success)
{
return FALSE;
}
BlockIndex++;
}
Success = RegistryHive->FileFlush(RegistryHive, HFILE_TYPE_PRIMARY, NULL, 0);
if (!Success)
{
DPRINT("FileFlush failed\n");
}
/* Update second update counter and CheckSum */
RegistryHive->BaseBlock->Sequence2++;
RegistryHive->BaseBlock->CheckSum =
HvpHiveHeaderChecksum(RegistryHive->BaseBlock);
/* Write hive block */
FileOffset = 0;
Success = RegistryHive->FileWrite(RegistryHive, HFILE_TYPE_PRIMARY,
&FileOffset, RegistryHive->BaseBlock,
sizeof(HBASE_BLOCK));
if (!Success)
{
return FALSE;
}
Success = RegistryHive->FileFlush(RegistryHive, HFILE_TYPE_PRIMARY, NULL, 0);
if (!Success)
{
DPRINT("FileFlush failed\n");
}
return TRUE;
}
BOOLEAN CMAPI
HvSyncHive(
PHHIVE RegistryHive)
{
ASSERT(RegistryHive->ReadOnly == FALSE);
if (RtlFindSetBits(&RegistryHive->DirtyVector, 1, 0) == ~0U)
{
return TRUE;
}
/* Update hive header modification time */
KeQuerySystemTime(&RegistryHive->BaseBlock->TimeStamp);
/* Update log file */
if (!HvpWriteLog(RegistryHive))
{
return FALSE;
}
/* Update hive file */
if (!HvpWriteHive(RegistryHive, TRUE))
{
return FALSE;
}
/* Clear dirty bitmap. */
RtlClearAllBits(&RegistryHive->DirtyVector);
return TRUE;
}
BOOLEAN
CMAPI
HvHiveWillShrink(IN PHHIVE RegistryHive)
{
/* No shrinking yet */
return FALSE;
}
BOOLEAN CMAPI
HvWriteHive(
PHHIVE RegistryHive)
{
ASSERT(RegistryHive->ReadOnly == FALSE);
/* Update hive header modification time */
KeQuerySystemTime(&RegistryHive->BaseBlock->TimeStamp);
/* Update hive file */
if (!HvpWriteHive(RegistryHive, FALSE))
{
return FALSE;
}
return TRUE;
}