Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

549 lines
16 KiB

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
hiveinit.c
Abstract:
Hive initialization code.
Author:
Bryan M. Willman (bryanwi) 12-Sep-91
Environment:
Revision History:
--*/
#include "cmp.h"
VOID
HvpFillFileName(
PHBASE_BLOCK BaseBlock,
PUNICODE_STRING FileName
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,HvInitializeHive)
#pragma alloc_text(PAGE,HvpFillFileName)
#endif
NTSTATUS
HvInitializeHive(
PHHIVE Hive,
ULONG OperationType,
ULONG HiveFlags,
ULONG FileType,
PVOID HiveData OPTIONAL,
PALLOCATE_ROUTINE AllocateRoutine,
PFREE_ROUTINE FreeRoutine,
PFILE_SET_SIZE_ROUTINE FileSetSizeRoutine,
PFILE_WRITE_ROUTINE FileWriteRoutine,
PFILE_READ_ROUTINE FileReadRoutine,
PFILE_FLUSH_ROUTINE FileFlushRoutine,
ULONG Cluster,
PUNICODE_STRING FileName OPTIONAL
)
/*++
Routine Description:
Initialize a hive.
Core HHive fields are always inited.
File calls WILL be made BEFORE this call returns.
Caller is expected to create/open files and store file handles
in a way that can be derived from the hive pointer.
Three kinds of initialization can be done, selected by OperationType:
HINIT_CREATE
Create a new hive from scratch. Will have 0 storage.
[Used to do things like create HARDWARE hive and for parts
of SaveKey and RestoreKey]
HINIT_MEMORY_INPLACE
Build a hive control structure which allows read only
access to a contiguous in-memory image of a hive.
No part of the image will be copied, but a map will
be made.
[Used by osloader.]
HINIT_FLAT
Support very limited (read-only, no checking code) operation
against a hive image.
HINIT_MEMORY
Create a new hive, using a hive image already in memory,
at address supplied by pointer HiveData. The data will
be copied. Caller is expected to free HiveData.
[Used for SYSTEM hive]
HINIT_FILE
Create a hive, reading its data from a file. Recovery processing
via log file will be done if a log is available. If a log
is recovered, flush and clear operation will proceed.
NOTE: The HHive is not a completely opaque structure, because it
is really only used by a limited set of code. Do not assume
that only this routine sets all of these values.
Arguments:
Hive - supplies a pointer to hive control structure to be initialized
to describe this hive.
OperationType - specifies whether to create a new hive from scratch,
from a memory image, or by reading a file from disk.
HiveFlags - HIVE_VOLATILE - Entire hive is to be volatile, regardless
of the types of cells allocated
HIVE_NO_LAZY_FLUSH - Data in this hive is never written
to disk except by an explicit FlushKey
FileType - HFILE_TYPE_*, HFILE_TYPE_LOG or HFILE_TYPE_ALTERNATE set
up for logging or alternate support respectively.
HiveData - if present, supplies a pointer to an in memory image of
from which to init the hive. Only useful when OperationType
is set to HINIT_MEMORY.
AllocateRoutine - supplies a pointer to routine called to allocate
memory. WILL be called before this routine returns.
FreeRoutine - supplies a pointer to routine called to free memory.
CAN be called before this routine returns.
FileSetSizeRoutine - supplies a pointer to a routine used to set the
size of a file. CAN be called before this
routine returns.
FileWriteRoutine - supplies a pointer to routine called to write memory
to a file.
FileReadRoutine - supplies a pointer to routine called to read from
a file into memory. CAN be called before this
routine returns.
FileFlushRoutine - supplies a pointer to routine called to flush a file.
Cluster - clustering factor in HSECTOR_SIZE units. (i.e. Size of
physical sector in media / HSECTOR_SIZE. 1 for 512 byte
physical sectors (or smaller), 2 for 1024, 4 for 2048, etc.
(Numbers greater than 8 won't work.)
FileName - some path like "...\system32\config\system", last
32 or so characters will be copied into baseblock
(and thus to disk) as a debugging aid. May be null.
Return Value:
NTSTATUS code.
--*/
{
BOOLEAN UseForIo;
PHBASE_BLOCK BaseBlock = NULL;
NTSTATUS Status;
NTSTATUS Status2;
PVOID Image;
ULONG i;
PHBIN Pbin;
ULONG Alignment;
CMLOG(CML_MAJOR, CMS_INIT) {
KdPrint(("HvInitializeHive:\n"));
KdPrint(("\tHive=%08lx\n", Hive));
}
//
// reject invalid parameter combinations
//
if ( (! ARGUMENT_PRESENT(HiveData)) &&
((OperationType == HINIT_MEMORY) ||
(OperationType == HINIT_FLAT) ||
(OperationType == HINIT_MEMORY_INPLACE))
)
{
return STATUS_INVALID_PARAMETER;
}
if ( ! ((OperationType == HINIT_CREATE) ||
(OperationType == HINIT_MEMORY) ||
(OperationType == HINIT_MEMORY_INPLACE) ||
(OperationType == HINIT_FLAT) ||
(OperationType == HINIT_FILE))
)
{
return STATUS_INVALID_PARAMETER;
}
//
// static and global control values
//
Hive->Signature = HHIVE_SIGNATURE;
Hive->Allocate = AllocateRoutine;
Hive->Free = FreeRoutine;
Hive->FileSetSize = FileSetSizeRoutine;
Hive->FileWrite = FileWriteRoutine;
Hive->FileRead = FileReadRoutine;
Hive->FileFlush = FileFlushRoutine;
Hive->Log = (BOOLEAN)((FileType == HFILE_TYPE_LOG) ? TRUE : FALSE);
Hive->Alternate = (BOOLEAN)((FileType == HFILE_TYPE_ALTERNATE) ? TRUE : FALSE);
if ((Hive->Log || Hive->Alternate) && (HiveFlags & HIVE_VOLATILE)) {
return STATUS_INVALID_PARAMETER;
}
Hive->HiveFlags = HiveFlags;
if ((Cluster == 0) || (Cluster > HSECTOR_COUNT)) {
return STATUS_INVALID_PARAMETER;
}
Hive->Cluster = Cluster;
Hive->RefreshCount = 0;
Hive->StorageTypeCount = HTYPE_COUNT;
Hive->Storage[Volatile].Length = 0;
Hive->Storage[Volatile].Map = NULL;
Hive->Storage[Volatile].SmallDir = NULL;
Hive->Storage[Volatile].Guard = (ULONG)-1;
Hive->Storage[Volatile].FreeSummary = 0;
InitializeListHead(&Hive->Storage[Volatile].FreeBins);
for (i = 0; i < HHIVE_FREE_DISPLAY_SIZE; i++) {
Hive->Storage[Volatile].FreeDisplay[i] = HCELL_NIL;
}
Hive->Storage[Stable].Length = 0;
Hive->Storage[Stable].Map = NULL;
Hive->Storage[Stable].SmallDir = NULL;
Hive->Storage[Stable].Guard = (ULONG)-1;
Hive->Storage[Stable].FreeSummary = 0;
InitializeListHead(&Hive->Storage[Stable].FreeBins);
for (i = 0; i < HHIVE_FREE_DISPLAY_SIZE; i++) {
Hive->Storage[Stable].FreeDisplay[i] = HCELL_NIL;
}
RtlInitializeBitMap(&(Hive->DirtyVector), NULL, 0);
Hive->DirtyCount = 0;
Hive->DirtyAlloc = 0;
Hive->LogSize = 0;
Hive->GetCellRoutine = HvpGetCellPaged;
Hive->Flat = FALSE;
Hive->ReadOnly = FALSE;
UseForIo = (BOOLEAN)!(Hive->HiveFlags & HIVE_VOLATILE);
//
// new create case
//
if (OperationType == HINIT_CREATE) {
BaseBlock = (PHBASE_BLOCK)((Hive->Allocate)(sizeof(HBASE_BLOCK), UseForIo));
if (BaseBlock == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Make sure the buffer we got back is cluster-aligned. If not, try
// harder to get an aligned buffer.
//
Alignment = Cluster * HSECTOR_SIZE - 1;
if (((ULONG)BaseBlock & Alignment) != 0) {
(Hive->Free)(BaseBlock, sizeof(HBASE_BLOCK));
BaseBlock = (PHBASE_BLOCK)((Hive->Allocate)(PAGE_SIZE, TRUE));
if (BaseBlock == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
}
BaseBlock->Signature = HBASE_BLOCK_SIGNATURE;
BaseBlock->Sequence1 = 1;
BaseBlock->Sequence2 = 1;
BaseBlock->TimeStamp.HighPart = 0;
BaseBlock->TimeStamp.LowPart = 0;
BaseBlock->Major = HSYS_MAJOR;
BaseBlock->Minor = HSYS_MINOR;
BaseBlock->Type = HFILE_TYPE_PRIMARY;
BaseBlock->Format = HBASE_FORMAT_MEMORY;
BaseBlock->RootCell = HCELL_NIL;
BaseBlock->Length = 0;
BaseBlock->Cluster = Cluster;
BaseBlock->CheckSum = 0;
HvpFillFileName(BaseBlock, FileName);
Hive->BaseBlock = BaseBlock;
Hive->Version = HSYS_MINOR;
return STATUS_SUCCESS;
}
//
// flat image case
//
if (OperationType == HINIT_FLAT) {
Hive->BaseBlock = (PHBASE_BLOCK)HiveData;
Hive->Version = Hive->BaseBlock->Minor;
Hive->Flat = TRUE;
Hive->ReadOnly = TRUE;
Hive->GetCellRoutine = HvpGetCellFlat;
Hive->Storage[Stable].Length = Hive->BaseBlock->Length;
Hive->StorageTypeCount = 1;
return STATUS_SUCCESS;
}
//
// readonly image case
//
if (OperationType == HINIT_MEMORY_INPLACE) {
BaseBlock = (PHBASE_BLOCK)HiveData;
if ( (BaseBlock->Signature != HBASE_BLOCK_SIGNATURE) ||
(BaseBlock->Type != HFILE_TYPE_PRIMARY) ||
(BaseBlock->Major != HSYS_MAJOR) ||
(BaseBlock->Minor > HSYS_MINOR) ||
(BaseBlock->Format != HBASE_FORMAT_MEMORY) ||
(BaseBlock->Sequence1 != BaseBlock->Sequence2) ||
(HvpHeaderCheckSum(BaseBlock) !=
(BaseBlock->CheckSum))
)
{
return STATUS_REGISTRY_CORRUPT;
}
Hive->BaseBlock = BaseBlock;
Hive->Version = BaseBlock->Minor;
Hive->ReadOnly = TRUE;
Hive->StorageTypeCount = 1;
if (FileType == HFILE_TYPE_ALTERNATE) {
//
// Mark the baseblock with Type==HFILE_TYPE_ALTERNATE. This
// case will never show up on disk, because we always flush
// Type==HFILE_TYPE_PRIMARY to the alternate file. Any
// baseblock with Type==HFILE_TYPE_ALTERNATE indicates that
// the primary is corrupt and must be rewritten.
//
BaseBlock->Type=HFILE_TYPE_ALTERNATE;
//
// baseblock has changed, recompute the checksum.
//
BaseBlock->CheckSum=HvpHeaderCheckSum(BaseBlock);
}
if ( !NT_SUCCESS(HvpBuildMap(
Hive,
(PUCHAR)HiveData + HBLOCK_SIZE
)))
{
return STATUS_REGISTRY_CORRUPT;
}
return(STATUS_SUCCESS);
}
//
// memory copy case
//
if (OperationType == HINIT_MEMORY) {
BaseBlock = (PHBASE_BLOCK)HiveData;
if ( (BaseBlock->Signature != HBASE_BLOCK_SIGNATURE) ||
((BaseBlock->Type != HFILE_TYPE_PRIMARY) &&
(BaseBlock->Type != HFILE_TYPE_ALTERNATE)) ||
(BaseBlock->Format != HBASE_FORMAT_MEMORY) ||
(BaseBlock->Major != HSYS_MAJOR) ||
(BaseBlock->Minor > HSYS_MINOR) ||
(HvpHeaderCheckSum(BaseBlock) !=
(BaseBlock->CheckSum))
)
{
return STATUS_REGISTRY_CORRUPT;
}
Hive->BaseBlock = (PHBASE_BLOCK)((Hive->Allocate)(sizeof(HBASE_BLOCK), UseForIo));
if (Hive->BaseBlock==NULL) {
return(STATUS_INSUFFICIENT_RESOURCES);
}
//
// Make sure the buffer we got back is cluster-aligned. If not, try
// harder to get an aligned buffer.
//
Alignment = Cluster * HSECTOR_SIZE - 1;
if (((ULONG)Hive->BaseBlock & Alignment) != 0) {
(Hive->Free)(Hive->BaseBlock, sizeof(HBASE_BLOCK));
Hive->BaseBlock = (PHBASE_BLOCK)((Hive->Allocate)(PAGE_SIZE, TRUE));
if (Hive->BaseBlock == NULL) {
return (STATUS_INSUFFICIENT_RESOURCES);
}
}
RtlCopyMemory(Hive->BaseBlock, BaseBlock, HSECTOR_SIZE);
Hive->Version = Hive->BaseBlock->Minor;
if ( !NT_SUCCESS(HvpBuildMapAndCopy(Hive,
(PUCHAR)HiveData + HBLOCK_SIZE))) {
(Hive->Free)(Hive->BaseBlock, sizeof(HBASE_BLOCK));
Hive->BaseBlock = NULL;
return STATUS_REGISTRY_CORRUPT;
}
if (BaseBlock->Type == HFILE_TYPE_ALTERNATE) {
//
// Note that Type==HFILE_TYPE_ALTERNATE will NEVER occur in
// an on-disk image. The only way this can show up in the
// baseblock is when the osloader rejects the SYSTEM hive and
// successfully loads SYSTEM.ALT. When this happens, it
// forces HFILE_TYPE_ALTERNATE into the in-memory image of
// the baseblock.
//
// We've booted from SYSTEM.ALT. Mark the whole hive dirty
// so everything gets flushed to SYSTEM as soon as we can
// do I/O.
//
RtlSetAllBits(&(Hive->DirtyVector));
Hive->DirtyCount=Hive->DirtyVector.SizeOfBitMap;
}
HvpFillFileName(Hive->BaseBlock, FileName);
return(STATUS_SUCCESS);
}
//
// file read case
//
if (OperationType == HINIT_FILE) {
//
// get the file image (possible recovered via log) into memory
//
Status = HvLoadHive(Hive, &Image);
if ((Status != STATUS_SUCCESS) && (Status != STATUS_REGISTRY_RECOVERED)) {
return Status;
}
//
// build the map for the hive
//
Status2 = HvpBuildMap(Hive, Image);
if (!NT_SUCCESS(Status2)) {
Pbin = (PHBIN)Image;
(Hive->Free)(Pbin, Pbin->MemAlloc);
return Status2;
}
if (Status == STATUS_REGISTRY_RECOVERED) {
//
// We have a good hive, with a log, and a dirty map,
// all set up. Only problem is that we need to flush
// the file so the log can be cleared and new writes
// posted against the hive. Since we know we have
// a good log in hand, we just write the hive image.
//
if ( ! HvpDoWriteHive(Hive, HFILE_TYPE_PRIMARY)) {
Pbin = (PHBIN)Image;
(Hive->Free)(Pbin, Pbin->MemAlloc);
return STATUS_REGISTRY_IO_FAILED;
}
//
// If we get here, we have recovered the hive, and
// written it out to disk correctly. So we clear
// the log here.
//
RtlClearAllBits(&(Hive->DirtyVector));
Hive->DirtyCount = 0;
(Hive->FileSetSize)(Hive, HFILE_TYPE_LOG, 0);
Hive->LogSize = 0;
}
//
// slam debug name data into base block
//
HvpFillFileName(Hive->BaseBlock, FileName);
return STATUS_SUCCESS;
}
return STATUS_INVALID_PARAMETER;
}
VOID
HvpFillFileName(
PHBASE_BLOCK BaseBlock,
PUNICODE_STRING FileName
)
/*++
Routine Description:
Zero out the filename portion of the base block.
If FileName is not NULL, copy last 64 bytes into name tail
field of base block
Arguments:
BaseBlock - supplies pointer to a base block
FileName - supplies pointer to a unicode STRING
Return Value:
None.
--*/
{
ULONG offset;
ULONG length;
PUCHAR sptr;
RtlZeroMemory((PVOID)&(BaseBlock->FileName[0]), HBASE_NAME_ALLOC);
if (FileName == NULL) {
return;
}
if (FileName->Length <= HBASE_NAME_ALLOC) {
offset = 0;
length = FileName->Length;
} else {
offset = FileName->Length - HBASE_NAME_ALLOC;
length = HBASE_NAME_ALLOC;
}
sptr = (PUCHAR)&(FileName->Buffer[0]);
RtlMoveMemory(
(PVOID)&(BaseBlock->FileName[0]),
(PVOID)&(sptr[offset]),
length
);
}