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 initalize 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
= HV_BLOCK_SIZE
;
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 initalize 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(
149 // This hack is similar in magnitude to the US's National Debt
151 ChunkSize
= ((PHBASE_BLOCK
)ChunkBase
)->Length
;
152 ((PHBASE_BLOCK
)ChunkBase
)->Length
= HV_BLOCK_SIZE
;
153 DPRINT("ChunkSize: %lx\n", ChunkSize
);
155 if (ChunkSize
< sizeof(HBASE_BLOCK
) ||
156 !HvpVerifyHiveHeader((PHBASE_BLOCK
)ChunkBase
))
158 DPRINT1("Registry is corrupt: ChunkSize %lu < sizeof(HBASE_BLOCK) %lu, "
159 "or HvpVerifyHiveHeader() failed\n", ChunkSize
, (SIZE_T
)sizeof(HBASE_BLOCK
));
160 return STATUS_REGISTRY_CORRUPT
;
163 Hive
->BaseBlock
= Hive
->Allocate(sizeof(HBASE_BLOCK
), FALSE
, TAG_CM
);
164 if (Hive
->BaseBlock
== NULL
)
166 return STATUS_NO_MEMORY
;
168 RtlCopyMemory(Hive
->BaseBlock
, ChunkBase
, sizeof(HBASE_BLOCK
));
171 * Build a block list from the in-memory chunk and copy the data as
175 Hive
->Storage
[Stable
].Length
= (ULONG
)(ChunkSize
/ HV_BLOCK_SIZE
) - 1;
176 Hive
->Storage
[Stable
].BlockList
=
177 Hive
->Allocate(Hive
->Storage
[Stable
].Length
*
178 sizeof(HMAP_ENTRY
), FALSE
, TAG_CM
);
179 if (Hive
->Storage
[Stable
].BlockList
== NULL
)
181 DPRINT1("Allocating block list failed\n");
182 Hive
->Free(Hive
->BaseBlock
, 0);
183 return STATUS_NO_MEMORY
;
186 for (BlockIndex
= 0; BlockIndex
< Hive
->Storage
[Stable
].Length
; )
188 Bin
= (PHBIN
)((ULONG_PTR
)ChunkBase
+ (BlockIndex
+ 1) * HV_BLOCK_SIZE
);
189 if (Bin
->Signature
!= HV_BIN_SIGNATURE
||
190 (Bin
->Size
% HV_BLOCK_SIZE
) != 0)
192 Hive
->Free(Hive
->BaseBlock
, 0);
193 Hive
->Free(Hive
->Storage
[Stable
].BlockList
, 0);
194 return STATUS_REGISTRY_CORRUPT
;
197 NewBin
= Hive
->Allocate(Bin
->Size
, TRUE
, TAG_CM
);
200 Hive
->Free(Hive
->BaseBlock
, 0);
201 Hive
->Free(Hive
->Storage
[Stable
].BlockList
, 0);
202 return STATUS_NO_MEMORY
;
205 Hive
->Storage
[Stable
].BlockList
[BlockIndex
].BinAddress
= (ULONG_PTR
)NewBin
;
206 Hive
->Storage
[Stable
].BlockList
[BlockIndex
].BlockAddress
= (ULONG_PTR
)NewBin
;
208 RtlCopyMemory(NewBin
, Bin
, Bin
->Size
);
210 if (Bin
->Size
> HV_BLOCK_SIZE
)
212 for (i
= 1; i
< Bin
->Size
/ HV_BLOCK_SIZE
; i
++)
214 Hive
->Storage
[Stable
].BlockList
[BlockIndex
+ i
].BinAddress
= (ULONG_PTR
)NewBin
;
215 Hive
->Storage
[Stable
].BlockList
[BlockIndex
+ i
].BlockAddress
=
216 ((ULONG_PTR
)NewBin
+ (i
* HV_BLOCK_SIZE
));
220 BlockIndex
+= Bin
->Size
/ HV_BLOCK_SIZE
;
223 if (HvpCreateHiveFreeCellList(Hive
))
225 HvpFreeHiveBins(Hive
);
226 Hive
->Free(Hive
->BaseBlock
, 0);
227 return STATUS_NO_MEMORY
;
230 BitmapSize
= ROUND_UP(Hive
->Storage
[Stable
].Length
,
231 sizeof(ULONG
) * 8) / 8;
232 BitmapBuffer
= (PULONG
)Hive
->Allocate(BitmapSize
, TRUE
, TAG_CM
);
233 if (BitmapBuffer
== NULL
)
235 HvpFreeHiveBins(Hive
);
236 Hive
->Free(Hive
->BaseBlock
, 0);
237 return STATUS_NO_MEMORY
;
240 RtlInitializeBitMap(&Hive
->DirtyVector
, BitmapBuffer
, BitmapSize
* 8);
241 RtlClearAllBits(&Hive
->DirtyVector
);
243 return STATUS_SUCCESS
;
247 * @name HvpInitializeMemoryInplaceHive
249 * Internal helper function to initalize hive descriptor structure for
250 * a hive stored in memory. The in-memory data of the hive are directly
251 * used and it is read-only accessible.
257 HvpInitializeMemoryInplaceHive(
261 if (!HvpVerifyHiveHeader((PHBASE_BLOCK
)ChunkBase
))
263 return STATUS_REGISTRY_CORRUPT
;
266 Hive
->BaseBlock
= (PHBASE_BLOCK
)ChunkBase
;
267 Hive
->ReadOnly
= TRUE
;
270 return STATUS_SUCCESS
;
285 HvpGetHiveHeader(IN PHHIVE Hive
,
286 IN PHBASE_BLOCK
*HiveBaseBlock
,
287 IN PLARGE_INTEGER TimeStamp
)
289 PHBASE_BLOCK BaseBlock
;
293 ASSERT(sizeof(HBASE_BLOCK
) >= (HV_BLOCK_SIZE
* Hive
->Cluster
));
295 /* Assume failure and allocate the buffer */
297 BaseBlock
= Hive
->Allocate(sizeof(HBASE_BLOCK
), TRUE
, TAG_CM
);
298 if (!BaseBlock
) return NoMemory
;
300 /* Check for, and enforce, alignment */
301 Alignment
= Hive
->Cluster
* HV_BLOCK_SIZE
-1;
302 if ((ULONG_PTR
)BaseBlock
& Alignment
)
304 /* Free the old header */
305 Hive
->Free(BaseBlock
, 0);
306 BaseBlock
= Hive
->Allocate(PAGE_SIZE
, TRUE
, TAG_CM
);
307 if (!BaseBlock
) return NoMemory
;
309 //BaseBlock->Length = PAGE_SIZE; ??
313 RtlZeroMemory(BaseBlock
, sizeof(HBASE_BLOCK
));
315 /* Now read it from disk */
316 Result
= Hive
->FileRead(Hive
,
320 Hive
->Cluster
* HV_BLOCK_SIZE
);
322 /* Couldn't read: assume it's not a hive */
323 if (!Result
) return NotHive
;
326 if (!HvpVerifyHiveHeader(BaseBlock
)) return NotHive
;
328 /* Return information */
329 *HiveBaseBlock
= BaseBlock
;
330 *TimeStamp
= BaseBlock
->TimeStamp
;
335 HvLoadHive(IN PHHIVE Hive
,
338 PHBASE_BLOCK BaseBlock
= NULL
;
340 LARGE_INTEGER TimeStamp
;
344 /* Get the hive header */
345 Result
= HvpGetHiveHeader(Hive
, &BaseBlock
, &TimeStamp
);
352 return STATUS_INSUFFICIENT_RESOURCES
;
358 return STATUS_NOT_REGISTRY_FILE
;
360 /* Has recovery data */
365 return STATUS_REGISTRY_CORRUPT
;
368 /* Set default boot type */
369 BaseBlock
->BootType
= 0;
371 /* Setup hive data */
372 Hive
->BaseBlock
= BaseBlock
;
373 Hive
->Version
= Hive
->BaseBlock
->Minor
;
375 /* Allocate a buffer large enough to hold the hive */
376 HiveData
= Hive
->Allocate(FileSize
, TRUE
, TAG_CM
);
377 if (!HiveData
) return STATUS_INSUFFICIENT_RESOURCES
;
379 /* Now read the whole hive */
380 Result
= Hive
->FileRead(Hive
,
385 if (!Result
) return STATUS_NOT_REGISTRY_FILE
;
387 /* Apply "US National Debt" hack */
388 ((PHBASE_BLOCK
)HiveData
)->Length
= FileSize
;
390 /* Free our base block... it's usless in this implementation */
391 Hive
->Free(BaseBlock
, 0);
393 /* Initialize the hive directly from memory */
394 return HvpInitializeMemoryHive(Hive
, HiveData
);
400 * Allocate a new hive descriptor structure and intialize it.
402 * @param RegistryHive
403 * Output variable to store pointer to the hive descriptor.
405 * - HV_OPERATION_CREATE_HIVE
406 * Create a new hive for read/write access.
407 * - HV_OPERATION_MEMORY
408 * Load and copy in-memory hive for read/write access. The
409 * pointer to data passed to this routine can be freed after
410 * the function is executed.
411 * - HV_OPERATION_MEMORY_INPLACE
412 * Load an in-memory hive for read-only access. The pointer
413 * to data passed to this routine MUSTN'T be freed until
416 * Pointer to hive data.
418 * Size of passed hive data.
421 * STATUS_NO_MEMORY - A memory allocation failed.
422 * STATUS_REGISTRY_CORRUPT - Registry corruption was detected.
434 PVOID HiveData OPTIONAL
,
435 PALLOCATE_ROUTINE Allocate
,
437 PFILE_SET_SIZE_ROUTINE FileSetSize
,
438 PFILE_WRITE_ROUTINE FileWrite
,
439 PFILE_READ_ROUTINE FileRead
,
440 PFILE_FLUSH_ROUTINE FileFlush
,
441 ULONG Cluster OPTIONAL
,
442 PUNICODE_STRING FileName
)
445 PHHIVE Hive
= RegistryHive
;
447 UNREFERENCED_PARAMETER(HiveType
);
448 UNREFERENCED_PARAMETER(FileName
);
451 * Create a new hive structure that will hold all the maintenance data.
454 RtlZeroMemory(Hive
, sizeof(HHIVE
));
456 Hive
->Allocate
= Allocate
;
458 Hive
->FileRead
= FileRead
;
459 Hive
->FileWrite
= FileWrite
;
460 Hive
->FileSetSize
= FileSetSize
;
461 Hive
->FileFlush
= FileFlush
;
462 Hive
->StorageTypeCount
= HTYPE_COUNT
;
464 Hive
->Version
= HSYS_MINOR
;
465 Hive
->HiveFlags
= HiveFlags
&~ HIVE_NOLAZYFLUSH
;
470 Status
= HvpCreateHive(Hive
);
474 Status
= HvpInitializeMemoryHive(Hive
, HiveData
);
478 Status
= HvpInitializeMemoryInplaceHive(Hive
, HiveData
);
483 /* Hack of doom: Cluster is actually the file size. */
484 Status
= HvLoadHive(Hive
, Cluster
);
485 if ((Status
!= STATUS_SUCCESS
) &&
486 (Status
!= STATUS_REGISTRY_RECOVERED
))
488 /* Unrecoverable failure */
492 /* Check for previous damage */
493 if (Status
== STATUS_REGISTRY_RECOVERED
) ASSERT(FALSE
);
497 /* FIXME: A better return status value is needed */
498 Status
= STATUS_NOT_IMPLEMENTED
;
502 if (!NT_SUCCESS(Status
))
505 if (Operation
!= HINIT_CREATE
) CmPrepareHive(Hive
);
513 * Free all stroage and handles associated with hive descriptor.
520 if (!RegistryHive
->ReadOnly
)
522 /* Release hive bitmap */
523 if (RegistryHive
->DirtyVector
.Buffer
)
525 RegistryHive
->Free(RegistryHive
->DirtyVector
.Buffer
, 0);
528 HvpFreeHiveBins(RegistryHive
);
531 RegistryHive
->Free(RegistryHive
, 0);