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 ASSERT(CellIndex
!= HCELL_NULL
);
20 if (!RegistryHive
->Flat
)
26 CellType
= (CellIndex
& HCELL_TYPE_MASK
) >> HCELL_TYPE_SHIFT
;
27 CellBlock
= (CellIndex
& HCELL_BLOCK_MASK
) >> HCELL_BLOCK_SHIFT
;
28 CellOffset
= (CellIndex
& HCELL_OFFSET_MASK
) >> HCELL_OFFSET_SHIFT
;
29 ASSERT(CellBlock
< RegistryHive
->Storage
[CellType
].Length
);
30 Block
= (PVOID
)RegistryHive
->Storage
[CellType
].BlockList
[CellBlock
].Block
;
31 ASSERT(Block
!= NULL
);
32 return (PVOID
)((ULONG_PTR
)Block
+ CellOffset
);
36 ASSERT((CellIndex
& HCELL_TYPE_MASK
) == HvStable
);
37 return (PVOID
)((ULONG_PTR
)RegistryHive
->HiveHeader
+ HV_BLOCK_SIZE
+
45 HCELL_INDEX CellIndex
)
47 return (PVOID
)(HvpGetCellHeader(RegistryHive
, CellIndex
) + 1);
50 static LONG __inline CMAPI
55 return ((PHCELL
)Cell
- 1)->Size
;
65 CellHeader
= (PHCELL
)Cell
- 1;
66 if (CellHeader
->Size
< 0)
67 return CellHeader
->Size
+ sizeof(HCELL
);
69 return CellHeader
->Size
- sizeof(HCELL
);
75 HCELL_INDEX CellIndex
)
81 ASSERT(RegistryHive
->ReadOnly
== FALSE
);
83 if ((CellIndex
& HCELL_TYPE_MASK
) >> HCELL_TYPE_SHIFT
!= HvStable
)
86 CellBlock
= (CellIndex
& HCELL_BLOCK_MASK
) >> HCELL_BLOCK_SHIFT
;
87 CellLastBlock
= ((CellIndex
+ HV_BLOCK_SIZE
- 1) & HCELL_BLOCK_MASK
) >> HCELL_BLOCK_SHIFT
;
89 CellSize
= HvpGetCellFullSize(RegistryHive
, HvGetCell(RegistryHive
, CellIndex
));
93 RtlSetBits(&RegistryHive
->DirtyVector
,
94 CellBlock
, CellLastBlock
- CellBlock
);
97 static ULONG __inline CMAPI
98 HvpComputeFreeListIndex(
102 static CCHAR FindFirstSet
[256] = {
103 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
104 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
105 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
106 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
107 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
108 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
109 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
110 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
111 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
112 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
113 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
114 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
115 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
116 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
117 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
118 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7};
120 Index
= (Size
>> 3) - 1;
126 Index
= FindFirstSet
[Index
] + 7;
132 static NTSTATUS CMAPI
136 HCELL_INDEX FreeIndex
)
138 PHCELL_INDEX FreeBlockData
;
139 HV_STORAGE_TYPE Storage
;
142 ASSERT(RegistryHive
!= NULL
);
143 ASSERT(FreeBlock
!= NULL
);
145 Storage
= (FreeIndex
& HCELL_TYPE_MASK
) >> HCELL_TYPE_SHIFT
;
146 Index
= HvpComputeFreeListIndex((ULONG
)FreeBlock
->Size
);
148 FreeBlockData
= (PHCELL_INDEX
)(FreeBlock
+ 1);
149 *FreeBlockData
= RegistryHive
->Storage
[Storage
].FreeDisplay
[Index
];
150 RegistryHive
->Storage
[Storage
].FreeDisplay
[Index
] = FreeIndex
;
152 /* FIXME: Eventually get rid of free bins. */
154 return STATUS_SUCCESS
;
161 HCELL_INDEX CellIndex
)
163 PHCELL_INDEX FreeCellData
;
164 PHCELL_INDEX pFreeCellOffset
;
165 HV_STORAGE_TYPE Storage
;
168 ASSERT(RegistryHive
->ReadOnly
== FALSE
);
170 Storage
= (CellIndex
& HCELL_TYPE_MASK
) >> HCELL_TYPE_SHIFT
;
171 Index
= HvpComputeFreeListIndex((ULONG
)CellBlock
->Size
);
173 pFreeCellOffset
= &RegistryHive
->Storage
[Storage
].FreeDisplay
[Index
];
174 while (*pFreeCellOffset
!= HCELL_NULL
)
176 FreeCellData
= (PHCELL_INDEX
)HvGetCell(RegistryHive
, *pFreeCellOffset
);
177 if (*pFreeCellOffset
== CellIndex
)
179 *pFreeCellOffset
= *FreeCellData
;
182 pFreeCellOffset
= FreeCellData
;
188 static HCELL_INDEX CMAPI
192 HV_STORAGE_TYPE Storage
)
194 PHCELL_INDEX FreeCellData
;
195 HCELL_INDEX FreeCellOffset
;
196 PHCELL_INDEX pFreeCellOffset
;
199 for (Index
= HvpComputeFreeListIndex(Size
); Index
< 24; Index
++)
201 pFreeCellOffset
= &RegistryHive
->Storage
[Storage
].FreeDisplay
[Index
];
202 while (*pFreeCellOffset
!= HCELL_NULL
)
204 FreeCellData
= (PHCELL_INDEX
)HvGetCell(RegistryHive
, *pFreeCellOffset
);
205 if ((ULONG
)HvpGetCellFullSize(RegistryHive
, FreeCellData
) >= Size
)
207 FreeCellOffset
= *pFreeCellOffset
;
208 *pFreeCellOffset
= *FreeCellData
;
209 return FreeCellOffset
;
211 pFreeCellOffset
= FreeCellData
;
219 HvpCreateHiveFreeCellList(
222 HCELL_INDEX BlockOffset
;
230 /* Initialize the free cell list */
231 for (Index
= 0; Index
< 24; Index
++)
233 Hive
->Storage
[HvStable
].FreeDisplay
[Index
] = HCELL_NULL
;
234 Hive
->Storage
[HvVolatile
].FreeDisplay
[Index
] = HCELL_NULL
;
239 while (BlockIndex
< Hive
->Storage
[HvStable
].Length
)
241 Bin
= (PHBIN
)Hive
->Storage
[HvStable
].BlockList
[BlockIndex
].Bin
;
243 /* Search free blocks and add to list */
244 FreeOffset
= sizeof(HBIN
);
245 while (FreeOffset
< Bin
->Size
)
247 FreeBlock
= (PHCELL
)((ULONG_PTR
)Bin
+ FreeOffset
);
248 if (FreeBlock
->Size
> 0)
250 Status
= HvpAddFree(Hive
, FreeBlock
, Bin
->FileOffset
+ FreeOffset
);
251 if (!NT_SUCCESS(Status
))
254 FreeOffset
+= FreeBlock
->Size
;
258 FreeOffset
-= FreeBlock
->Size
;
262 BlockIndex
+= Bin
->Size
/ HV_BLOCK_SIZE
;
263 BlockOffset
+= Bin
->Size
;
266 return STATUS_SUCCESS
;
273 HV_STORAGE_TYPE Storage
)
276 HCELL_INDEX FreeCellOffset
;
280 ASSERT(RegistryHive
->ReadOnly
== FALSE
);
282 /* Round to 16 bytes multiple. */
283 Size
= ROUND_UP(Size
+ sizeof(HCELL
), 16);
285 /* First search in free blocks. */
286 FreeCellOffset
= HvpFindFree(RegistryHive
, Size
, Storage
);
288 /* If no free cell was found we need to extend the hive file. */
289 if (FreeCellOffset
== HCELL_NULL
)
291 Bin
= HvpAddBin(RegistryHive
, Size
, Storage
);
294 FreeCellOffset
= Bin
->FileOffset
+ sizeof(HBIN
);
295 FreeCellOffset
|= Storage
<< HCELL_TYPE_SHIFT
;
298 FreeCell
= HvpGetCellHeader(RegistryHive
, FreeCellOffset
);
300 /* Split the block in two parts */
301 /* FIXME: There is some minimal cell size that we must respect. */
302 if ((ULONG
)FreeCell
->Size
> Size
+ sizeof(HCELL_INDEX
))
304 NewCell
= (PHCELL
)((ULONG_PTR
)FreeCell
+ Size
);
305 NewCell
->Size
= FreeCell
->Size
- Size
;
306 FreeCell
->Size
= Size
;
307 HvpAddFree(RegistryHive
, NewCell
, FreeCellOffset
+ Size
);
308 if (Storage
== HvStable
)
309 HvMarkCellDirty(RegistryHive
, FreeCellOffset
+ Size
);
312 if (Storage
== HvStable
)
313 HvMarkCellDirty(RegistryHive
, FreeCellOffset
);
314 FreeCell
->Size
= -FreeCell
->Size
;
315 RtlZeroMemory(FreeCell
+ 1, Size
- sizeof(HCELL
));
317 return FreeCellOffset
;
323 HCELL_INDEX CellIndex
,
329 HCELL_INDEX NewCellIndex
;
330 HV_STORAGE_TYPE Storage
;
332 ASSERT(CellIndex
!= HCELL_NULL
);
334 Storage
= (CellIndex
& HCELL_TYPE_MASK
) >> HCELL_TYPE_SHIFT
;
336 OldCell
= HvGetCell(RegistryHive
, CellIndex
);
337 OldCellSize
= HvGetCellSize(RegistryHive
, OldCell
);
338 ASSERT(OldCellSize
< 0);
341 * If new data size is larger than the current, destroy current
342 * data block and allocate a new one.
344 * FIXME: Merge with adjacent free cell if possible.
345 * FIXME: Implement shrinking.
347 if (Size
> (ULONG
)-OldCellSize
)
349 NewCellIndex
= HvAllocateCell(RegistryHive
, Size
, Storage
);
350 if (NewCellIndex
== HCELL_NULL
)
353 NewCell
= HvGetCell(RegistryHive
, NewCellIndex
);
354 RtlCopyMemory(NewCell
, OldCell
, (SIZE_T
)-OldCellSize
);
356 HvFreeCell(RegistryHive
, CellIndex
);
367 HCELL_INDEX CellIndex
)
375 ASSERT(RegistryHive
->ReadOnly
== FALSE
);
377 Free
= HvpGetCellHeader(RegistryHive
, CellIndex
);
379 ASSERT(Free
->Size
< 0);
381 Free
->Size
= -Free
->Size
;
383 CellType
= (CellIndex
& HCELL_TYPE_MASK
) >> HCELL_TYPE_SHIFT
;
384 CellBlock
= (CellIndex
& HCELL_BLOCK_MASK
) >> HCELL_BLOCK_SHIFT
;
386 /* FIXME: Merge free blocks */
387 Bin
= (PHBIN
)RegistryHive
->Storage
[CellType
].BlockList
[CellBlock
].Bin
;
389 if ((CellIndex
& ~HCELL_TYPE_MASK
) + Free
->Size
<
390 Bin
->FileOffset
+ Bin
->Size
)
392 Neighbor
= (PHCELL
)((ULONG_PTR
)Free
+ Free
->Size
);
393 if (Neighbor
->Size
> 0)
395 HvpRemoveFree(RegistryHive
, Neighbor
,
396 ((HCELL_INDEX
)((ULONG_PTR
)Neighbor
- (ULONG_PTR
)Bin
+
397 Bin
->FileOffset
)) | (CellIndex
& HCELL_TYPE_MASK
));
398 Free
->Size
+= Neighbor
->Size
;
402 Neighbor
= (PHCELL
)(Bin
+ 1);
403 while (Neighbor
< Free
)
405 if (Neighbor
->Size
> 0)
407 if ((ULONG_PTR
)Neighbor
+ Neighbor
->Size
== (ULONG_PTR
)Free
)
409 Neighbor
->Size
+= Free
->Size
;
410 if (CellType
== HvStable
)
411 HvMarkCellDirty(RegistryHive
,
412 (HCELL_INDEX
)((ULONG_PTR
)Neighbor
- (ULONG_PTR
)Bin
+
416 Neighbor
= (PHCELL
)((ULONG_PTR
)Neighbor
+ Neighbor
->Size
);
420 Neighbor
= (PHCELL
)((ULONG_PTR
)Neighbor
- Neighbor
->Size
);
424 /* Add block to the list of free blocks */
425 HvpAddFree(RegistryHive
, Free
, CellIndex
);
427 if (CellType
== HvStable
)
428 HvMarkCellDirty(RegistryHive
, CellIndex
);