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 HiveHeader
)
22 if (HiveHeader
->Signature
!= HV_SIGNATURE
||
23 HiveHeader
->Major
!= HV_MAJOR_VER
||
24 HiveHeader
->Minor
< HV_MINOR_VER
||
25 HiveHeader
->Type
!= HV_TYPE_PRIMARY
||
26 HiveHeader
->Format
!= HV_FORMAT_MEMORY
||
27 HiveHeader
->Cluster
!= 1 ||
28 HiveHeader
->Sequence1
!= HiveHeader
->Sequence2
||
29 HvpHiveHeaderChecksum(HiveHeader
) != HiveHeader
->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 HiveHeader
->Signature
, HV_SIGNATURE
, HiveHeader
->Major
, HV_MAJOR_VER
);
34 DPRINT1(" Minor: 0x%x is not >= 0x%x, Type: 0x%x and not 0x%x\n",
35 HiveHeader
->Minor
, HV_MINOR_VER
, HiveHeader
->Type
, HV_TYPE_PRIMARY
);
36 DPRINT1(" Format: 0x%x and not 0x%x, Cluster: 0x%x and not 1\n",
37 HiveHeader
->Format
, HV_FORMAT_MEMORY
, HiveHeader
->Cluster
);
38 DPRINT1(" Sequence: 0x%x and not 0x%x, Checksum: 0x%x and not 0x%x\n",
39 HiveHeader
->Sequence1
, HiveHeader
->Sequence2
,
40 HvpHiveHeaderChecksum(HiveHeader
), HiveHeader
->Checksum
);
48 * @name HvpFreeHiveBins
50 * Internal function to free all bin storage associated with hive
62 for (Storage
= HvStable
; Storage
< HvMaxStorageType
; Storage
++)
65 for (i
= 0; i
< Hive
->Storage
[Storage
].Length
; i
++)
67 if (Hive
->Storage
[Storage
].BlockList
[i
].Bin
== (ULONG_PTR
)NULL
)
69 if (Hive
->Storage
[Storage
].BlockList
[i
].Bin
!= (ULONG_PTR
)Bin
)
71 Bin
= (PHBIN
)Hive
->Storage
[Storage
].BlockList
[i
].Bin
;
72 Hive
->Free((PHBIN
)Hive
->Storage
[Storage
].BlockList
[i
].Bin
);
74 Hive
->Storage
[Storage
].BlockList
[i
].Bin
= (ULONG_PTR
)NULL
;
75 Hive
->Storage
[Storage
].BlockList
[i
].Block
= (ULONG_PTR
)NULL
;
78 if (Hive
->Storage
[Storage
].Length
)
79 Hive
->Free(Hive
->Storage
[Storage
].BlockList
);
86 * Internal helper function to initalize hive descriptor structure for
96 PHBASE_BLOCK HiveHeader
;
99 HiveHeader
= RegistryHive
->Allocate(sizeof(HBASE_BLOCK
), FALSE
);
100 if (HiveHeader
== NULL
)
101 return STATUS_NO_MEMORY
;
102 RtlZeroMemory(HiveHeader
, sizeof(HBASE_BLOCK
));
103 HiveHeader
->Signature
= HV_SIGNATURE
;
104 HiveHeader
->Major
= HV_MAJOR_VER
;
105 HiveHeader
->Minor
= HV_MINOR_VER
;
106 HiveHeader
->Type
= HV_TYPE_PRIMARY
;
107 HiveHeader
->Format
= HV_FORMAT_MEMORY
;
108 HiveHeader
->Cluster
= 1;
109 HiveHeader
->RootCell
= HCELL_NULL
;
110 HiveHeader
->Length
= HV_BLOCK_SIZE
;
111 HiveHeader
->Sequence1
= 1;
112 HiveHeader
->Sequence2
= 1;
113 /* FIXME: Fill in the file name */
114 HiveHeader
->Checksum
= HvpHiveHeaderChecksum(HiveHeader
);
116 RegistryHive
->HiveHeader
= HiveHeader
;
117 for (Index
= 0; Index
< 24; Index
++)
119 RegistryHive
->Storage
[HvStable
].FreeDisplay
[Index
] = HCELL_NULL
;
120 RegistryHive
->Storage
[HvVolatile
].FreeDisplay
[Index
] = HCELL_NULL
;
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 %d < sizeof(HBASE_BLOCK) %d, "
160 "or HvpVerifyHiveHeader() failed\n", ChunkSize
, sizeof(HBASE_BLOCK
));
161 return STATUS_REGISTRY_CORRUPT
;
164 Hive
->HiveHeader
= Hive
->Allocate(sizeof(HBASE_BLOCK
), FALSE
);
165 if (Hive
->HiveHeader
== NULL
)
167 return STATUS_NO_MEMORY
;
169 RtlCopyMemory(Hive
->HiveHeader
, (PVOID
)ChunkBase
, sizeof(HBASE_BLOCK
));
172 * Build a block list from the in-memory chunk and copy the data as
176 Hive
->Storage
[HvStable
].Length
= (ULONG
)(ChunkSize
/ HV_BLOCK_SIZE
) - 1;
177 Hive
->Storage
[HvStable
].BlockList
=
178 Hive
->Allocate(Hive
->Storage
[HvStable
].Length
*
179 sizeof(HMAP_ENTRY
), FALSE
);
180 if (Hive
->Storage
[HvStable
].BlockList
== NULL
)
182 DPRINT1("Allocating block list failed\n");
183 Hive
->Free(Hive
->HiveHeader
);
184 return STATUS_NO_MEMORY
;
187 for (BlockIndex
= 0; BlockIndex
< Hive
->Storage
[HvStable
].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
->HiveHeader
);
194 Hive
->Free(Hive
->Storage
[HvStable
].BlockList
);
195 return STATUS_REGISTRY_CORRUPT
;
198 NewBin
= Hive
->Allocate(Bin
->Size
, TRUE
);
201 Hive
->Free(Hive
->HiveHeader
);
202 Hive
->Free(Hive
->Storage
[HvStable
].BlockList
);
203 return STATUS_NO_MEMORY
;
206 Hive
->Storage
[HvStable
].BlockList
[BlockIndex
].Bin
= (ULONG_PTR
)NewBin
;
207 Hive
->Storage
[HvStable
].BlockList
[BlockIndex
].Block
= (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
[HvStable
].BlockList
[BlockIndex
+ i
].Bin
= (ULONG_PTR
)NewBin
;
216 Hive
->Storage
[HvStable
].BlockList
[BlockIndex
+ i
].Block
=
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
->HiveHeader
);
228 return STATUS_NO_MEMORY
;
231 BitmapSize
= ROUND_UP(Hive
->Storage
[HvStable
].Length
,
232 sizeof(ULONG
) * 8) / 8;
233 BitmapBuffer
= (PULONG
)Hive
->Allocate(BitmapSize
, TRUE
);
234 if (BitmapBuffer
== NULL
)
236 HvpFreeHiveBins(Hive
);
237 Hive
->Free(Hive
->HiveHeader
);
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
->HiveHeader
= (PHBASE_BLOCK
)ChunkBase
;
268 Hive
->ReadOnly
= TRUE
;
271 return STATUS_SUCCESS
;
286 HvpGetHiveHeader(IN PHHIVE Hive
,
287 IN PHBASE_BLOCK
*BaseBlock
,
288 IN PLARGE_INTEGER TimeStamp
)
290 PHBASE_BLOCK HiveHeader
;
293 ULONGLONG Offset
= 0;
294 ASSERT(sizeof(HBASE_BLOCK
) >= (HV_BLOCK_SIZE
* Hive
->Cluster
));
296 /* Assume failure and allocate the buffer */
298 HiveHeader
= Hive
->Allocate(sizeof(HBASE_BLOCK
), TRUE
);
299 if (!HiveHeader
) return NoMemory
;
301 /* Check for, and enforce, alignment */
302 Alignment
= Hive
->Cluster
* HV_BLOCK_SIZE
-1;
303 if ((ULONG_PTR
)HiveHeader
& Alignment
)
305 /* Free the old header */
306 Hive
->Free(HiveHeader
);
307 HiveHeader
= Hive
->Allocate(PAGE_SIZE
, TRUE
);
308 if (!HiveHeader
) return NoMemory
;
310 //HiveHeader->Length = PAGE_SIZE; ??
314 RtlZeroMemory(HiveHeader
, 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(HiveHeader
)) return NotHive
;
329 /* Return information */
330 *BaseBlock
= HiveHeader
;
331 *TimeStamp
= HiveHeader
->TimeStamp
;
336 HvLoadHive(IN PHHIVE Hive
,
339 PHBASE_BLOCK BaseBlock
= NULL
;
341 LARGE_INTEGER TimeStamp
;
342 ULONGLONG Offset
= 0;
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
->HiveHeader
= BaseBlock
;
374 Hive
->Version
= Hive
->HiveHeader
->Minor
;
376 /* Allocate a buffer large enough to hold the hive */
377 HiveData
= Hive
->Allocate(FileSize
, TRUE
);
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
);
394 /* Initialize the hive directly from memory */
395 return HvpInitializeMemoryHive(Hive
, (ULONG_PTR
)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 ULONG_PTR HiveData OPTIONAL
,
436 ULONG Cluster OPTIONAL
,
437 PALLOCATE_ROUTINE Allocate
,
439 PFILE_READ_ROUTINE FileRead
,
440 PFILE_WRITE_ROUTINE FileWrite
,
441 PFILE_SET_SIZE_ROUTINE FileSetSize
,
442 PFILE_FLUSH_ROUTINE FileFlush
,
443 IN PUNICODE_STRING FileName
)
446 PHHIVE Hive
= RegistryHive
;
449 * Create a new hive structure that will hold all the maintenance data.
452 RtlZeroMemory(Hive
, sizeof(HHIVE
));
454 Hive
->Allocate
= Allocate
;
456 Hive
->FileRead
= FileRead
;
457 Hive
->FileWrite
= FileWrite
;
458 Hive
->FileSetSize
= FileSetSize
;
459 Hive
->FileFlush
= FileFlush
;
460 Hive
->StorageTypeCount
= 2;
462 Hive
->Version
= HV_MINOR_VER
;
466 case HV_OPERATION_CREATE_HIVE
:
467 Status
= HvpCreateHive(Hive
);
470 case HV_OPERATION_MEMORY
:
471 Status
= HvpInitializeMemoryHive(Hive
, HiveData
);
474 case HV_OPERATION_MEMORY_INPLACE
:
475 Status
= HvpInitializeMemoryInplaceHive(Hive
, HiveData
);
480 /* Hack of doom: Cluster is actually the file size. */
481 Status
= HvLoadHive(Hive
, Cluster
);
482 if ((Status
!= STATUS_SUCCESS
) &&
483 (Status
!= STATUS_REGISTRY_RECOVERED
))
485 /* Unrecoverable failure */
489 /* Check for previous damage */
490 if (Status
== STATUS_REGISTRY_RECOVERED
) ASSERT(FALSE
);
494 /* FIXME: A better return status value is needed */
495 Status
= STATUS_NOT_IMPLEMENTED
;
499 if (!NT_SUCCESS(Status
))
511 * Free all stroage and handles associated with hive descriptor.
518 if (!RegistryHive
->ReadOnly
)
520 /* Release hive bitmap */
521 if (RegistryHive
->DirtyVector
.Buffer
)
523 RegistryHive
->Free(RegistryHive
->DirtyVector
.Buffer
);
526 HvpFreeHiveBins(RegistryHive
);
529 RegistryHive
->Free(RegistryHive
);