- Make HHIVE part of EREGISTRY_HIVE, similarly to NT.
[reactos.git] / reactos / lib / cmlib / hiveinit.c
1 /*
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
6 */
7
8 #include "cmlib.h"
9 #define NDEBUG
10 #include <debug.h>
11
12 /**
13 * @name HvpVerifyHiveHeader
14 *
15 * Internal function to verify that a hive header has valid format.
16 */
17
18 BOOLEAN CMAPI
19 HvpVerifyHiveHeader(
20 PHBASE_BLOCK HiveHeader)
21 {
22 if (HiveHeader->Signature != HV_SIGNATURE ||
23 HiveHeader->Major != HV_MAJOR_VER ||
24 HiveHeader->Minor > HV_MINOR_VER ||
25 HiveHeader->Type != HV_TYPE_PRIMARY ||
26 HiveHeader->Format != HV_FORMAT_MEMORY ||
27 HiveHeader->Cluster != 1 ||
28 HiveHeader->Sequence1 != HiveHeader->Sequence2 ||
29 HvpHiveHeaderChecksum(HiveHeader) != HiveHeader->Checksum)
30 {
31 DPRINT1("Verify Hive Header failed: \n");
32 DPRINT1(" Signature: 0x%x and not 0x%x, Major: 0x%x and not 0x%x\n",
33 HiveHeader->Signature, HV_SIGNATURE, HiveHeader->Major, HV_MAJOR_VER);
34 DPRINT1(" Minor: 0x%x is not > 0x%x, Type: 0x%x and not 0x%x\n",
35 HiveHeader->Minor, HV_MINOR_VER, HiveHeader->Type, HV_TYPE_PRIMARY);
36 DPRINT1(" Format: 0x%x and not 0x%x, Cluster: 0x%x and not 1\n",
37 HiveHeader->Format, HV_FORMAT_MEMORY, HiveHeader->Cluster);
38 DPRINT1(" Sequence: 0x%x and not 0x%x, Checksum: 0x%x and not 0x%x\n",
39 HiveHeader->Sequence1, HiveHeader->Sequence2,
40 HvpHiveHeaderChecksum(HiveHeader), HiveHeader->Checksum);
41 return FALSE;
42 }
43
44 return TRUE;
45 }
46
47 /**
48 * @name HvpFreeHiveBins
49 *
50 * Internal function to free all bin storage associated with hive
51 * descriptor.
52 */
53
54 VOID CMAPI
55 HvpFreeHiveBins(
56 PHHIVE Hive)
57 {
58 ULONG i;
59 PHBIN Bin;
60 ULONG Storage;
61
62 for (Storage = HvStable; Storage < HvMaxStorageType; Storage++)
63 {
64 Bin = NULL;
65 for (i = 0; i < Hive->Storage[Storage].Length; i++)
66 {
67 if (Hive->Storage[Storage].BlockList[i].Bin == (ULONG_PTR)NULL)
68 continue;
69 if (Hive->Storage[Storage].BlockList[i].Bin != (ULONG_PTR)Bin)
70 {
71 Bin = (PHBIN)Hive->Storage[Storage].BlockList[i].Bin;
72 Hive->Free((PHBIN)Hive->Storage[Storage].BlockList[i].Bin);
73 }
74 Hive->Storage[Storage].BlockList[i].Bin = (ULONG_PTR)NULL;
75 Hive->Storage[Storage].BlockList[i].Block = (ULONG_PTR)NULL;
76 }
77
78 if (Hive->Storage[Storage].Length)
79 Hive->Free(Hive->Storage[Storage].BlockList);
80 }
81 }
82
83 /**
84 * @name HvpCreateHive
85 *
86 * Internal helper function to initalize hive descriptor structure for
87 * newly created hive.
88 *
89 * @see HvInitialize
90 */
91
92 NTSTATUS CMAPI
93 HvpCreateHive(
94 PHHIVE RegistryHive)
95 {
96 PHBASE_BLOCK HiveHeader;
97 ULONG Index;
98
99 HiveHeader = RegistryHive->Allocate(sizeof(HBASE_BLOCK), FALSE);
100 if (HiveHeader == NULL)
101 return STATUS_NO_MEMORY;
102 RtlZeroMemory(HiveHeader, sizeof(HBASE_BLOCK));
103 HiveHeader->Signature = HV_SIGNATURE;
104 HiveHeader->Major = HV_MAJOR_VER;
105 HiveHeader->Minor = HV_MINOR_VER;
106 HiveHeader->Type = HV_TYPE_PRIMARY;
107 HiveHeader->Format = HV_FORMAT_MEMORY;
108 HiveHeader->Cluster = 1;
109 HiveHeader->RootCell = HCELL_NULL;
110 HiveHeader->Length = HV_BLOCK_SIZE;
111 HiveHeader->Sequence1 = 1;
112 HiveHeader->Sequence2 = 1;
113 /* FIXME: Fill in the file name */
114 HiveHeader->Checksum = HvpHiveHeaderChecksum(HiveHeader);
115
116 RegistryHive->HiveHeader = HiveHeader;
117 for (Index = 0; Index < 24; Index++)
118 {
119 RegistryHive->Storage[HvStable].FreeDisplay[Index] = HCELL_NULL;
120 RegistryHive->Storage[HvVolatile].FreeDisplay[Index] = HCELL_NULL;
121 }
122 RtlInitializeBitMap(&RegistryHive->DirtyVector, NULL, 0);
123
124 return STATUS_SUCCESS;
125 }
126
127 /**
128 * @name HvpInitializeMemoryHive
129 *
130 * Internal helper function to initalize hive descriptor structure for
131 * a hive stored in memory. The data of the hive are copied and it is
132 * prepared for read/write access.
133 *
134 * @see HvInitialize
135 */
136
137 NTSTATUS CMAPI
138 HvpInitializeMemoryHive(
139 PHHIVE Hive,
140 ULONG_PTR ChunkBase,
141 SIZE_T ChunkSize)
142 {
143 SIZE_T BlockIndex;
144 PHBIN Bin, NewBin;
145 ULONG i;
146 ULONG BitmapSize;
147 PULONG BitmapBuffer;
148
149 if (ChunkSize < sizeof(HBASE_BLOCK) ||
150 !HvpVerifyHiveHeader((PHBASE_BLOCK)ChunkBase))
151 {
152 DPRINT1("Registry is corrupt: ChunkSize %d < sizeof(HBASE_BLOCK) %d, "
153 "or HvpVerifyHiveHeader() failed\n", ChunkSize, sizeof(HBASE_BLOCK));
154 return STATUS_REGISTRY_CORRUPT;
155 }
156
157 Hive->HiveHeader = Hive->Allocate(sizeof(HBASE_BLOCK), FALSE);
158 if (Hive->HiveHeader == NULL)
159 {
160 return STATUS_NO_MEMORY;
161 }
162 RtlCopyMemory(Hive->HiveHeader, (PVOID)ChunkBase, sizeof(HBASE_BLOCK));
163
164 /*
165 * Build a block list from the in-memory chunk and copy the data as
166 * we go.
167 */
168
169 Hive->Storage[HvStable].Length = (ChunkSize / HV_BLOCK_SIZE) - 1;
170 Hive->Storage[HvStable].BlockList =
171 Hive->Allocate(Hive->Storage[HvStable].Length *
172 sizeof(HMAP_ENTRY), FALSE);
173 if (Hive->Storage[HvStable].BlockList == NULL)
174 {
175 DPRINT1("Allocating block list failed\n");
176 Hive->Free(Hive->HiveHeader);
177 return STATUS_NO_MEMORY;
178 }
179
180 for (BlockIndex = 0; BlockIndex < Hive->Storage[HvStable].Length; )
181 {
182 Bin = (PHBIN)((ULONG_PTR)ChunkBase + (BlockIndex + 1) * HV_BLOCK_SIZE);
183 if (Bin->Signature != HV_BIN_SIGNATURE ||
184 (Bin->Size % HV_BLOCK_SIZE) != 0)
185 {
186 Hive->Free(Hive->HiveHeader);
187 Hive->Free(Hive->Storage[HvStable].BlockList);
188 return STATUS_REGISTRY_CORRUPT;
189 }
190
191 NewBin = Hive->Allocate(Bin->Size, TRUE);
192 if (NewBin == NULL)
193 {
194 Hive->Free(Hive->HiveHeader);
195 Hive->Free(Hive->Storage[HvStable].BlockList);
196 return STATUS_NO_MEMORY;
197 }
198
199 Hive->Storage[HvStable].BlockList[BlockIndex].Bin = (ULONG_PTR)NewBin;
200 Hive->Storage[HvStable].BlockList[BlockIndex].Block = (ULONG_PTR)NewBin;
201
202 RtlCopyMemory(NewBin, Bin, Bin->Size);
203
204 if (Bin->Size > HV_BLOCK_SIZE)
205 {
206 for (i = 1; i < Bin->Size / HV_BLOCK_SIZE; i++)
207 {
208 Hive->Storage[HvStable].BlockList[BlockIndex + i].Bin = (ULONG_PTR)NewBin;
209 Hive->Storage[HvStable].BlockList[BlockIndex + i].Block =
210 ((ULONG_PTR)NewBin + (i * HV_BLOCK_SIZE));
211 }
212 }
213
214 BlockIndex += Bin->Size / HV_BLOCK_SIZE;
215 }
216
217 if (HvpCreateHiveFreeCellList(Hive))
218 {
219 HvpFreeHiveBins(Hive);
220 Hive->Free(Hive->HiveHeader);
221 return STATUS_NO_MEMORY;
222 }
223
224 BitmapSize = ROUND_UP(Hive->Storage[HvStable].Length,
225 sizeof(ULONG) * 8) / 8;
226 BitmapBuffer = (PULONG)Hive->Allocate(BitmapSize, TRUE);
227 if (BitmapBuffer == NULL)
228 {
229 HvpFreeHiveBins(Hive);
230 Hive->Free(Hive->HiveHeader);
231 return STATUS_NO_MEMORY;
232 }
233
234 RtlInitializeBitMap(&Hive->DirtyVector, BitmapBuffer, BitmapSize * 8);
235 RtlClearAllBits(&Hive->DirtyVector);
236
237 return STATUS_SUCCESS;
238 }
239
240 /**
241 * @name HvpInitializeMemoryInplaceHive
242 *
243 * Internal helper function to initalize hive descriptor structure for
244 * a hive stored in memory. The in-memory data of the hive are directly
245 * used and it is read-only accessible.
246 *
247 * @see HvInitialize
248 */
249
250 NTSTATUS CMAPI
251 HvpInitializeMemoryInplaceHive(
252 PHHIVE Hive,
253 ULONG_PTR ChunkBase,
254 SIZE_T ChunkSize)
255 {
256 if (ChunkSize < sizeof(HBASE_BLOCK) ||
257 !HvpVerifyHiveHeader((PHBASE_BLOCK)ChunkBase))
258 {
259 return STATUS_REGISTRY_CORRUPT;
260 }
261
262 Hive->HiveHeader = (PHBASE_BLOCK)ChunkBase;
263 Hive->ReadOnly = TRUE;
264 Hive->Flat = TRUE;
265
266 return STATUS_SUCCESS;
267 }
268
269 /**
270 * @name HvInitialize
271 *
272 * Allocate a new hive descriptor structure and intialize it.
273 *
274 * @param RegistryHive
275 * Output variable to store pointer to the hive descriptor.
276 * @param Operation
277 * - HV_OPERATION_CREATE_HIVE
278 * Create a new hive for read/write access.
279 * - HV_OPERATION_MEMORY
280 * Load and copy in-memory hive for read/write access. The
281 * pointer to data passed to this routine can be freed after
282 * the function is executed.
283 * - HV_OPERATION_MEMORY_INPLACE
284 * Load an in-memory hive for read-only access. The pointer
285 * to data passed to this routine MUSTN'T be freed until
286 * HvFree is called.
287 * @param ChunkBase
288 * Pointer to hive data.
289 * @param ChunkSize
290 * Size of passed hive data.
291 *
292 * @return
293 * STATUS_NO_MEMORY - A memory allocation failed.
294 * STATUS_REGISTRY_CORRUPT - Registry corruption was detected.
295 * STATUS_SUCCESS
296 *
297 * @see HvFree
298 */
299
300 NTSTATUS CMAPI
301 HvInitialize(
302 PHHIVE RegistryHive,
303 ULONG Operation,
304 ULONG_PTR ChunkBase,
305 SIZE_T ChunkSize,
306 PALLOCATE_ROUTINE Allocate,
307 PFREE_ROUTINE Free,
308 PFILE_READ_ROUTINE FileRead,
309 PFILE_WRITE_ROUTINE FileWrite,
310 PFILE_SET_SIZE_ROUTINE FileSetSize,
311 PFILE_FLUSH_ROUTINE FileFlush,
312 IN PUNICODE_STRING FileName)
313 {
314 NTSTATUS Status;
315 PHHIVE Hive = RegistryHive;
316
317 /*
318 * Create a new hive structure that will hold all the maintenance data.
319 */
320
321 RtlZeroMemory(Hive, sizeof(HHIVE));
322
323 Hive->Allocate = Allocate;
324 Hive->Free = Free;
325 Hive->FileRead = FileRead;
326 Hive->FileWrite = FileWrite;
327 Hive->FileSetSize = FileSetSize;
328 Hive->FileFlush = FileFlush;
329
330 switch (Operation)
331 {
332 case HV_OPERATION_CREATE_HIVE:
333 Status = HvpCreateHive(Hive);
334 break;
335
336 case HV_OPERATION_MEMORY:
337 Status = HvpInitializeMemoryHive(Hive, ChunkBase, ChunkSize);
338 break;
339
340 case HV_OPERATION_MEMORY_INPLACE:
341 Status = HvpInitializeMemoryInplaceHive(Hive, ChunkBase, ChunkSize);
342 break;
343
344 default:
345 /* FIXME: A better return status value is needed */
346 Status = STATUS_NOT_IMPLEMENTED;
347 ASSERT(FALSE);
348 }
349
350 if (!NT_SUCCESS(Status))
351 {
352 Hive->Free(Hive);
353 return Status;
354 }
355
356 return Status;
357 }
358
359 /**
360 * @name HvFree
361 *
362 * Free all stroage and handles associated with hive descriptor.
363 */
364
365 VOID CMAPI
366 HvFree(
367 PHHIVE RegistryHive)
368 {
369 if (!RegistryHive->ReadOnly)
370 {
371 /* Release hive bitmap */
372 if (RegistryHive->DirtyVector.Buffer)
373 {
374 RegistryHive->Free(RegistryHive->DirtyVector.Buffer);
375 }
376
377 HvpFreeHiveBins(RegistryHive);
378 }
379
380 RegistryHive->Free(RegistryHive);
381 }
382
383 /* EOF */