525 lines
12 KiB
C++
525 lines
12 KiB
C++
/*++
|
||
|
||
Copyright (c) 1989 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
scan.cpp
|
||
|
||
Abstract:
|
||
|
||
This module contains the scanning code for the chkhash program.
|
||
|
||
Author:
|
||
|
||
Johnson Apacible (JohnsonA) 25-Sept-1995
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "..\..\tigris.hxx"
|
||
#include "chkhash.h"
|
||
|
||
VOID
|
||
PrintHeadStats(
|
||
PHASH_RESERVED_PAGE Head
|
||
)
|
||
{
|
||
|
||
if ( !Verbose ) {
|
||
return;
|
||
}
|
||
|
||
printf("Signature [%x]\n",Head->Signature);
|
||
|
||
printf("Pages %d",Head->NumPages);
|
||
printf("\t\t\tDir depth %d\n",Head->DirDepth);
|
||
printf("Insertions %d",Head->InsertionCount);
|
||
printf("\t\tDeletions %d\n",Head->DeletionCount);
|
||
printf("Searches %d",Head->SearchCount);
|
||
printf("\t\tSplits %d\n",Head->PageSplits);
|
||
printf("Dir expansions %d",Head->DirExpansions);
|
||
printf("\tTable expansions %d\n",Head->TableExpansions);
|
||
printf("Duplicate Inserts %d\n",Head->DupInserts);
|
||
|
||
} // PrintHeadStats
|
||
|
||
VOID
|
||
PrintPageStats(
|
||
PHTABLE HTable,
|
||
PMAP_PAGE Page
|
||
)
|
||
{
|
||
DWORD nDel = 0;
|
||
DWORD nOk = 0;
|
||
DWORD j;
|
||
SHORT offset;
|
||
|
||
if ( Verbose ) {
|
||
printf("Hash prefix %x\t\tDepth %d\n",Page->HashPrefix,Page->PageDepth);
|
||
printf("Entries %d",Page->EntryCount);
|
||
printf("\t\tUndel Entries %d\n",Page->ActualCount);
|
||
printf("Flag %x",Page->Flags);
|
||
printf("\t\t\tBytes Available %d\n", Page->LastFree-Page->NextFree);
|
||
|
||
if ( Page->FragmentedBytes != 0 ) {
|
||
printf("Fragmented bytes %d\n", Page->FragmentedBytes);
|
||
}
|
||
}
|
||
|
||
HTable->Entries += Page->EntryCount;
|
||
|
||
//
|
||
// Make sure entries are correct
|
||
//
|
||
|
||
for (j=0; j<MAX_LEAF_ENTRIES;j++ ) {
|
||
|
||
offset = Page->ArtOffset[j];
|
||
if ( offset != 0 ) {
|
||
|
||
if ( offset < 0 ) {
|
||
|
||
nDel++;
|
||
continue;
|
||
}
|
||
|
||
nOk++;
|
||
|
||
//
|
||
// Make sure hash values are mapped to correct pages
|
||
//
|
||
|
||
if ( Page->PageDepth == 0 ) {
|
||
|
||
//
|
||
// if PageDepth is zero, then everything is ok.
|
||
//
|
||
|
||
continue;
|
||
}
|
||
|
||
if ( HTable->Signature == ART_HEAD_SIGNATURE ) {
|
||
|
||
PART_MAP_ENTRY aEntry;
|
||
aEntry = (PART_MAP_ENTRY)((PCHAR)Page + offset);
|
||
if ( Page->HashPrefix !=
|
||
(aEntry->Header.HashValue >> (32 - Page->PageDepth)) ) {
|
||
|
||
printf("Invalid: HashValue %x\n",aEntry->Header.HashValue);
|
||
HTable->Flags |= HASH_FLAG_BAD_HASH;
|
||
}
|
||
|
||
} else if ( HTable->Signature == HIST_HEAD_SIGNATURE ) {
|
||
|
||
PHISTORY_MAP_ENTRY hEntry;
|
||
hEntry = (PHISTORY_MAP_ENTRY)((PCHAR)Page + offset);
|
||
if ( Page->HashPrefix !=
|
||
(hEntry->Header.HashValue >> (32 - Page->PageDepth)) ) {
|
||
|
||
printf("Invalid: HashValue %x\n",hEntry->Header.HashValue);
|
||
HTable->Flags |= HASH_FLAG_BAD_HASH;
|
||
}
|
||
|
||
} else if ( HTable->Signature == XOVER_HEAD_SIGNATURE ) {
|
||
|
||
PXOVER_MAP_ENTRY xEntry;
|
||
xEntry = (PXOVER_MAP_ENTRY)((PCHAR)Page + offset);
|
||
|
||
if ( Page->HashPrefix !=
|
||
(xEntry->Header.HashValue >> (32 - Page->PageDepth)) ) {
|
||
|
||
printf("Invalid: HashValue %x\n",xEntry->Header.HashValue);
|
||
HTable->Flags |= HASH_FLAG_BAD_HASH;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Check to see that all numbers are consistent
|
||
//
|
||
|
||
if ( nDel + nOk != Page->EntryCount ) {
|
||
printf("!!!!!!! counts don't match\n");
|
||
HTable->Flags |= HASH_FLAG_BAD_ENTRY_COUNT;
|
||
}
|
||
|
||
if ( Verbose ) {
|
||
printf("Deleted %d Ok %d Total %d\n\n",nDel,nOk,nDel+nOk);
|
||
}
|
||
|
||
HTable->TotDels += nDel;
|
||
HTable->TotIns += nOk;
|
||
|
||
} // PrintPageStats
|
||
|
||
BOOL
|
||
checklink(
|
||
PHTABLE HTable
|
||
)
|
||
{
|
||
|
||
DWORD fileSize = 0;
|
||
DWORD nPages;
|
||
HANDLE hFile = INVALID_HANDLE_VALUE, hMap = NULL;
|
||
PMAP_PAGE hashPages = NULL;
|
||
PHASH_RESERVED_PAGE headPage = NULL;
|
||
DWORD dirDepth;
|
||
DWORD nEntries;
|
||
PDWORD directory = NULL;
|
||
PMAP_PAGE curPage;
|
||
DWORD i;
|
||
DWORD j;
|
||
DWORD status;
|
||
BOOL ret = FALSE;
|
||
|
||
//
|
||
// Open the hash file
|
||
//
|
||
|
||
hFile = CreateFile(
|
||
HTable->FileName,
|
||
GENERIC_READ | GENERIC_WRITE,
|
||
0,
|
||
NULL,
|
||
OPEN_EXISTING,
|
||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
|
||
NULL
|
||
);
|
||
|
||
if ( hFile == INVALID_HANDLE_VALUE ) {
|
||
status = GetLastError();
|
||
if ( status == ERROR_FILE_NOT_FOUND ) {
|
||
HTable->Flags |= HASH_FLAG_NO_FILE;
|
||
if ( Verbose ) {
|
||
printf("File not found\n");
|
||
}
|
||
} else {
|
||
HTable->Flags |= HASH_FLAG_ABORT_SCAN;
|
||
printf("Error %d in CreateFile.\n",status);
|
||
}
|
||
goto error;
|
||
}
|
||
|
||
//
|
||
// Get the size of the file. This will tell us how many pages
|
||
// are currently filled.
|
||
//
|
||
|
||
fileSize = GetFileSize( hFile, NULL );
|
||
if ( fileSize == 0xffffffff ) {
|
||
status = GetLastError();
|
||
printf("Error %d in GetFileSize\n",status);
|
||
HTable->Flags |= HASH_FLAG_ABORT_SCAN;
|
||
goto error;
|
||
}
|
||
|
||
if ( Verbose ) {
|
||
printf("File size is %d\n",fileSize);
|
||
}
|
||
HTable->FileSize = fileSize;
|
||
|
||
//
|
||
// Make sure the file size is a multiple of a page
|
||
//
|
||
|
||
if ( (fileSize % HASH_PAGE_SIZE) != 0 ) {
|
||
|
||
//
|
||
// Not a page multiple! Corrupted!
|
||
//
|
||
|
||
printf("File size(%d) is not page multiple.\n",fileSize);
|
||
HTable->Flags |= HASH_FLAG_BAD_SIZE;
|
||
goto error;
|
||
}
|
||
|
||
nPages = fileSize / HASH_PAGE_SIZE;
|
||
|
||
if ( Verbose ) {
|
||
printf("pages allocated %d\n", nPages);
|
||
}
|
||
|
||
//
|
||
// Create File Mapping
|
||
//
|
||
|
||
hMap = CreateFileMapping(
|
||
hFile,
|
||
NULL,
|
||
PAGE_READWRITE,
|
||
0,
|
||
0,
|
||
NULL
|
||
);
|
||
|
||
if ( hMap == NULL ) {
|
||
status = GetLastError();
|
||
printf("Error %d in CreateFileMapping\n",status);
|
||
HTable->Flags |= HASH_FLAG_ABORT_SCAN;
|
||
goto error;
|
||
}
|
||
|
||
//
|
||
// create our view
|
||
//
|
||
|
||
headPage = (PHASH_RESERVED_PAGE)MapViewOfFileEx(
|
||
hMap,
|
||
FILE_MAP_ALL_ACCESS,
|
||
0, // offset high
|
||
0, // offset low
|
||
0, // bytes to map
|
||
NULL // base address
|
||
);
|
||
|
||
if ( headPage == NULL ) {
|
||
status = GetLastError();
|
||
printf("Error %d in MapViewOfFile\n",status);
|
||
HTable->Flags |= HASH_FLAG_ABORT_SCAN;
|
||
goto error;
|
||
}
|
||
|
||
//
|
||
// Print out the header stats
|
||
//
|
||
|
||
PrintHeadStats( headPage );
|
||
|
||
//
|
||
// Check the signature and the initialize bit
|
||
//
|
||
|
||
if ( headPage->Signature != HTable->Signature ) {
|
||
|
||
//
|
||
// Wrong signature
|
||
//
|
||
|
||
printf("Invalid signature %x (expected %x)\n",
|
||
headPage->Signature, HTable->Signature);
|
||
HTable->Flags |= HASH_FLAG_BAD_SIGN;
|
||
goto error;
|
||
}
|
||
|
||
if ( !headPage->Initialized ) {
|
||
|
||
//
|
||
// Not initialized !
|
||
//
|
||
|
||
printf("Existing file uninitialized!!!!.\n");
|
||
HTable->Flags |= HASH_FLAG_NOT_INIT;
|
||
goto error;
|
||
}
|
||
|
||
if ( headPage->NumPages > nPages ) {
|
||
|
||
//
|
||
// bad count. Corrupt file.
|
||
//
|
||
|
||
printf("NumPages in Header(%d) more than actual(%d)\n",
|
||
headPage->NumPages, nPages);
|
||
HTable->Flags |= HASH_FLAG_BAD_PAGE_COUNT;
|
||
goto error;
|
||
}
|
||
|
||
//
|
||
// Create links and print stats for each page
|
||
//
|
||
|
||
nPages = headPage->NumPages;
|
||
dirDepth = headPage->DirDepth;
|
||
|
||
hashPages = (PMAP_PAGE)((PCHAR)headPage + HASH_PAGE_SIZE);
|
||
|
||
//
|
||
// OK, build the directory
|
||
//
|
||
|
||
nEntries = (DWORD)(1 << dirDepth);
|
||
if ( nEntries <= nPages ) {
|
||
printf("dir depth is not sufficient for pages\n");
|
||
HTable->Flags |= HASH_FLAG_BAD_DIR_DEPTH;
|
||
goto error;
|
||
}
|
||
|
||
if ( Verbose ) {
|
||
printf("\nSetting up directory of %d entries\n",nEntries);
|
||
}
|
||
|
||
directory = (PDWORD)ALLOCATE_HEAP( nEntries * sizeof(DWORD) );
|
||
if ( directory == NULL ) {
|
||
printf("Cannot allocate directory of %d entries!!!\n",nEntries);
|
||
HTable->Flags |= HASH_FLAG_ABORT_SCAN;
|
||
goto error;
|
||
}
|
||
|
||
//
|
||
// Initialize the directory to zero.
|
||
//
|
||
|
||
ZeroMemory( directory, nEntries * sizeof(DWORD) );
|
||
|
||
//
|
||
// Initialize the links. Here we go through all the pages and update the directory
|
||
// links
|
||
//
|
||
|
||
curPage = hashPages;
|
||
for ( i = 1; i < nPages; i++ ) {
|
||
|
||
//
|
||
// Set the pointers for this page
|
||
//
|
||
|
||
DWORD startPage, endPage;
|
||
DWORD j;
|
||
|
||
if ( Verbose ) {
|
||
printf("Processing page %d\n",i);
|
||
}
|
||
|
||
//
|
||
// Get the range of directory entries that point to this page
|
||
//
|
||
|
||
startPage = curPage->HashPrefix << (dirDepth - curPage->PageDepth);
|
||
endPage = ((curPage->HashPrefix+1) << (dirDepth - curPage->PageDepth));
|
||
|
||
if ( Verbose ) {
|
||
printf("\tDirectory ptrs <%d:%d>\n",startPage,endPage-1);
|
||
}
|
||
|
||
if ( (startPage > nEntries) ||
|
||
(endPage > nEntries) ) {
|
||
printf("Corrupt prefix for page %d\n",i);
|
||
HTable->Flags |= HASH_FLAG_CORRUPT;
|
||
goto error;
|
||
}
|
||
|
||
|
||
for ( j = startPage; j < endPage; j++ ) {
|
||
directory[j] = i;
|
||
}
|
||
|
||
//
|
||
// Print page stats
|
||
//
|
||
|
||
PrintPageStats( HTable, curPage );
|
||
|
||
//
|
||
// go to the next page
|
||
//
|
||
|
||
curPage = (PMAP_PAGE)((PCHAR)curPage + HASH_PAGE_SIZE);
|
||
}
|
||
|
||
//
|
||
// Make sure all the links have been initialized. If not, then something terrible
|
||
// has happened. Do a comprehensive rebuilt.
|
||
//
|
||
|
||
for (i=0;i<nEntries;i++) {
|
||
if ( directory[i] == 0 ) {
|
||
printf("Directory link check failed on %d\n",i);
|
||
HTable->Flags |= HASH_FLAG_BAD_LINK;
|
||
goto error;
|
||
}
|
||
}
|
||
|
||
ret = TRUE;
|
||
|
||
error:
|
||
|
||
//
|
||
// Delete the Directory
|
||
//
|
||
|
||
if ( directory != NULL ) {
|
||
FREE_HEAP(directory);
|
||
directory = NULL;
|
||
}
|
||
|
||
//
|
||
// Destroy the view
|
||
//
|
||
|
||
if ( headPage != NULL ) {
|
||
|
||
//
|
||
// Flush the hash table
|
||
//
|
||
|
||
(VOID)FlushViewOfFile( headPage, 0 );
|
||
|
||
//
|
||
// Close the view
|
||
//
|
||
|
||
(VOID) UnmapViewOfFile( headPage );
|
||
headPage = NULL;
|
||
}
|
||
|
||
//
|
||
// Destroy the file mapping
|
||
//
|
||
|
||
if ( hMap != NULL ) {
|
||
|
||
CloseHandle( hMap );
|
||
hMap = NULL;
|
||
}
|
||
|
||
//
|
||
// Close the file
|
||
//
|
||
|
||
if ( hFile != INVALID_HANDLE_VALUE ) {
|
||
CloseHandle( hFile );
|
||
hFile = INVALID_HANDLE_VALUE;
|
||
}
|
||
|
||
return(ret);
|
||
|
||
} // chklink
|
||
|
||
BOOL
|
||
diagnose(
|
||
PHTABLE HTable
|
||
)
|
||
{
|
||
DWORD flags = HTable->Flags;
|
||
|
||
printf("Status: ");
|
||
if ( flags == 0 ) {
|
||
printf("Good.\n");
|
||
return(TRUE);
|
||
}
|
||
|
||
//
|
||
// Missing?
|
||
//
|
||
|
||
if ( flags & HASH_FLAG_NO_FILE ) {
|
||
if ( !DoClean ) {
|
||
printf("Missing File.\n");
|
||
}
|
||
goto exit;
|
||
}
|
||
|
||
if ( flags & HASH_FLAG_ABORT_SCAN ) {
|
||
printf("Internal error occurred while processing.\n");
|
||
goto exit;
|
||
}
|
||
|
||
printf("Corrupt. Diagnostic Code %x.\n",flags);
|
||
|
||
exit:
|
||
return(FALSE);
|
||
}
|