2 * PROJECT: registry manipulation library
3 * LICENSE: GPL - See COPYING in the top level directory
4 * COPYRIGHT: Copyright 2005 Filip Navara <navaraf@reactos.org>
5 * Copyright 2001 - 2005 Eric Kohl
12 static PHCELL __inline CMAPI
15 HCELL_INDEX CellIndex
)
19 CMLTRACE(CMLIB_HCELL_DEBUG
, "%s - Hive %p, CellIndex %08lx\n",
20 __FUNCTION__
, RegistryHive
, CellIndex
);
22 ASSERT(CellIndex
!= HCELL_NIL
);
23 if (!RegistryHive
->Flat
)
29 CellType
= (CellIndex
& HCELL_TYPE_MASK
) >> HCELL_TYPE_SHIFT
;
30 CellBlock
= (CellIndex
& HCELL_BLOCK_MASK
) >> HCELL_BLOCK_SHIFT
;
31 CellOffset
= (CellIndex
& HCELL_OFFSET_MASK
) >> HCELL_OFFSET_SHIFT
;
32 ASSERT(CellBlock
< RegistryHive
->Storage
[CellType
].Length
);
33 Block
= (PVOID
)RegistryHive
->Storage
[CellType
].BlockList
[CellBlock
].BlockAddress
;
34 ASSERT(Block
!= NULL
);
35 return (PVOID
)((ULONG_PTR
)Block
+ CellOffset
);
39 ASSERT((CellIndex
& HCELL_TYPE_MASK
) == Stable
);
40 return (PVOID
)((ULONG_PTR
)RegistryHive
->BaseBlock
+ HV_BLOCK_SIZE
+
46 HvIsCellAllocated(IN PHHIVE RegistryHive
,
47 IN HCELL_INDEX CellIndex
)
51 /* If it's a flat hive, the cell is always allocated */
52 if (RegistryHive
->Flat
)
55 /* Otherwise, get the type and make sure it's valid */
56 Type
= HvGetCellType(CellIndex
);
57 Block
= HvGetCellBlock(CellIndex
);
58 if (Block
>= RegistryHive
->Storage
[Type
].Length
)
61 /* Try to get the cell block */
62 if (RegistryHive
->Storage
[Type
].BlockList
[Block
].BlockAddress
)
65 /* No valid block, fail */
72 HCELL_INDEX CellIndex
)
74 return (PVOID
)(HvpGetCellHeader(RegistryHive
, CellIndex
) + 1);
77 static LONG __inline CMAPI
82 return ((PHCELL
)Cell
- 1)->Size
;
86 HvGetCellSize(IN PHHIVE Hive
,
92 CellHeader
= (PHCELL
)Address
- 1;
93 Size
= CellHeader
->Size
* -1;
94 Size
-= sizeof(HCELL
);
101 HCELL_INDEX CellIndex
,
107 ASSERT(RegistryHive
->ReadOnly
== FALSE
);
109 CMLTRACE(CMLIB_HCELL_DEBUG
, "%s - Hive %p, CellIndex %08lx, HoldingLock %b\n",
110 __FUNCTION__
, RegistryHive
, CellIndex
, HoldingLock
);
112 if ((CellIndex
& HCELL_TYPE_MASK
) >> HCELL_TYPE_SHIFT
!= Stable
)
115 CellBlock
= (CellIndex
& HCELL_BLOCK_MASK
) >> HCELL_BLOCK_SHIFT
;
116 CellLastBlock
= ((CellIndex
+ HV_BLOCK_SIZE
- 1) & HCELL_BLOCK_MASK
) >> HCELL_BLOCK_SHIFT
;
118 RtlSetBits(&RegistryHive
->DirtyVector
,
119 CellBlock
, CellLastBlock
- CellBlock
);
124 HvIsCellDirty(IN PHHIVE Hive
,
128 ASSERT(Hive
->ReadOnly
== FALSE
);
130 /* Volatile cells are always "dirty" */
131 if (HvGetCellType(Cell
) == Volatile
)
134 /* Check if the dirty bit is set */
135 return RtlCheckBit(&Hive
->DirtyVector
, Cell
/ HV_BLOCK_SIZE
);
138 static ULONG __inline CMAPI
139 HvpComputeFreeListIndex(
143 static CCHAR FindFirstSet
[256] = {
144 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
145 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
146 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
147 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
148 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
149 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
150 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
151 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
152 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
153 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
154 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
155 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
156 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
157 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
158 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
159 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7};
161 Index
= (Size
>> 3) - 1;
167 Index
= FindFirstSet
[Index
] + 7;
173 static NTSTATUS CMAPI
177 HCELL_INDEX FreeIndex
)
179 PHCELL_INDEX FreeBlockData
;
180 HSTORAGE_TYPE Storage
;
183 ASSERT(RegistryHive
!= NULL
);
184 ASSERT(FreeBlock
!= NULL
);
186 Storage
= (FreeIndex
& HCELL_TYPE_MASK
) >> HCELL_TYPE_SHIFT
;
187 Index
= HvpComputeFreeListIndex((ULONG
)FreeBlock
->Size
);
189 FreeBlockData
= (PHCELL_INDEX
)(FreeBlock
+ 1);
190 *FreeBlockData
= RegistryHive
->Storage
[Storage
].FreeDisplay
[Index
];
191 RegistryHive
->Storage
[Storage
].FreeDisplay
[Index
] = FreeIndex
;
193 /* FIXME: Eventually get rid of free bins. */
195 return STATUS_SUCCESS
;
202 HCELL_INDEX CellIndex
)
204 PHCELL_INDEX FreeCellData
;
205 PHCELL_INDEX pFreeCellOffset
;
206 HSTORAGE_TYPE Storage
;
207 ULONG Index
, FreeListIndex
;
209 ASSERT(RegistryHive
->ReadOnly
== FALSE
);
211 Storage
= (CellIndex
& HCELL_TYPE_MASK
) >> HCELL_TYPE_SHIFT
;
212 Index
= HvpComputeFreeListIndex((ULONG
)CellBlock
->Size
);
214 pFreeCellOffset
= &RegistryHive
->Storage
[Storage
].FreeDisplay
[Index
];
215 while (*pFreeCellOffset
!= HCELL_NIL
)
217 FreeCellData
= (PHCELL_INDEX
)HvGetCell(RegistryHive
, *pFreeCellOffset
);
218 if (*pFreeCellOffset
== CellIndex
)
220 *pFreeCellOffset
= *FreeCellData
;
223 pFreeCellOffset
= FreeCellData
;
226 /* Something bad happened, print a useful trace info and bugcheck */
227 CMLTRACE(CMLIB_HCELL_DEBUG
, "-- beginning of HvpRemoveFree trace --\n");
228 CMLTRACE(CMLIB_HCELL_DEBUG
, "block we are about to free: %08x\n", CellIndex
);
229 CMLTRACE(CMLIB_HCELL_DEBUG
, "chosen free list index: %d\n", Index
);
230 for (FreeListIndex
= 0; FreeListIndex
< 24; FreeListIndex
++)
232 CMLTRACE(CMLIB_HCELL_DEBUG
, "free list [%d]: ", FreeListIndex
);
233 pFreeCellOffset
= &RegistryHive
->Storage
[Storage
].FreeDisplay
[FreeListIndex
];
234 while (*pFreeCellOffset
!= HCELL_NIL
)
236 CMLTRACE(CMLIB_HCELL_DEBUG
, "%08x ", *pFreeCellOffset
);
237 FreeCellData
= (PHCELL_INDEX
)HvGetCell(RegistryHive
, *pFreeCellOffset
);
238 pFreeCellOffset
= FreeCellData
;
240 CMLTRACE(CMLIB_HCELL_DEBUG
, "\n");
242 CMLTRACE(CMLIB_HCELL_DEBUG
, "-- end of HvpRemoveFree trace --\n");
247 static HCELL_INDEX CMAPI
251 HSTORAGE_TYPE Storage
)
253 PHCELL_INDEX FreeCellData
;
254 HCELL_INDEX FreeCellOffset
;
255 PHCELL_INDEX pFreeCellOffset
;
258 for (Index
= HvpComputeFreeListIndex(Size
); Index
< 24; Index
++)
260 pFreeCellOffset
= &RegistryHive
->Storage
[Storage
].FreeDisplay
[Index
];
261 while (*pFreeCellOffset
!= HCELL_NIL
)
263 FreeCellData
= (PHCELL_INDEX
)HvGetCell(RegistryHive
, *pFreeCellOffset
);
264 if ((ULONG
)HvpGetCellFullSize(RegistryHive
, FreeCellData
) >= Size
)
266 FreeCellOffset
= *pFreeCellOffset
;
267 *pFreeCellOffset
= *FreeCellData
;
268 return FreeCellOffset
;
270 pFreeCellOffset
= FreeCellData
;
278 HvpCreateHiveFreeCellList(
281 HCELL_INDEX BlockOffset
;
289 /* Initialize the free cell list */
290 for (Index
= 0; Index
< 24; Index
++)
292 Hive
->Storage
[Stable
].FreeDisplay
[Index
] = HCELL_NIL
;
293 Hive
->Storage
[Volatile
].FreeDisplay
[Index
] = HCELL_NIL
;
298 while (BlockIndex
< Hive
->Storage
[Stable
].Length
)
300 Bin
= (PHBIN
)Hive
->Storage
[Stable
].BlockList
[BlockIndex
].BinAddress
;
302 /* Search free blocks and add to list */
303 FreeOffset
= sizeof(HBIN
);
304 while (FreeOffset
< Bin
->Size
)
306 FreeBlock
= (PHCELL
)((ULONG_PTR
)Bin
+ FreeOffset
);
307 if (FreeBlock
->Size
> 0)
309 Status
= HvpAddFree(Hive
, FreeBlock
, Bin
->FileOffset
+ FreeOffset
);
310 if (!NT_SUCCESS(Status
))
313 FreeOffset
+= FreeBlock
->Size
;
317 FreeOffset
-= FreeBlock
->Size
;
321 BlockIndex
+= Bin
->Size
/ HV_BLOCK_SIZE
;
322 BlockOffset
+= Bin
->Size
;
325 return STATUS_SUCCESS
;
332 HSTORAGE_TYPE Storage
,
333 HCELL_INDEX Vicinity
)
336 HCELL_INDEX FreeCellOffset
;
340 ASSERT(RegistryHive
->ReadOnly
== FALSE
);
342 CMLTRACE(CMLIB_HCELL_DEBUG
, "%s - Hive %p, Size %x, %s, Vicinity %08lx\n",
343 __FUNCTION__
, RegistryHive
, Size
, (Storage
== 0) ? "Stable" : "Volatile", Vicinity
);
345 /* Round to 16 bytes multiple. */
346 Size
= ROUND_UP(Size
+ sizeof(HCELL
), 16);
348 /* First search in free blocks. */
349 FreeCellOffset
= HvpFindFree(RegistryHive
, Size
, Storage
);
351 /* If no free cell was found we need to extend the hive file. */
352 if (FreeCellOffset
== HCELL_NIL
)
354 Bin
= HvpAddBin(RegistryHive
, Size
, Storage
);
357 FreeCellOffset
= Bin
->FileOffset
+ sizeof(HBIN
);
358 FreeCellOffset
|= Storage
<< HCELL_TYPE_SHIFT
;
361 FreeCell
= HvpGetCellHeader(RegistryHive
, FreeCellOffset
);
363 /* Split the block in two parts */
365 /* The free block that is created has to be at least
366 sizeof(HCELL) + sizeof(HCELL_INDEX) big, so that free
367 cell list code can work. Moreover we round cell sizes
368 to 16 bytes, so creating a smaller block would result in
369 a cell that would never be allocated. */
370 if ((ULONG
)FreeCell
->Size
> Size
+ 16)
372 NewCell
= (PHCELL
)((ULONG_PTR
)FreeCell
+ Size
);
373 NewCell
->Size
= FreeCell
->Size
- Size
;
374 FreeCell
->Size
= Size
;
375 HvpAddFree(RegistryHive
, NewCell
, FreeCellOffset
+ Size
);
376 if (Storage
== Stable
)
377 HvMarkCellDirty(RegistryHive
, FreeCellOffset
+ Size
, FALSE
);
380 if (Storage
== Stable
)
381 HvMarkCellDirty(RegistryHive
, FreeCellOffset
, FALSE
);
382 FreeCell
->Size
= -FreeCell
->Size
;
383 RtlZeroMemory(FreeCell
+ 1, Size
- sizeof(HCELL
));
385 CMLTRACE(CMLIB_HCELL_DEBUG
, "%s - CellIndex %08lx\n",
386 __FUNCTION__
, FreeCellOffset
);
388 return FreeCellOffset
;
394 HCELL_INDEX CellIndex
,
400 HCELL_INDEX NewCellIndex
;
401 HSTORAGE_TYPE Storage
;
403 ASSERT(CellIndex
!= HCELL_NIL
);
405 CMLTRACE(CMLIB_HCELL_DEBUG
, "%s - Hive %p, CellIndex %08lx, Size %x\n",
406 __FUNCTION__
, RegistryHive
, CellIndex
, Size
);
408 Storage
= (CellIndex
& HCELL_TYPE_MASK
) >> HCELL_TYPE_SHIFT
;
410 OldCell
= HvGetCell(RegistryHive
, CellIndex
);
411 OldCellSize
= HvGetCellSize(RegistryHive
, OldCell
);
412 ASSERT(OldCellSize
> 0);
415 * If new data size is larger than the current, destroy current
416 * data block and allocate a new one.
418 * FIXME: Merge with adjacent free cell if possible.
419 * FIXME: Implement shrinking.
421 if (Size
> OldCellSize
)
423 NewCellIndex
= HvAllocateCell(RegistryHive
, Size
, Storage
, HCELL_NIL
);
424 if (NewCellIndex
== HCELL_NIL
)
427 NewCell
= HvGetCell(RegistryHive
, NewCellIndex
);
428 RtlCopyMemory(NewCell
, OldCell
, (SIZE_T
)OldCellSize
);
430 HvFreeCell(RegistryHive
, CellIndex
);
441 HCELL_INDEX CellIndex
)
449 ASSERT(RegistryHive
->ReadOnly
== FALSE
);
451 CMLTRACE(CMLIB_HCELL_DEBUG
, "%s - Hive %p, CellIndex %08lx\n",
452 __FUNCTION__
, RegistryHive
, CellIndex
);
454 Free
= HvpGetCellHeader(RegistryHive
, CellIndex
);
456 ASSERT(Free
->Size
< 0);
458 Free
->Size
= -Free
->Size
;
460 CellType
= (CellIndex
& HCELL_TYPE_MASK
) >> HCELL_TYPE_SHIFT
;
461 CellBlock
= (CellIndex
& HCELL_BLOCK_MASK
) >> HCELL_BLOCK_SHIFT
;
463 /* FIXME: Merge free blocks */
464 Bin
= (PHBIN
)RegistryHive
->Storage
[CellType
].BlockList
[CellBlock
].BinAddress
;
466 if ((CellIndex
& ~HCELL_TYPE_MASK
) + Free
->Size
<
467 Bin
->FileOffset
+ Bin
->Size
)
469 Neighbor
= (PHCELL
)((ULONG_PTR
)Free
+ Free
->Size
);
470 if (Neighbor
->Size
> 0)
472 HvpRemoveFree(RegistryHive
, Neighbor
,
473 ((HCELL_INDEX
)((ULONG_PTR
)Neighbor
- (ULONG_PTR
)Bin
+
474 Bin
->FileOffset
)) | (CellIndex
& HCELL_TYPE_MASK
));
475 Free
->Size
+= Neighbor
->Size
;
479 Neighbor
= (PHCELL
)(Bin
+ 1);
480 while (Neighbor
< Free
)
482 if (Neighbor
->Size
> 0)
484 if ((ULONG_PTR
)Neighbor
+ Neighbor
->Size
== (ULONG_PTR
)Free
)
486 HCELL_INDEX NeighborCellIndex
=
487 (HCELL_INDEX
)((ULONG_PTR
)Neighbor
- (ULONG_PTR
)Bin
+
488 Bin
->FileOffset
) | (CellIndex
& HCELL_TYPE_MASK
);
490 if (HvpComputeFreeListIndex(Neighbor
->Size
) !=
491 HvpComputeFreeListIndex(Neighbor
->Size
+ Free
->Size
))
493 HvpRemoveFree(RegistryHive
, Neighbor
, NeighborCellIndex
);
494 Neighbor
->Size
+= Free
->Size
;
495 HvpAddFree(RegistryHive
, Neighbor
, NeighborCellIndex
);
498 Neighbor
->Size
+= Free
->Size
;
500 if (CellType
== Stable
)
501 HvMarkCellDirty(RegistryHive
, NeighborCellIndex
, FALSE
);
505 Neighbor
= (PHCELL
)((ULONG_PTR
)Neighbor
+ Neighbor
->Size
);
509 Neighbor
= (PHCELL
)((ULONG_PTR
)Neighbor
- Neighbor
->Size
);
513 /* Add block to the list of free blocks */
514 HvpAddFree(RegistryHive
, Free
, CellIndex
);
516 if (CellType
== Stable
)
517 HvMarkCellDirty(RegistryHive
, CellIndex
, FALSE
);