|
|
/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
hiveinit.c
Abstract:
Hive initialization code.
Author:
Bryan M. Willman (bryanwi) 12-Sep-91
Environment:
Revision History: Dragos C. Sambotin (dragoss) 25-Jan-99 Implementation of bin-size chunk loading of hives. --*/
#include "cmp.h"
VOID HvpFillFileName( PHBASE_BLOCK BaseBlock, PUNICODE_STRING FileName );
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,HvInitializeHive)
#pragma alloc_text(PAGE,HvpFillFileName)
#pragma alloc_text(PAGE,HvpFreeAllocatedBins)
#endif
// Dragos: Modified functions
VOID HvpFreeAllocatedBins( PHHIVE Hive ) /*++
Routine Description:
Free all the bins allocated for the specified hive. It applies only to stable storage. Not all bins are allocated. Those that are not allocated have BinAddress set to 0 Arguments:
Hive - supplies a pointer to hive control structure for hive who's bin to free.
Return Value:
NONE.
--*/ { ULONG Length; PHBIN Bin; ULONG MapSlots; ULONG Tables; PHMAP_ENTRY Me; PHMAP_TABLE Tab; ULONG i; ULONG j;
//
// calculate the number of tables in the map
//
Length = Hive->Storage[Stable].Length; MapSlots = Length / HBLOCK_SIZE; if( MapSlots > 0 ) { Tables = (MapSlots-1) / HTABLE_SLOTS; } else { Tables = 0; }
if( Hive->Storage[Stable].Map ) { //
// iterate through the directory
//
for (i = 0; i <= Tables; i++) { Tab = Hive->Storage[Stable].Map->Directory[i];
ASSERT(Tab); //
// iterate through the slots in the directory
//
for(j=0;j<HTABLE_SLOTS;j++) { Me = &(Tab->Table[j]); //
// BinAddress non-zero means allocated bin
//
if( Me->BinAddress ) { //
// a bin is freed if it is a new alloc AND it resides in paged pool
//
if( (Me->BinAddress & HMAP_NEWALLOC) && (Me->BinAddress & HMAP_INPAGEDPOOL) ) { Bin = (PHBIN)HBIN_BASE(Me->BinAddress); (Hive->Free)(Bin, HvpGetBinMemAlloc(Hive,Bin,Stable)); } Me->BinAddress = 0; } } } } }
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.
HINIT_MAPFILE
Create a hive, reading its data from a file. Data reading is done by mapping views of the file in the system cache.
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 set up for logging 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; ULONG i; ULONG Alignment;
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_INIT,"HvInitializeHive:\n")); CmKdPrintEx((DPFLTR_CONFIG_ID,CML_INIT,"\tHive=%p\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) || (OperationType == HINIT_MAPFILE)) ) { 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);
if (Hive->Log && (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; #ifdef HV_TRACK_FREE_SPACE
Hive->Storage[Volatile].FreeStorage = 0; #endif
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++) { RtlInitializeBitMap(&(Hive->Storage[Volatile].FreeDisplay[i].Display), NULL, 0); Hive->Storage[Volatile].FreeDisplay[i].RealVectorSize = 0; }
Hive->Storage[Stable].Length = 0; #ifdef HV_TRACK_FREE_SPACE
Hive->Storage[Stable].FreeStorage = 0; #endif
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++) { RtlInitializeBitMap(&(Hive->Storage[Stable].FreeDisplay[i].Display), NULL, 0); Hive->Storage[Stable].FreeDisplay[i].RealVectorSize = 0; }
RtlInitializeBitMap(&(Hive->DirtyVector), NULL, 0); Hive->DirtyCount = 0; Hive->DirtyAlloc = 0; Hive->LogSize = 0; Hive->BaseBlockAlloc = sizeof(HBASE_BLOCK);
Hive->GetCellRoutine = HvpGetCellPaged; Hive->ReleaseCellRoutine = NULL; Hive->Flat = FALSE; Hive->ReadOnly = FALSE; UseForIo = (BOOLEAN)!(Hive->HiveFlags & HIVE_VOLATILE);
//
// new create case
//
if (OperationType == HINIT_CREATE) {
BaseBlock = (PHBASE_BLOCK)((Hive->Allocate)(Hive->BaseBlockAlloc, UseForIo,CM_FIND_LEAK_TAG11)); 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_PTR)BaseBlock & Alignment) != 0) { (Hive->Free)(BaseBlock, Hive->BaseBlockAlloc); BaseBlock = (PHBASE_BLOCK)((Hive->Allocate)(PAGE_SIZE, TRUE,CM_FIND_LEAK_TAG12)); if (BaseBlock == NULL) { return STATUS_INSUFFICIENT_RESOURCES; } Hive->BaseBlockAlloc = PAGE_SIZE; }
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; Hive->BaseBlock->BootType = 0;
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; Hive->BaseBlock->BootType = 0;
// don't init this as we don't need it!!!
//Status = HvpAdjustHiveFreeDisplay(Hive,Hive->Storage[Stable].Length,Stable);
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_SUPPORTED) || (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; Hive->BaseBlock->BootType = 0; Status = HvpAdjustHiveFreeDisplay(Hive,BaseBlock->Length,Stable); if( !NT_SUCCESS(Status) ) { return Status; }
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->Format != HBASE_FORMAT_MEMORY) || (BaseBlock->Major != HSYS_MAJOR) || (BaseBlock->Minor > HSYS_MINOR_SUPPORTED) || (HvpHeaderCheckSum(BaseBlock) != (BaseBlock->CheckSum)) ) { return STATUS_REGISTRY_CORRUPT; }
Hive->BaseBlock = (PHBASE_BLOCK)((Hive->Allocate)(Hive->BaseBlockAlloc, UseForIo,CM_FIND_LEAK_TAG13)); 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_PTR)Hive->BaseBlock & Alignment) != 0) { (Hive->Free)(Hive->BaseBlock, Hive->BaseBlockAlloc); Hive->BaseBlock = (PHBASE_BLOCK)((Hive->Allocate)(PAGE_SIZE, TRUE,CM_FIND_LEAK_TAG14)); if (Hive->BaseBlock == NULL) { return (STATUS_INSUFFICIENT_RESOURCES); } Hive->BaseBlockAlloc = PAGE_SIZE; } RtlCopyMemory(Hive->BaseBlock, BaseBlock, HSECTOR_SIZE); Hive->BaseBlock->BootRecover = BaseBlock->BootRecover; Hive->BaseBlock->BootType = BaseBlock->BootType;
Hive->Version = Hive->BaseBlock->Minor;
Status = HvpAdjustHiveFreeDisplay(Hive,BaseBlock->Length,Stable); if( !NT_SUCCESS(Status) ) { (Hive->Free)(Hive->BaseBlock, Hive->BaseBlockAlloc); Hive->BaseBlock = NULL; return Status; }
if ( !NT_SUCCESS(HvpBuildMapAndCopy(Hive, (PUCHAR)HiveData + HBLOCK_SIZE))) {
(Hive->Free)(Hive->BaseBlock, Hive->BaseBlockAlloc); Hive->BaseBlock = NULL; return STATUS_REGISTRY_CORRUPT; }
HvpFillFileName(Hive->BaseBlock, FileName); return(STATUS_SUCCESS); }
#ifndef CM_ENABLE_MAPPED_VIEWS
if( OperationType == HINIT_MAPFILE ) { OperationType = HINIT_FILE; } #endif //CM_ENABLE_MAPPED_VIEWS
//
// file read case
//
if (OperationType == HINIT_FILE) {
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BIN_MAP,"HvInitializeHive(%wZ,HINIT_FILE) :\n", FileName)); //
// get the file image (possible recovered via log) into memory
//
Status = HvLoadHive(Hive); if ((Status != STATUS_SUCCESS) && (Status != STATUS_REGISTRY_RECOVERED)) { return Status; }
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BIN_MAP,"\n")); 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)) { //
// DRAGOS: Here we need cleanup
// Clean up the bins already allocated
//
HvpFreeAllocatedBins( Hive );
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,0); Hive->LogSize = 0; }
//
// slam debug name data into base block
//
HvpFillFileName(Hive->BaseBlock, FileName);
return STATUS_SUCCESS; }
//
// file map case
//
if (OperationType == HINIT_MAPFILE) {
Hive->GetCellRoutine = HvpGetCellMapped; Hive->ReleaseCellRoutine = HvpReleaseCellMapped;
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BIN_MAP,"HvInitializeHive(%wZ,HINIT_MAPFILE) :\n", FileName));
Status = HvMapHive(Hive); if ((Status != STATUS_SUCCESS) && (Status != STATUS_REGISTRY_RECOVERED)) { return Status; }
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BIN_MAP,"\n")); 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)) { //
// DRAGOS: Here we need cleanup
// Clean up the bins already allocated
//
HvpFreeAllocatedBins( Hive );
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,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;
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_HIVE,"HvpFillFileName: %wZ\n", FileName));
RtlZeroMemory((PVOID)&(BaseBlock->FileName[0]), HBASE_NAME_ALLOC);
if (FileName == NULL) { return; }
//
// Account for 0 at the end, so we have nice debug spews
//
if (FileName->Length < HBASE_NAME_ALLOC) { offset = 0; length = FileName->Length; } else { offset = FileName->Length - HBASE_NAME_ALLOC + sizeof(WCHAR); length = HBASE_NAME_ALLOC - sizeof(WCHAR); }
sptr = (PUCHAR)&(FileName->Buffer[0]); RtlCopyMemory( (PVOID)&(BaseBlock->FileName[0]), (PVOID)&(sptr[offset]), length ); }
|