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
13 * @name HvpVerifyHiveHeader
15 * Internal function to verify that a hive header has valid format.
20 PHBASE_BLOCK BaseBlock
)
22 if (BaseBlock
->Signature
!= HV_SIGNATURE
||
23 BaseBlock
->Major
!= HSYS_MAJOR
||
24 BaseBlock
->Minor
< HSYS_MINOR
||
25 BaseBlock
->Type
!= HFILE_TYPE_PRIMARY
||
26 BaseBlock
->Format
!= HBASE_FORMAT_MEMORY
||
27 BaseBlock
->Cluster
!= 1 ||
28 BaseBlock
->Sequence1
!= BaseBlock
->Sequence2
||
29 HvpHiveHeaderChecksum(BaseBlock
) != BaseBlock
->CheckSum
)
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 BaseBlock
->Signature
, HV_SIGNATURE
, BaseBlock
->Major
, HSYS_MAJOR
);
34 DPRINT1(" Minor: 0x%x is not >= 0x%x, Type: 0x%x and not 0x%x\n",
35 BaseBlock
->Minor
, HSYS_MINOR
, BaseBlock
->Type
, HFILE_TYPE_PRIMARY
);
36 DPRINT1(" Format: 0x%x and not 0x%x, Cluster: 0x%x and not 1\n",
37 BaseBlock
->Format
, HBASE_FORMAT_MEMORY
, BaseBlock
->Cluster
);
38 DPRINT1(" Sequence: 0x%x and not 0x%x, Checksum: 0x%x and not 0x%x\n",
39 BaseBlock
->Sequence1
, BaseBlock
->Sequence2
,
40 HvpHiveHeaderChecksum(BaseBlock
), BaseBlock
->CheckSum
);
48 * @name HvpFreeHiveBins
50 * Internal function to free all bin storage associated with hive
62 for (Storage
= Stable
; Storage
< HTYPE_COUNT
; Storage
++)
65 for (i
= 0; i
< Hive
->Storage
[Storage
].Length
; i
++)
67 if (Hive
->Storage
[Storage
].BlockList
[i
].BinAddress
== (ULONG_PTR
)NULL
)
69 if (Hive
->Storage
[Storage
].BlockList
[i
].BinAddress
!= (ULONG_PTR
)Bin
)
71 Bin
= (PHBIN
)Hive
->Storage
[Storage
].BlockList
[i
].BinAddress
;
72 Hive
->Free((PHBIN
)Hive
->Storage
[Storage
].BlockList
[i
].BinAddress
, 0);
74 Hive
->Storage
[Storage
].BlockList
[i
].BinAddress
= (ULONG_PTR
)NULL
;
75 Hive
->Storage
[Storage
].BlockList
[i
].BlockAddress
= (ULONG_PTR
)NULL
;
78 if (Hive
->Storage
[Storage
].Length
)
79 Hive
->Free(Hive
->Storage
[Storage
].BlockList
, 0);
86 * Internal helper function to initialize hive descriptor structure for
96 PHBASE_BLOCK BaseBlock
;
99 BaseBlock
= RegistryHive
->Allocate(sizeof(HBASE_BLOCK
), FALSE
, TAG_CM
);
100 if (BaseBlock
== NULL
)
101 return STATUS_NO_MEMORY
;
102 RtlZeroMemory(BaseBlock
, sizeof(HBASE_BLOCK
));
103 BaseBlock
->Signature
= HV_SIGNATURE
;
104 BaseBlock
->Major
= HSYS_MAJOR
;
105 BaseBlock
->Minor
= HSYS_MINOR
;
106 BaseBlock
->Type
= HFILE_TYPE_PRIMARY
;
107 BaseBlock
->Format
= HBASE_FORMAT_MEMORY
;
108 BaseBlock
->Cluster
= 1;
109 BaseBlock
->RootCell
= HCELL_NIL
;
110 BaseBlock
->Length
= 0;
111 BaseBlock
->Sequence1
= 1;
112 BaseBlock
->Sequence2
= 1;
113 /* FIXME: Fill in the file name */
114 BaseBlock
->CheckSum
= HvpHiveHeaderChecksum(BaseBlock
);
116 RegistryHive
->BaseBlock
= BaseBlock
;
117 for (Index
= 0; Index
< 24; Index
++)
119 RegistryHive
->Storage
[Stable
].FreeDisplay
[Index
] = HCELL_NIL
;
120 RegistryHive
->Storage
[Volatile
].FreeDisplay
[Index
] = HCELL_NIL
;
123 return STATUS_SUCCESS
;
127 * @name HvpInitializeMemoryHive
129 * Internal helper function to initialize hive descriptor structure for
130 * a hive stored in memory. The data of the hive are copied and it is
131 * prepared for read/write access.
137 HvpInitializeMemoryHive(
148 ChunkSize
= ((PHBASE_BLOCK
)ChunkBase
)->Length
;
149 DPRINT("ChunkSize: %lx\n", ChunkSize
);
151 if (ChunkSize
< sizeof(HBASE_BLOCK
) ||
152 !HvpVerifyHiveHeader((PHBASE_BLOCK
)ChunkBase
))
154 DPRINT1("Registry is corrupt: ChunkSize %lu < sizeof(HBASE_BLOCK) %lu, "
155 "or HvpVerifyHiveHeader() failed\n", ChunkSize
, (SIZE_T
)sizeof(HBASE_BLOCK
));
156 return STATUS_REGISTRY_CORRUPT
;
159 Hive
->BaseBlock
= Hive
->Allocate(sizeof(HBASE_BLOCK
), FALSE
, TAG_CM
);
160 if (Hive
->BaseBlock
== NULL
)
162 return STATUS_NO_MEMORY
;
164 RtlCopyMemory(Hive
->BaseBlock
, ChunkBase
, sizeof(HBASE_BLOCK
));
167 * Build a block list from the in-memory chunk and copy the data as
171 Hive
->Storage
[Stable
].Length
= (ULONG
)(ChunkSize
/ HV_BLOCK_SIZE
);
172 Hive
->Storage
[Stable
].BlockList
=
173 Hive
->Allocate(Hive
->Storage
[Stable
].Length
*
174 sizeof(HMAP_ENTRY
), FALSE
, TAG_CM
);
175 if (Hive
->Storage
[Stable
].BlockList
== NULL
)
177 DPRINT1("Allocating block list failed\n");
178 Hive
->Free(Hive
->BaseBlock
, 0);
179 return STATUS_NO_MEMORY
;
182 for (BlockIndex
= 0; BlockIndex
< Hive
->Storage
[Stable
].Length
; )
184 Bin
= (PHBIN
)((ULONG_PTR
)ChunkBase
+ (BlockIndex
+ 1) * HV_BLOCK_SIZE
);
185 if (Bin
->Signature
!= HV_BIN_SIGNATURE
||
186 (Bin
->Size
% HV_BLOCK_SIZE
) != 0)
188 Hive
->Free(Hive
->BaseBlock
, 0);
189 Hive
->Free(Hive
->Storage
[Stable
].BlockList
, 0);
190 return STATUS_REGISTRY_CORRUPT
;
193 NewBin
= Hive
->Allocate(Bin
->Size
, TRUE
, TAG_CM
);
196 Hive
->Free(Hive
->BaseBlock
, 0);
197 Hive
->Free(Hive
->Storage
[Stable
].BlockList
, 0);
198 return STATUS_NO_MEMORY
;
201 Hive
->Storage
[Stable
].BlockList
[BlockIndex
].BinAddress
= (ULONG_PTR
)NewBin
;
202 Hive
->Storage
[Stable
].BlockList
[BlockIndex
].BlockAddress
= (ULONG_PTR
)NewBin
;
204 RtlCopyMemory(NewBin
, Bin
, Bin
->Size
);
206 if (Bin
->Size
> HV_BLOCK_SIZE
)
208 for (i
= 1; i
< Bin
->Size
/ HV_BLOCK_SIZE
; i
++)
210 Hive
->Storage
[Stable
].BlockList
[BlockIndex
+ i
].BinAddress
= (ULONG_PTR
)NewBin
;
211 Hive
->Storage
[Stable
].BlockList
[BlockIndex
+ i
].BlockAddress
=
212 ((ULONG_PTR
)NewBin
+ (i
* HV_BLOCK_SIZE
));
216 BlockIndex
+= Bin
->Size
/ HV_BLOCK_SIZE
;
219 if (HvpCreateHiveFreeCellList(Hive
))
221 HvpFreeHiveBins(Hive
);
222 Hive
->Free(Hive
->BaseBlock
, 0);
223 return STATUS_NO_MEMORY
;
226 BitmapSize
= ROUND_UP(Hive
->Storage
[Stable
].Length
,
227 sizeof(ULONG
) * 8) / 8;
228 BitmapBuffer
= (PULONG
)Hive
->Allocate(BitmapSize
, TRUE
, TAG_CM
);
229 if (BitmapBuffer
== NULL
)
231 HvpFreeHiveBins(Hive
);
232 Hive
->Free(Hive
->BaseBlock
, 0);
233 return STATUS_NO_MEMORY
;
236 RtlInitializeBitMap(&Hive
->DirtyVector
, BitmapBuffer
, BitmapSize
* 8);
237 RtlClearAllBits(&Hive
->DirtyVector
);
239 return STATUS_SUCCESS
;
243 * @name HvpInitializeMemoryInplaceHive
245 * Internal helper function to initialize hive descriptor structure for
246 * a hive stored in memory. The in-memory data of the hive are directly
247 * used and it is read-only accessible.
253 HvpInitializeMemoryInplaceHive(
257 if (!HvpVerifyHiveHeader((PHBASE_BLOCK
)ChunkBase
))
259 return STATUS_REGISTRY_CORRUPT
;
262 Hive
->BaseBlock
= (PHBASE_BLOCK
)ChunkBase
;
263 Hive
->ReadOnly
= TRUE
;
266 return STATUS_SUCCESS
;
281 HvpGetHiveHeader(IN PHHIVE Hive
,
282 IN PHBASE_BLOCK
*HiveBaseBlock
,
283 IN PLARGE_INTEGER TimeStamp
)
285 PHBASE_BLOCK BaseBlock
;
289 ASSERT(sizeof(HBASE_BLOCK
) >= (HV_BLOCK_SIZE
* Hive
->Cluster
));
291 /* Assume failure and allocate the buffer */
293 BaseBlock
= Hive
->Allocate(sizeof(HBASE_BLOCK
), TRUE
, TAG_CM
);
294 if (!BaseBlock
) return NoMemory
;
296 /* Check for, and enforce, alignment */
297 Alignment
= Hive
->Cluster
* HV_BLOCK_SIZE
-1;
298 if ((ULONG_PTR
)BaseBlock
& Alignment
)
300 /* Free the old header */
301 Hive
->Free(BaseBlock
, 0);
302 BaseBlock
= Hive
->Allocate(PAGE_SIZE
, TRUE
, TAG_CM
);
303 if (!BaseBlock
) return NoMemory
;
307 RtlZeroMemory(BaseBlock
, sizeof(HBASE_BLOCK
));
309 /* Now read it from disk */
310 Result
= Hive
->FileRead(Hive
,
314 Hive
->Cluster
* HV_BLOCK_SIZE
);
316 /* Couldn't read: assume it's not a hive */
317 if (!Result
) return NotHive
;
320 if (!HvpVerifyHiveHeader(BaseBlock
)) return NotHive
;
322 /* Return information */
323 *HiveBaseBlock
= BaseBlock
;
324 *TimeStamp
= BaseBlock
->TimeStamp
;
329 HvLoadHive(IN PHHIVE Hive
,
332 PHBASE_BLOCK BaseBlock
= NULL
;
334 LARGE_INTEGER TimeStamp
;
338 /* Get the hive header */
339 Result
= HvpGetHiveHeader(Hive
, &BaseBlock
, &TimeStamp
);
346 return STATUS_INSUFFICIENT_RESOURCES
;
352 return STATUS_NOT_REGISTRY_FILE
;
354 /* Has recovery data */
359 return STATUS_REGISTRY_CORRUPT
;
362 /* Set default boot type */
363 BaseBlock
->BootType
= 0;
365 /* Setup hive data */
366 Hive
->BaseBlock
= BaseBlock
;
367 Hive
->Version
= Hive
->BaseBlock
->Minor
;
369 /* Allocate a buffer large enough to hold the hive */
370 HiveData
= Hive
->Allocate(FileSize
, TRUE
, TAG_CM
);
371 if (!HiveData
) return STATUS_INSUFFICIENT_RESOURCES
;
373 /* Now read the whole hive */
374 Result
= Hive
->FileRead(Hive
,
379 if (!Result
) return STATUS_NOT_REGISTRY_FILE
;
382 /* Free our base block... it's usless in this implementation */
383 Hive
->Free(BaseBlock
, 0);
385 /* Initialize the hive directly from memory */
386 return HvpInitializeMemoryHive(Hive
, HiveData
);
392 * Allocate a new hive descriptor structure and intialize it.
394 * @param RegistryHive
395 * Output variable to store pointer to the hive descriptor.
397 * - HV_OPERATION_CREATE_HIVE
398 * Create a new hive for read/write access.
399 * - HV_OPERATION_MEMORY
400 * Load and copy in-memory hive for read/write access. The
401 * pointer to data passed to this routine can be freed after
402 * the function is executed.
403 * - HV_OPERATION_MEMORY_INPLACE
404 * Load an in-memory hive for read-only access. The pointer
405 * to data passed to this routine MUSTN'T be freed until
408 * Pointer to hive data.
410 * Size of passed hive data.
413 * STATUS_NO_MEMORY - A memory allocation failed.
414 * STATUS_REGISTRY_CORRUPT - Registry corruption was detected.
426 PVOID HiveData OPTIONAL
,
427 PALLOCATE_ROUTINE Allocate
,
429 PFILE_SET_SIZE_ROUTINE FileSetSize
,
430 PFILE_WRITE_ROUTINE FileWrite
,
431 PFILE_READ_ROUTINE FileRead
,
432 PFILE_FLUSH_ROUTINE FileFlush
,
433 ULONG Cluster OPTIONAL
,
434 PUNICODE_STRING FileName
)
437 PHHIVE Hive
= RegistryHive
;
439 UNREFERENCED_PARAMETER(HiveType
);
440 UNREFERENCED_PARAMETER(FileName
);
443 * Create a new hive structure that will hold all the maintenance data.
446 RtlZeroMemory(Hive
, sizeof(HHIVE
));
448 Hive
->Allocate
= Allocate
;
450 Hive
->FileRead
= FileRead
;
451 Hive
->FileWrite
= FileWrite
;
452 Hive
->FileSetSize
= FileSetSize
;
453 Hive
->FileFlush
= FileFlush
;
454 Hive
->StorageTypeCount
= HTYPE_COUNT
;
456 Hive
->Version
= HSYS_MINOR
;
457 Hive
->HiveFlags
= HiveFlags
&~ HIVE_NOLAZYFLUSH
;
462 Status
= HvpCreateHive(Hive
);
466 Status
= HvpInitializeMemoryHive(Hive
, HiveData
);
470 Status
= HvpInitializeMemoryInplaceHive(Hive
, HiveData
);
475 /* Hack of doom: Cluster is actually the file size. */
476 Status
= HvLoadHive(Hive
, Cluster
);
477 if ((Status
!= STATUS_SUCCESS
) &&
478 (Status
!= STATUS_REGISTRY_RECOVERED
))
480 /* Unrecoverable failure */
484 /* Check for previous damage */
485 if (Status
== STATUS_REGISTRY_RECOVERED
) ASSERT(FALSE
);
489 /* FIXME: A better return status value is needed */
490 Status
= STATUS_NOT_IMPLEMENTED
;
494 if (!NT_SUCCESS(Status
))
497 if (Operation
!= HINIT_CREATE
) CmPrepareHive(Hive
);
505 * Free all stroage and handles associated with hive descriptor.
512 if (!RegistryHive
->ReadOnly
)
514 /* Release hive bitmap */
515 if (RegistryHive
->DirtyVector
.Buffer
)
517 RegistryHive
->Free(RegistryHive
->DirtyVector
.Buffer
, 0);
520 HvpFreeHiveBins(RegistryHive
);
523 RegistryHive
->Free(RegistryHive
, 0);