windows-nt/Source/XPSP1/NT/windows/winstate/cobra/utils/memdb/memdbfile.c

890 lines
20 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
memdbfile.c
Abstract:
file operations for memdb saving/loading/exporting/importing
Author:
Jim Schmidt (jimschm) 8-Aug-1996
Revision History:
mvander 13-Aug-1999 split from memdb.c
--*/
#include "pch.h"
#include "memdbp.h"
//
// This is our version stamp. Change MEMDB_VERSION_STAMP only.
//
#define MEMDB_VERSION_STAMP L"v9 "
#define VERSION_BASE_SIGNATURE L"memdb dat file "
#define MEMDB_DEBUG_SIGNATURE L"debug"
#define MEMDB_NODBG_SIGNATURE L"nodbg"
#define VERSION_SIGNATURE VERSION_BASE_SIGNATURE MEMDB_VERSION_STAMP
#define DEBUG_FILE_SIGNATURE VERSION_SIGNATURE MEMDB_DEBUG_SIGNATURE
#define RETAIL_FILE_SIGNATURE VERSION_SIGNATURE MEMDB_NODBG_SIGNATURE
#ifdef DEBUG
#define FILE_SIGNATURE DEBUG_FILE_SIGNATURE
#else
#define FILE_SIGNATURE RETAIL_FILE_SIGNATURE
#endif
PBYTE
MapFileFromHandle (
HANDLE hFile,
PHANDLE hMap
)
{
MYASSERT(hMap);
if (!hFile || hFile == INVALID_HANDLE_VALUE) {
return NULL;
}
*hMap = CreateFileMappingA (
hFile,
NULL,
PAGE_READWRITE,
0,
0,
NULL
);
if (*hMap == NULL) {
return NULL;
}
return MapViewOfFile (*hMap, FILE_MAP_WRITE, 0, 0, 0);
}
BOOL
SetSizeOfFile (
HANDLE hFile,
LONGLONG Size
)
{
LONG a;
LONG b;
PLONG sizeHi;
a = (LONG) Size;
b = (LONG) (SHIFTRIGHT32(Size));
if (b) {
sizeHi = &b;
} else {
sizeHi = NULL;
}
if (SetFilePointer (hFile, a, sizeHi, FILE_BEGIN) == INVALID_SET_FILE_POINTER) {
return FALSE;
}
if (!SetEndOfFile (hFile)) {
return FALSE;
}
return TRUE;
}
BOOL
WriteBlocks (
IN OUT PBYTE *Buf,
IN PMEMDBHASH pHashTable,
IN PGROWBUFFER pOffsetBuffer
)
{
MYASSERT(Buf);
MYASSERT(pHashTable);
MYASSERT(pOffsetBuffer);
if (!WriteHashBlock (pHashTable, Buf)) {
return FALSE;
}
if (!WriteOffsetBlock (pOffsetBuffer, Buf)) {
return FALSE;
}
return TRUE;
}
BOOL
ReadBlocks (
IN OUT PBYTE *Buf,
OUT PMEMDBHASH *ppHashTable,
OUT PGROWBUFFER pOffsetBuffer
)
{
MYASSERT(Buf);
MYASSERT(ppHashTable);
MYASSERT(pOffsetBuffer);
//
// fill hash block
//
if (!*ppHashTable) {
return FALSE;
}
if (!ReadHashBlock (*ppHashTable, Buf)) {
return FALSE;
}
if (!ReadOffsetBlock (pOffsetBuffer, Buf)) {
return FALSE;
}
return TRUE;
}
BOOL
pPrivateMemDbSave (
PCSTR FileName
)
{
HANDLE FileHandle = NULL;
HANDLE hMap = INVALID_HANDLE_VALUE;
PBYTE Buf = NULL;
PBYTE MapPtr = NULL;
BOOL result = FALSE;
EnterCriticalSection (&g_MemDbCs);
__try {
if (!SelectDatabase (DB_PERMANENT)) {
__leave;
}
//
// now we resize file to fit everything in it.
//
FileHandle = BfCreateFileA (FileName);
if (!FileHandle) {
__leave;
}
if (!SetSizeOfFile (
FileHandle,
(LONGLONG)(sizeof (FILE_SIGNATURE)) +
g_CurrentDatabase->AllocSize +
GetHashTableBlockSize (g_CurrentDatabase->HashTable) +
GetOffsetBufferBlockSize (&g_CurrentDatabase->OffsetBuffer)
)) {
__leave;
}
Buf = MapFileFromHandle (FileHandle, &hMap);
if (Buf == NULL) {
__leave;
}
MapPtr = Buf;
CopyMemory (Buf, FILE_SIGNATURE, sizeof (FILE_SIGNATURE));
Buf += sizeof (FILE_SIGNATURE);
CopyMemory (Buf, g_CurrentDatabase, g_CurrentDatabase->AllocSize);
Buf += g_CurrentDatabase->AllocSize;
if (!WriteBlocks (
&Buf,
g_CurrentDatabase->HashTable,
&g_CurrentDatabase->OffsetBuffer
)) {
__leave;
}
result = TRUE;
}
__finally {
UnmapFile (MapPtr, hMap, FileHandle);
PushError();
// lint is not familiar with __finally so...
if (!result) { //lint !e774
if (FileHandle) {
CloseHandle (FileHandle);
}
DeleteFileA (FileName);
}
LeaveCriticalSection (&g_MemDbCs);
PopError();
}
return result;
}
BOOL
MemDbSaveA (
PCSTR FileName
)
{
return pPrivateMemDbSave (FileName); // TRUE=UNICODE
}
BOOL
MemDbSaveW (
PCWSTR FileName
)
{
PCSTR p;
BOOL b = FALSE;
p = ConvertWtoA (FileName);
if (p) {
b = pPrivateMemDbSave (p);
FreeConvertedStr (p);
}
return b;
}
BOOL
pPrivateMemDbLoad (
IN PCSTR AnsiFileName,
IN PCWSTR UnicodeFileName,
OUT PMEMDB_VERSION Version, OPTIONAL
IN BOOL QueryVersionOnly
)
{
HANDLE FileHandle = NULL;
HANDLE hMap = INVALID_HANDLE_VALUE;
WCHAR FileSig[sizeof(FILE_SIGNATURE)];
PCWSTR VerPtr;
UINT DbSize;
PMEMDBHASH pHashTable;
PBYTE Buf = NULL;
PBYTE SavedBuf = NULL;
PCSTR databaseLocation = NULL;
BOOL result = FALSE;
EnterCriticalSection (&g_MemDbCs);
__try {
__try {
if (Version) {
ZeroMemory (Version, sizeof (MEMDB_VERSION));
}
//
// Blow away existing resources
//
if (!QueryVersionOnly) {
databaseLocation = DuplicatePathStringA (DatabasesGetBasePath (), 0);
DatabasesTerminate (FALSE);
DatabasesInitializeA (databaseLocation);
FreePathStringA (databaseLocation);
if (!SelectDatabase (DB_PERMANENT)) {
__leave;
}
}
if (AnsiFileName) {
Buf = MapFileIntoMemoryA (AnsiFileName, &FileHandle, &hMap);
} else {
Buf = MapFileIntoMemoryW (UnicodeFileName, &FileHandle, &hMap);
}
if (Buf == NULL) {
__leave;
}
SavedBuf = Buf;
//
// Obtain the file signature
//
// NOTE: Entire file read is in UNICODE char set
//
CopyMemory (FileSig, Buf, sizeof(FILE_SIGNATURE));
if (Version) {
if (StringMatchByteCountW (
VERSION_BASE_SIGNATURE,
FileSig,
sizeof (VERSION_BASE_SIGNATURE) - sizeof (WCHAR)
)) {
Version->Valid = TRUE;
//
// Identify version number
//
VerPtr = (PCWSTR) ((PBYTE)FileSig + sizeof (VERSION_BASE_SIGNATURE) - sizeof (WCHAR));
if (StringMatchByteCountW (
MEMDB_VERSION_STAMP,
VerPtr,
sizeof (MEMDB_VERSION_STAMP) - sizeof (WCHAR)
)) {
Version->CurrentVersion = TRUE;
}
Version->Version = (UINT) _wtoi (VerPtr + 1);
//
// Identify checked or free build
//
VerPtr += (sizeof (MEMDB_VERSION_STAMP) / sizeof (WCHAR)) - 1;
if (StringMatchByteCountW (
MEMDB_DEBUG_SIGNATURE,
VerPtr,
sizeof (MEMDB_DEBUG_SIGNATURE) - sizeof (WCHAR)
)) {
Version->Debug = TRUE;
} else if (!StringMatchByteCountW (
VerPtr,
MEMDB_NODBG_SIGNATURE,
sizeof (MEMDB_NODBG_SIGNATURE) - sizeof (WCHAR)
)) {
Version->Valid = FALSE;
}
}
}
if (!QueryVersionOnly) {
if (!StringMatchW (FileSig, FILE_SIGNATURE)) {
#ifdef DEBUG
if (StringMatchW (FileSig, DEBUG_FILE_SIGNATURE)) {
g_UseDebugStructs = TRUE;
} else if (StringMatchW (FileSig, RETAIL_FILE_SIGNATURE)) {
DEBUGMSG ((DBG_ERROR, "memdb dat file is from free build; checked version expected"));
g_UseDebugStructs = FALSE;
} else {
#endif
SetLastError (ERROR_BAD_FORMAT);
LOG ((LOG_WARNING, "Warning: data file could be from checked build; free version expected"));
__leave;
#ifdef DEBUG
}
#endif
}
Buf += sizeof(FILE_SIGNATURE);
DbSize = *((PUINT)Buf);
//
// resize the database. SizeDatabaseBuffer also fixes g_CurrentDatabase
// and other global variables, so we dont have to worry.
//
if (!SizeDatabaseBuffer(g_CurrentDatabaseIndex, DbSize)) {
__leave;
}
MYASSERT (g_CurrentDatabase);
//
// save hashtable pointer (which points to hashtable created
// in InitializeDatabases (above)), then load database, then
// fix hashtable pointer.
//
pHashTable = g_CurrentDatabase->HashTable;
CopyMemory (g_CurrentDatabase, Buf, DbSize);
g_CurrentDatabase->HashTable = pHashTable;
Buf += DbSize;
if (!ReadBlocks (
&Buf,
&g_CurrentDatabase->HashTable,
&g_CurrentDatabase->OffsetBuffer
)) {
__leave;
}
result = TRUE;
}
UnmapFile (SavedBuf, hMap, FileHandle);
}
__except (TRUE) {
result = FALSE;
PushError();
#ifdef DEBUG
if (AnsiFileName) {
LOGA ((LOG_ERROR, "MemDb dat file %s could not be loaded because of an exception", AnsiFileName));
} else {
LOGW ((LOG_ERROR, "MemDb dat file %s could not be loaded because of an exception", UnicodeFileName));
}
#endif
PopError();
}
}
__finally {
PushError();
if (!result && !QueryVersionOnly) {
databaseLocation = DuplicatePathStringA (DatabasesGetBasePath (), 0);
DatabasesTerminate (FALSE);
DatabasesInitializeA (databaseLocation);
FreePathStringA (databaseLocation);
}
LeaveCriticalSection (&g_MemDbCs);
PopError();
}
return result;
}
BOOL
MemDbLoadA (
IN PCSTR FileName
)
{
return pPrivateMemDbLoad (FileName, NULL, NULL, FALSE);
}
BOOL
MemDbLoadW (
IN PCWSTR FileName
)
{
return pPrivateMemDbLoad (NULL, FileName, NULL, FALSE);
}
BOOL
MemDbQueryVersionA (
PCSTR FileName,
PMEMDB_VERSION Version
)
{
BOOL b;
b = pPrivateMemDbLoad (FileName, NULL, Version, TRUE);
return b ? Version->Valid : FALSE;
}
BOOL
MemDbQueryVersionW (
PCWSTR FileName,
PMEMDB_VERSION Version
)
{
pPrivateMemDbLoad (NULL, FileName, Version, TRUE);
return Version->Valid;
}
/* format for binary file export
DWORD Signature
UINT Version
UINT GlobalFlags// 0x00000001 mask for Ansi format
// 0x00000002 mask for debug mode
//
// each _KEY block is followed by its children,
// and each of those is followed by its children,
// etc., so it is easy to recurse to gather
// the whole tree.
//
struct _KEY {
#if (GlobalFlags & MEMDB_EXPORT_FLAGS_DEBUG)
WORD DebugSig // signature for each keystruct block.
#endif
WORD StructSize; // total number of bytes including this member
WORD NameSize; // total number of bytes in Key[]
WORD DataSize; // total number of bytes in Data[]
WORD NumChildren // number of children, whose data structures will follow
// this one (though not necessarily one after another, if
// any of them have children themselves)
BYTE Key[]; // Should be PCSTR or PCWSTR (not zero terminated).
// the first key in the exported file will have the full
// key path as its key name.
BYTE Data[]; // block of data pieces, all in same format as in datablock.c
}
*/
#define MEMDB_EXPORT_SIGNATURE ('M'+('D'<<8)+('B'<<16)+('X'<<24))
// NTRAID#NTBUG9-153308-2000/08/01-jimschm reenable the line below when implementing export and import functions
//#define MEMDB_EXPORT_DEBUG_SIG ('K'+('Y'<<8))
#define MEMDB_EXPORT_VERSION 0x00000003
#define MEMDB_EXPORT_FLAGS_ANSI 0x00000001
#define MEMDB_EXPORT_FLAGS_DEBUG 0x00000002
// NTRAID#NTBUG9-153308-2000/08/01-jimschm Implement the function and remove lint comments
//lint -save -e713 -e715
BOOL
pMemDbExportWorker (
IN HANDLE FileHandle,
IN UINT KeyIndex,
IN BOOL AnsiFormat,
IN PCWSTR FullKeyPath
)
/*++
Routine Description:
exports a key to a file, and then recurses through
that key's children.
Arguments:
FileHandle - already opened handle to write to
KeyIndex - index of key to write
AnsiFormat - if TRUE, then FullKeyPath (above) and KeyName
(below) are actually ANSI strings (not unicode).
FullKeyPath - only used for first keystruct to be written
to file. it specifies the full path of the root key.
for all others, this argument should be NULL.
Return Value:
TRUE if successful, FALSE otherwise.
--*/
{
return TRUE;
}
//lint -restore
BOOL
pMemDbExport (
IN PCWSTR RootTree,
IN PCSTR FileName,
IN BOOL AnsiFormat
)
/*++
Routine Description:
exports a MemDb tree to a file
Arguments:
RootTree - full key path of the top level key to write
to the file.
FileName - file to write to.
AnsiFormat - if TRUE, then RootTree and FileName are
actually ANSI strings (not unicode).
Return Value:
TRUE if successful, FALSE otherwise.
--*/
{
HANDLE FileHandle = NULL;
UINT Flags;
DWORD written;
UINT RootIndex = INVALID_OFFSET;
PCWSTR SubRootTreeW, RootTreeW;
BOOL b;
if (AnsiFormat) {
//
// if we are in ansi mode, everything is ANSI strings,
// but we still need unicode string for SelectHiveW ()
//
RootTreeW = ConvertAtoW ((PCSTR)RootTree);
if (!RootTreeW) {
return FALSE;
}
} else {
RootTreeW = RootTree;
}
SubRootTreeW = SelectHiveW (RootTreeW);
if (SubRootTreeW) {
RootIndex = FindKeyStruct (SubRootTreeW);
}
if (AnsiFormat) {
FreeConvertedStr(RootTreeW);
}
if (RootIndex == INVALID_OFFSET) {
return FALSE;
}
FileHandle = BfCreateFileA (FileName);
if (!FileHandle) {
return FALSE;
}
Flags = MEMDB_EXPORT_SIGNATURE;
WriteFile (FileHandle, &Flags, sizeof (DWORD), &written, NULL);
Flags = MEMDB_EXPORT_VERSION;
WriteFile (FileHandle, &Flags, sizeof (UINT), &written, NULL);
Flags = AnsiFormat ? MEMDB_EXPORT_FLAGS_ANSI : 0;
#ifdef DEBUG
Flags |= MEMDB_EXPORT_FLAGS_DEBUG;
#endif
WriteFile (FileHandle, &Flags, sizeof (UINT), &written, NULL);
//
// write root index key and all children to file.
//
b = pMemDbExportWorker(FileHandle, RootIndex, AnsiFormat, RootTree);
//
// finally write the zero terminator
//
Flags = 0;
WriteFile (FileHandle, &Flags, sizeof (WORD), &written, NULL);
CloseHandle (FileHandle);
return b;
}
BOOL
MemDbExportA (
IN PCSTR RootTree,
IN PCSTR FileName,
IN BOOL AnsiFormat
)
{
PCWSTR p;
BOOL b;
if (!AnsiFormat) {
p = ConvertAtoW (RootTree);
if (!p) {
return FALSE;
}
b = pMemDbExport (p, FileName, FALSE);
FreeConvertedStr (p);
} else {
b = pMemDbExport ((PCWSTR)RootTree, FileName, TRUE);
}
return b;
}
BOOL
MemDbExportW (
IN PCWSTR RootTree,
IN PCWSTR FileName,
IN BOOL AnsiFormat
)
{
PCSTR p, FileNameA;
BOOL b;
FileNameA = ConvertWtoA (FileName);
if (!FileNameA) {
return FALSE;
}
if (AnsiFormat) {
p = ConvertWtoA (RootTree);
if (!p) {
FreeConvertedStr (FileNameA);
return FALSE;
}
b = pMemDbExport ((PCWSTR)p, FileNameA, TRUE);
FreeConvertedStr (p);
} else {
b = pMemDbExport (RootTree, FileNameA, FALSE);
}
FreeConvertedStr (FileNameA);
return b;
}
// NTRAID#NTBUG9-153308-2000/08/01-jimschm Implement the function and remove lint comments
//lint -save -e713 -e715
BOOL
pMemDbImportWorker (
IN PBYTE *FileBuffer,
IN BOOL AnsiFormat,
IN BOOL DebugMode,
IN BOOL ExportRoot
)
/*++
Routine Description:
imports a key from a file, and then recurses through
that key's children.
Arguments:
FileBuffer - pointer to a memory pointer, which should
initially point to the beginning of the
memory-mapped file to read. this will be updated
as the function runs
AnsiFormat - TRUE if the file is in ANSI mode (determined
by file header)
DebugMode - TRUE if the file is in debug mode (determined
by file header)
ExportRoot - TRUE if this is the first call to this function
for a file (the name of the first keystruct in a file
is the full key path for that keystruct, all other keys
in the file have only the relative name).
Return Value:
TRUE if successful, FALSE otherwise.
--*/
{
return TRUE;
}
//lint -restore
BOOL
MemDbImportA (
IN PCSTR FileName
)
{
PCWSTR FileNameW;
BOOL b = FALSE;
FileNameW = ConvertAtoW (FileName);
if (FileNameW) {
b = MemDbImportW (FileNameW);
FreeConvertedStr (FileNameW);
}
return b;
}
BOOL
MemDbImportW (
IN PCWSTR FileName
)
/*++
Routine Description:
MemDbImportW imports a tree from a private binary format. The format is described above.
Arguments:
FileName - Name of the binary format file to import from.
Return Value:
TRUE is successfull, FALSE if not.
--*/
{
PBYTE fileBuff, BufferPtr;
HANDLE fileHandle;
HANDLE mapHandle;
BOOL b = FALSE;
UINT Flags;
fileBuff = MapFileIntoMemoryW (FileName, &fileHandle, &mapHandle);
if (fileBuff == NULL) {
DEBUGMSGW ((DBG_ERROR, "Could not execute MemDbImport for %s", FileName));
return FALSE;
}
__try {
BufferPtr = fileBuff;
if (*((PDWORD) BufferPtr) != MEMDB_EXPORT_SIGNATURE) {
DEBUGMSGW ((DBG_ERROR, "Unknown signature for file to import: %s", FileName));
b = FALSE;
} else {
BufferPtr += sizeof (DWORD);
if (*((PUINT) BufferPtr) != MEMDB_EXPORT_VERSION) {
DEBUGMSGW ((DBG_ERROR, "Unknown or outdated version for file to import: %s", FileName));
b = FALSE;
} else {
BufferPtr += sizeof (UINT);
Flags = *((PUINT) BufferPtr);
BufferPtr += sizeof (UINT);
b = pMemDbImportWorker (
&BufferPtr,
Flags & MEMDB_EXPORT_FLAGS_ANSI,
Flags & MEMDB_EXPORT_FLAGS_DEBUG,
TRUE
);
}
}
}
__except (1) {
DEBUGMSGW ((DBG_ERROR, "Access violation while importing: %s", FileName));
}
UnmapFile (fileBuff, mapHandle, fileHandle);
return b;
}