3023 lines
71 KiB
C
3023 lines
71 KiB
C
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
memdb.c
|
|
|
|
Abstract:
|
|
|
|
A simple memory-based database for associating flags
|
|
with a string.
|
|
|
|
Author:
|
|
|
|
Jim Schmidt (jimschm) 8-Aug-1996
|
|
|
|
Revision History:
|
|
|
|
jimschm 23-Sep-1998 Expanded user flags to 24 bits (from 12 bits)
|
|
calinn 12-Dec-1997 Extended MemDbMakePrintableKey and MemDbMakeNonPrintableKey
|
|
jimschm 03-Dec-1997 Added multi-thread synchronization
|
|
jimschm 22-Oct-1997 Split into multiple source files,
|
|
added multiple memory block capability
|
|
jimschm 16-Sep-1997 Hashing: delete fix
|
|
jimschm 29-Jul-1997 Hashing, user flags added
|
|
jimschm 07-Mar-1997 Signature changes
|
|
jimschm 03-Mar-1997 PrivateBuildKeyFromOffset changes
|
|
jimschm 18-Dec-1996 Fixed deltree bug
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
#include "memdbp.h"
|
|
|
|
#ifndef UNICODE
|
|
#error UNICODE required
|
|
#endif
|
|
|
|
|
|
//
|
|
// Global delcaration
|
|
//
|
|
|
|
PDATABASE g_db;
|
|
GROWLIST g_DatabaseList = GROWLIST_INIT;
|
|
BYTE g_SelectedDatabase;
|
|
PHIVE g_HeadHive;
|
|
CRITICAL_SECTION g_MemDbCs;
|
|
|
|
#ifdef DEBUG
|
|
|
|
#define FILE_SIGNATURE DEBUG_FILE_SIGNATURE
|
|
BOOL g_UseDebugStructs = TRUE;
|
|
|
|
#else
|
|
|
|
#define FILE_SIGNATURE RETAIL_FILE_SIGNATURE
|
|
|
|
#endif
|
|
|
|
//
|
|
// Private prototypes
|
|
//
|
|
|
|
INT
|
|
pCreateDatabase (
|
|
PCWSTR Name
|
|
);
|
|
|
|
BOOL
|
|
pInitializeDatabase (
|
|
OUT PDATABASE Database,
|
|
IN PCWSTR Name
|
|
);
|
|
|
|
BOOL
|
|
pFreeDatabase (
|
|
IN OUT PDATABASE Database
|
|
);
|
|
|
|
VOID
|
|
pFreeSelectedDatabase (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
pFreeAllDatabases (
|
|
VOID
|
|
);
|
|
|
|
BOOL
|
|
pPrivateMemDbGetValueW (
|
|
IN PCWSTR KeyStr,
|
|
OUT PDWORD Value, OPTIONAL
|
|
OUT PDWORD UserFlagsPtr OPTIONAL
|
|
);
|
|
|
|
BOOL
|
|
pInitializeMemDb (
|
|
VOID
|
|
);
|
|
|
|
|
|
//
|
|
// Implementation
|
|
//
|
|
|
|
|
|
BOOL
|
|
MemDb_Entry (
|
|
IN HINSTANCE hinstDLL,
|
|
IN DWORD Reason,
|
|
IN PVOID lpv
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
DllMain is called after the C runtime is initialized, and its purpose
|
|
is to initialize the globals for this process.
|
|
|
|
Arguments:
|
|
|
|
hinstDLL - (OS-supplied) Instance handle for the DLL
|
|
Reason - (OS-supplied) Type of initialization or termination
|
|
lpv - (OS-supplied) Unused
|
|
|
|
Return Value:
|
|
|
|
TRUE because DLL always initializes properly.
|
|
|
|
--*/
|
|
|
|
{
|
|
switch (Reason) {
|
|
|
|
case DLL_PROCESS_ATTACH:
|
|
if (!pInitializeMemDb()) {
|
|
return FALSE;
|
|
}
|
|
|
|
InitializeCriticalSection (&g_MemDbCs);
|
|
|
|
InitOperationTable();
|
|
|
|
break;
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
pFreeAllDatabases();
|
|
FreeGrowList (&g_DatabaseList);
|
|
DeleteCriticalSection (&g_MemDbCs);
|
|
|
|
DumpBinTreeStats();
|
|
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
pInitializeMemDb (
|
|
VOID
|
|
)
|
|
{
|
|
FreeGrowList (&g_DatabaseList);
|
|
ZeroMemory (&g_DatabaseList, sizeof (g_DatabaseList));
|
|
g_db = NULL;
|
|
|
|
if (!InitializeHashBlock()) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (pCreateDatabase (L"") != 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
g_SelectedDatabase = 1;
|
|
SelectDatabase (0);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
pInitializeDatabase (
|
|
OUT PDATABASE Database,
|
|
IN PCWSTR Name
|
|
)
|
|
{
|
|
UINT u;
|
|
|
|
Database->AllocSize = BLOCK_SIZE;
|
|
|
|
Database->Buf = (PBYTE) MemAlloc (g_hHeap, 0, Database->AllocSize);
|
|
|
|
Database->End = 0;
|
|
Database->FirstLevelRoot = INVALID_OFFSET;
|
|
Database->FirstDeleted = INVALID_OFFSET;
|
|
|
|
MYASSERT (INVALID_OFFSET == 0xFFFFFFFF);
|
|
FillMemory (Database->TokenBuckets, sizeof (Database->TokenBuckets), 0xFF);
|
|
|
|
_wcssafecpy (Database->Hive, Name, MAX_HIVE_NAME);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
pFreeDatabase (
|
|
IN OUT PDATABASE Database
|
|
)
|
|
{
|
|
if (Database->Buf) {
|
|
MemFree (g_hHeap, 0, Database->Buf);
|
|
Database->Buf = NULL;
|
|
}
|
|
Database->End = 0;
|
|
Database->FirstLevelRoot = INVALID_OFFSET;
|
|
Database->FirstDeleted = INVALID_OFFSET;
|
|
Database->Hive[0] = 0;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
INT
|
|
pCreateDatabase (
|
|
PCWSTR Name
|
|
)
|
|
{
|
|
DATABASE Database;
|
|
BYTE Index;
|
|
UINT Count;
|
|
UINT u;
|
|
|
|
//
|
|
// Does key exist already?
|
|
//
|
|
|
|
if (g_db) {
|
|
SelectDatabase (0);
|
|
|
|
if (INVALID_OFFSET != FindKeyStruct (g_db->FirstLevelRoot, Name)) {
|
|
DEBUGMSG ((DBG_WHOOPS, "Cannot create %ls because it already exists!", Name));
|
|
SetLastError (ERROR_ALREADY_EXISTS);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Scan list for a blank spot
|
|
//
|
|
|
|
Count = GrowListGetSize (&g_DatabaseList);
|
|
for (u = 0 ; u < Count ; u++) {
|
|
if (!GrowListGetItem (&g_DatabaseList, u)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (u < Count) {
|
|
//
|
|
// Use empty slot
|
|
//
|
|
|
|
Index = (BYTE) u;
|
|
} else if (Count < 256) {
|
|
//
|
|
// No empty slot; grow the list
|
|
//
|
|
|
|
Index = (BYTE) Count;
|
|
if (!GrowListAppend (&g_DatabaseList, NULL, 0)) {
|
|
DEBUGMSG ((DBG_WARNING, "Could not create database because GrowListAppend failed"));
|
|
return -1;
|
|
}
|
|
} else {
|
|
DEBUGMSG ((DBG_ERROR, "Cannot have more than 256 databases in memdb!"));
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
// Create the database memory block
|
|
//
|
|
|
|
pInitializeDatabase (&Database, Name);
|
|
|
|
if (!GrowListSetItem (&g_DatabaseList, (UINT) Index, (PBYTE) &Database, sizeof (Database))) {
|
|
DEBUGMSG ((DBG_WARNING, "Could not create database because GrowListSetItem failed"));
|
|
pFreeDatabase (&Database);
|
|
return -1;
|
|
}
|
|
|
|
return (INT) Index;
|
|
}
|
|
|
|
|
|
VOID
|
|
pDestroySelectedDatabase (
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// Free all resources for the database
|
|
//
|
|
|
|
pFreeSelectedDatabase ();
|
|
|
|
//
|
|
// For all databases except for the root, free the DATABASE
|
|
// structure in g_DatabaseList.
|
|
//
|
|
|
|
if (g_SelectedDatabase) {
|
|
GrowListResetItem (&g_DatabaseList, (UINT) g_SelectedDatabase);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
pFreeSelectedDatabase (
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// Free all resources used by a single database
|
|
//
|
|
|
|
if (g_db->Buf) {
|
|
MemFree (g_hHeap, 0, g_db->Buf);
|
|
}
|
|
|
|
FreeAllBinaryBlocks();
|
|
|
|
ZeroMemory (g_db, sizeof (DATABASE));
|
|
}
|
|
|
|
|
|
VOID
|
|
pFreeAllDatabases (
|
|
VOID
|
|
)
|
|
{
|
|
UINT Count;
|
|
UINT Index;
|
|
|
|
//
|
|
// Free all database blocks
|
|
//
|
|
|
|
Count = GrowListGetSize (&g_DatabaseList);
|
|
for (Index = 0 ; Index < Count ; Index++) {
|
|
if (SelectDatabase ((BYTE) Index)) {
|
|
pDestroySelectedDatabase();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Free global hash table
|
|
//
|
|
|
|
FreeHashBlock();
|
|
|
|
SelectDatabase(0);
|
|
}
|
|
|
|
|
|
BOOL
|
|
SelectDatabase (
|
|
BYTE DatabaseId
|
|
)
|
|
{
|
|
PDATABASE Database;
|
|
|
|
if (g_SelectedDatabase == DatabaseId) {
|
|
return TRUE;
|
|
}
|
|
|
|
Database = (PDATABASE) GrowListGetItem (&g_DatabaseList, (UINT) DatabaseId);
|
|
if (!Database) {
|
|
DEBUGMSG ((DBG_WHOOPS, "MemDb: Invalid database selection!"));
|
|
return FALSE;
|
|
}
|
|
|
|
g_db = Database;
|
|
g_SelectedDatabase = DatabaseId;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
PCWSTR
|
|
SelectHive (
|
|
PCWSTR FullKeyStr
|
|
)
|
|
{
|
|
UINT Count;
|
|
UINT Index;
|
|
PDATABASE Database;
|
|
PCWSTR End;
|
|
|
|
//
|
|
// Determine if root of FullKeyStr is part of a hive
|
|
//
|
|
|
|
End = wcschr (FullKeyStr, L'\\');
|
|
if (End) {
|
|
Count = GrowListGetSize (&g_DatabaseList);
|
|
for (Index = 1 ; Index < Count ; Index++) {
|
|
Database = (PDATABASE) GrowListGetItem (&g_DatabaseList, Index);
|
|
|
|
if (Database && StringIMatchABW (Database->Hive, FullKeyStr, End)) {
|
|
//
|
|
// Match found; select the database and return the subkey
|
|
//
|
|
|
|
SelectDatabase ((BYTE) Index);
|
|
End = _wcsinc (End);
|
|
return End;
|
|
}
|
|
}
|
|
}
|
|
SelectDatabase (0);
|
|
|
|
return FullKeyStr;
|
|
}
|
|
|
|
|
|
BOOL
|
|
IsTemporaryKey (
|
|
PCWSTR FullKeyStr
|
|
)
|
|
{
|
|
UINT Count;
|
|
UINT Index;
|
|
PDATABASE Database;
|
|
PCWSTR End;
|
|
|
|
End = wcschr (FullKeyStr, L'\\');
|
|
if (!End) {
|
|
End = GetEndOfStringW (FullKeyStr);
|
|
}
|
|
Count = GrowListGetSize (&g_DatabaseList);
|
|
for (Index = 1 ; Index < Count ; Index++) {
|
|
Database = (PDATABASE) GrowListGetItem (&g_DatabaseList, Index);
|
|
|
|
if (Database && StringIMatchABW (Database->Hive, FullKeyStr, End)) {
|
|
//
|
|
// Match found; return true
|
|
//
|
|
return TRUE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// MemDbSetValue creates or modifies KeyStr. The value of the key is changed
|
|
// when the return value is TRUE.
|
|
//
|
|
|
|
BOOL
|
|
PrivateMemDbSetValueA (
|
|
PCSTR Key,
|
|
DWORD Val,
|
|
DWORD SetFlags,
|
|
DWORD ClearFlags,
|
|
PDWORD Offset
|
|
)
|
|
{
|
|
PCWSTR p;
|
|
BOOL b = FALSE;
|
|
|
|
p = ConvertAtoW (Key);
|
|
if (p) {
|
|
b = PrivateMemDbSetValueW (p, Val, SetFlags, ClearFlags, Offset);
|
|
FreeConvertedStr (p);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
BOOL
|
|
PrivateMemDbSetValueW (
|
|
PCWSTR Key,
|
|
DWORD Val,
|
|
DWORD SetFlags,
|
|
DWORD ClearFlags,
|
|
PDWORD Offset
|
|
)
|
|
{
|
|
DWORD KeyOffset;
|
|
PKEYSTRUCT KeyStruct;
|
|
PCWSTR SubKey;
|
|
BOOL b = FALSE;
|
|
|
|
EnterCriticalSection (&g_MemDbCs);
|
|
|
|
__try {
|
|
SubKey = SelectHive (Key);
|
|
|
|
KeyOffset = FindKey (SubKey);
|
|
if (KeyOffset == INVALID_OFFSET) {
|
|
KeyOffset = NewKey (SubKey, Key);
|
|
if (KeyOffset == INVALID_OFFSET) {
|
|
__leave;
|
|
}
|
|
}
|
|
|
|
KeyStruct = GetKeyStruct (KeyOffset);
|
|
FreeKeyStructBinaryBlock (KeyStruct);
|
|
|
|
KeyStruct->dwValue = Val;
|
|
if (Offset) {
|
|
*Offset = KeyOffset | (g_SelectedDatabase << RESERVED_BITS);
|
|
}
|
|
KeyStruct->Flags = KeyStruct->Flags & ~(ClearFlags & KSF_USERFLAG_MASK);
|
|
KeyStruct->Flags = KeyStruct->Flags | (SetFlags & KSF_USERFLAG_MASK);
|
|
|
|
b = TRUE;
|
|
}
|
|
__finally {
|
|
LeaveCriticalSection (&g_MemDbCs);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
BOOL
|
|
PrivateMemDbSetBinaryValueA (
|
|
IN PCSTR Key,
|
|
IN PCBYTE Data,
|
|
IN DWORD SizeOfData,
|
|
OUT PDWORD Offset OPTIONAL
|
|
)
|
|
{
|
|
PCWSTR p;
|
|
BOOL b = FALSE;
|
|
|
|
p = ConvertAtoW (Key);
|
|
if (p) {
|
|
b = PrivateMemDbSetBinaryValueW (p, Data, SizeOfData, Offset);
|
|
FreeConvertedStr (p);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
BOOL
|
|
PrivateMemDbSetBinaryValueW (
|
|
IN PCWSTR Key,
|
|
IN PCBYTE Data,
|
|
IN DWORD SizeOfData,
|
|
OUT PDWORD Offset OPTIONAL
|
|
)
|
|
{
|
|
DWORD KeyOffset;
|
|
PKEYSTRUCT KeyStruct;
|
|
PCWSTR SubKey;
|
|
BOOL b = FALSE;
|
|
|
|
EnterCriticalSection (&g_MemDbCs);
|
|
|
|
__try {
|
|
SubKey = SelectHive (Key);
|
|
|
|
KeyOffset = FindKey (SubKey);
|
|
if (KeyOffset == INVALID_OFFSET) {
|
|
KeyOffset = NewKey (SubKey, Key);
|
|
if (KeyOffset == INVALID_OFFSET) {
|
|
__leave;
|
|
}
|
|
|
|
}
|
|
|
|
KeyStruct = GetKeyStruct (KeyOffset);
|
|
|
|
// Free existing buffer
|
|
FreeKeyStructBinaryBlock (KeyStruct);
|
|
|
|
// Alloc new buffer
|
|
KeyStruct->BinaryPtr = AllocBinaryBlock (Data, SizeOfData, KeyOffset);
|
|
if (!KeyStruct->BinaryPtr) {
|
|
__leave;
|
|
}
|
|
|
|
KeyStruct->Flags |= KSF_BINARY;
|
|
|
|
if (Offset) {
|
|
*Offset = KeyOffset | (g_SelectedDatabase << RESERVED_BITS);
|
|
}
|
|
|
|
b = TRUE;
|
|
}
|
|
__finally {
|
|
LeaveCriticalSection (&g_MemDbCs);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
BOOL
|
|
MemDbSetValueA (
|
|
IN PCSTR KeyStr,
|
|
IN DWORD dwValue
|
|
)
|
|
{
|
|
return PrivateMemDbSetValueA (KeyStr, dwValue, 0, 0, NULL);
|
|
}
|
|
|
|
BOOL
|
|
MemDbSetValueW (
|
|
IN PCWSTR KeyStr,
|
|
IN DWORD dwValue
|
|
)
|
|
{
|
|
return PrivateMemDbSetValueW (KeyStr, dwValue, 0, 0, NULL);
|
|
}
|
|
|
|
BOOL
|
|
MemDbSetValueAndFlagsA (
|
|
IN PCSTR KeyStr,
|
|
IN DWORD dwValue,
|
|
IN DWORD SetUserFlags,
|
|
IN DWORD ClearUserFlags
|
|
)
|
|
{
|
|
return PrivateMemDbSetValueA (KeyStr, dwValue, SetUserFlags, ClearUserFlags, NULL);
|
|
}
|
|
|
|
BOOL
|
|
MemDbSetValueAndFlagsW (
|
|
IN PCWSTR KeyStr,
|
|
IN DWORD dwValue,
|
|
IN DWORD SetUserFlags,
|
|
IN DWORD ClearUserFlags
|
|
)
|
|
{
|
|
return PrivateMemDbSetValueW (KeyStr, dwValue, SetUserFlags, ClearUserFlags, NULL);
|
|
}
|
|
|
|
BOOL
|
|
MemDbSetBinaryValueA (
|
|
IN PCSTR KeyStr,
|
|
IN PCBYTE Data,
|
|
IN DWORD DataSize
|
|
)
|
|
{
|
|
return PrivateMemDbSetBinaryValueA (KeyStr, Data, DataSize, NULL);
|
|
}
|
|
|
|
|
|
BOOL
|
|
MemDbSetBinaryValueW (
|
|
IN PCWSTR KeyStr,
|
|
IN PCBYTE Data,
|
|
IN DWORD DataSize
|
|
)
|
|
{
|
|
return PrivateMemDbSetBinaryValueW (KeyStr, Data, DataSize, NULL);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// GetValue takes a full key string and returns the
|
|
// value to the caller-supplied DWORD. Value
|
|
// may be NULL to check only for existance of the
|
|
// value.
|
|
//
|
|
|
|
BOOL
|
|
pPrivateMemDbGetValueA (
|
|
IN PCSTR KeyStr,
|
|
OUT PDWORD Value, OPTIONAL
|
|
OUT PDWORD UserFlagsPtr OPTIONAL
|
|
)
|
|
{
|
|
PCWSTR p;
|
|
BOOL b = FALSE;
|
|
|
|
p = ConvertAtoW (KeyStr);
|
|
if (p) {
|
|
b = pPrivateMemDbGetValueW (p, Value, UserFlagsPtr);
|
|
FreeConvertedStr (p);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
BOOL
|
|
pPrivateMemDbGetValueW (
|
|
IN PCWSTR KeyStr,
|
|
OUT PDWORD Value, OPTIONAL
|
|
OUT PDWORD UserFlagsPtr OPTIONAL
|
|
)
|
|
{
|
|
DWORD KeyOffset;
|
|
PCWSTR SubKey;
|
|
BOOL b = FALSE;
|
|
|
|
EnterCriticalSection (&g_MemDbCs);
|
|
|
|
__try {
|
|
SubKey = SelectHive (KeyStr);
|
|
|
|
KeyOffset = FindKey (SubKey);
|
|
if (KeyOffset == INVALID_OFFSET) {
|
|
__leave;
|
|
}
|
|
|
|
CopyValToPtr (GetKeyStruct (KeyOffset), Value);
|
|
CopyFlagsToPtr (GetKeyStruct (KeyOffset), UserFlagsPtr);
|
|
|
|
b = TRUE;
|
|
}
|
|
__finally {
|
|
LeaveCriticalSection (&g_MemDbCs);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
BOOL
|
|
MemDbGetValueA (
|
|
IN PCSTR Key,
|
|
OUT PDWORD ValuePtr OPTIONAL
|
|
)
|
|
{
|
|
return pPrivateMemDbGetValueA (Key, ValuePtr, NULL);
|
|
}
|
|
|
|
BOOL
|
|
MemDbGetValueW (
|
|
IN PCWSTR Key,
|
|
OUT PDWORD ValuePtr OPTIONAL
|
|
)
|
|
{
|
|
return pPrivateMemDbGetValueW (Key, ValuePtr, NULL);
|
|
}
|
|
|
|
BOOL
|
|
MemDbGetValueAndFlagsA (
|
|
IN PCSTR Key,
|
|
OUT PDWORD ValuePtr, OPTIONAL
|
|
OUT PDWORD UserFlagsPtr
|
|
)
|
|
{
|
|
return pPrivateMemDbGetValueA (Key, ValuePtr, UserFlagsPtr);
|
|
}
|
|
|
|
BOOL
|
|
MemDbGetValueAndFlagsW (
|
|
IN PCWSTR Key,
|
|
OUT PDWORD ValuePtr, OPTIONAL
|
|
OUT PDWORD UserFlagsPtr
|
|
)
|
|
{
|
|
return pPrivateMemDbGetValueW (Key, ValuePtr, UserFlagsPtr);
|
|
}
|
|
|
|
|
|
PCBYTE
|
|
MemDbGetBinaryValueA (
|
|
IN PCSTR KeyStr,
|
|
OUT PDWORD DataSize OPTIONAL
|
|
)
|
|
{
|
|
PCWSTR p;
|
|
BYTE const * b = NULL;
|
|
|
|
p = ConvertAtoW (KeyStr);
|
|
if (p) {
|
|
b = MemDbGetBinaryValueW (p, DataSize);
|
|
FreeConvertedStr (p);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
PCBYTE
|
|
MemDbGetBinaryValueW (
|
|
IN PCWSTR KeyStr,
|
|
OUT PDWORD DataSize OPTIONAL
|
|
)
|
|
{
|
|
DWORD KeyOffset;
|
|
PKEYSTRUCT KeyStruct;
|
|
PCWSTR SubKey;
|
|
PCBYTE Result = NULL;
|
|
|
|
EnterCriticalSection (&g_MemDbCs);
|
|
|
|
__try {
|
|
SubKey = SelectHive (KeyStr);
|
|
|
|
KeyOffset = FindKey (SubKey);
|
|
if (KeyOffset == INVALID_OFFSET) {
|
|
__leave;
|
|
}
|
|
|
|
KeyStruct = GetKeyStruct (KeyOffset);
|
|
|
|
if (DataSize) {
|
|
*DataSize = GetKeyStructBinarySize (KeyStruct);
|
|
}
|
|
|
|
Result = GetKeyStructBinaryData (KeyStruct);
|
|
}
|
|
__finally {
|
|
LeaveCriticalSection (&g_MemDbCs);
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
|
|
//
|
|
// GetPatternValue takes a full key string and returns the
|
|
// value to the caller-supplied DWORD. The stored value string
|
|
// is treated as a pattern, but KeyStr is not a pattern.
|
|
// The return value represents the first match found.
|
|
//
|
|
|
|
BOOL
|
|
MemDbGetPatternValueA (
|
|
IN PCSTR KeyStr,
|
|
OUT PDWORD Value
|
|
)
|
|
{
|
|
PCWSTR p;
|
|
BOOL b = FALSE;
|
|
|
|
p = ConvertAtoW (KeyStr);
|
|
if (p) {
|
|
b = MemDbGetPatternValueW (p, Value);
|
|
FreeConvertedStr (p);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
BOOL
|
|
MemDbGetPatternValueW (
|
|
IN PCWSTR KeyStr,
|
|
OUT PDWORD Value
|
|
)
|
|
{
|
|
DWORD KeyOffset;
|
|
PCWSTR SubKey;
|
|
BOOL b = FALSE;
|
|
|
|
EnterCriticalSection (&g_MemDbCs);
|
|
|
|
__try {
|
|
|
|
SubKey = SelectHive (KeyStr);
|
|
|
|
KeyOffset = FindPatternKey (g_db->FirstLevelRoot, SubKey, FALSE);
|
|
if (KeyOffset == INVALID_OFFSET) {
|
|
__leave;
|
|
}
|
|
|
|
CopyValToPtr (GetKeyStruct (KeyOffset), Value);
|
|
|
|
b = TRUE;
|
|
}
|
|
__finally {
|
|
LeaveCriticalSection (&g_MemDbCs);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
//
|
|
// MemDbGetStoredEndPatternValue takes a full key string and returns the
|
|
// value to the caller-supplied DWORD. The stored value string
|
|
// is treated as a pattern, but KeyStr is not a pattern.
|
|
// The return value represents the first match found.
|
|
//
|
|
// If the last stored key segment is an asterisk, then the pattern
|
|
// is considered to match.
|
|
//
|
|
|
|
BOOL
|
|
MemDbGetStoredEndPatternValueA (
|
|
IN PCSTR KeyStr,
|
|
OUT PDWORD Value
|
|
)
|
|
{
|
|
PCWSTR p;
|
|
BOOL b = FALSE;
|
|
|
|
p = ConvertAtoW (KeyStr);
|
|
if (p) {
|
|
b = MemDbGetStoredEndPatternValueW (p, Value);
|
|
FreeConvertedStr (p);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
BOOL
|
|
MemDbGetStoredEndPatternValueW (
|
|
IN PCWSTR KeyStr,
|
|
OUT PDWORD Value
|
|
)
|
|
{
|
|
DWORD KeyOffset;
|
|
PCWSTR SubKey;
|
|
BOOL b = FALSE;
|
|
|
|
EnterCriticalSection (&g_MemDbCs);
|
|
|
|
__try {
|
|
|
|
SubKey = SelectHive (KeyStr);
|
|
|
|
KeyOffset = FindPatternKey (g_db->FirstLevelRoot, SubKey, TRUE);
|
|
if (KeyOffset == INVALID_OFFSET) {
|
|
__leave;
|
|
}
|
|
|
|
CopyValToPtr (GetKeyStruct (KeyOffset), Value);
|
|
|
|
b = TRUE;
|
|
}
|
|
__finally {
|
|
LeaveCriticalSection (&g_MemDbCs);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
//
|
|
// GetValueWithPattern takes a full key string that may contain
|
|
// wildcards between the backslashes, and returns the value
|
|
// to the caller-supplied DWORD. The stored value string
|
|
// is not treated as a pattern. The return value represents
|
|
// the first match found.
|
|
//
|
|
|
|
BOOL
|
|
MemDbGetValueWithPatternA (
|
|
IN PCSTR KeyPattern,
|
|
OUT PDWORD Value
|
|
)
|
|
{
|
|
PCWSTR p;
|
|
BOOL b = FALSE;
|
|
|
|
p = ConvertAtoW (KeyPattern);
|
|
if (p) {
|
|
b = MemDbGetValueWithPatternW (p, Value);
|
|
FreeConvertedStr (p);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
BOOL
|
|
MemDbGetValueWithPatternW (
|
|
IN PCWSTR KeyPattern,
|
|
OUT PDWORD Value
|
|
)
|
|
{
|
|
DWORD KeyOffset;
|
|
PCWSTR SubKey;
|
|
BOOL b = FALSE;
|
|
|
|
EnterCriticalSection (&g_MemDbCs);
|
|
|
|
__try {
|
|
SubKey = SelectHive (KeyPattern);
|
|
|
|
KeyOffset = FindKeyUsingPattern (g_db->FirstLevelRoot, SubKey);
|
|
if (KeyOffset == INVALID_OFFSET) {
|
|
__leave;
|
|
}
|
|
|
|
CopyValToPtr (GetKeyStruct (KeyOffset), Value);
|
|
|
|
b = TRUE;
|
|
}
|
|
__finally {
|
|
LeaveCriticalSection (&g_MemDbCs);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
MemDbGetPatternValueWithPatternA (
|
|
IN PCSTR KeyPattern,
|
|
OUT PDWORD Value
|
|
)
|
|
{
|
|
PCWSTR p;
|
|
BOOL b = FALSE;
|
|
|
|
p = ConvertAtoW (KeyPattern);
|
|
if (p) {
|
|
b = MemDbGetPatternValueWithPatternW (p, Value);
|
|
FreeConvertedStr (p);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
BOOL
|
|
MemDbGetPatternValueWithPatternW (
|
|
IN PCWSTR KeyPattern,
|
|
OUT PDWORD Value
|
|
)
|
|
{
|
|
DWORD KeyOffset;
|
|
PCWSTR SubKey;
|
|
BOOL b = FALSE;
|
|
|
|
EnterCriticalSection (&g_MemDbCs);
|
|
|
|
__try {
|
|
SubKey = SelectHive (KeyPattern);
|
|
|
|
KeyOffset = FindPatternKeyUsingPattern (g_db->FirstLevelRoot, SubKey);
|
|
if (KeyOffset == INVALID_OFFSET) {
|
|
__leave;
|
|
}
|
|
|
|
CopyValToPtr (GetKeyStruct (KeyOffset), Value);
|
|
|
|
b = TRUE;
|
|
}
|
|
__finally {
|
|
LeaveCriticalSection (&g_MemDbCs);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
VOID
|
|
MemDbDeleteValueA (
|
|
IN PCSTR KeyStr
|
|
)
|
|
{
|
|
PCWSTR p;
|
|
|
|
p = ConvertAtoW (KeyStr);
|
|
if (p) {
|
|
MemDbDeleteValueW (p);
|
|
FreeConvertedStr (p);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
MemDbDeleteValueW (
|
|
IN PCWSTR KeyStr
|
|
)
|
|
{
|
|
PCWSTR SubKey;
|
|
|
|
EnterCriticalSection (&g_MemDbCs);
|
|
|
|
SubKey = SelectHive (KeyStr);
|
|
DeleteKey (SubKey, &g_db->FirstLevelRoot, TRUE);
|
|
|
|
LeaveCriticalSection (&g_MemDbCs);
|
|
}
|
|
|
|
|
|
VOID
|
|
MemDbDeleteTreeA (
|
|
IN PCSTR KeyStr
|
|
)
|
|
{
|
|
PCWSTR p;
|
|
|
|
p = ConvertAtoW (KeyStr);
|
|
if (p) {
|
|
MemDbDeleteTreeW (p);
|
|
FreeConvertedStr (p);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
MemDbDeleteTreeW (
|
|
IN PCWSTR KeyStr
|
|
)
|
|
{
|
|
PCWSTR SubKey;
|
|
|
|
EnterCriticalSection (&g_MemDbCs);
|
|
|
|
SubKey = SelectHive (KeyStr);
|
|
DeleteKey (SubKey, &g_db->FirstLevelRoot, FALSE);
|
|
|
|
LeaveCriticalSection (&g_MemDbCs);
|
|
}
|
|
|
|
|
|
//
|
|
// Enum functions
|
|
//
|
|
|
|
BOOL
|
|
MemDbEnumFirstValueA (
|
|
OUT PMEMDB_ENUMA EnumPtr,
|
|
IN PCSTR PatternStr,
|
|
IN INT Depth,
|
|
IN DWORD Flags
|
|
)
|
|
{
|
|
BOOL b = FALSE;
|
|
PCWSTR p;
|
|
PCSTR str;
|
|
MEMDB_ENUMW enumw;
|
|
|
|
p = ConvertAtoW (PatternStr);
|
|
if (p) {
|
|
b = MemDbEnumFirstValueW (&enumw, p, Depth, Flags);
|
|
FreeConvertedStr (p);
|
|
} else {
|
|
b = FALSE;
|
|
}
|
|
|
|
if (b) {
|
|
str = ConvertWtoA (enumw.szName);
|
|
if (str) {
|
|
// ANSI struct is padded to match UNICODE
|
|
MYASSERT (sizeof (MEMDB_ENUMW) == sizeof (MEMDB_ENUMA));
|
|
CopyMemory (EnumPtr, &enumw, sizeof (MEMDB_ENUMW));
|
|
|
|
// Only the output key name needs to be converted
|
|
StringCopyA (EnumPtr->szName, str);
|
|
FreeConvertedStr (str);
|
|
} else {
|
|
b = FALSE;
|
|
}
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
BOOL
|
|
MemDbEnumFirstValueW (
|
|
OUT PMEMDB_ENUMW EnumPtr,
|
|
IN PCWSTR PatternStr,
|
|
IN INT Depth,
|
|
IN DWORD Flags
|
|
)
|
|
{
|
|
PCWSTR Start;
|
|
PCWSTR wstrLastWack;
|
|
PCWSTR SubPatternStr;
|
|
|
|
SubPatternStr = SelectHive (PatternStr);
|
|
|
|
//
|
|
// Init the EnumPtr struct
|
|
//
|
|
|
|
ZeroMemory (EnumPtr, sizeof (MEMDB_ENUM));
|
|
|
|
if (!Depth) {
|
|
Depth = MAX_ENUM_POS;
|
|
}
|
|
|
|
EnumPtr->Depth = Depth;
|
|
EnumPtr->Flags = Flags;
|
|
|
|
//
|
|
// If pattern has wack, locate the starting level by
|
|
// counting the number of parts that do not have
|
|
// wildcard characters.
|
|
//
|
|
|
|
Start = SubPatternStr;
|
|
while (wstrLastWack = wcschr (Start, L'\\')) {
|
|
|
|
// See if part has a wildcard character
|
|
while (Start < wstrLastWack) {
|
|
if (*Start == L'*' || *Start == L'?')
|
|
break;
|
|
Start++;
|
|
}
|
|
|
|
// If a wildcard character was found, we have to stop here
|
|
if (Start < wstrLastWack)
|
|
break;
|
|
|
|
// Otherwise, look at next part of the pattern
|
|
Start = wstrLastWack + 1;
|
|
EnumPtr->Start++;
|
|
}
|
|
|
|
EnumPtr->PosCount = 1;
|
|
EnumPtr->LastPos[0] = INVALID_OFFSET;
|
|
StringCopyW (EnumPtr->PatternStr, PatternStr);
|
|
|
|
return MemDbEnumNextValueW (EnumPtr);
|
|
}
|
|
|
|
|
|
BOOL
|
|
MemDbEnumNextValueA (
|
|
IN OUT PMEMDB_ENUMA EnumPtr
|
|
)
|
|
{
|
|
BOOL b = FALSE;
|
|
PCSTR str;
|
|
MEMDB_ENUMW enumw;
|
|
|
|
// ANSI struct is padded to match UNICODE
|
|
MYASSERT (sizeof (MEMDB_ENUMW) == sizeof (MEMDB_ENUMA));
|
|
CopyMemory (&enumw, EnumPtr, sizeof (MEMDB_ENUMW));
|
|
|
|
// ANSI output members are ignored (i.e. EnumPtr->szName)
|
|
b = MemDbEnumNextValueW (&enumw);
|
|
|
|
if (b) {
|
|
str = ConvertWtoA (enumw.szName);
|
|
if (str) {
|
|
// ANSI struct is padded to match UNICODE
|
|
MYASSERT (sizeof (MEMDB_ENUMW) == sizeof (MEMDB_ENUMA));
|
|
CopyMemory (EnumPtr, &enumw, sizeof (MEMDB_ENUMW));
|
|
|
|
// Only the output key name needs to be converted
|
|
StringCopyA (EnumPtr->szName, str);
|
|
FreeConvertedStr (str);
|
|
} else {
|
|
b = FALSE;
|
|
}
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
BOOL
|
|
MemDbEnumNextValueW (
|
|
IN OUT PMEMDB_ENUMW EnumPtr
|
|
)
|
|
{
|
|
// no init allowed in declarations
|
|
PKEYSTRUCT KeyStruct = NULL;
|
|
int Count;
|
|
int Level;
|
|
WCHAR PartBuf[MEMDB_MAX];
|
|
PWSTR PartStr;
|
|
PWSTR Src, Dest;
|
|
int Pos;
|
|
BOOL Wildcard;
|
|
BOOL MatchNotFound;
|
|
PCWSTR SubPatternStr;
|
|
|
|
EnterCriticalSection (&g_MemDbCs);
|
|
|
|
SubPatternStr = SelectHive (EnumPtr->PatternStr);
|
|
|
|
MatchNotFound = TRUE;
|
|
|
|
do {
|
|
|
|
Wildcard = FALSE;
|
|
|
|
//
|
|
// The following states exist upon entry:
|
|
//
|
|
// STATE DESCRIPTION
|
|
// First time through PosCount == 1, LastPos[0] == INVALID_OFFSET
|
|
//
|
|
// Not first time LastPos[PosCount - 1] == INVALID_OFFSET
|
|
// through
|
|
//
|
|
// Not first time LastPos[PosCount - 1] != INVALID_OFFSET
|
|
// through, last match
|
|
// hit the depth
|
|
// ceiling
|
|
//
|
|
// PosCount points to the current unprocessed level, or when the
|
|
// depth ceiling is reached, it points to the level of the last
|
|
// match.
|
|
//
|
|
|
|
do {
|
|
//
|
|
// Build PartStr
|
|
//
|
|
|
|
Pos = EnumPtr->PosCount - 1;
|
|
Count = Pos + 1;
|
|
|
|
// Locate start of pattern part (if it is long enough)
|
|
PartStr = PartBuf;
|
|
for (Src = (PWSTR) SubPatternStr ; Count > 1 ; Count--) {
|
|
|
|
Src = wcschr (Src, L'\\');
|
|
|
|
if (!Src) {
|
|
break;
|
|
}
|
|
|
|
Src++;
|
|
}
|
|
|
|
// Copy part from pattern to buffer
|
|
if (Src) {
|
|
Dest = PartStr;
|
|
while (*Src && *Src != L'\\') {
|
|
*Dest = *Src;
|
|
Wildcard = Wildcard || (*Dest == L'*') || (*Dest == L'?');
|
|
Dest++;
|
|
Src++;
|
|
}
|
|
|
|
// Truncate
|
|
*Dest = 0;
|
|
}
|
|
|
|
// Use asterisk when pattern is shorter than current level
|
|
else {
|
|
PartStr = L"*";
|
|
Wildcard = TRUE;
|
|
}
|
|
|
|
//
|
|
// If current level is set to invalid offset, we have not yet
|
|
// tried it.
|
|
//
|
|
|
|
if (EnumPtr->LastPos[Pos] == INVALID_OFFSET) {
|
|
|
|
//
|
|
// Initialize the level
|
|
//
|
|
|
|
if (Pos == 0) {
|
|
EnumPtr->LastPos[0] = g_db->FirstLevelRoot;
|
|
} else {
|
|
KeyStruct = GetKeyStruct (EnumPtr->LastPos[Pos - 1]);
|
|
EnumPtr->LastPos[Pos] = KeyStruct->NextLevelRoot;
|
|
}
|
|
|
|
//
|
|
// If still invalid, the level is complete, and we need to
|
|
// go back.
|
|
//
|
|
|
|
if (EnumPtr->LastPos[Pos] == INVALID_OFFSET) {
|
|
EnumPtr->PosCount--;
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Level ready to be processed
|
|
//
|
|
|
|
if (!Wildcard) {
|
|
//
|
|
// Use binary tree to locate this item. If no match, the pattern
|
|
// will not match anything. Otherwise, we found something to
|
|
// return.
|
|
//
|
|
|
|
EnumPtr->LastPos[Pos] = FindKeyStruct (EnumPtr->LastPos[Pos], PartStr);
|
|
if (EnumPtr->LastPos[Pos] == INVALID_OFFSET) {
|
|
//
|
|
// Non-wildcard ot found. We can try going back because
|
|
// there might be a pattern at a higher level.
|
|
//
|
|
if (Pos > 0) {
|
|
PCWSTR p;
|
|
INT ParentLevel = 0;
|
|
INT LastParentLevel;
|
|
|
|
LastParentLevel = 0;
|
|
|
|
// Locate the previous pattern level
|
|
p = SubPatternStr;
|
|
while (*p && ParentLevel < Pos) {
|
|
// Locate wack, pattern or nul
|
|
while (*p && *p != L'\\') {
|
|
if (*p == L'?' || *p == L'*') {
|
|
break;
|
|
}
|
|
p++;
|
|
}
|
|
|
|
// If pattern or nul, set last pattern level
|
|
if (*p != L'\\') {
|
|
LastParentLevel = ParentLevel + 1;
|
|
|
|
// Jump to wack if not at nul
|
|
while (*p && *p != L'\\') {
|
|
p++;
|
|
}
|
|
}
|
|
|
|
// If more pattern exists, skip wack
|
|
if (p[0] && p[1]) {
|
|
MYASSERT (p[0] == L'\\');
|
|
p++;
|
|
}
|
|
ParentLevel++;
|
|
}
|
|
|
|
// Default: when no pattern, last pattern level is parent
|
|
// (Pos is zero-based while LastParentLevel is one-based)
|
|
if (!(*p)) {
|
|
LastParentLevel = Pos;
|
|
}
|
|
|
|
if (LastParentLevel) {
|
|
// Yes, a pattern does exist at a higher level
|
|
EnumPtr->PosCount = LastParentLevel;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// Pattern not found, we have exhausted all possibilities
|
|
LeaveCriticalSection (&g_MemDbCs);
|
|
return FALSE;
|
|
}
|
|
|
|
// If level is before start, keep searching forward instead
|
|
// of reporting a result.
|
|
|
|
if (EnumPtr->PosCount <= EnumPtr->Start) {
|
|
EnumPtr->PosCount++;
|
|
EnumPtr->LastPos[Pos + 1] = INVALID_OFFSET;
|
|
continue;
|
|
}
|
|
|
|
// Break out of last nested loop
|
|
break;
|
|
} else {
|
|
//
|
|
// Because of pattern, each item in the level must be examined.
|
|
// Set the pos to the first item and fall through to the pattern
|
|
// search code.
|
|
//
|
|
|
|
EnumPtr->LastPos[Pos] = GetFirstOffset (EnumPtr->LastPos[Pos]);
|
|
}
|
|
|
|
//
|
|
// Else if current level is not invalid, last time through we had a
|
|
// match and we need to increment the offset (wildcard patterns only).
|
|
//
|
|
|
|
} else {
|
|
|
|
if (Wildcard) {
|
|
EnumPtr->LastPos[Pos] = GetNextOffset (EnumPtr->LastPos[Pos]);
|
|
|
|
// If there are no more items, go back a level
|
|
if (EnumPtr->LastPos[Pos] == INVALID_OFFSET) {
|
|
EnumPtr->PosCount--;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we are here, it is because we are looking at a level, trying
|
|
// to find a pattern match. Loop until either a match is found,
|
|
// or we run out of items.
|
|
//
|
|
// The only exception is when the last match hit the depth ceiling
|
|
// and PartStr does not have a wildcard. In this case, we must
|
|
// reset the last pos and go back one level.
|
|
//
|
|
|
|
if (Wildcard) {
|
|
do {
|
|
// Get current key, advance, then check current key against pattern
|
|
KeyStruct = GetKeyStruct (EnumPtr->LastPos[Pos]);
|
|
if (IsPatternMatch (PartStr, GetKeyToken (KeyStruct->KeyToken)))
|
|
break;
|
|
|
|
EnumPtr->LastPos[Pos] = GetNextOffset (EnumPtr->LastPos[Pos]);
|
|
} while (EnumPtr->LastPos[Pos] != INVALID_OFFSET);
|
|
|
|
// Match found so break out of last nested loop
|
|
if (EnumPtr->LastPos[Pos] != INVALID_OFFSET)
|
|
break;
|
|
} else {
|
|
EnumPtr->LastPos[Pos] = INVALID_OFFSET;
|
|
}
|
|
|
|
//
|
|
// We ran out of items before finding a match, so it is time to
|
|
// go back up a level.
|
|
//
|
|
|
|
EnumPtr->PosCount--;
|
|
} while (EnumPtr->PosCount);
|
|
|
|
// Return if no items found
|
|
if (!EnumPtr->PosCount) {
|
|
LeaveCriticalSection (&g_MemDbCs);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// A match was found. Build output string and prepare position for
|
|
// next level.
|
|
//
|
|
|
|
// Build the name of the item and get the value
|
|
EnumPtr->szName[0] = 0;
|
|
for (Level = EnumPtr->Start ; Level < EnumPtr->PosCount ; Level++) {
|
|
PWSTR namePointer = EnumPtr->szName;
|
|
KeyStruct = GetKeyStruct (EnumPtr->LastPos[Level]);
|
|
if (Level > EnumPtr -> Start) {
|
|
namePointer = _wcsappend(namePointer,L"\\");
|
|
}
|
|
_wcsappend (namePointer, GetKeyToken (KeyStruct->KeyToken));
|
|
}
|
|
|
|
MYASSERT (KeyStruct);
|
|
EnumPtr->bEndpoint = (KeyStruct->Flags & KSF_ENDPOINT) != 0;
|
|
EnumPtr->bBinary = (KeyStruct->Flags & KSF_BINARY) != 0;
|
|
EnumPtr->bProxy = (KeyStruct->Flags & KSF_PROXY_NODE) != 0;
|
|
EnumPtr->UserFlags = (KeyStruct->Flags & KSF_USERFLAG_MASK);
|
|
EnumPtr->BinaryPtr = GetKeyStructBinaryData (KeyStruct);
|
|
EnumPtr->BinarySize = GetKeyStructBinarySize (KeyStruct);
|
|
if (EnumPtr->bBinary) {
|
|
EnumPtr->dwValue = 0;
|
|
} else {
|
|
EnumPtr->dwValue = KeyStruct->dwValue;
|
|
}
|
|
|
|
EnumPtr->Offset = EnumPtr->LastPos[Pos] | (g_SelectedDatabase << RESERVED_BITS);
|
|
|
|
// Prepare position for next level
|
|
if ((EnumPtr->PosCount + 1) <= (EnumPtr->Depth + EnumPtr->Start)) {
|
|
EnumPtr->LastPos[Pos + 1] = INVALID_OFFSET;
|
|
EnumPtr->PosCount++;
|
|
}
|
|
|
|
switch (EnumPtr->Flags) {
|
|
|
|
case MEMDB_ALL_MATCHES:
|
|
MatchNotFound = FALSE;
|
|
break;
|
|
|
|
case MEMDB_ENDPOINTS_ONLY:
|
|
MatchNotFound = (KeyStruct->Flags & (KSF_ENDPOINT|KSF_PROXY_NODE)) != KSF_ENDPOINT;
|
|
break;
|
|
|
|
case MEMDB_BINARY_NODES_ONLY:
|
|
MatchNotFound = (KeyStruct->Flags & KSF_BINARY) == 0;
|
|
break;
|
|
|
|
case MEMDB_PROXY_NODES_ONLY:
|
|
MatchNotFound = (KeyStruct->Flags & KSF_PROXY_NODE) == 0;
|
|
break;
|
|
|
|
case MEMDB_ALL_BUT_PROXY:
|
|
MatchNotFound = (KeyStruct->Flags & KSF_PROXY_NODE) != 0;
|
|
break;
|
|
}
|
|
|
|
// Loop until flag match is found
|
|
} while (MatchNotFound);
|
|
|
|
LeaveCriticalSection (&g_MemDbCs);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// Save and restore functions
|
|
//
|
|
|
|
BOOL
|
|
pPrivateMemDbSave (
|
|
PCWSTR FileName,
|
|
BOOL bUnicode
|
|
)
|
|
{
|
|
HANDLE FileHandle;
|
|
BOOL b = FALSE;
|
|
DWORD BytesWritten;
|
|
|
|
EnterCriticalSection (&g_MemDbCs);
|
|
|
|
__try {
|
|
|
|
SelectDatabase(0);
|
|
|
|
if (bUnicode) {
|
|
FileHandle = CreateFileW (FileName, GENERIC_WRITE, 0, NULL,
|
|
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
} else {
|
|
FileHandle = CreateFileA ((PCSTR) FileName, GENERIC_WRITE, 0, NULL,
|
|
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
}
|
|
|
|
if (FileHandle == INVALID_HANDLE_VALUE) {
|
|
if (bUnicode) {
|
|
DEBUGMSGW ((DBG_ERROR, "Can't open %s", FileName));
|
|
} else {
|
|
DEBUGMSGA ((DBG_ERROR, "Can't open %s", FileName));
|
|
}
|
|
__leave;
|
|
}
|
|
|
|
// entire file written in UNICODE char set
|
|
b = WriteFile (FileHandle, FILE_SIGNATURE, sizeof(FILE_SIGNATURE), &BytesWritten, NULL);
|
|
|
|
if (b) {
|
|
b = WriteFile (FileHandle, g_db, sizeof (DATABASE), &BytesWritten, NULL);
|
|
}
|
|
|
|
if (b) {
|
|
b = WriteFile (FileHandle, g_db->Buf, g_db->AllocSize, &BytesWritten, NULL);
|
|
if (BytesWritten != g_db->AllocSize)
|
|
b = FALSE;
|
|
}
|
|
|
|
if (b) {
|
|
b = SaveHashBlock (FileHandle);
|
|
}
|
|
|
|
if (b) {
|
|
b = SaveBinaryBlocks (FileHandle);
|
|
}
|
|
|
|
PushError();
|
|
CloseHandle (FileHandle);
|
|
PopError();
|
|
|
|
if (!b) {
|
|
if (bUnicode) {
|
|
DEBUGMSGW ((DBG_ERROR, "Error writing %s", FileName));
|
|
DeleteFileW (FileName);
|
|
} else {
|
|
DEBUGMSGA ((DBG_ERROR, "Error writing %s", FileName));
|
|
DeleteFileA ((PCSTR) FileName);
|
|
}
|
|
__leave;
|
|
}
|
|
|
|
MYASSERT (b == TRUE);
|
|
}
|
|
__finally {
|
|
PushError();
|
|
LeaveCriticalSection (&g_MemDbCs);
|
|
PopError();
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
BOOL
|
|
MemDbSaveA (
|
|
PCSTR FileName
|
|
)
|
|
{
|
|
return pPrivateMemDbSave ((PCWSTR) FileName, FALSE); // FALSE=ANSI
|
|
}
|
|
|
|
|
|
BOOL
|
|
MemDbSaveW (
|
|
PCWSTR FileName
|
|
)
|
|
{
|
|
return pPrivateMemDbSave (FileName, TRUE); // TRUE=UNICODE
|
|
}
|
|
|
|
|
|
BOOL
|
|
pPrivateMemDbLoad (
|
|
IN PCWSTR FileName,
|
|
IN BOOL bUnicode,
|
|
OUT PMEMDB_VERSION Version, OPTIONAL
|
|
IN BOOL QueryVersionOnly
|
|
)
|
|
{
|
|
HANDLE FileHandle;
|
|
BOOL b;
|
|
DWORD BytesRead;
|
|
WCHAR Buf[sizeof(FILE_SIGNATURE)];
|
|
PBYTE TempBuf = NULL;
|
|
PCWSTR VerPtr;
|
|
|
|
EnterCriticalSection (&g_MemDbCs);
|
|
|
|
if (Version) {
|
|
ZeroMemory (Version, sizeof (MEMDB_VERSION));
|
|
}
|
|
|
|
//
|
|
// Blow away existing resources
|
|
//
|
|
|
|
if (!QueryVersionOnly) {
|
|
pFreeAllDatabases();
|
|
}
|
|
|
|
//
|
|
// Load in file
|
|
//
|
|
|
|
if (*FileName && FileName) {
|
|
if (bUnicode) {
|
|
FileHandle = CreateFileW (FileName, GENERIC_READ, 0, NULL,
|
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
} else {
|
|
FileHandle = CreateFileA ((PCSTR) FileName, GENERIC_READ, 0, NULL,
|
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
}
|
|
} else {
|
|
FileHandle = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
b = (FileHandle != INVALID_HANDLE_VALUE);
|
|
|
|
__try {
|
|
//
|
|
// Obtain the file signature
|
|
//
|
|
// NOTE: Entire file read is in UNICODE char set
|
|
//
|
|
|
|
if (b) {
|
|
b = ReadFile (FileHandle, Buf, sizeof(FILE_SIGNATURE), &BytesRead, NULL);
|
|
|
|
if (Version) {
|
|
if (StringMatchByteCountW (
|
|
VERSION_BASE_SIGNATURE,
|
|
Buf,
|
|
sizeof (VERSION_BASE_SIGNATURE) - sizeof (WCHAR)
|
|
)) {
|
|
|
|
Version->Valid = TRUE;
|
|
|
|
//
|
|
// Identify version number
|
|
//
|
|
|
|
VerPtr = (PCWSTR) ((PBYTE) Buf + sizeof (VERSION_BASE_SIGNATURE) - sizeof (WCHAR));
|
|
|
|
if (StringMatchByteCountW (
|
|
MEMDB_VERSION,
|
|
VerPtr,
|
|
sizeof (MEMDB_VERSION) - sizeof (WCHAR)
|
|
)) {
|
|
Version->CurrentVersion = TRUE;
|
|
}
|
|
|
|
Version->Version = (UINT) _wtoi (VerPtr + 1);
|
|
|
|
//
|
|
// Identify checked or free build
|
|
//
|
|
|
|
VerPtr += (sizeof (MEMDB_VERSION) / 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) {
|
|
b = FALSE;
|
|
}
|
|
|
|
if (b) {
|
|
b = StringMatchW (Buf, FILE_SIGNATURE);
|
|
|
|
#ifdef DEBUG
|
|
//
|
|
// This code allows a debug build of memdb to work with both
|
|
// debug and retail versions of the DAT file
|
|
//
|
|
|
|
if (!b) {
|
|
if (StringMatchW (Buf, DEBUG_FILE_SIGNATURE)) {
|
|
g_UseDebugStructs = TRUE;
|
|
b = TRUE;
|
|
} else if (StringMatchW (Buf, RETAIL_FILE_SIGNATURE)) {
|
|
DEBUGMSG ((DBG_ERROR, "memdb dat file is from free build; checked version expected"));
|
|
g_UseDebugStructs = FALSE;
|
|
b = TRUE;
|
|
}
|
|
}
|
|
#else
|
|
if (!b) {
|
|
SetLastError (ERROR_BAD_FORMAT);
|
|
LOG ((LOG_WARNING, "Warning: data file could be from checked build; free version expected"));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Obtain the database struct
|
|
//
|
|
|
|
if (b) {
|
|
b = ReadFile (FileHandle, (PBYTE) g_db, sizeof (DATABASE), &BytesRead, NULL);
|
|
if (BytesRead != sizeof (DATABASE)) {
|
|
b = FALSE;
|
|
SetLastError (ERROR_BAD_FORMAT);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Allocate the memory block
|
|
//
|
|
|
|
if (b) {
|
|
TempBuf = (PBYTE) MemAlloc (g_hHeap, 0, g_db->AllocSize);
|
|
if (TempBuf) {
|
|
g_db->Buf = TempBuf;
|
|
TempBuf = NULL;
|
|
} else {
|
|
b = FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Read the memory block
|
|
//
|
|
|
|
if (b) {
|
|
b = ReadFile (FileHandle, g_db->Buf, g_db->AllocSize, &BytesRead, NULL);
|
|
if (BytesRead != g_db->AllocSize) {
|
|
b = FALSE;
|
|
SetLastError (ERROR_BAD_FORMAT);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Read the hash table
|
|
//
|
|
|
|
if (b) {
|
|
b = LoadHashBlock (FileHandle);
|
|
}
|
|
|
|
//
|
|
// Read binary blocks
|
|
//
|
|
|
|
if (b) {
|
|
b = LoadBinaryBlocks (FileHandle);
|
|
}
|
|
}
|
|
|
|
__except (TRUE) {
|
|
b = FALSE;
|
|
PushError();
|
|
LOG ((LOG_ERROR, "MemDb dat file %s could not be loaded because of an exception", FileName));
|
|
|
|
FreeAllBinaryBlocks();
|
|
PopError();
|
|
}
|
|
|
|
PushError();
|
|
if (FileHandle != INVALID_HANDLE_VALUE) {
|
|
CloseHandle (FileHandle);
|
|
}
|
|
|
|
if (!b && !QueryVersionOnly) {
|
|
pFreeAllDatabases();
|
|
pInitializeMemDb();
|
|
}
|
|
|
|
LeaveCriticalSection (&g_MemDbCs);
|
|
PopError();
|
|
|
|
if (QueryVersionOnly) {
|
|
return TRUE;
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
BOOL
|
|
MemDbLoadA (
|
|
IN PCSTR FileName
|
|
)
|
|
{
|
|
return pPrivateMemDbLoad ((PCWSTR) FileName, FALSE, NULL, FALSE);
|
|
}
|
|
|
|
BOOL
|
|
MemDbLoadW (
|
|
IN PCWSTR FileName
|
|
)
|
|
{
|
|
return pPrivateMemDbLoad (FileName, TRUE, NULL, FALSE);
|
|
}
|
|
|
|
|
|
BOOL
|
|
MemDbValidateDatabase (
|
|
VOID
|
|
)
|
|
{
|
|
MEMDB_ENUMW e;
|
|
|
|
if (MemDbEnumFirstValueW (&e, L"*", 0, MEMDB_ENDPOINTS_ONLY)) {
|
|
|
|
do {
|
|
if (!pPrivateMemDbGetValueW (e.szName, NULL, NULL)) {
|
|
return FALSE;
|
|
}
|
|
} while (MemDbEnumNextValueW (&e));
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
MemDbCreateTemporaryKeyA (
|
|
IN PCSTR KeyName
|
|
)
|
|
{
|
|
PCWSTR KeyNameW;
|
|
BOOL b = FALSE;
|
|
|
|
KeyNameW = ConvertAtoW (KeyName);
|
|
|
|
if (KeyNameW) {
|
|
b = MemDbCreateTemporaryKeyW (KeyNameW);
|
|
FreeConvertedStr (KeyNameW);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
BOOL
|
|
MemDbCreateTemporaryKeyW (
|
|
IN PCWSTR KeyName
|
|
)
|
|
{
|
|
UINT Count;
|
|
UINT Index;
|
|
PDATABASE Database;
|
|
DWORD KeyOffset;
|
|
PCWSTR SubKey;
|
|
BOOL b = FALSE;
|
|
|
|
EnterCriticalSection (&g_MemDbCs);
|
|
|
|
__try {
|
|
|
|
if (wcslen (KeyName) >= MAX_HIVE_NAME) {
|
|
SetLastError (ERROR_INVALID_PARAMETER);
|
|
__leave;
|
|
}
|
|
|
|
SubKey = SelectHive (KeyName);
|
|
|
|
KeyOffset = FindKey (SubKey);
|
|
if (KeyOffset != INVALID_OFFSET) {
|
|
SetLastError (ERROR_ALREADY_EXISTS);
|
|
__leave;
|
|
}
|
|
|
|
Count = GrowListGetSize (&g_DatabaseList);
|
|
for (Index = 1 ; Index < Count ; Index++) {
|
|
Database = (PDATABASE) GrowListGetItem (&g_DatabaseList, Index);
|
|
|
|
if (Database && StringIMatchW (Database->Hive, KeyName)) {
|
|
SetLastError (ERROR_ALREADY_EXISTS);
|
|
__leave;
|
|
}
|
|
}
|
|
|
|
b = pCreateDatabase (KeyName);
|
|
}
|
|
__finally {
|
|
LeaveCriticalSection (&g_MemDbCs);
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
MemDbMakeNonPrintableKey converts the double-backslashe pairs in a string
|
|
to ASCII 1, a non-printable character. This allows the caller to store
|
|
properly escaped strings in MemDb.
|
|
|
|
This routine is desinged to be expanded for other types of escape
|
|
processing.
|
|
|
|
Arguments:
|
|
|
|
KeyName - Specifies the key text; receives the converted text. The DBCS
|
|
version may grow the text buffer, so the text buffer must be twice
|
|
the length of the inbound string.
|
|
|
|
Flags - Specifies the type of conversion. Currently only
|
|
MEMDB_CONVERT_DOUBLEWACKS_TO_ASCII_1 is supported.
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
VOID
|
|
MemDbMakeNonPrintableKeyA (
|
|
IN OUT PSTR KeyName,
|
|
IN DWORD Flags
|
|
)
|
|
{
|
|
while (*KeyName) {
|
|
if (Flags & MEMDB_CONVERT_DOUBLEWACKS_TO_ASCII_1) {
|
|
if (_mbsnextc (KeyName) == '\\' &&
|
|
_mbsnextc (_mbsinc (KeyName)) == '\\'
|
|
) {
|
|
_setmbchar (KeyName, 1);
|
|
KeyName = _mbsinc (KeyName);
|
|
MYASSERT (_mbsnextc (KeyName) == '\\');
|
|
_setmbchar (KeyName, 1);
|
|
}
|
|
|
|
DEBUGMSG_IF ((
|
|
_mbsnextc (KeyName) == 1,
|
|
DBG_WHOOPS,
|
|
"MemDbMakeNonPrintableKeyA: Non-printable character "
|
|
"collision detected; key was damaged"
|
|
));
|
|
}
|
|
if (Flags & MEMDB_CONVERT_WILD_STAR_TO_ASCII_2) {
|
|
if (_mbsnextc (KeyName) == '*') {
|
|
_setmbchar (KeyName, 2);
|
|
}
|
|
|
|
DEBUGMSG_IF ((
|
|
_mbsnextc (_mbsinc (KeyName)) == 2,
|
|
DBG_WHOOPS,
|
|
"MemDbMakeNonPrintableKeyA: Non-printable character "
|
|
"collision detected; key was damaged"
|
|
));
|
|
}
|
|
if (Flags & MEMDB_CONVERT_WILD_QMARK_TO_ASCII_3) {
|
|
if (_mbsnextc (KeyName) == '?') {
|
|
_setmbchar (KeyName, 3);
|
|
}
|
|
|
|
DEBUGMSG_IF ((
|
|
_mbsnextc (_mbsinc (KeyName)) == 3,
|
|
DBG_WHOOPS,
|
|
"MemDbMakeNonPrintableKeyA: Non-printable character "
|
|
"collision detected; key was damaged"
|
|
));
|
|
}
|
|
KeyName = _mbsinc (KeyName);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
MemDbMakeNonPrintableKeyW (
|
|
IN OUT PWSTR KeyName,
|
|
IN DWORD Flags
|
|
)
|
|
{
|
|
while (*KeyName) {
|
|
if (Flags & MEMDB_CONVERT_DOUBLEWACKS_TO_ASCII_1) {
|
|
if (KeyName[0] == L'\\' && KeyName[1] == L'\\') {
|
|
KeyName[0] = 1;
|
|
KeyName[1] = 1;
|
|
KeyName++;
|
|
}
|
|
|
|
DEBUGMSG_IF ((
|
|
KeyName[0] == 1,
|
|
DBG_WHOOPS,
|
|
"MemDbMakeNonPrintableKeyW: Non-printable character "
|
|
"collision detected; key was damaged"
|
|
));
|
|
}
|
|
if (Flags & MEMDB_CONVERT_WILD_STAR_TO_ASCII_2) {
|
|
if (KeyName[0] == L'*') {
|
|
KeyName[0] = 2;
|
|
}
|
|
|
|
DEBUGMSG_IF ((
|
|
KeyName[1] == 2,
|
|
DBG_WHOOPS,
|
|
"MemDbMakeNonPrintableKeyW: Non-printable character "
|
|
"collision detected; key was damaged"
|
|
));
|
|
}
|
|
if (Flags & MEMDB_CONVERT_WILD_QMARK_TO_ASCII_3) {
|
|
if (KeyName[0] == L'*') {
|
|
KeyName[0] = 3;
|
|
}
|
|
|
|
DEBUGMSG_IF ((
|
|
KeyName[1] == 3,
|
|
DBG_WHOOPS,
|
|
"MemDbMakeNonPrintableKeyW: Non-printable character "
|
|
"collision detected; key was damaged"
|
|
));
|
|
}
|
|
KeyName++;
|
|
}
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
MemDbMakePrintableKey converts the ASCII 1 characters to backslashes,
|
|
restoring the string converted by MemDbMakeNonPrintableKey.
|
|
|
|
This routine is desinged to be expanded for other types of escape
|
|
processing.
|
|
|
|
Arguments:
|
|
|
|
KeyName - Specifies the key text; receives the converted text. The DBCS
|
|
version may grow the text buffer, so the text buffer must be twice
|
|
the length of the inbound string.
|
|
|
|
Flags - Specifies the type of conversion. Currently only
|
|
MEMDB_CONVERT_DOUBLEWACKS_TO_ASCII_1 is supported.
|
|
|
|
Return Value:
|
|
|
|
none
|
|
|
|
--*/
|
|
|
|
VOID
|
|
MemDbMakePrintableKeyA (
|
|
IN OUT PSTR KeyName,
|
|
IN DWORD Flags
|
|
)
|
|
{
|
|
while (*KeyName) {
|
|
if (Flags & MEMDB_CONVERT_DOUBLEWACKS_TO_ASCII_1) {
|
|
if (_mbsnextc (KeyName) == 1) {
|
|
_setmbchar (KeyName, '\\');
|
|
}
|
|
}
|
|
if (Flags & MEMDB_CONVERT_WILD_STAR_TO_ASCII_2) {
|
|
if (_mbsnextc (KeyName) == 2) {
|
|
_setmbchar (KeyName, '*');
|
|
}
|
|
}
|
|
if (Flags & MEMDB_CONVERT_WILD_QMARK_TO_ASCII_3) {
|
|
if (_mbsnextc (KeyName) == 3) {
|
|
_setmbchar (KeyName, '?');
|
|
}
|
|
}
|
|
KeyName = _mbsinc (KeyName);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
MemDbMakePrintableKeyW (
|
|
IN OUT PWSTR KeyName,
|
|
IN DWORD Flags
|
|
)
|
|
{
|
|
while (*KeyName) {
|
|
if (Flags & MEMDB_CONVERT_DOUBLEWACKS_TO_ASCII_1) {
|
|
if (KeyName[0] == 1) {
|
|
KeyName[0] = L'\\';
|
|
}
|
|
}
|
|
if (Flags & MEMDB_CONVERT_WILD_STAR_TO_ASCII_2) {
|
|
if (KeyName[0] == 2) {
|
|
KeyName[0] = L'*';
|
|
}
|
|
}
|
|
if (Flags & MEMDB_CONVERT_WILD_QMARK_TO_ASCII_3) {
|
|
if (KeyName[0] == 3) {
|
|
KeyName[0] = L'?';
|
|
}
|
|
}
|
|
KeyName++;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
GetFixedUserNameA (
|
|
IN OUT PSTR SrcUserBuf
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
GetFixedUserName looks in memdb for the user specified in SrcUserBuf,
|
|
and if found, returns the changed name.
|
|
|
|
Arguments:
|
|
|
|
SrcUserBuf - Specifies the user to look up as returned from the Win9x
|
|
registry. Receives the user name to create on NT.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
CHAR EncodedName[MEMDB_MAX];
|
|
CHAR FixedName[MEMDB_MAX];
|
|
|
|
StringCopyA (EncodedName, SrcUserBuf);
|
|
MemDbMakeNonPrintableKeyA (
|
|
EncodedName,
|
|
MEMDB_CONVERT_DOUBLEWACKS_TO_ASCII_1|
|
|
MEMDB_CONVERT_WILD_STAR_TO_ASCII_2|
|
|
MEMDB_CONVERT_WILD_QMARK_TO_ASCII_3
|
|
);
|
|
|
|
if (MemDbGetEndpointValueExA (
|
|
MEMDB_CATEGORY_FIXEDUSERNAMESA,
|
|
EncodedName,
|
|
NULL,
|
|
FixedName
|
|
)) {
|
|
StringCopyA (SrcUserBuf, FixedName);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
GetFixedUserNameW (
|
|
IN OUT PWSTR SrcUserBuf
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
GetFixedUserName looks in memdb for the user specified in SrcUserBuf,
|
|
and if found, returns the changed name.
|
|
|
|
Arguments:
|
|
|
|
SrcUserBuf - Specifies the user to look up as returned from the Win9x
|
|
registry. Receives the user name to create on NT.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
WCHAR EncodedName[MEMDB_MAX];
|
|
WCHAR FixedName[MEMDB_MAX];
|
|
|
|
StringCopyW (EncodedName, SrcUserBuf);
|
|
MemDbMakeNonPrintableKeyW (
|
|
EncodedName,
|
|
MEMDB_CONVERT_DOUBLEWACKS_TO_ASCII_1|
|
|
MEMDB_CONVERT_WILD_STAR_TO_ASCII_2|
|
|
MEMDB_CONVERT_WILD_QMARK_TO_ASCII_3
|
|
);
|
|
|
|
if (MemDbGetEndpointValueExW (
|
|
MEMDB_CATEGORY_FIXEDUSERNAMESW,
|
|
EncodedName,
|
|
NULL,
|
|
FixedName
|
|
)) {
|
|
StringCopyW (SrcUserBuf, FixedName);
|
|
}
|
|
}
|
|
|
|
/*
|
|
The format of the binary file for MemDb export
|
|
|
|
DWORD Signature
|
|
|
|
DWORD Version
|
|
|
|
DWORD GlobalFlags// 0x00000001 mask for Ansi format
|
|
// 0x00000002 mask for Temporary key
|
|
|
|
BYTE Root[]; // The root of the tree (zero terminated).
|
|
|
|
struct _KEY {
|
|
|
|
WORD Flags; // 0xF000 mask for accessing the entry flags
|
|
// - 0x1000 - Mask for Key name (0 - root relative, 1 - previous key relative)
|
|
// - 0x2000 - Mask for existing data (0 - no data, 1 - some data)
|
|
// - 0x4000 - Mast for data type (0 - DWORD, 1 - binary data)
|
|
// - 0x8000 - Mast for key flags (0 - nonexistent, 1 - existent)
|
|
// 0x0FFF mask for accessing size of the entry (except the data)
|
|
|
|
BYTE Key[]; // Should be PCSTR or PCWSTR (not zero terminated)
|
|
|
|
DWORD KeyFlags; //optional (dependant on Flags).
|
|
|
|
BYTE Data[]; // optional (dependant on Flags).
|
|
// if BLOB first DWORD is the size of the BLOB
|
|
// if DWORD then has exactly 4 bytes
|
|
}
|
|
...
|
|
*/
|
|
|
|
#define MEMDB_EXPORT_SIGNATURE 0x42444D4D
|
|
#define MEMDB_EXPORT_VERSION 0x00000001
|
|
#define MEMDB_EXPORT_FLAGS_ANSI 0x00000001
|
|
#define MEMDB_EXPORT_FLAGS_TEMP_KEY 0x00000002
|
|
#define MEMDB_EXPORT_FLAGS_PREV_RELATIVE 0x1000
|
|
#define MEMDB_EXPORT_FLAGS_DATA_PRESENT 0x2000
|
|
#define MEMDB_EXPORT_FLAGS_BINARY_DATA 0x4000
|
|
#define MEMDB_EXPORT_FLAGS_FLAGS_PRESENT 0x8000
|
|
#define MEMDB_EXPORT_FLAGS_SIZE_MASK 0x0FFF
|
|
|
|
BOOL
|
|
pMemDbExportWorkerA (
|
|
IN PCSTR RootTree,
|
|
IN PCSTR FileName
|
|
)
|
|
{
|
|
HANDLE fileHandle = INVALID_HANDLE_VALUE;
|
|
PCWSTR uRootTree;
|
|
PCSTR lastWackPtr;
|
|
DWORD globalFlags;
|
|
WORD localFlags;
|
|
CHAR key[MEMDB_MAX];
|
|
DWORD keySize;
|
|
DWORD copySize;
|
|
MEMDB_ENUMA e;
|
|
WORD blobSize;
|
|
DWORD written;
|
|
|
|
fileHandle = CreateFileA (FileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
if (fileHandle == INVALID_HANDLE_VALUE) {
|
|
return FALSE;
|
|
}
|
|
|
|
globalFlags = MEMDB_EXPORT_SIGNATURE;
|
|
WriteFile (fileHandle, &globalFlags, sizeof (DWORD), &written, NULL);
|
|
|
|
globalFlags = MEMDB_EXPORT_VERSION;
|
|
WriteFile (fileHandle, &globalFlags, sizeof (DWORD), &written, NULL);
|
|
|
|
globalFlags = MEMDB_EXPORT_FLAGS_ANSI;
|
|
|
|
// get the information if this key is a temporary key and set the flags if true
|
|
uRootTree = ConvertAtoW (RootTree);
|
|
if (IsTemporaryKey (uRootTree)) {
|
|
globalFlags |= MEMDB_EXPORT_FLAGS_TEMP_KEY;
|
|
}
|
|
FreeConvertedStr (uRootTree);
|
|
|
|
WriteFile (fileHandle, &globalFlags, sizeof (DWORD), &written, NULL);
|
|
|
|
// now write the root tree
|
|
WriteFile (fileHandle, RootTree, SizeOfStringA (RootTree), &written, NULL);
|
|
|
|
MemDbBuildKeyA (key, RootTree, "*", NULL, NULL);
|
|
|
|
if (MemDbEnumFirstValueA (&e, key, MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY)) {
|
|
key [0] = 0;
|
|
keySize = 0;
|
|
do {
|
|
// initialize the flags
|
|
localFlags = 0;
|
|
if (e.bBinary) {
|
|
localFlags |= MEMDB_EXPORT_FLAGS_DATA_PRESENT;
|
|
localFlags |= MEMDB_EXPORT_FLAGS_BINARY_DATA;
|
|
} else {
|
|
if (e.dwValue) {
|
|
localFlags |= MEMDB_EXPORT_FLAGS_DATA_PRESENT;
|
|
}
|
|
}
|
|
if (e.UserFlags) {
|
|
localFlags |= MEMDB_EXPORT_FLAGS_FLAGS_PRESENT;
|
|
}
|
|
|
|
// let's compute the size for this blob
|
|
blobSize = sizeof (WORD); // Flags
|
|
|
|
if (keySize &&
|
|
StringIMatchByteCountA (key, e.szName, keySize - sizeof (CHAR)) &&
|
|
(e.szName [keySize - 1] == '\\')
|
|
) {
|
|
localFlags |= MEMDB_EXPORT_FLAGS_PREV_RELATIVE;
|
|
copySize = SizeOfStringA (e.szName) - keySize - sizeof (CHAR);
|
|
} else {
|
|
copySize = SizeOfStringA (e.szName) - sizeof (CHAR);
|
|
keySize = 0;
|
|
}
|
|
MYASSERT (copySize < 4096);
|
|
blobSize += (WORD) copySize;
|
|
|
|
localFlags |= blobSize;
|
|
|
|
// write the flags
|
|
WriteFile (fileHandle, &localFlags, sizeof (WORD), &written, NULL);
|
|
|
|
// write the key
|
|
WriteFile (fileHandle, ((PBYTE) e.szName) + keySize, copySize, &written, NULL);
|
|
|
|
// write the key flags if appropriate
|
|
if (localFlags & MEMDB_EXPORT_FLAGS_FLAGS_PRESENT) {
|
|
WriteFile (fileHandle, &e.UserFlags, sizeof (DWORD), &written, NULL);
|
|
}
|
|
|
|
// write the data if appropriate
|
|
if (localFlags & MEMDB_EXPORT_FLAGS_DATA_PRESENT) {
|
|
if (localFlags & MEMDB_EXPORT_FLAGS_BINARY_DATA) {
|
|
WriteFile (fileHandle, &e.BinarySize, sizeof (DWORD), &written, NULL);
|
|
WriteFile (fileHandle, e.BinaryPtr, e.BinarySize, &written, NULL);
|
|
} else {
|
|
WriteFile (fileHandle, &e.dwValue, sizeof (DWORD), &written, NULL);
|
|
}
|
|
}
|
|
lastWackPtr = _mbsrchr (e.szName, '\\');
|
|
if (lastWackPtr) {
|
|
keySize = ByteCountABA (e.szName, lastWackPtr) + sizeof (CHAR);
|
|
StringCopyByteCountA (key, e.szName, keySize);
|
|
} else {
|
|
keySize = 0;
|
|
}
|
|
|
|
} while (MemDbEnumNextValueA (&e));
|
|
}
|
|
|
|
localFlags = 0;
|
|
|
|
// finally write the zero terminator
|
|
WriteFile (fileHandle, &localFlags, sizeof (WORD), &written, NULL);
|
|
|
|
CloseHandle (fileHandle);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
pMemDbExportWorkerW (
|
|
IN PCWSTR RootTree,
|
|
IN PCWSTR FileName
|
|
)
|
|
{
|
|
HANDLE fileHandle = INVALID_HANDLE_VALUE;
|
|
PCWSTR lastWackPtr;
|
|
DWORD globalFlags;
|
|
WORD localFlags;
|
|
WCHAR key[MEMDB_MAX];
|
|
DWORD keySize;
|
|
DWORD copySize;
|
|
MEMDB_ENUMW e;
|
|
WORD blobSize;
|
|
DWORD written;
|
|
|
|
fileHandle = CreateFileW (FileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
if (fileHandle == INVALID_HANDLE_VALUE) {
|
|
return FALSE;
|
|
}
|
|
|
|
globalFlags = MEMDB_EXPORT_SIGNATURE;
|
|
WriteFile (fileHandle, &globalFlags, sizeof (DWORD), &written, NULL);
|
|
|
|
globalFlags = MEMDB_EXPORT_VERSION;
|
|
WriteFile (fileHandle, &globalFlags, sizeof (DWORD), &written, NULL);
|
|
|
|
// get the information if this key is a temporary key and set the flags if true
|
|
if (IsTemporaryKey (RootTree)) {
|
|
globalFlags |= MEMDB_EXPORT_FLAGS_TEMP_KEY;
|
|
}
|
|
|
|
WriteFile (fileHandle, &globalFlags, sizeof (DWORD), &written, NULL);
|
|
|
|
// now write the root tree
|
|
WriteFile (fileHandle, RootTree, SizeOfStringW (RootTree), &written, NULL);
|
|
|
|
MemDbBuildKeyW (key, RootTree, L"*", NULL, NULL);
|
|
|
|
if (MemDbEnumFirstValueW (&e, key, MEMDB_ALL_SUBLEVELS, MEMDB_ENDPOINTS_ONLY)) {
|
|
key [0] = 0;
|
|
keySize = 0;
|
|
do {
|
|
// initialize the flags
|
|
localFlags = 0;
|
|
if (e.bBinary) {
|
|
localFlags |= MEMDB_EXPORT_FLAGS_DATA_PRESENT;
|
|
localFlags |= MEMDB_EXPORT_FLAGS_BINARY_DATA;
|
|
} else {
|
|
if (e.dwValue) {
|
|
localFlags |= MEMDB_EXPORT_FLAGS_DATA_PRESENT;
|
|
}
|
|
}
|
|
if (e.UserFlags) {
|
|
localFlags |= MEMDB_EXPORT_FLAGS_FLAGS_PRESENT;
|
|
}
|
|
|
|
// let's compute the size for this blob
|
|
blobSize = sizeof (WORD); // Flags
|
|
|
|
if (keySize &&
|
|
StringIMatchByteCountW (key, e.szName, keySize - sizeof (WCHAR)) &&
|
|
(e.szName [keySize - 1] == L'\\')
|
|
) {
|
|
localFlags |= MEMDB_EXPORT_FLAGS_PREV_RELATIVE;
|
|
copySize = SizeOfStringW (e.szName) - keySize - sizeof (WCHAR);
|
|
} else {
|
|
copySize = SizeOfStringW (e.szName) - sizeof (WCHAR);
|
|
keySize = 0;
|
|
}
|
|
MYASSERT (copySize < 4096);
|
|
blobSize += (WORD) copySize;
|
|
|
|
localFlags |= blobSize;
|
|
|
|
// write the flags
|
|
WriteFile (fileHandle, &localFlags, sizeof (WORD), &written, NULL);
|
|
|
|
// write the key
|
|
WriteFile (fileHandle, ((PBYTE) e.szName) + keySize, copySize, &written, NULL);
|
|
|
|
// write the key flags if appropriate
|
|
if (localFlags & MEMDB_EXPORT_FLAGS_FLAGS_PRESENT) {
|
|
WriteFile (fileHandle, &e.UserFlags, sizeof (DWORD), &written, NULL);
|
|
}
|
|
|
|
// write the data if appropriate
|
|
if (localFlags & MEMDB_EXPORT_FLAGS_DATA_PRESENT) {
|
|
if (localFlags & MEMDB_EXPORT_FLAGS_BINARY_DATA) {
|
|
WriteFile (fileHandle, &e.BinarySize, sizeof (DWORD), &written, NULL);
|
|
WriteFile (fileHandle, e.BinaryPtr, e.BinarySize, &written, NULL);
|
|
} else {
|
|
WriteFile (fileHandle, &e.dwValue, sizeof (DWORD), &written, NULL);
|
|
}
|
|
}
|
|
lastWackPtr = wcsrchr (e.szName, L'\\');
|
|
if (lastWackPtr) {
|
|
keySize = ByteCountABW (e.szName, lastWackPtr) + sizeof (WCHAR);
|
|
StringCopyByteCountW (key, e.szName, keySize);
|
|
} else {
|
|
keySize = 0;
|
|
}
|
|
|
|
} while (MemDbEnumNextValueW (&e));
|
|
}
|
|
|
|
localFlags = 0;
|
|
|
|
// finally write the zero terminator
|
|
WriteFile (fileHandle, &localFlags, sizeof (WORD), &written, NULL);
|
|
|
|
CloseHandle (fileHandle);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
MemDbExportA (
|
|
IN PCSTR RootTree,
|
|
IN PCSTR FileName,
|
|
IN BOOL AnsiFormat
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
MemDbExportA exports a tree in a private binary format. The format is described above.
|
|
|
|
Arguments:
|
|
|
|
RootTree - Specifies the tree to be exported
|
|
FileName - Name of the binary format file to export to.
|
|
AnsiFormat - Keys should be written in ANSI rather than in Unicode.
|
|
|
|
Return Value:
|
|
|
|
TRUE is successfull, FALSE if not.
|
|
|
|
--*/
|
|
|
|
{
|
|
PCWSTR uRootTree, uFileName;
|
|
BOOL result = TRUE;
|
|
|
|
if (AnsiFormat) {
|
|
result = pMemDbExportWorkerA (RootTree, FileName);
|
|
} else {
|
|
uRootTree = ConvertAtoW (RootTree);
|
|
uFileName = ConvertAtoW (FileName);
|
|
result = pMemDbExportWorkerW (uRootTree, uFileName);
|
|
FreeConvertedStr (uFileName);
|
|
FreeConvertedStr (uRootTree);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
BOOL
|
|
MemDbExportW (
|
|
IN PCWSTR RootTree,
|
|
IN PCWSTR FileName,
|
|
IN BOOL AnsiFormat
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
MemDbExportW exports a tree in a private binary format. The format is described above.
|
|
|
|
Arguments:
|
|
|
|
RootTree - Specifies the tree to be exported
|
|
FileName - Name of the binary format file to export to.
|
|
AnsiFormat - Keys should be written in ANSI rather than in Unicode.
|
|
|
|
Return Value:
|
|
|
|
TRUE is successfull, FALSE if not.
|
|
|
|
--*/
|
|
|
|
{
|
|
PCSTR aRootTree, aFileName;
|
|
BOOL result = TRUE;
|
|
|
|
if (!AnsiFormat) {
|
|
result = pMemDbExportWorkerW (RootTree, FileName);
|
|
} else {
|
|
aRootTree = ConvertWtoA (RootTree);
|
|
aFileName = ConvertWtoA (FileName);
|
|
result = pMemDbExportWorkerA (aRootTree, aFileName);
|
|
FreeConvertedStr (aFileName);
|
|
FreeConvertedStr (aRootTree);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
BOOL
|
|
pMemDbImportWorkerA (
|
|
IN PBYTE FileBuffer
|
|
)
|
|
{
|
|
DWORD globalFlags;
|
|
WORD localFlags;
|
|
PCSTR rootTree;
|
|
CHAR lastKey [MEMDB_MAX];
|
|
PSTR lastKeyPtr;
|
|
CHAR node [MEMDB_MAX];
|
|
CHAR localKey [MEMDB_MAX];
|
|
DWORD flags = 0;
|
|
|
|
globalFlags = *((PDWORD) FileBuffer);
|
|
|
|
// FileBuffer will point to the tree that's imported
|
|
FileBuffer += sizeof (DWORD);
|
|
rootTree = (PCSTR) FileBuffer;
|
|
|
|
if (globalFlags & MEMDB_EXPORT_FLAGS_TEMP_KEY) {
|
|
// a temporary key was exported
|
|
MemDbCreateTemporaryKeyA ((PCSTR) FileBuffer);
|
|
}
|
|
|
|
// let's pass the string
|
|
FileBuffer = GetEndOfStringA ((PCSTR) FileBuffer) + sizeof (CHAR);
|
|
|
|
// ok from this point on we read and add all keys
|
|
lastKey [0] = 0;
|
|
localFlags = *((PWORD) FileBuffer);
|
|
|
|
while (localFlags) {
|
|
|
|
localKey [0] = 0;
|
|
|
|
StringCopyByteCountA (localKey, (PSTR)(FileBuffer + sizeof (WORD)), (localFlags & MEMDB_EXPORT_FLAGS_SIZE_MASK) - sizeof (WORD) + sizeof (CHAR));
|
|
|
|
MemDbBuildKeyA (node, rootTree, (localFlags & MEMDB_EXPORT_FLAGS_PREV_RELATIVE)?lastKey:NULL, localKey, NULL);
|
|
|
|
FileBuffer += (localFlags & MEMDB_EXPORT_FLAGS_SIZE_MASK);
|
|
|
|
MYASSERT (!((localFlags & MEMDB_EXPORT_FLAGS_BINARY_DATA) && (localFlags & MEMDB_EXPORT_FLAGS_FLAGS_PRESENT)));
|
|
|
|
if (localFlags & MEMDB_EXPORT_FLAGS_FLAGS_PRESENT) {
|
|
|
|
flags = *(PDWORD)FileBuffer;
|
|
FileBuffer += sizeof (DWORD);
|
|
}
|
|
|
|
if (localFlags & MEMDB_EXPORT_FLAGS_DATA_PRESENT) {
|
|
if (localFlags & MEMDB_EXPORT_FLAGS_BINARY_DATA) {
|
|
MemDbSetBinaryValueA (node, FileBuffer + sizeof (DWORD), *(PDWORD)FileBuffer);
|
|
FileBuffer += (*(PDWORD)FileBuffer + sizeof (DWORD));
|
|
} else {
|
|
MemDbSetValueAndFlagsA (node, *(PDWORD)FileBuffer, flags, 0);
|
|
FileBuffer += sizeof (DWORD);
|
|
}
|
|
} else {
|
|
MemDbSetValueA (node, 0);
|
|
}
|
|
|
|
if (localFlags & MEMDB_EXPORT_FLAGS_PREV_RELATIVE) {
|
|
|
|
StringCatA (lastKey, "\\");
|
|
StringCatA (lastKey, localKey);
|
|
lastKeyPtr = _mbsrchr (lastKey, '\\');
|
|
if (lastKeyPtr) {
|
|
*lastKeyPtr = 0;
|
|
} else {
|
|
lastKey [0] = 0;
|
|
}
|
|
} else {
|
|
|
|
StringCopyA (lastKey, localKey);
|
|
lastKeyPtr = _mbsrchr (lastKey, '\\');
|
|
if (lastKeyPtr) {
|
|
*lastKeyPtr = 0;
|
|
} else {
|
|
lastKey [0] = 0;
|
|
}
|
|
}
|
|
localFlags = *((PWORD) FileBuffer);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
pMemDbImportWorkerW (
|
|
IN PBYTE FileBuffer
|
|
)
|
|
{
|
|
DWORD globalFlags;
|
|
WORD localFlags;
|
|
PCWSTR rootTree;
|
|
WCHAR lastKey [MEMDB_MAX];
|
|
PWSTR lastKeyPtr;
|
|
WCHAR node [MEMDB_MAX];
|
|
WCHAR localKey [MEMDB_MAX];
|
|
DWORD flags = 0;
|
|
|
|
globalFlags = *((PDWORD) FileBuffer);
|
|
|
|
// FileBuffer will point to the tree that's imported
|
|
FileBuffer += sizeof (DWORD);
|
|
rootTree = (PCWSTR) FileBuffer;
|
|
|
|
if (globalFlags & MEMDB_EXPORT_FLAGS_TEMP_KEY) {
|
|
// a temporary key was exported
|
|
MemDbCreateTemporaryKeyW ((PCWSTR) FileBuffer);
|
|
}
|
|
|
|
// let's pass the string
|
|
FileBuffer = (PBYTE)GetEndOfStringW ((PCWSTR) FileBuffer) + sizeof (WCHAR);
|
|
|
|
// ok from this point on we read and add all keys
|
|
lastKey [0] = 0;
|
|
localFlags = *((PWORD) FileBuffer);
|
|
|
|
while (localFlags) {
|
|
|
|
localKey [0] = 0;
|
|
|
|
StringCopyByteCountW (localKey, (PWSTR)(FileBuffer + sizeof (WORD)), (localFlags & MEMDB_EXPORT_FLAGS_SIZE_MASK) - sizeof (WORD) + sizeof (WCHAR));
|
|
|
|
MemDbBuildKeyW (node, rootTree, (localFlags & MEMDB_EXPORT_FLAGS_PREV_RELATIVE)?lastKey:NULL, localKey, NULL);
|
|
|
|
FileBuffer += (localFlags & MEMDB_EXPORT_FLAGS_SIZE_MASK);
|
|
|
|
MYASSERT (!((localFlags & MEMDB_EXPORT_FLAGS_BINARY_DATA) && (localFlags & MEMDB_EXPORT_FLAGS_FLAGS_PRESENT)));
|
|
|
|
if (localFlags & MEMDB_EXPORT_FLAGS_FLAGS_PRESENT) {
|
|
|
|
flags = *(PDWORD)FileBuffer;
|
|
FileBuffer += sizeof (DWORD);
|
|
}
|
|
|
|
if (localFlags & MEMDB_EXPORT_FLAGS_DATA_PRESENT) {
|
|
if (localFlags & MEMDB_EXPORT_FLAGS_BINARY_DATA) {
|
|
MemDbSetBinaryValueW (node, FileBuffer + sizeof (DWORD), *(PDWORD)FileBuffer);
|
|
FileBuffer += (*(PDWORD)FileBuffer + sizeof (DWORD));
|
|
} else {
|
|
MemDbSetValueAndFlagsW (node, *(PDWORD)FileBuffer, flags, 0);
|
|
FileBuffer += sizeof (DWORD);
|
|
}
|
|
} else {
|
|
MemDbSetValueW (node, 0);
|
|
}
|
|
|
|
if (localFlags & MEMDB_EXPORT_FLAGS_PREV_RELATIVE) {
|
|
|
|
StringCatW (lastKey, L"\\");
|
|
StringCatW (lastKey, localKey);
|
|
lastKeyPtr = wcsrchr (lastKey, L'\\');
|
|
if (lastKeyPtr) {
|
|
*lastKeyPtr = 0;
|
|
} else {
|
|
lastKey [0] = 0;
|
|
}
|
|
} else {
|
|
|
|
StringCopyW (lastKey, localKey);
|
|
lastKeyPtr = wcsrchr (lastKey, L'\\');
|
|
if (lastKeyPtr) {
|
|
*lastKeyPtr = 0;
|
|
} else {
|
|
lastKey [0] = 0;
|
|
}
|
|
}
|
|
localFlags = *((PWORD) FileBuffer);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
MemDbImportA (
|
|
IN PCSTR FileName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
MemDbImportA 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;
|
|
HANDLE fileHandle;
|
|
HANDLE mapHandle;
|
|
BOOL result = TRUE;
|
|
|
|
fileBuff = MapFileIntoMemoryA (FileName, &fileHandle, &mapHandle);
|
|
if (fileBuff == NULL) {
|
|
DEBUGMSGA ((DBG_ERROR, "Could not execute MemDbImport for %s", FileName));
|
|
return FALSE;
|
|
}
|
|
|
|
__try {
|
|
if (*((PDWORD) fileBuff) != MEMDB_EXPORT_SIGNATURE) {
|
|
DEBUGMSGA ((DBG_ERROR, "Unknown signature for file to import: %s", FileName));
|
|
result = FALSE;
|
|
} else {
|
|
|
|
fileBuff += sizeof (DWORD);
|
|
|
|
if (*((PDWORD) fileBuff) != MEMDB_EXPORT_VERSION) {
|
|
|
|
DEBUGMSGA ((DBG_ERROR, "Unknown version for file to import: %s", FileName));
|
|
result = FALSE;
|
|
|
|
} else {
|
|
|
|
fileBuff += sizeof (DWORD);
|
|
|
|
if (*((PDWORD) fileBuff) & MEMDB_EXPORT_FLAGS_ANSI) {
|
|
result = pMemDbImportWorkerA (fileBuff);
|
|
} else {
|
|
result = pMemDbImportWorkerW (fileBuff);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
__except (1) {
|
|
DEBUGMSGA ((DBG_ERROR, "Access violation while importing: %s", FileName));
|
|
}
|
|
|
|
UnmapFile (fileBuff, mapHandle, fileHandle);
|
|
|
|
return result;
|
|
}
|
|
|
|
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;
|
|
HANDLE fileHandle;
|
|
HANDLE mapHandle;
|
|
BOOL result;
|
|
|
|
fileBuff = MapFileIntoMemoryW (FileName, &fileHandle, &mapHandle);
|
|
if (fileBuff == NULL) {
|
|
DEBUGMSGW ((DBG_ERROR, "Could not execute MemDbImport for %s", FileName));
|
|
return FALSE;
|
|
}
|
|
|
|
__try {
|
|
if (*((PDWORD) fileBuff) != MEMDB_EXPORT_SIGNATURE) {
|
|
|
|
DEBUGMSGW ((DBG_ERROR, "Unknown signature for file to import: %s", FileName));
|
|
result = FALSE;
|
|
|
|
} else {
|
|
|
|
fileBuff += sizeof (DWORD);
|
|
|
|
if (*((PDWORD) fileBuff) != MEMDB_EXPORT_VERSION) {
|
|
|
|
DEBUGMSGW ((DBG_ERROR, "Unknown version for file to import: %s", FileName));
|
|
result = FALSE;
|
|
|
|
} else {
|
|
|
|
fileBuff += sizeof (DWORD);
|
|
|
|
if (*((PDWORD) fileBuff) & MEMDB_EXPORT_FLAGS_ANSI) {
|
|
result = pMemDbImportWorkerA (fileBuff);
|
|
} else {
|
|
result = pMemDbImportWorkerW (fileBuff);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
__except (1) {
|
|
DEBUGMSGW ((DBG_ERROR, "Access violation while importing: %s", FileName));
|
|
}
|
|
|
|
UnmapFile (fileBuff, mapHandle, fileHandle);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
BOOL
|
|
MemDbQueryVersionA (
|
|
PCSTR FileName,
|
|
PMEMDB_VERSION Version
|
|
)
|
|
{
|
|
pPrivateMemDbLoad ((PCWSTR) FileName, FALSE, Version, TRUE);
|
|
|
|
return Version->Valid;
|
|
}
|
|
|
|
|
|
BOOL
|
|
MemDbQueryVersionW (
|
|
PCWSTR FileName,
|
|
PMEMDB_VERSION Version
|
|
)
|
|
{
|
|
pPrivateMemDbLoad (FileName, TRUE, Version, TRUE);
|
|
|
|
return Version->Valid;
|
|
}
|
|
|
|
|