#define NDEBUG
#include <debug.h>
-static PHCELL __inline CMAPI
+static __inline PHCELL CMAPI
HvpGetCellHeader(
PHHIVE RegistryHive,
HCELL_INDEX CellIndex)
{
PVOID Block;
- ASSERT(CellIndex != HCELL_NULL);
+ CMLTRACE(CMLIB_HCELL_DEBUG, "%s - Hive %p, CellIndex %08lx\n",
+ __FUNCTION__, RegistryHive, CellIndex);
+
+ ASSERT(CellIndex != HCELL_NIL);
if (!RegistryHive->Flat)
{
ULONG CellType;
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].Block;
+ Block = (PVOID)RegistryHive->Storage[CellType].BlockList[CellBlock].BlockAddress;
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 +
+ 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,
return (PVOID)(HvpGetCellHeader(RegistryHive, CellIndex) + 1);
}
-static LONG __inline CMAPI
+static __inline LONG CMAPI
HvpGetCellFullSize(
PHHIVE RegistryHive,
PVOID Cell)
{
+ UNREFERENCED_PARAMETER(RegistryHive);
return ((PHCELL)Cell - 1)->Size;
}
LONG CMAPI
-HvGetCellSize(
- PHHIVE RegistryHive,
- PVOID Cell)
+HvGetCellSize(IN PHHIVE Hive,
+ IN PVOID Address)
{
PHCELL CellHeader;
+ LONG Size;
- CellHeader = (PHCELL)Cell - 1;
- if (CellHeader->Size < 0)
- return CellHeader->Size + sizeof(HCELL);
- else
- return CellHeader->Size - sizeof(HCELL);
+ UNREFERENCED_PARAMETER(Hive);
+
+ CellHeader = (PHCELL)Address - 1;
+ Size = CellHeader->Size * -1;
+ Size -= sizeof(HCELL);
+ return Size;
}
-VOID CMAPI
+BOOLEAN CMAPI
HvMarkCellDirty(
PHHIVE RegistryHive,
- HCELL_INDEX CellIndex)
+ HCELL_INDEX CellIndex,
+ BOOLEAN HoldingLock)
{
- LONG CellSize;
ULONG CellBlock;
ULONG CellLastBlock;
ASSERT(RegistryHive->ReadOnly == FALSE);
- if ((CellIndex & HCELL_TYPE_MASK) >> HCELL_TYPE_SHIFT != HvStable)
- return;
+ 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 FALSE;
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->DirtyVector,
CellBlock, CellLastBlock - CellBlock);
+ return TRUE;
}
-static ULONG __inline CMAPI
+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)
{
HCELL_INDEX FreeIndex)
{
PHCELL_INDEX FreeBlockData;
- HV_STORAGE_TYPE Storage;
+ HSTORAGE_TYPE Storage;
ULONG Index;
ASSERT(RegistryHive != NULL);
{
PHCELL_INDEX FreeCellData;
PHCELL_INDEX pFreeCellOffset;
- HV_STORAGE_TYPE Storage;
- ULONG Index;
+ HSTORAGE_TYPE Storage;
+ ULONG Index, FreeListIndex;
ASSERT(RegistryHive->ReadOnly == FALSE);
Index = HvpComputeFreeListIndex((ULONG)CellBlock->Size);
pFreeCellOffset = &RegistryHive->Storage[Storage].FreeDisplay[Index];
- while (*pFreeCellOffset != HCELL_NULL)
+ while (*pFreeCellOffset != HCELL_NIL)
{
FreeCellData = (PHCELL_INDEX)HvGetCell(RegistryHive, *pFreeCellOffset);
if (*pFreeCellOffset == CellIndex)
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);
}
HvpFindFree(
PHHIVE RegistryHive,
ULONG Size,
- HV_STORAGE_TYPE Storage)
+ HSTORAGE_TYPE Storage)
{
PHCELL_INDEX FreeCellData;
HCELL_INDEX FreeCellOffset;
for (Index = HvpComputeFreeListIndex(Size); Index < 24; Index++)
{
pFreeCellOffset = &RegistryHive->Storage[Storage].FreeDisplay[Index];
- while (*pFreeCellOffset != HCELL_NULL)
+ while (*pFreeCellOffset != HCELL_NIL)
{
FreeCellData = (PHCELL_INDEX)HvGetCell(RegistryHive, *pFreeCellOffset);
if ((ULONG)HvpGetCellFullSize(RegistryHive, FreeCellData) >= Size)
}
}
- return HCELL_NULL;
+ return HCELL_NIL;
}
NTSTATUS CMAPI
/* Initialize the free cell list */
for (Index = 0; Index < 24; Index++)
{
- Hive->Storage[HvStable].FreeDisplay[Index] = HCELL_NULL;
- Hive->Storage[HvVolatile].FreeDisplay[Index] = HCELL_NULL;
+ Hive->Storage[Stable].FreeDisplay[Index] = HCELL_NIL;
+ Hive->Storage[Volatile].FreeDisplay[Index] = HCELL_NIL;
}
BlockOffset = 0;
BlockIndex = 0;
- while (BlockIndex < Hive->Storage[HvStable].Length)
+ while (BlockIndex < Hive->Storage[Stable].Length)
{
- Bin = (PHBIN)Hive->Storage[HvStable].BlockList[BlockIndex].Bin;
+ Bin = (PHBIN)Hive->Storage[Stable].BlockList[BlockIndex].BinAddress;
/* Search free blocks and add to list */
FreeOffset = sizeof(HBIN);
HCELL_INDEX CMAPI
HvAllocateCell(
PHHIVE RegistryHive,
- ULONG Size,
- HV_STORAGE_TYPE Storage)
+ SIZE_T Size,
+ HSTORAGE_TYPE Storage,
+ HCELL_INDEX Vicinity)
{
PHCELL FreeCell;
HCELL_INDEX FreeCellOffset;
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);
FreeCellOffset = HvpFindFree(RegistryHive, Size, Storage);
/* If no free cell was found we need to extend the hive file. */
- if (FreeCellOffset == HCELL_NULL)
+ if (FreeCellOffset == HCELL_NIL)
{
Bin = HvpAddBin(RegistryHive, Size, Storage);
if (Bin == NULL)
- return HCELL_NULL;
+ return HCELL_NIL;
FreeCellOffset = Bin->FileOffset + 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 ((ULONG)FreeCell->Size > Size + sizeof(HCELL_INDEX))
+
+ /* 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 == HvStable)
- HvMarkCellDirty(RegistryHive, FreeCellOffset + Size);
+ if (Storage == Stable)
+ HvMarkCellDirty(RegistryHive, FreeCellOffset + Size, FALSE);
}
- if (Storage == HvStable)
- HvMarkCellDirty(RegistryHive, FreeCellOffset);
+ 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;
}
PVOID NewCell;
LONG OldCellSize;
HCELL_INDEX NewCellIndex;
- HV_STORAGE_TYPE Storage;
+ HSTORAGE_TYPE Storage;
- ASSERT(CellIndex != HCELL_NULL);
+ 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);
-
+ 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)
+ if (Size > (ULONG)OldCellSize)
{
- NewCellIndex = HvAllocateCell(RegistryHive, Size, Storage);
- if (NewCellIndex == HCELL_NULL)
- return HCELL_NULL;
+ NewCellIndex = HvAllocateCell(RegistryHive, Size, Storage, HCELL_NIL);
+ if (NewCellIndex == HCELL_NIL)
+ return HCELL_NIL;
NewCell = HvGetCell(RegistryHive, NewCellIndex);
- RtlCopyMemory(NewCell, OldCell, (SIZE_T)-OldCellSize);
-
+ RtlCopyMemory(NewCell, OldCell, (SIZE_T)OldCellSize);
+
HvFreeCell(RegistryHive, CellIndex);
return NewCellIndex;
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);
-
+ 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].Bin;
+ Bin = (PHBIN)RegistryHive->Storage[CellType].BlockList[CellBlock].BinAddress;
if ((CellIndex & ~HCELL_TYPE_MASK) + Free->Size <
Bin->FileOffset + Bin->Size)
{
if ((ULONG_PTR)Neighbor + Neighbor->Size == (ULONG_PTR)Free)
{
- Neighbor->Size += Free->Size;
- if (CellType == HvStable)
- HvMarkCellDirty(RegistryHive,
- (HCELL_INDEX)((ULONG_PTR)Neighbor - (ULONG_PTR)Bin +
- Bin->FileOffset));
+ 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);
/* Add block to the list of free blocks */
HvpAddFree(RegistryHive, Free, CellIndex);
- if (CellType == HvStable)
- HvMarkCellDirty(RegistryHive, CellIndex);
+ if (CellType == Stable)
+ HvMarkCellDirty(RegistryHive, CellIndex, FALSE);
}