|
|
/*++
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; }
|