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
;
122 RtlInitializeBitMap(&RegistryHive
->DirtyVector
, NULL
, 0);
124 return STATUS_SUCCESS
;
128 * @name HvpInitializeMemoryHive
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.
138 HvpInitializeMemoryHive(
150 // This hack is similar in magnitude to the US's National Debt
152 ChunkSize
= ((PHBASE_BLOCK
)ChunkBase
)->Length
;
153 ((PHBASE_BLOCK
)ChunkBase
)->Length
= HV_BLOCK_SIZE
;
154 DPRINT("ChunkSize: %lx\n", ChunkSize
);
156 if (ChunkSize
< sizeof(HBASE_BLOCK
) ||
157 !HvpVerifyHiveHeader((PHBASE_BLOCK
)ChunkBase
))
159 DPRINT1("Registry is corrupt: ChunkSize %lu < sizeof(HBASE_BLOCK) %lu, "
160 "or HvpVerifyHiveHeader() failed\n", ChunkSize
, (SIZE_T
)sizeof(HBASE_BLOCK
));
161 return STATUS_REGISTRY_CORRUPT
;
164 Hive
->BaseBlock
= Hive
->Allocate(sizeof(HBASE_BLOCK
), FALSE
, TAG_CM
);
165 if (Hive
->BaseBlock
== NULL
)
167 return STATUS_NO_MEMORY
;
169 RtlCopyMemory(Hive
->BaseBlock
, ChunkBase
, sizeof(HBASE_BLOCK
));
172 * Build a block list from the in-memory chunk and copy the data as
176 Hive
->Storage
[Stable
].Length
= (ULONG
)(ChunkSize
/ HV_BLOCK_SIZE
) - 1;
177 Hive
->Storage
[Stable
].BlockList
=
178 Hive
->Allocate(Hive
->Storage
[Stable
].Length
*
179 sizeof(HMAP_ENTRY
), FALSE
, TAG_CM
);
180 if (Hive
->Storage
[Stable
].BlockList
== NULL
)
182 DPRINT1("Allocating block list failed\n");
183 Hive
->Free(Hive
->BaseBlock
, 0);
184 return STATUS_NO_MEMORY
;
187 for (BlockIndex
= 0; BlockIndex
< Hive
->Storage
[Stable
].Length
; )
189 Bin
= (PHBIN
)((ULONG_PTR
)ChunkBase
+ (BlockIndex
+ 1) * HV_BLOCK_SIZE
);
190 if (Bin
->Signature
!= HV_BIN_SIGNATURE
||
191 (Bin
->Size
% HV_BLOCK_SIZE
) != 0)
193 Hive
->Free(Hive
->BaseBlock
, 0);
194 Hive
->Free(Hive
->Storage
[Stable
].BlockList
, 0);
195 return STATUS_REGISTRY_CORRUPT
;
198 NewBin
= Hive
->Allocate(Bin
->Size
, TRUE
, TAG_CM
);
201 Hive
->Free(Hive
->BaseBlock
, 0);
202 Hive
->Free(Hive
->Storage
[Stable
].BlockList
, 0);
203 return STATUS_NO_MEMORY
;
206 Hive
->Storage
[Stable
].BlockList
[BlockIndex
].BinAddress
= (ULONG_PTR
)NewBin
;
207 Hive
->Storage
[Stable
].BlockList
[BlockIndex
].BlockAddress
= (ULONG_PTR
)NewBin
;
209 RtlCopyMemory(NewBin
, Bin
, Bin
->Size
);
211 if (Bin
->Size
> HV_BLOCK_SIZE
)
213 for (i
= 1; i
< Bin
->Size
/ HV_BLOCK_SIZE
; i
++)
215 Hive
->Storage
[Stable
].BlockList
[BlockIndex
+ i
].BinAddress
= (ULONG_PTR
)NewBin
;
216 Hive
->Storage
[Stable
].BlockList
[BlockIndex
+ i
].BlockAddress
=
217 ((ULONG_PTR
)NewBin
+ (i
* HV_BLOCK_SIZE
));
221 BlockIndex
+= Bin
->Size
/ HV_BLOCK_SIZE
;
224 if (HvpCreateHiveFreeCellList(Hive
))
226 HvpFreeHiveBins(Hive
);
227 Hive
->Free(Hive
->BaseBlock
, 0);
228 return STATUS_NO_MEMORY
;
231 BitmapSize
= ROUND_UP(Hive
->Storage
[Stable
].Length
,
232 sizeof(ULONG
) * 8) / 8;
233 BitmapBuffer
= (PULONG
)Hive
->Allocate(BitmapSize
, TRUE
, TAG_CM
);
234 if (BitmapBuffer
== NULL
)
236 HvpFreeHiveBins(Hive
);
237 Hive
->Free(Hive
->BaseBlock
, 0);
238 return STATUS_NO_MEMORY
;
241 RtlInitializeBitMap(&Hive
->DirtyVector
, BitmapBuffer
, BitmapSize
* 8);
242 RtlClearAllBits(&Hive
->DirtyVector
);
244 return STATUS_SUCCESS
;
248 * @name HvpInitializeMemoryInplaceHive
250 * Internal helper function to initalize hive descriptor structure for
251 * a hive stored in memory. The in-memory data of the hive are directly
252 * used and it is read-only accessible.
258 HvpInitializeMemoryInplaceHive(
262 if (!HvpVerifyHiveHeader((PHBASE_BLOCK
)ChunkBase
))
264 return STATUS_REGISTRY_CORRUPT
;
267 Hive
->BaseBlock
= (PHBASE_BLOCK
)ChunkBase
;
268 Hive
->ReadOnly
= TRUE
;
271 return STATUS_SUCCESS
;
286 HvpGetHiveHeader(IN PHHIVE Hive
,
287 IN PHBASE_BLOCK
*HiveBaseBlock
,
288 IN PLARGE_INTEGER TimeStamp
)
290 PHBASE_BLOCK BaseBlock
;
294 ASSERT(sizeof(HBASE_BLOCK
) >= (HV_BLOCK_SIZE
* Hive
->Cluster
));
296 /* Assume failure and allocate the buffer */
298 BaseBlock
= Hive
->Allocate(sizeof(HBASE_BLOCK
), TRUE
, TAG_CM
);
299 if (!BaseBlock
) return NoMemory
;
301 /* Check for, and enforce, alignment */
302 Alignment
= Hive
->Cluster
* HV_BLOCK_SIZE
-1;
303 if ((ULONG_PTR
)BaseBlock
& Alignment
)
305 /* Free the old header */
306 Hive
->Free(BaseBlock
, 0);
307 BaseBlock
= Hive
->Allocate(PAGE_SIZE
, TRUE
, TAG_CM
);
308 if (!BaseBlock
) return NoMemory
;
310 //BaseBlock->Length = PAGE_SIZE; ??
314 RtlZeroMemory(BaseBlock
, sizeof(HBASE_BLOCK
));
316 /* Now read it from disk */
317 Result
= Hive
->FileRead(Hive
,
321 Hive
->Cluster
* HV_BLOCK_SIZE
);
323 /* Couldn't read: assume it's not a hive */
324 if (!Result
) return NotHive
;
327 if (!HvpVerifyHiveHeader(BaseBlock
)) return NotHive
;
329 /* Return information */
330 *HiveBaseBlock
= BaseBlock
;
331 *TimeStamp
= BaseBlock
->TimeStamp
;
336 HvLoadHive(IN PHHIVE Hive
,
339 PHBASE_BLOCK BaseBlock
= NULL
;
341 LARGE_INTEGER TimeStamp
;
345 /* Get the hive header */
346 Result
= HvpGetHiveHeader(Hive
, &BaseBlock
, &TimeStamp
);
353 return STATUS_INSUFFICIENT_RESOURCES
;
359 return STATUS_NOT_REGISTRY_FILE
;
361 /* Has recovery data */
366 return STATUS_REGISTRY_CORRUPT
;
369 /* Set default boot type */
370 BaseBlock
->BootType
= 0;
372 /* Setup hive data */
373 Hive
->BaseBlock
= BaseBlock
;
374 Hive
->Version
= Hive
->BaseBlock
->Minor
;
376 /* Allocate a buffer large enough to hold the hive */
377 HiveData
= Hive
->Allocate(FileSize
, TRUE
, TAG_CM
);
378 if (!HiveData
) return STATUS_INSUFFICIENT_RESOURCES
;
380 /* Now read the whole hive */
381 Result
= Hive
->FileRead(Hive
,
386 if (!Result
) return STATUS_NOT_REGISTRY_FILE
;
388 /* Apply "US National Debt" hack */
389 ((PHBASE_BLOCK
)HiveData
)->Length
= FileSize
;
391 /* Free our base block... it's usless in this implementation */
392 Hive
->Free(BaseBlock
, 0);
394 /* Initialize the hive directly from memory */
395 return HvpInitializeMemoryHive(Hive
, HiveData
);
401 * Allocate a new hive descriptor structure and intialize it.
403 * @param RegistryHive
404 * Output variable to store pointer to the hive descriptor.
406 * - HV_OPERATION_CREATE_HIVE
407 * Create a new hive for read/write access.
408 * - HV_OPERATION_MEMORY
409 * Load and copy in-memory hive for read/write access. The
410 * pointer to data passed to this routine can be freed after
411 * the function is executed.
412 * - HV_OPERATION_MEMORY_INPLACE
413 * Load an in-memory hive for read-only access. The pointer
414 * to data passed to this routine MUSTN'T be freed until
417 * Pointer to hive data.
419 * Size of passed hive data.
422 * STATUS_NO_MEMORY - A memory allocation failed.
423 * STATUS_REGISTRY_CORRUPT - Registry corruption was detected.
435 PVOID HiveData OPTIONAL
,
436 PALLOCATE_ROUTINE Allocate
,
438 PFILE_SET_SIZE_ROUTINE FileSetSize
,
439 PFILE_WRITE_ROUTINE FileWrite
,
440 PFILE_READ_ROUTINE FileRead
,
441 PFILE_FLUSH_ROUTINE FileFlush
,
442 ULONG Cluster OPTIONAL
,
443 PUNICODE_STRING FileName
)
446 PHHIVE Hive
= RegistryHive
;
448 UNREFERENCED_PARAMETER(HiveType
);
449 UNREFERENCED_PARAMETER(FileName
);
452 * Create a new hive structure that will hold all the maintenance data.
455 RtlZeroMemory(Hive
, sizeof(HHIVE
));
457 Hive
->Allocate
= Allocate
;
459 Hive
->FileRead
= FileRead
;
460 Hive
->FileWrite
= FileWrite
;
461 Hive
->FileSetSize
= FileSetSize
;
462 Hive
->FileFlush
= FileFlush
;
463 Hive
->StorageTypeCount
= HTYPE_COUNT
;
465 Hive
->Version
= HSYS_MINOR
;
466 Hive
->HiveFlags
= HiveFlags
&~ HIVE_NOLAZYFLUSH
;
471 Status
= HvpCreateHive(Hive
);
475 Status
= HvpInitializeMemoryHive(Hive
, HiveData
);
479 Status
= HvpInitializeMemoryInplaceHive(Hive
, HiveData
);
484 /* Hack of doom: Cluster is actually the file size. */
485 Status
= HvLoadHive(Hive
, Cluster
);
486 if ((Status
!= STATUS_SUCCESS
) &&
487 (Status
!= STATUS_REGISTRY_RECOVERED
))
489 /* Unrecoverable failure */
493 /* Check for previous damage */
494 if (Status
== STATUS_REGISTRY_RECOVERED
) ASSERT(FALSE
);
498 /* FIXME: A better return status value is needed */
499 Status
= STATUS_NOT_IMPLEMENTED
;
503 if (!NT_SUCCESS(Status
))
506 if (Operation
!= HINIT_CREATE
) CmPrepareHive(Hive
);
514 * Free all stroage and handles associated with hive descriptor.
521 if (!RegistryHive
->ReadOnly
)
523 /* Release hive bitmap */
524 if (RegistryHive
->DirtyVector
.Buffer
)
526 RegistryHive
->Free(RegistryHive
->DirtyVector
.Buffer
, 0);
529 HvpFreeHiveBins(RegistryHive
);
532 RegistryHive
->Free(RegistryHive
, 0);