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, expected 0x%x; Major: 0x%x, expected 0x%x\n",
33 BaseBlock
->Signature
, HV_SIGNATURE
, BaseBlock
->Major
, HSYS_MAJOR
);
34 DPRINT1(" Minor: 0x%x is not >= 0x%x; Type: 0x%x, expected 0x%x\n",
35 BaseBlock
->Minor
, HSYS_MINOR
, BaseBlock
->Type
, HFILE_TYPE_PRIMARY
);
36 DPRINT1(" Format: 0x%x, expected 0x%x; Cluster: 0x%x, expected 1\n",
37 BaseBlock
->Format
, HBASE_FORMAT_MEMORY
, BaseBlock
->Cluster
);
38 DPRINT1(" Sequence: 0x%x, expected 0x%x; Checksum: 0x%x, expected 0x%x\n",
39 BaseBlock
->Sequence1
, BaseBlock
->Sequence2
,
40 HvpHiveHeaderChecksum(BaseBlock
), BaseBlock
->CheckSum
);
49 * @name HvpFreeHiveBins
51 * Internal function to free all bin storage associated with hive
63 for (Storage
= Stable
; Storage
< HTYPE_COUNT
; Storage
++)
66 for (i
= 0; i
< Hive
->Storage
[Storage
].Length
; i
++)
68 if (Hive
->Storage
[Storage
].BlockList
[i
].BinAddress
== (ULONG_PTR
)NULL
)
70 if (Hive
->Storage
[Storage
].BlockList
[i
].BinAddress
!= (ULONG_PTR
)Bin
)
72 Bin
= (PHBIN
)Hive
->Storage
[Storage
].BlockList
[i
].BinAddress
;
73 Hive
->Free((PHBIN
)Hive
->Storage
[Storage
].BlockList
[i
].BinAddress
, 0);
75 Hive
->Storage
[Storage
].BlockList
[i
].BinAddress
= (ULONG_PTR
)NULL
;
76 Hive
->Storage
[Storage
].BlockList
[i
].BlockAddress
= (ULONG_PTR
)NULL
;
79 if (Hive
->Storage
[Storage
].Length
)
80 Hive
->Free(Hive
->Storage
[Storage
].BlockList
, 0);
87 * Internal helper function to initialize hive descriptor structure for
96 PCUNICODE_STRING FileName OPTIONAL
)
98 PHBASE_BLOCK BaseBlock
;
101 BaseBlock
= RegistryHive
->Allocate(sizeof(HBASE_BLOCK
), FALSE
, TAG_CM
);
102 if (BaseBlock
== NULL
)
103 return STATUS_NO_MEMORY
;
105 RtlZeroMemory(BaseBlock
, sizeof(HBASE_BLOCK
));
107 BaseBlock
->Signature
= HV_SIGNATURE
;
108 BaseBlock
->Major
= HSYS_MAJOR
;
109 BaseBlock
->Minor
= HSYS_MINOR
;
110 BaseBlock
->Type
= HFILE_TYPE_PRIMARY
;
111 BaseBlock
->Format
= HBASE_FORMAT_MEMORY
;
112 BaseBlock
->Cluster
= 1;
113 BaseBlock
->RootCell
= HCELL_NIL
;
114 BaseBlock
->Length
= 0;
115 BaseBlock
->Sequence1
= 1;
116 BaseBlock
->Sequence2
= 1;
118 /* Copy the 31 last characters of the hive file name if any */
121 if (FileName
->Length
/ sizeof(WCHAR
) <= 31)
123 RtlCopyMemory(BaseBlock
->FileName
,
129 RtlCopyMemory(BaseBlock
->FileName
,
130 FileName
->Buffer
+ FileName
->Length
/ sizeof(WCHAR
) - 31,
135 BaseBlock
->FileName
[31] = L
'\0';
138 BaseBlock
->CheckSum
= HvpHiveHeaderChecksum(BaseBlock
);
140 RegistryHive
->BaseBlock
= BaseBlock
;
141 for (Index
= 0; Index
< 24; Index
++)
143 RegistryHive
->Storage
[Stable
].FreeDisplay
[Index
] = HCELL_NIL
;
144 RegistryHive
->Storage
[Volatile
].FreeDisplay
[Index
] = HCELL_NIL
;
147 return STATUS_SUCCESS
;
151 * @name HvpInitializeMemoryHive
153 * Internal helper function to initialize hive descriptor structure for
154 * a hive stored in memory. The data of the hive are copied and it is
155 * prepared for read/write access.
161 HvpInitializeMemoryHive(
172 ChunkSize
= ((PHBASE_BLOCK
)ChunkBase
)->Length
;
173 DPRINT("ChunkSize: %lx\n", ChunkSize
);
175 if (ChunkSize
< sizeof(HBASE_BLOCK
) ||
176 !HvpVerifyHiveHeader((PHBASE_BLOCK
)ChunkBase
))
178 DPRINT1("Registry is corrupt: ChunkSize %lu < sizeof(HBASE_BLOCK) %lu, "
179 "or HvpVerifyHiveHeader() failed\n", ChunkSize
, (SIZE_T
)sizeof(HBASE_BLOCK
));
180 return STATUS_REGISTRY_CORRUPT
;
183 Hive
->BaseBlock
= Hive
->Allocate(sizeof(HBASE_BLOCK
), FALSE
, TAG_CM
);
184 if (Hive
->BaseBlock
== NULL
)
186 return STATUS_NO_MEMORY
;
188 RtlCopyMemory(Hive
->BaseBlock
, ChunkBase
, sizeof(HBASE_BLOCK
));
191 * Build a block list from the in-memory chunk and copy the data as
195 Hive
->Storage
[Stable
].Length
= (ULONG
)(ChunkSize
/ HV_BLOCK_SIZE
);
196 Hive
->Storage
[Stable
].BlockList
=
197 Hive
->Allocate(Hive
->Storage
[Stable
].Length
*
198 sizeof(HMAP_ENTRY
), FALSE
, TAG_CM
);
199 if (Hive
->Storage
[Stable
].BlockList
== NULL
)
201 DPRINT1("Allocating block list failed\n");
202 Hive
->Free(Hive
->BaseBlock
, 0);
203 return STATUS_NO_MEMORY
;
206 for (BlockIndex
= 0; BlockIndex
< Hive
->Storage
[Stable
].Length
; )
208 Bin
= (PHBIN
)((ULONG_PTR
)ChunkBase
+ (BlockIndex
+ 1) * HV_BLOCK_SIZE
);
209 if (Bin
->Signature
!= HV_BIN_SIGNATURE
||
210 (Bin
->Size
% HV_BLOCK_SIZE
) != 0)
212 Hive
->Free(Hive
->BaseBlock
, 0);
213 Hive
->Free(Hive
->Storage
[Stable
].BlockList
, 0);
214 return STATUS_REGISTRY_CORRUPT
;
217 NewBin
= Hive
->Allocate(Bin
->Size
, TRUE
, TAG_CM
);
220 Hive
->Free(Hive
->BaseBlock
, 0);
221 Hive
->Free(Hive
->Storage
[Stable
].BlockList
, 0);
222 return STATUS_NO_MEMORY
;
225 Hive
->Storage
[Stable
].BlockList
[BlockIndex
].BinAddress
= (ULONG_PTR
)NewBin
;
226 Hive
->Storage
[Stable
].BlockList
[BlockIndex
].BlockAddress
= (ULONG_PTR
)NewBin
;
228 RtlCopyMemory(NewBin
, Bin
, Bin
->Size
);
230 if (Bin
->Size
> HV_BLOCK_SIZE
)
232 for (i
= 1; i
< Bin
->Size
/ HV_BLOCK_SIZE
; i
++)
234 Hive
->Storage
[Stable
].BlockList
[BlockIndex
+ i
].BinAddress
= (ULONG_PTR
)NewBin
;
235 Hive
->Storage
[Stable
].BlockList
[BlockIndex
+ i
].BlockAddress
=
236 ((ULONG_PTR
)NewBin
+ (i
* HV_BLOCK_SIZE
));
240 BlockIndex
+= Bin
->Size
/ HV_BLOCK_SIZE
;
243 if (HvpCreateHiveFreeCellList(Hive
))
245 HvpFreeHiveBins(Hive
);
246 Hive
->Free(Hive
->BaseBlock
, 0);
247 return STATUS_NO_MEMORY
;
250 BitmapSize
= ROUND_UP(Hive
->Storage
[Stable
].Length
,
251 sizeof(ULONG
) * 8) / 8;
252 BitmapBuffer
= (PULONG
)Hive
->Allocate(BitmapSize
, TRUE
, TAG_CM
);
253 if (BitmapBuffer
== NULL
)
255 HvpFreeHiveBins(Hive
);
256 Hive
->Free(Hive
->BaseBlock
, 0);
257 return STATUS_NO_MEMORY
;
260 RtlInitializeBitMap(&Hive
->DirtyVector
, BitmapBuffer
, BitmapSize
* 8);
261 RtlClearAllBits(&Hive
->DirtyVector
);
263 return STATUS_SUCCESS
;
267 * @name HvpInitializeMemoryInplaceHive
269 * Internal helper function to initialize hive descriptor structure for
270 * a hive stored in memory. The in-memory data of the hive are directly
271 * used and it is read-only accessible.
277 HvpInitializeMemoryInplaceHive(
281 if (!HvpVerifyHiveHeader((PHBASE_BLOCK
)ChunkBase
))
283 return STATUS_REGISTRY_CORRUPT
;
286 Hive
->BaseBlock
= (PHBASE_BLOCK
)ChunkBase
;
287 Hive
->ReadOnly
= TRUE
;
290 return STATUS_SUCCESS
;
305 HvpGetHiveHeader(IN PHHIVE Hive
,
306 IN PHBASE_BLOCK
*HiveBaseBlock
,
307 IN PLARGE_INTEGER TimeStamp
)
309 PHBASE_BLOCK BaseBlock
;
313 ASSERT(sizeof(HBASE_BLOCK
) >= (HV_BLOCK_SIZE
* Hive
->Cluster
));
315 /* Assume failure and allocate the buffer */
317 BaseBlock
= Hive
->Allocate(sizeof(HBASE_BLOCK
), TRUE
, TAG_CM
);
318 if (!BaseBlock
) return NoMemory
;
320 /* Check for, and enforce, alignment */
321 Alignment
= Hive
->Cluster
* HV_BLOCK_SIZE
-1;
322 if ((ULONG_PTR
)BaseBlock
& Alignment
)
324 /* Free the old header */
325 Hive
->Free(BaseBlock
, 0);
326 BaseBlock
= Hive
->Allocate(PAGE_SIZE
, TRUE
, TAG_CM
);
327 if (!BaseBlock
) return NoMemory
;
331 RtlZeroMemory(BaseBlock
, sizeof(HBASE_BLOCK
));
333 /* Now read it from disk */
334 Result
= Hive
->FileRead(Hive
,
338 Hive
->Cluster
* HV_BLOCK_SIZE
);
340 /* Couldn't read: assume it's not a hive */
341 if (!Result
) return NotHive
;
344 if (!HvpVerifyHiveHeader(BaseBlock
)) return NotHive
;
346 /* Return information */
347 *HiveBaseBlock
= BaseBlock
;
348 *TimeStamp
= BaseBlock
->TimeStamp
;
353 HvLoadHive(IN PHHIVE Hive
,
356 PHBASE_BLOCK BaseBlock
= NULL
;
358 LARGE_INTEGER TimeStamp
;
362 /* Get the hive header */
363 Result
= HvpGetHiveHeader(Hive
, &BaseBlock
, &TimeStamp
);
370 return STATUS_INSUFFICIENT_RESOURCES
;
376 return STATUS_NOT_REGISTRY_FILE
;
378 /* Has recovery data */
383 return STATUS_REGISTRY_CORRUPT
;
386 /* Set default boot type */
387 BaseBlock
->BootType
= 0;
389 /* Setup hive data */
390 Hive
->BaseBlock
= BaseBlock
;
391 Hive
->Version
= Hive
->BaseBlock
->Minor
;
393 /* Allocate a buffer large enough to hold the hive */
394 HiveData
= Hive
->Allocate(FileSize
, TRUE
, TAG_CM
);
395 if (!HiveData
) return STATUS_INSUFFICIENT_RESOURCES
;
397 /* Now read the whole hive */
398 Result
= Hive
->FileRead(Hive
,
403 if (!Result
) return STATUS_NOT_REGISTRY_FILE
;
406 /* Free our base block... it's usless in this implementation */
407 Hive
->Free(BaseBlock
, 0);
409 /* Initialize the hive directly from memory */
410 return HvpInitializeMemoryHive(Hive
, HiveData
);
416 * Allocate a new hive descriptor structure and intialize it.
418 * @param RegistryHive
419 * Output variable to store pointer to the hive descriptor.
421 * - HV_OPERATION_CREATE_HIVE
422 * Create a new hive for read/write access.
423 * - HV_OPERATION_MEMORY
424 * Load and copy in-memory hive for read/write access. The
425 * pointer to data passed to this routine can be freed after
426 * the function is executed.
427 * - HV_OPERATION_MEMORY_INPLACE
428 * Load an in-memory hive for read-only access. The pointer
429 * to data passed to this routine MUSTN'T be freed until
432 * Pointer to hive data.
434 * Size of passed hive data.
437 * STATUS_NO_MEMORY - A memory allocation failed.
438 * STATUS_REGISTRY_CORRUPT - Registry corruption was detected.
450 PVOID HiveData OPTIONAL
,
451 PALLOCATE_ROUTINE Allocate
,
453 PFILE_SET_SIZE_ROUTINE FileSetSize
,
454 PFILE_WRITE_ROUTINE FileWrite
,
455 PFILE_READ_ROUTINE FileRead
,
456 PFILE_FLUSH_ROUTINE FileFlush
,
457 ULONG Cluster OPTIONAL
,
458 PCUNICODE_STRING FileName OPTIONAL
)
461 PHHIVE Hive
= RegistryHive
;
463 UNREFERENCED_PARAMETER(HiveType
);
466 * Create a new hive structure that will hold all the maintenance data.
469 RtlZeroMemory(Hive
, sizeof(HHIVE
));
471 Hive
->Allocate
= Allocate
;
473 Hive
->FileRead
= FileRead
;
474 Hive
->FileWrite
= FileWrite
;
475 Hive
->FileSetSize
= FileSetSize
;
476 Hive
->FileFlush
= FileFlush
;
477 Hive
->StorageTypeCount
= HTYPE_COUNT
;
479 Hive
->Version
= HSYS_MINOR
;
480 Hive
->HiveFlags
= HiveFlags
&~ HIVE_NOLAZYFLUSH
;
485 Status
= HvpCreateHive(Hive
, FileName
);
489 Status
= HvpInitializeMemoryHive(Hive
, HiveData
);
493 Status
= HvpInitializeMemoryInplaceHive(Hive
, HiveData
);
498 /* HACK of doom: Cluster is actually the file size. */
499 Status
= HvLoadHive(Hive
, Cluster
);
500 if ((Status
!= STATUS_SUCCESS
) &&
501 (Status
!= STATUS_REGISTRY_RECOVERED
))
503 /* Unrecoverable failure */
507 /* Check for previous damage */
508 if (Status
== STATUS_REGISTRY_RECOVERED
) ASSERT(FALSE
);
513 /* FIXME: A better return status value is needed */
514 Status
= STATUS_NOT_IMPLEMENTED
;
518 if (!NT_SUCCESS(Status
)) return Status
;
520 if (Operation
!= HINIT_CREATE
) CmPrepareHive(Hive
);
528 * Free all stroage and handles associated with hive descriptor.
535 if (!RegistryHive
->ReadOnly
)
537 /* Release hive bitmap */
538 if (RegistryHive
->DirtyVector
.Buffer
)
540 RegistryHive
->Free(RegistryHive
->DirtyVector
.Buffer
, 0);
543 HvpFreeHiveBins(RegistryHive
);
546 RegistryHive
->Free(RegistryHive
, 0);