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.
 
 
 
 
 
 

689 lines
16 KiB

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
hivemap.c
Abstract:
This module implements HvpBuildMap - used to build the initial map for a hive
Author:
Bryan M. Willman (bryanwi) 28-Mar-92
Environment:
Revision History:
--*/
#include "cmp.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,HvpBuildMap)
#pragma alloc_text(PAGE,HvpFreeMap)
#pragma alloc_text(PAGE,HvpAllocateMap)
#pragma alloc_text(PAGE,HvpBuildMapAndCopy)
#pragma alloc_text(PAGE,HvpEnlistFreeCells)
#endif
extern struct {
PHHIVE Hive;
ULONG Status;
ULONG Space;
HCELL_INDEX MapPoint;
PHBIN BinPoint;
} HvCheckHiveDebug;
NTSTATUS
HvpBuildMapAndCopy(
PHHIVE Hive,
PVOID Image
)
/*++
Routine Description:
Creates the map for the Stable storage of the hive, and inits
the map for the volatile storage.
Following fields in hive must already be filled in:
Allocate, Free
Will initialize Storage structure of HHIVE.
The difference between this routine and HvpBuildMapAndCopy is that
this routine will create a "sparse" map. As it copies the SourceImage
to the newly allocated memory for the destination, it will avoid
allocating space for HBINs that contain nothing but free space. The
HBLOCKs in these HBINs will be marked as discarded, and HvGetCell
will allocate memory for them if necessary.
Arguments:
Hive - Pointer to hive control structure to build map for.
Image - pointer to flat memory image of original hive.
Return Value:
TRUE - it worked
FALSE - either hive is corrupt or no memory for map
--*/
{
PHBASE_BLOCK BaseBlock;
ULONG Length;
ULONG MapSlots;
ULONG Tables;
PHMAP_TABLE t = NULL;
PHMAP_DIRECTORY d = NULL;
PHBIN Bin;
PHBIN NewBins;
PHBIN CurrentBin;
ULONG Offset;
ULONG Address;
PHMAP_ENTRY Me;
NTSTATUS Status;
PULONG Vector;
ULONG Size;
CMLOG(CML_FLOW, CMS_HIVE) {
KdPrint(("HvpBuildMap:\n"));
KdPrint(("\tHive=%08lx",Hive));
}
//
// Compute size of data region to be mapped
//
BaseBlock = Hive->BaseBlock;
Length = BaseBlock->Length;
if ((Length % HBLOCK_SIZE) != 0) {
Status = STATUS_REGISTRY_CORRUPT;
goto ErrorExit1;
}
MapSlots = Length / HBLOCK_SIZE;
Tables = (MapSlots-1) / HTABLE_SLOTS;
Hive->Storage[Stable].Length = Length;
//
// allocate dirty vector if one is not already present (from HvpRecoverData)
//
if (Hive->DirtyVector.Buffer == NULL) {
Vector = (PULONG)((Hive->Allocate)(ROUND_UP(Length/HSECTOR_SIZE/8,sizeof(ULONG)), TRUE));
if (Vector == NULL) {
Status = STATUS_NO_MEMORY;
goto ErrorExit1;
}
RtlZeroMemory(Vector, Length / HSECTOR_SIZE / 8);
RtlInitializeBitMap(&Hive->DirtyVector, Vector, Length / HSECTOR_SIZE);
Hive->DirtyAlloc = (Length/HSECTOR_SIZE/8);
}
//
// allocate and build structure for map
//
if (Tables == 0) {
//
// Just 1 table, no need for directory
//
t = (Hive->Allocate)(sizeof(HMAP_TABLE), FALSE);
if (t == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto ErrorExit1;
}
RtlZeroMemory(t, sizeof(HMAP_TABLE));
Hive->Storage[Stable].Map =
(PHMAP_DIRECTORY)&(Hive->Storage[Stable].SmallDir);
Hive->Storage[Stable].SmallDir = t;
} else {
//
// Need directory and multiple tables
//
d = (PHMAP_DIRECTORY)(Hive->Allocate)(sizeof(HMAP_DIRECTORY), FALSE);
if (d == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto ErrorExit1;
}
RtlZeroMemory(d, sizeof(HMAP_DIRECTORY));
//
// Allocate tables and fill in dir
//
if (HvpAllocateMap(Hive, d, 0, Tables) == FALSE) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto ErrorExit2;
}
Hive->Storage[Stable].Map = d;
Hive->Storage[Stable].SmallDir = 0;
}
//
// Now we have to allocate the memory for the HBINs and fill in
// the map appropriately. We are careful never to allocate less
// than a page to avoid fragmenting pool. As long as the page
// size is a multiple of HBLOCK_SIZE (a fairly good assumption as
// long as HBLOCK_SIZE is 4k) this strategy will prevent pool
// fragmentation.
//
// If we come across an HBIN that is entirely composed of a freed
// HCELL, then we do not allocate memory, but mark its HBLOCKs in
// the map as not present. HvAllocateCell will allocate memory for
// the bin when it is needed.
//
Offset = 0;
Size = 0;
Bin = (PHBIN)Image;
while (Bin < (PHBIN)((PUCHAR)(Image) + Length)) {
if ( (Bin->Size > (Length-Offset)) ||
(Bin->Signature != HBIN_SIGNATURE) ||
(Bin->FileOffset != (Offset+Size))
)
{
//
// Bin is bogus
//
Status = STATUS_REGISTRY_CORRUPT;
goto ErrorExit2;
}
Size += Bin->Size;
if ((Size < PAGE_SIZE) &&
(Size + Length - Offset > PAGE_SIZE)) {
//
// We haven't accumulated enough bins to fill up a page
// yet, and there are still bins left, so group this one
// in with the next one.
//
Bin = (PHBIN)((ULONG)Bin + Bin->Size);
continue;
}
//
// We now have a series of HBINs to group together in one
// chunk of memory.
//
NewBins = (PHBIN)(Hive->Allocate)(Size, FALSE);
if (NewBins==NULL) {
goto ErrorExit2; //fixfix
}
RtlCopyMemory(NewBins,
(PUCHAR)Image+Offset,
Size);
NewBins->MemAlloc = Size;
//
// create map entries for each block/page in bin
//
Address = (ULONG)NewBins;
do {
CurrentBin = (PHBIN)Address;
do {
Me = HvpGetCellMap(Hive, Offset);
ASSERT(Me != NULL);
Me->BlockAddress = Address;
Me->BinAddress = (ULONG)CurrentBin;
if (CurrentBin == NewBins) {
Me->BinAddress |= HMAP_NEWALLOC;
} else {
CurrentBin->MemAlloc = 0;
}
Address += HBLOCK_SIZE;
Offset += HBLOCK_SIZE;
} while ( Address < ((ULONG)CurrentBin + CurrentBin->Size ));
if (Hive->ReadOnly == FALSE) {
//
// add free cells in the bin to the appropriate free lists
//
if ( ! HvpEnlistFreeCells(Hive,
CurrentBin,
CurrentBin->FileOffset)) {
Status = STATUS_REGISTRY_CORRUPT;
goto ErrorExit2;
}
}
} while ( Address < (ULONG)NewBins + Size );
Bin = (PHBIN)((ULONG)Bin + Bin->Size);
Size = 0;
}
return STATUS_SUCCESS;
ErrorExit2:
if (d != NULL) {
//
// directory was built and allocated, so clean it up
//
HvpFreeMap(Hive, d, 0, Tables);
(Hive->Free)(d, sizeof(HMAP_DIRECTORY));
}
ErrorExit1:
return Status;
}
NTSTATUS
HvpBuildMap(
PHHIVE Hive,
PVOID Image
)
/*++
Routine Description:
Creates the map for the Stable storage of the hive, and inits
the map for the volatile storage.
Following fields in hive must already be filled in:
Allocate, Free
Will initialize Storage structure of HHIVE.
Arguments:
Hive - Pointer to hive control structure to build map for.
Image - pointer to in memory image of the hive
Return Value:
TRUE - it worked
FALSE - either hive is corrupt or no memory for map
--*/
{
PHBASE_BLOCK BaseBlock;
ULONG Length;
ULONG MapSlots;
ULONG Tables;
PHMAP_TABLE t = NULL;
PHMAP_DIRECTORY d = NULL;
PHBIN Bin;
ULONG Offset;
ULONG BinOffset;
ULONG Address;
PHMAP_ENTRY Me;
NTSTATUS Status;
PULONG Vector;
CMLOG(CML_FLOW, CMS_HIVE) {
KdPrint(("HvpBuildMap:\n"));
KdPrint(("\tHive=%08lx",Hive));
}
//
// Compute size of data region to be mapped
//
BaseBlock = Hive->BaseBlock;
Length = BaseBlock->Length;
if ((Length % HBLOCK_SIZE) != 0) {
Status = STATUS_REGISTRY_CORRUPT;
goto ErrorExit1;
}
MapSlots = Length / HBLOCK_SIZE;
Tables = (MapSlots-1) / HTABLE_SLOTS;
Hive->Storage[Stable].Length = Length;
//
// allocate dirty vector if one is not already present (from HvpRecoverData)
//
if (Hive->DirtyVector.Buffer == NULL) {
Vector = (PULONG)((Hive->Allocate)(Length/HSECTOR_SIZE/8, TRUE));
if (Vector == NULL) {
Status = STATUS_NO_MEMORY;
goto ErrorExit1;
}
RtlZeroMemory(Vector, Length / HSECTOR_SIZE / 8);
RtlInitializeBitMap(&Hive->DirtyVector, Vector, Length / HSECTOR_SIZE);
Hive->DirtyAlloc = (Length/HSECTOR_SIZE/8);
}
//
// allocate and build structure for map
//
if (Tables == 0) {
//
// Just 1 table, no need for directory
//
t = (Hive->Allocate)(sizeof(HMAP_TABLE), FALSE);
if (t == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto ErrorExit1;
}
RtlZeroMemory(t, sizeof(HMAP_TABLE));
Hive->Storage[Stable].Map =
(PHMAP_DIRECTORY)&(Hive->Storage[Stable].SmallDir);
Hive->Storage[Stable].SmallDir = t;
} else {
//
// Need directory and multiple tables
//
d = (PHMAP_DIRECTORY)(Hive->Allocate)(sizeof(HMAP_DIRECTORY), FALSE);
if (d == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto ErrorExit1;
}
RtlZeroMemory(d, sizeof(HMAP_DIRECTORY));
//
// Allocate tables and fill in dir
//
if (HvpAllocateMap(Hive, d, 0, Tables) == FALSE) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto ErrorExit2;
}
Hive->Storage[Stable].Map = d;
Hive->Storage[Stable].SmallDir = 0;
}
//
// Fill in the map
//
Offset = 0;
Bin = (PHBIN)Image;
while (Bin < (PHBIN)((PUCHAR)(Image) + BaseBlock->Length)) {
if ( (Bin->Size > Length) ||
(Bin->Signature != HBIN_SIGNATURE) ||
(Bin->FileOffset != Offset)
)
{
//
// Bin is bogus
//
Status = STATUS_REGISTRY_CORRUPT;
HvCheckHiveDebug.Hive = Hive;
HvCheckHiveDebug.Status = 0xA001;
HvCheckHiveDebug.Space = Length;
HvCheckHiveDebug.MapPoint = Offset;
HvCheckHiveDebug.BinPoint = Bin;
goto ErrorExit2;
}
if (Offset > 0) {
Bin->MemAlloc = 0;
}
//
// create map entries for each block/page in bin
//
BinOffset = Offset;
for (Address = (ULONG)Bin;
Address < ((ULONG)Bin + Bin->Size);
Address += HBLOCK_SIZE
)
{
Me = HvpGetCellMap(Hive, Offset);
ASSERT(Me != NULL);
Me->BlockAddress = Address;
Me->BinAddress = (ULONG)Bin;
if (Offset == 0) {
Me->BinAddress |= HMAP_NEWALLOC;
}
Offset += HBLOCK_SIZE;
}
if (Hive->ReadOnly == FALSE) {
//
// add free cells in the bin to the appropriate free lists
//
if ( ! HvpEnlistFreeCells(Hive, Bin, BinOffset)) {
HvCheckHiveDebug.Hive = Hive;
HvCheckHiveDebug.Status = 0xA002;
HvCheckHiveDebug.Space = Length;
HvCheckHiveDebug.MapPoint = BinOffset;
HvCheckHiveDebug.BinPoint = Bin;
Status = STATUS_REGISTRY_CORRUPT;
goto ErrorExit2;
}
}
Bin = (PHBIN)((ULONG)Bin + Bin->Size);
}
return STATUS_SUCCESS;
ErrorExit2:
if (d != NULL) {
//
// directory was built and allocated, so clean it up
//
HvpFreeMap(Hive, d, 0, Tables);
(Hive->Free)(d, sizeof(HMAP_DIRECTORY));
}
ErrorExit1:
return Status;
}
BOOLEAN
HvpEnlistFreeCells(
PHHIVE Hive,
PHBIN Bin,
ULONG BinOffset
)
/*++
Routine Description:
Scan through the cells in the bin, locating the free ones.
Enlist them in the hive's free list set.
N.B. Bin MUST already be mapped when this is called.
Arguments:
Hive - pointer to hive control structure map is being built for
Bin - pointer to bin to enlist cells from
BinOffset - offset of Bin in image
Return Value:
FALSE - registry is corrupt
TRUE - it worked
--*/
{
PHCELL p;
ULONG celloffset;
ULONG size;
HCELL_INDEX cellindex;
//
// Scan all the cells in the bin, total free and allocated, check
// for impossible pointers.
//
celloffset = sizeof(HBIN);
p = (PHCELL)((PUCHAR)Bin + sizeof(HBIN));
while (p < (PHCELL)((PUCHAR)Bin + Bin->Size)) {
//
// if free cell, check it out, add it to free list for hive
//
if (p->Size >= 0) {
size = (ULONG)p->Size;
if ( (size > Bin->Size) ||
( (PHCELL)(size + (PUCHAR)p) >
(PHCELL)((PUCHAR)Bin + Bin->Size) ) ||
((size % HCELL_PAD(Hive)) != 0) ||
(size == 0) )
{
return FALSE;
}
//
// cell is free, and is not obviously corrupt, add to free list
//
celloffset = (PUCHAR)p - (PUCHAR)Bin;
cellindex = BinOffset + celloffset;
HvpEnlistFreeCell(Hive, cellindex, size, Stable);
} else {
size = (ULONG)(p->Size * -1);
if ( (size > Bin->Size) ||
( (PHCELL)(size + (PUCHAR)p) >
(PHCELL)((PUCHAR)Bin + Bin->Size) ) ||
((size % HCELL_PAD(Hive)) != 0) ||
(size == 0) )
{
return FALSE;
}
}
ASSERT(size >= 0);
p = (PHCELL)((PUCHAR)p + size);
}
return TRUE;
}
VOID
HvpFreeMap(
PHHIVE Hive,
PHMAP_DIRECTORY Dir,
ULONG Start,
ULONG End
)
/*++
Routine Description:
Sweeps through the directory Dir points to and frees Tables.
Will free Start-th through End-th entries, INCLUSIVE.
Arguments:
Hive - supplies pointer to hive control block of interest
Dir - supplies address of an HMAP_DIRECTORY structure
Start - index of first map table pointer to clean up
End - index of last map table pointer to clean up
Return Value:
NONE.
--*/
{
ULONG i;
if (End >= HDIRECTORY_SLOTS) {
End = HDIRECTORY_SLOTS - 1;
}
for (i = Start; i <= End; i++) {
if (Dir->Directory[i] != NULL) {
(Hive->Free)(Dir->Directory[i], sizeof(HMAP_TABLE));
Dir->Directory[i] = NULL;
}
}
return;
}
BOOLEAN
HvpAllocateMap(
PHHIVE Hive,
PHMAP_DIRECTORY Dir,
ULONG Start,
ULONG End
)
/*++
Routine Description:
Sweeps through the directory Dir points to and allocates Tables.
Will allocate Start-th through End-th entries, INCLUSIVE.
Does NOT clean up when out of memory, call HvpFreeMap to do that.
Arguments:
Hive - supplies pointer to hive control block of interest
Dir - supplies address of an HMAP_DIRECTORY structure
Start - index of first map table pointer to allocate for
End - index of last map table pointer to allocate for
Return Value:
TRUE - it worked
FALSE - insufficient memory
--*/
{
ULONG i;
PVOID t;
for (i = Start; i <= End; i++) {
ASSERT(Dir->Directory[i] == NULL);
t = (PVOID)((Hive->Allocate)(sizeof(HMAP_TABLE), FALSE));
if (t == NULL) {
return FALSE;
}
RtlZeroMemory(t, sizeof(HMAP_TABLE));
Dir->Directory[i] = (PHMAP_TABLE)t;
}
return TRUE;
}