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
) <= HIVE_FILENAME_MAXLEN
)
123 RtlCopyMemory(BaseBlock
->FileName
,
129 RtlCopyMemory(BaseBlock
->FileName
,
131 FileName
->Length
/ sizeof(WCHAR
) - HIVE_FILENAME_MAXLEN
,
132 HIVE_FILENAME_MAXLEN
* sizeof(WCHAR
));
136 BaseBlock
->FileName
[HIVE_FILENAME_MAXLEN
] = L
'\0';
139 BaseBlock
->CheckSum
= HvpHiveHeaderChecksum(BaseBlock
);
141 RegistryHive
->BaseBlock
= BaseBlock
;
142 for (Index
= 0; Index
< 24; Index
++)
144 RegistryHive
->Storage
[Stable
].FreeDisplay
[Index
] = HCELL_NIL
;
145 RegistryHive
->Storage
[Volatile
].FreeDisplay
[Index
] = HCELL_NIL
;
148 return STATUS_SUCCESS
;
152 * @name HvpInitializeMemoryHive
154 * Internal helper function to initialize hive descriptor structure for
155 * a hive stored in memory. The data of the hive are copied and it is
156 * prepared for read/write access.
162 HvpInitializeMemoryHive(
173 ChunkSize
= ((PHBASE_BLOCK
)ChunkBase
)->Length
;
174 DPRINT("ChunkSize: %lx\n", ChunkSize
);
176 if (ChunkSize
< sizeof(HBASE_BLOCK
) ||
177 !HvpVerifyHiveHeader((PHBASE_BLOCK
)ChunkBase
))
179 DPRINT1("Registry is corrupt: ChunkSize %lu < sizeof(HBASE_BLOCK) %lu, "
180 "or HvpVerifyHiveHeader() failed\n", ChunkSize
, (SIZE_T
)sizeof(HBASE_BLOCK
));
181 return STATUS_REGISTRY_CORRUPT
;
184 Hive
->BaseBlock
= Hive
->Allocate(sizeof(HBASE_BLOCK
), FALSE
, TAG_CM
);
185 if (Hive
->BaseBlock
== NULL
)
187 return STATUS_NO_MEMORY
;
189 RtlCopyMemory(Hive
->BaseBlock
, ChunkBase
, sizeof(HBASE_BLOCK
));
192 * Build a block list from the in-memory chunk and copy the data as
196 Hive
->Storage
[Stable
].Length
= (ULONG
)(ChunkSize
/ HV_BLOCK_SIZE
);
197 Hive
->Storage
[Stable
].BlockList
=
198 Hive
->Allocate(Hive
->Storage
[Stable
].Length
*
199 sizeof(HMAP_ENTRY
), FALSE
, TAG_CM
);
200 if (Hive
->Storage
[Stable
].BlockList
== NULL
)
202 DPRINT1("Allocating block list failed\n");
203 Hive
->Free(Hive
->BaseBlock
, 0);
204 return STATUS_NO_MEMORY
;
207 for (BlockIndex
= 0; BlockIndex
< Hive
->Storage
[Stable
].Length
; )
209 Bin
= (PHBIN
)((ULONG_PTR
)ChunkBase
+ (BlockIndex
+ 1) * HV_BLOCK_SIZE
);
210 if (Bin
->Signature
!= HV_BIN_SIGNATURE
||
211 (Bin
->Size
% HV_BLOCK_SIZE
) != 0)
213 DPRINT1("Invalid bin at BlockIndex %lu, Signature 0x%x, Size 0x%x\n",
214 (unsigned long)BlockIndex
, (unsigned)Bin
->Signature
, (unsigned)Bin
->Size
);
215 Hive
->Free(Hive
->BaseBlock
, 0);
216 Hive
->Free(Hive
->Storage
[Stable
].BlockList
, 0);
217 return STATUS_REGISTRY_CORRUPT
;
220 NewBin
= Hive
->Allocate(Bin
->Size
, TRUE
, TAG_CM
);
223 Hive
->Free(Hive
->BaseBlock
, 0);
224 Hive
->Free(Hive
->Storage
[Stable
].BlockList
, 0);
225 return STATUS_NO_MEMORY
;
228 Hive
->Storage
[Stable
].BlockList
[BlockIndex
].BinAddress
= (ULONG_PTR
)NewBin
;
229 Hive
->Storage
[Stable
].BlockList
[BlockIndex
].BlockAddress
= (ULONG_PTR
)NewBin
;
231 RtlCopyMemory(NewBin
, Bin
, Bin
->Size
);
233 if (Bin
->Size
> HV_BLOCK_SIZE
)
235 for (i
= 1; i
< Bin
->Size
/ HV_BLOCK_SIZE
; i
++)
237 Hive
->Storage
[Stable
].BlockList
[BlockIndex
+ i
].BinAddress
= (ULONG_PTR
)NewBin
;
238 Hive
->Storage
[Stable
].BlockList
[BlockIndex
+ i
].BlockAddress
=
239 ((ULONG_PTR
)NewBin
+ (i
* HV_BLOCK_SIZE
));
243 BlockIndex
+= Bin
->Size
/ HV_BLOCK_SIZE
;
246 if (HvpCreateHiveFreeCellList(Hive
))
248 HvpFreeHiveBins(Hive
);
249 Hive
->Free(Hive
->BaseBlock
, 0);
250 return STATUS_NO_MEMORY
;
253 BitmapSize
= ROUND_UP(Hive
->Storage
[Stable
].Length
,
254 sizeof(ULONG
) * 8) / 8;
255 BitmapBuffer
= (PULONG
)Hive
->Allocate(BitmapSize
, TRUE
, TAG_CM
);
256 if (BitmapBuffer
== NULL
)
258 HvpFreeHiveBins(Hive
);
259 Hive
->Free(Hive
->BaseBlock
, 0);
260 return STATUS_NO_MEMORY
;
263 RtlInitializeBitMap(&Hive
->DirtyVector
, BitmapBuffer
, BitmapSize
* 8);
264 RtlClearAllBits(&Hive
->DirtyVector
);
266 return STATUS_SUCCESS
;
270 * @name HvpInitializeMemoryInplaceHive
272 * Internal helper function to initialize hive descriptor structure for
273 * a hive stored in memory. The in-memory data of the hive are directly
274 * used and it is read-only accessible.
280 HvpInitializeMemoryInplaceHive(
284 if (!HvpVerifyHiveHeader((PHBASE_BLOCK
)ChunkBase
))
286 return STATUS_REGISTRY_CORRUPT
;
289 Hive
->BaseBlock
= (PHBASE_BLOCK
)ChunkBase
;
290 Hive
->ReadOnly
= TRUE
;
293 return STATUS_SUCCESS
;
308 HvpGetHiveHeader(IN PHHIVE Hive
,
309 IN PHBASE_BLOCK
*HiveBaseBlock
,
310 IN PLARGE_INTEGER TimeStamp
)
312 PHBASE_BLOCK BaseBlock
;
316 ASSERT(sizeof(HBASE_BLOCK
) >= (HV_BLOCK_SIZE
* Hive
->Cluster
));
318 /* Assume failure and allocate the buffer */
320 BaseBlock
= Hive
->Allocate(sizeof(HBASE_BLOCK
), TRUE
, TAG_CM
);
321 if (!BaseBlock
) return NoMemory
;
323 /* Check for, and enforce, alignment */
324 Alignment
= Hive
->Cluster
* HV_BLOCK_SIZE
-1;
325 if ((ULONG_PTR
)BaseBlock
& Alignment
)
327 /* Free the old header */
328 Hive
->Free(BaseBlock
, 0);
329 BaseBlock
= Hive
->Allocate(PAGE_SIZE
, TRUE
, TAG_CM
);
330 if (!BaseBlock
) return NoMemory
;
334 RtlZeroMemory(BaseBlock
, sizeof(HBASE_BLOCK
));
336 /* Now read it from disk */
337 Result
= Hive
->FileRead(Hive
,
341 Hive
->Cluster
* HV_BLOCK_SIZE
);
343 /* Couldn't read: assume it's not a hive */
344 if (!Result
) return NotHive
;
347 if (!HvpVerifyHiveHeader(BaseBlock
)) return NotHive
;
349 /* Return information */
350 *HiveBaseBlock
= BaseBlock
;
351 *TimeStamp
= BaseBlock
->TimeStamp
;
356 HvLoadHive(IN PHHIVE Hive
,
359 PHBASE_BLOCK BaseBlock
= NULL
;
361 LARGE_INTEGER TimeStamp
;
365 /* Get the hive header */
366 Result
= HvpGetHiveHeader(Hive
, &BaseBlock
, &TimeStamp
);
373 return STATUS_INSUFFICIENT_RESOURCES
;
379 return STATUS_NOT_REGISTRY_FILE
;
381 /* Has recovery data */
386 return STATUS_REGISTRY_CORRUPT
;
389 /* Set default boot type */
390 BaseBlock
->BootType
= 0;
392 /* Setup hive data */
393 Hive
->BaseBlock
= BaseBlock
;
394 Hive
->Version
= Hive
->BaseBlock
->Minor
;
396 /* Allocate a buffer large enough to hold the hive */
397 HiveData
= Hive
->Allocate(FileSize
, TRUE
, TAG_CM
);
398 if (!HiveData
) return STATUS_INSUFFICIENT_RESOURCES
;
400 /* Now read the whole hive */
401 Result
= Hive
->FileRead(Hive
,
406 if (!Result
) return STATUS_NOT_REGISTRY_FILE
;
409 /* Free our base block... it's usless in this implementation */
410 Hive
->Free(BaseBlock
, 0);
412 /* Initialize the hive directly from memory */
413 return HvpInitializeMemoryHive(Hive
, HiveData
);
419 * Allocate a new hive descriptor structure and intialize it.
421 * @param RegistryHive
422 * Output variable to store pointer to the hive descriptor.
424 * - HV_OPERATION_CREATE_HIVE
425 * Create a new hive for read/write access.
426 * - HV_OPERATION_MEMORY
427 * Load and copy in-memory hive for read/write access. The
428 * pointer to data passed to this routine can be freed after
429 * the function is executed.
430 * - HV_OPERATION_MEMORY_INPLACE
431 * Load an in-memory hive for read-only access. The pointer
432 * to data passed to this routine MUSTN'T be freed until
435 * Pointer to hive data.
437 * Size of passed hive data.
440 * STATUS_NO_MEMORY - A memory allocation failed.
441 * STATUS_REGISTRY_CORRUPT - Registry corruption was detected.
453 PVOID HiveData OPTIONAL
,
454 PALLOCATE_ROUTINE Allocate
,
456 PFILE_SET_SIZE_ROUTINE FileSetSize
,
457 PFILE_WRITE_ROUTINE FileWrite
,
458 PFILE_READ_ROUTINE FileRead
,
459 PFILE_FLUSH_ROUTINE FileFlush
,
460 ULONG Cluster OPTIONAL
,
461 PCUNICODE_STRING FileName OPTIONAL
)
464 PHHIVE Hive
= RegistryHive
;
466 UNREFERENCED_PARAMETER(HiveType
);
469 * Create a new hive structure that will hold all the maintenance data.
472 RtlZeroMemory(Hive
, sizeof(HHIVE
));
474 Hive
->Allocate
= Allocate
;
476 Hive
->FileRead
= FileRead
;
477 Hive
->FileWrite
= FileWrite
;
478 Hive
->FileSetSize
= FileSetSize
;
479 Hive
->FileFlush
= FileFlush
;
480 Hive
->StorageTypeCount
= HTYPE_COUNT
;
482 Hive
->Version
= HSYS_MINOR
;
483 Hive
->HiveFlags
= HiveFlags
&~ HIVE_NOLAZYFLUSH
;
488 Status
= HvpCreateHive(Hive
, FileName
);
492 Status
= HvpInitializeMemoryHive(Hive
, HiveData
);
496 Status
= HvpInitializeMemoryInplaceHive(Hive
, HiveData
);
501 /* HACK of doom: Cluster is actually the file size. */
502 Status
= HvLoadHive(Hive
, Cluster
);
503 if ((Status
!= STATUS_SUCCESS
) &&
504 (Status
!= STATUS_REGISTRY_RECOVERED
))
506 /* Unrecoverable failure */
510 /* Check for previous damage */
511 ASSERT(Status
!= STATUS_REGISTRY_RECOVERED
);
516 /* FIXME: A better return status value is needed */
517 Status
= STATUS_NOT_IMPLEMENTED
;
521 if (!NT_SUCCESS(Status
)) return Status
;
523 if (Operation
!= HINIT_CREATE
) CmPrepareHive(Hive
);
531 * Free all stroage and handles associated with hive descriptor.
538 if (!RegistryHive
->ReadOnly
)
540 /* Release hive bitmap */
541 if (RegistryHive
->DirtyVector
.Buffer
)
543 RegistryHive
->Free(RegistryHive
->DirtyVector
.Buffer
, 0);
546 HvpFreeHiveBins(RegistryHive
);
549 RegistryHive
->Free(RegistryHive
, 0);