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
) return TRUE
;
54 /* Otherwise, get the type and make sure it's valid */
55 Type
= HvGetCellType(CellIndex
);
56 if (((CellIndex
% ~HCELL_TYPE_MASK
) > RegistryHive
->Storage
[Type
].Length
) ||
57 (CellIndex
% (RegistryHive
->Version
>= 2 ? 8 : 16)))
59 /* Invalid cell index */
63 /* Try to get the cell block */
64 Block
= (CellIndex
& HCELL_BLOCK_MASK
) >> HCELL_BLOCK_SHIFT
;
65 if (RegistryHive
->Storage
[Type
].BlockList
[Block
].BlockAddress
) return TRUE
;
67 /* No valid block, fail */
74 HCELL_INDEX CellIndex
)
76 return (PVOID
)(HvpGetCellHeader(RegistryHive
, CellIndex
) + 1);
79 static LONG __inline CMAPI
84 return ((PHCELL
)Cell
- 1)->Size
;
88 HvGetCellSize(IN PHHIVE Hive
,
94 CellHeader
= (PHCELL
)Address
- 1;
95 Size
= CellHeader
->Size
* -1;
96 Size
-= sizeof(HCELL
);
103 HCELL_INDEX CellIndex
,
109 ASSERT(RegistryHive
->ReadOnly
== FALSE
);
111 CMLTRACE(CMLIB_HCELL_DEBUG
, "%s - Hive %p, CellIndex %08lx, HoldingLock %b\n",
112 __FUNCTION__
, RegistryHive
, CellIndex
, HoldingLock
);
114 if ((CellIndex
& HCELL_TYPE_MASK
) >> HCELL_TYPE_SHIFT
!= Stable
)
117 CellBlock
= (CellIndex
& HCELL_BLOCK_MASK
) >> HCELL_BLOCK_SHIFT
;
118 CellLastBlock
= ((CellIndex
+ HV_BLOCK_SIZE
- 1) & HCELL_BLOCK_MASK
) >> HCELL_BLOCK_SHIFT
;
120 RtlSetBits(&RegistryHive
->DirtyVector
,
121 CellBlock
, CellLastBlock
- CellBlock
);
126 HvIsCellDirty(IN PHHIVE Hive
,
130 ASSERT(Hive
->ReadOnly
== FALSE
);
132 /* Volatile cells are always "dirty" */
133 if (HvGetCellType(Cell
) == Volatile
) return TRUE
;
135 /* Check if the dirty bit is set */
136 return RtlCheckBit(&Hive
->DirtyVector
, Cell
/ HV_BLOCK_SIZE
);
139 static ULONG __inline CMAPI
140 HvpComputeFreeListIndex(
144 static CCHAR FindFirstSet
[256] = {
145 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
146 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
147 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
148 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
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 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
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,
160 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7};
162 Index
= (Size
>> 3) - 1;
168 Index
= FindFirstSet
[Index
] + 7;
174 static NTSTATUS CMAPI
178 HCELL_INDEX FreeIndex
)
180 PHCELL_INDEX FreeBlockData
;
181 HSTORAGE_TYPE Storage
;
184 ASSERT(RegistryHive
!= NULL
);
185 ASSERT(FreeBlock
!= NULL
);
187 Storage
= (FreeIndex
& HCELL_TYPE_MASK
) >> HCELL_TYPE_SHIFT
;
188 Index
= HvpComputeFreeListIndex((ULONG
)FreeBlock
->Size
);
190 FreeBlockData
= (PHCELL_INDEX
)(FreeBlock
+ 1);
191 *FreeBlockData
= RegistryHive
->Storage
[Storage
].FreeDisplay
[Index
];
192 RegistryHive
->Storage
[Storage
].FreeDisplay
[Index
] = FreeIndex
;
194 /* FIXME: Eventually get rid of free bins. */
196 return STATUS_SUCCESS
;
203 HCELL_INDEX CellIndex
)
205 PHCELL_INDEX FreeCellData
;
206 PHCELL_INDEX pFreeCellOffset
;
207 HSTORAGE_TYPE Storage
;
208 ULONG Index
, FreeListIndex
;
210 ASSERT(RegistryHive
->ReadOnly
== FALSE
);
212 Storage
= (CellIndex
& HCELL_TYPE_MASK
) >> HCELL_TYPE_SHIFT
;
213 Index
= HvpComputeFreeListIndex((ULONG
)CellBlock
->Size
);
215 pFreeCellOffset
= &RegistryHive
->Storage
[Storage
].FreeDisplay
[Index
];
216 while (*pFreeCellOffset
!= HCELL_NIL
)
218 FreeCellData
= (PHCELL_INDEX
)HvGetCell(RegistryHive
, *pFreeCellOffset
);
219 if (*pFreeCellOffset
== CellIndex
)
221 *pFreeCellOffset
= *FreeCellData
;
224 pFreeCellOffset
= FreeCellData
;
227 /* Something bad happened, print a useful trace info and bugcheck */
228 CMLTRACE(CMLIB_HCELL_DEBUG
, "-- beginning of HvpRemoveFree trace --\n");
229 CMLTRACE(CMLIB_HCELL_DEBUG
, "block we are about to free: %08x\n", CellIndex
);
230 CMLTRACE(CMLIB_HCELL_DEBUG
, "chosen free list index: %d\n", Index
);
231 for (FreeListIndex
= 0; FreeListIndex
< 24; FreeListIndex
++)
233 CMLTRACE(CMLIB_HCELL_DEBUG
, "free list [%d]: ", FreeListIndex
);
234 pFreeCellOffset
= &RegistryHive
->Storage
[Storage
].FreeDisplay
[FreeListIndex
];
235 while (*pFreeCellOffset
!= HCELL_NIL
)
237 CMLTRACE(CMLIB_HCELL_DEBUG
, "%08x ", *pFreeCellOffset
);
238 FreeCellData
= (PHCELL_INDEX
)HvGetCell(RegistryHive
, *pFreeCellOffset
);
239 pFreeCellOffset
= FreeCellData
;
241 CMLTRACE(CMLIB_HCELL_DEBUG
, "\n");
243 CMLTRACE(CMLIB_HCELL_DEBUG
, "-- end of HvpRemoveFree trace --\n");
248 static HCELL_INDEX CMAPI
252 HSTORAGE_TYPE Storage
)
254 PHCELL_INDEX FreeCellData
;
255 HCELL_INDEX FreeCellOffset
;
256 PHCELL_INDEX pFreeCellOffset
;
259 for (Index
= HvpComputeFreeListIndex(Size
); Index
< 24; Index
++)
261 pFreeCellOffset
= &RegistryHive
->Storage
[Storage
].FreeDisplay
[Index
];
262 while (*pFreeCellOffset
!= HCELL_NIL
)
264 FreeCellData
= (PHCELL_INDEX
)HvGetCell(RegistryHive
, *pFreeCellOffset
);
265 if ((ULONG
)HvpGetCellFullSize(RegistryHive
, FreeCellData
) >= Size
)
267 FreeCellOffset
= *pFreeCellOffset
;
268 *pFreeCellOffset
= *FreeCellData
;
269 return FreeCellOffset
;
271 pFreeCellOffset
= FreeCellData
;
279 HvpCreateHiveFreeCellList(
282 HCELL_INDEX BlockOffset
;
290 /* Initialize the free cell list */
291 for (Index
= 0; Index
< 24; Index
++)
293 Hive
->Storage
[Stable
].FreeDisplay
[Index
] = HCELL_NIL
;
294 Hive
->Storage
[Volatile
].FreeDisplay
[Index
] = HCELL_NIL
;
299 while (BlockIndex
< Hive
->Storage
[Stable
].Length
)
301 Bin
= (PHBIN
)Hive
->Storage
[Stable
].BlockList
[BlockIndex
].BinAddress
;
303 /* Search free blocks and add to list */
304 FreeOffset
= sizeof(HBIN
);
305 while (FreeOffset
< Bin
->Size
)
307 FreeBlock
= (PHCELL
)((ULONG_PTR
)Bin
+ FreeOffset
);
308 if (FreeBlock
->Size
> 0)
310 Status
= HvpAddFree(Hive
, FreeBlock
, Bin
->FileOffset
+ FreeOffset
);
311 if (!NT_SUCCESS(Status
))
314 FreeOffset
+= FreeBlock
->Size
;
318 FreeOffset
-= FreeBlock
->Size
;
322 BlockIndex
+= Bin
->Size
/ HV_BLOCK_SIZE
;
323 BlockOffset
+= Bin
->Size
;
326 return STATUS_SUCCESS
;
333 HSTORAGE_TYPE Storage
,
334 HCELL_INDEX Vicinity
)
337 HCELL_INDEX FreeCellOffset
;
341 ASSERT(RegistryHive
->ReadOnly
== FALSE
);
343 CMLTRACE(CMLIB_HCELL_DEBUG
, "%s - Hive %p, Size %x, %s, Vicinity %08lx\n",
344 __FUNCTION__
, RegistryHive
, Size
, (Storage
== 0) ? "Stable" : "Volatile", Vicinity
);
346 /* Round to 16 bytes multiple. */
347 Size
= ROUND_UP(Size
+ sizeof(HCELL
), 16);
349 /* First search in free blocks. */
350 FreeCellOffset
= HvpFindFree(RegistryHive
, Size
, Storage
);
352 /* If no free cell was found we need to extend the hive file. */
353 if (FreeCellOffset
== HCELL_NIL
)
355 Bin
= HvpAddBin(RegistryHive
, Size
, Storage
);
358 FreeCellOffset
= Bin
->FileOffset
+ sizeof(HBIN
);
359 FreeCellOffset
|= Storage
<< HCELL_TYPE_SHIFT
;
362 FreeCell
= HvpGetCellHeader(RegistryHive
, FreeCellOffset
);
364 /* Split the block in two parts */
366 /* The free block that is created has to be at least
367 sizeof(HCELL) + sizeof(HCELL_INDEX) big, so that free
368 cell list code can work. Moreover we round cell sizes
369 to 16 bytes, so creating a smaller block would result in
370 a cell that would never be allocated. */
371 if ((ULONG
)FreeCell
->Size
> Size
+ 16)
373 NewCell
= (PHCELL
)((ULONG_PTR
)FreeCell
+ Size
);
374 NewCell
->Size
= FreeCell
->Size
- Size
;
375 FreeCell
->Size
= Size
;
376 HvpAddFree(RegistryHive
, NewCell
, FreeCellOffset
+ Size
);
377 if (Storage
== Stable
)
378 HvMarkCellDirty(RegistryHive
, FreeCellOffset
+ Size
, FALSE
);
381 if (Storage
== Stable
)
382 HvMarkCellDirty(RegistryHive
, FreeCellOffset
, FALSE
);
383 FreeCell
->Size
= -FreeCell
->Size
;
384 RtlZeroMemory(FreeCell
+ 1, Size
- sizeof(HCELL
));
386 CMLTRACE(CMLIB_HCELL_DEBUG
, "%s - CellIndex %08lx\n",
387 __FUNCTION__
, FreeCellOffset
);
389 return FreeCellOffset
;
395 HCELL_INDEX CellIndex
,
401 HCELL_INDEX NewCellIndex
;
402 HSTORAGE_TYPE Storage
;
404 ASSERT(CellIndex
!= HCELL_NIL
);
406 CMLTRACE(CMLIB_HCELL_DEBUG
, "%s - Hive %p, CellIndex %08lx, Size %x\n",
407 __FUNCTION__
, RegistryHive
, CellIndex
, Size
);
409 Storage
= (CellIndex
& HCELL_TYPE_MASK
) >> HCELL_TYPE_SHIFT
;
411 OldCell
= HvGetCell(RegistryHive
, CellIndex
);
412 OldCellSize
= HvGetCellSize(RegistryHive
, OldCell
);
413 ASSERT(OldCellSize
> 0);
416 * If new data size is larger than the current, destroy current
417 * data block and allocate a new one.
419 * FIXME: Merge with adjacent free cell if possible.
420 * FIXME: Implement shrinking.
422 if (Size
> OldCellSize
)
424 NewCellIndex
= HvAllocateCell(RegistryHive
, Size
, Storage
, HCELL_NIL
);
425 if (NewCellIndex
== HCELL_NIL
)
428 NewCell
= HvGetCell(RegistryHive
, NewCellIndex
);
429 RtlCopyMemory(NewCell
, OldCell
, (SIZE_T
)OldCellSize
);
431 HvFreeCell(RegistryHive
, CellIndex
);
442 HCELL_INDEX CellIndex
)
450 ASSERT(RegistryHive
->ReadOnly
== FALSE
);
452 CMLTRACE(CMLIB_HCELL_DEBUG
, "%s - Hive %p, CellIndex %08lx\n",
453 __FUNCTION__
, RegistryHive
, CellIndex
);
455 Free
= HvpGetCellHeader(RegistryHive
, CellIndex
);
457 ASSERT(Free
->Size
< 0);
459 Free
->Size
= -Free
->Size
;
461 CellType
= (CellIndex
& HCELL_TYPE_MASK
) >> HCELL_TYPE_SHIFT
;
462 CellBlock
= (CellIndex
& HCELL_BLOCK_MASK
) >> HCELL_BLOCK_SHIFT
;
464 /* FIXME: Merge free blocks */
465 Bin
= (PHBIN
)RegistryHive
->Storage
[CellType
].BlockList
[CellBlock
].BinAddress
;
467 if ((CellIndex
& ~HCELL_TYPE_MASK
) + Free
->Size
<
468 Bin
->FileOffset
+ Bin
->Size
)
470 Neighbor
= (PHCELL
)((ULONG_PTR
)Free
+ Free
->Size
);
471 if (Neighbor
->Size
> 0)
473 HvpRemoveFree(RegistryHive
, Neighbor
,
474 ((HCELL_INDEX
)((ULONG_PTR
)Neighbor
- (ULONG_PTR
)Bin
+
475 Bin
->FileOffset
)) | (CellIndex
& HCELL_TYPE_MASK
));
476 Free
->Size
+= Neighbor
->Size
;
480 Neighbor
= (PHCELL
)(Bin
+ 1);
481 while (Neighbor
< Free
)
483 if (Neighbor
->Size
> 0)
485 if ((ULONG_PTR
)Neighbor
+ Neighbor
->Size
== (ULONG_PTR
)Free
)
487 HCELL_INDEX NeighborCellIndex
=
488 (HCELL_INDEX
)((ULONG_PTR
)Neighbor
- (ULONG_PTR
)Bin
+
489 Bin
->FileOffset
) | (CellIndex
& HCELL_TYPE_MASK
);
491 if (HvpComputeFreeListIndex(Neighbor
->Size
) !=
492 HvpComputeFreeListIndex(Neighbor
->Size
+ Free
->Size
))
494 HvpRemoveFree(RegistryHive
, Neighbor
, NeighborCellIndex
);
495 Neighbor
->Size
+= Free
->Size
;
496 HvpAddFree(RegistryHive
, Neighbor
, NeighborCellIndex
);
499 Neighbor
->Size
+= Free
->Size
;
501 if (CellType
== Stable
)
502 HvMarkCellDirty(RegistryHive
, NeighborCellIndex
, FALSE
);
506 Neighbor
= (PHCELL
)((ULONG_PTR
)Neighbor
+ Neighbor
->Size
);
510 Neighbor
= (PHCELL
)((ULONG_PTR
)Neighbor
- Neighbor
->Size
);
514 /* Add block to the list of free blocks */
515 HvpAddFree(RegistryHive
, Free
, CellIndex
);
517 if (CellType
== Stable
)
518 HvMarkCellDirty(RegistryHive
, CellIndex
, FALSE
);