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