|
|
/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
appdiff.c
Abstract:
Implements a stub tool that is designed to run with Win9x-side upgrade code.
Author:
Jim Schmidt (jimschm) 26-Feb-1998
Revision History:
<alias> <date> <comments>
--*/
#include "pch.h"
#define S_FILES TEXT("Files")
#define S_REG TEXT("Reg")
#define S_INIFILES TEXT("IniFiles")
#define S_EXCLUDE TEXT("Exclude")
#define S_PATHS TEXT("Paths")
#define S_REGISTRY TEXT("Registry")
#define S_SUBSTITUTIONS TEXT("Substitutions")
#define S_SRC TEXT("Src")
#define S_DEST TEXT("Dest")
#define S_ADDED TEXT("Added")
#define S_CHANGED TEXT("Changed")
#define S_ZERO TEXT("0")
typedef struct { BOOL SnapMode; BOOL DiffMode; BOOL CheckBits; PCTSTR SnapFile; PCTSTR AppFile; PCTSTR Name; PCTSTR OutputFile; PCTSTR RegRoot; PCTSTR FileSysRoot; BOOL UseAppDiffInf; BOOL NoRoots; BOOL QuietMode; } OPTIONS, *POPTIONS;
BOOL g_Quiet; BOOL g_Thorough;
typedef struct { DWORD dwFileAttributes; FILETIME ftCreationTime; FILETIME ftLastWriteTime; DWORD nFileSizeHigh; DWORD nFileSizeLow; } FILEINFO, *PFILEINFO;
BOOL DoSnapMode ( POPTIONS Options );
BOOL DoDiffMode ( POPTIONS Options );
HANDLE g_hHeap; HINSTANCE g_hInst;
BOOL WINAPI MigUtil_Entry ( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved );
BOOL WINAPI MemDb_Entry ( HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved );
BOOL Init ( VOID ) { HINSTANCE hInstance; DWORD dwReason; PVOID lpReserved;
//
// Simulate DllMain
//
hInstance = GetModuleHandle (NULL); dwReason = DLL_PROCESS_ATTACH; lpReserved = NULL;
g_hInst = hInstance; g_hHeap = GetProcessHeap();
MigUtil_Entry ( hInstance, dwReason, lpReserved );
MemDb_Entry ( hInstance, dwReason, lpReserved );
return TRUE; }
VOID Terminate ( VOID ) { HINSTANCE hInstance; DWORD dwReason; PVOID lpReserved;
//
// Simulate DllMain
//
hInstance = GetModuleHandle (NULL); dwReason = DLL_PROCESS_DETACH; lpReserved = NULL;
MemDb_Entry ( hInstance, dwReason, lpReserved );
MigUtil_Entry ( hInstance, dwReason, lpReserved ); }
VOID HelpAndExit ( VOID ) { printf ("Command line syntax:\n\n" "appdiff -s[:snapfile] [-r:<regroot>] [-f:<fileroot>]\n" "appdiff -d[:snapfile] [-a:appfilelist] [-n:name] [-o:outfile]\n" "appdiff -s[:snapfile] -d [-n:name] [-o:outfile] [-r:<regroot>]\n" " [-f:<fileroot>]\n" "\n" "-s Specifies snapshot mode, where snapfile is the name of\n" " the memdb output file, and is snap.dat by default.\n" "\n" "-d Specifies diff mode, where snapfile is the name of a\n" " previously generated snapshot file, and is snap.dat by\n" " default.\n" "\n" "-a Specifies the application file list, as generated by\n" " migfiles.exe.\n" "\n" "-n Specifies the application section name, and the default\n" " is Application.\n" "\n" "-o Specifies the name of the output INF fragment, and the\n" " default is output.inf\n" "\n" "-r Specifies a registry root to compare. If specified,\n" " only the registry is scanned, unless -f is also specified.\n" "\n" "-f Specifies a file system root to compare. If specified,\n" " only the file system is scanned, unless -r is also\n" " specified.\n" "\n" "Additional Options:" "\n" "-q Quiet mode -- disables stderr output.\n" "-u Use appdiff.inf and output.inf (for generation of uninstall\n" " sections)\n" "-t Thorough checks (computes checksums for all data)\n" "\n" "APPDIFF.INF specifies the registry and file system roots to scan on\n" "a per-app basis, and is used to generate uninstall sections for\n" "migdb.inf. See \\\\jimschm-dev\\team\\tools\\appdiff.inf for info.\n" "\n" "OUTPUT.INF is generated by this tool, and is designed to be cut &\n" "pasted into migdb.inf.\n" );
exit(0); }
BOOL pParseCommandLine ( IN INT ArgCount, IN PTSTR ArgArray[], OUT POPTIONS Options ) { INT i;
ZeroMemory (Options, sizeof (OPTIONS));
Options->NoRoots = TRUE;
for (i = 0 ; i < ArgCount ; i++) {
if (ArgArray[i][0] == TEXT('-') || ArgArray[i][0] == TEXT('/')) {
switch (_totlower (ArgArray[i][1])) {
case TEXT('s'): Options->SnapMode = TRUE;
if (ArgArray[i][2] == TEXT(':')) { if (Options->SnapFile) { return FALSE; }
Options->SnapFile = &ArgArray[i][3];
if (Options->SnapFile[0] == 0) { return FALSE; } }
break;
case TEXT('t'): if (g_Thorough) { return FALSE; }
Options->CheckBits = TRUE; g_Thorough = TRUE;
break;
case TEXT('d'): Options->DiffMode = TRUE;
if (ArgArray[i][2] == TEXT(':')) { if (Options->SnapFile) { return FALSE; }
Options->SnapFile = &ArgArray[i][3];
if (Options->SnapFile[0] == 0) { return FALSE; } }
break;
case TEXT('r'): Options->NoRoots = FALSE;
if (Options->RegRoot) { return FALSE; }
if (ArgArray[i][2] == TEXT(':')) { Options->RegRoot = &ArgArray[i][3]; } else if (i + 1 < ArgCount) { i++; Options->RegRoot = ArgArray[i]; } else { Options->RegRoot = &ArgArray[i][2]; }
if (Options->RegRoot[0] == 0) { return FALSE; }
break;
case TEXT('f'): Options->NoRoots = FALSE;
if (Options->FileSysRoot) { return FALSE; }
if (ArgArray[i][2] == TEXT(':')) { Options->FileSysRoot = &ArgArray[i][3]; } else if (i + 1 < ArgCount) { i++; Options->FileSysRoot = ArgArray[i]; } else { Options->FileSysRoot = &ArgArray[i][2]; }
if (Options->FileSysRoot[0] == 0) { return FALSE; }
break;
case TEXT('q'): if (g_Quiet) { return FALSE; }
Options->QuietMode = TRUE; g_Quiet = TRUE; break;
case TEXT('u'): if (Options->UseAppDiffInf) { return FALSE; }
Options->UseAppDiffInf = TRUE; break;
case TEXT('a'): if (Options->AppFile) { return FALSE; }
if (ArgArray[i][2] == TEXT(':')) { Options->AppFile = &ArgArray[i][3]; } else if (i + 1 < ArgCount) { i++; Options->AppFile = ArgArray[i]; } else { Options->AppFile = &ArgArray[i][2]; }
if (Options->AppFile[0] == 0) { return FALSE; }
break;
case TEXT('n'): if (Options->Name) { return FALSE; }
if (ArgArray[i][2] == TEXT(':')) { Options->Name = &ArgArray[i][3]; } else if (i + 1 < ArgCount) { i++; Options->Name = ArgArray[i]; } else { Options->Name = &ArgArray[i][2]; }
if (Options->Name[0] == 0) { return FALSE; }
break;
case TEXT('o'): if (Options->OutputFile) { return FALSE; }
if (ArgArray[i][2] == TEXT(':')) { Options->OutputFile = &ArgArray[i][3]; } else if (i + 1 < ArgCount) { i++; Options->OutputFile = ArgArray[i]; } else { Options->OutputFile = &ArgArray[i][2]; }
if (Options->OutputFile[0] == 0) { return FALSE; }
break;
default: return FALSE; } }
else { return FALSE; } }
if (!Options->SnapMode && !Options->DiffMode) { return FALSE; }
if (!Options->SnapFile) { Options->SnapFile = TEXT("snap.dat"); }
if (!Options->OutputFile && Options->UseAppDiffInf) { Options->OutputFile = TEXT("output.inf"); }
if (!Options->Name) { Options->Name = TEXT("Application"); }
if (!g_Quiet) { _ftprintf (stderr, TEXT("Snap file: %s\n"), Options->SnapFile);
if (Options->OutputFile) { _ftprintf (stderr, TEXT("Output file: %s\n"), Options->OutputFile); }
_ftprintf (stderr, TEXT("Thorough checks: %s\n"), Options->CheckBits ? "ENABLED" : "DISABLED");
_ftprintf (stderr, TEXT("Application Name: %s\n\n"), Options->Name); }
return TRUE; }
INT __cdecl _tmain ( INT argc, TCHAR *argv[] ) { OPTIONS Options;
if (!pParseCommandLine (argc - 1, &argv[1], &Options)) { HelpAndExit(); }
if (!Init()) { printf ("Unable to initialize!\n"); return 255; }
//
// Snap Mode: Gather the directory, registry and INI files
//
if (Options.SnapMode) { DoSnapMode (&Options); }
//
// Diff Mode: Gather another snapshot, then compare against
// original
//
if (Options.DiffMode) { if (Options.SnapMode) { _ftprintf (stderr, TEXT("Do your thing, then hit Enter.\n")); getchar(); _ftprintf (stderr, TEXT("\n")); }
DoDiffMode (&Options); }
Terminate();
return 0; }
BOOL pCompareData ( IN PCBYTE Src, IN PCBYTE Dest, IN UINT Size ) { PCWSTR p, q;
if (Size >= sizeof (WCHAR)) {
p = (PCWSTR) (Src + Size - sizeof (WCHAR)); q = (PCWSTR) (Dest + Size - sizeof (WCHAR));
if (*p == 0 && *q == 0) { if (StringIMatchW ((PCWSTR) Src, (PCWSTR) Dest)) { return TRUE; }
return FALSE; } }
return memcmp (Src, Dest, Size) == 0; }
VOID pSetMemDbKey ( IN BOOL DiffMode, IN PCTSTR Group, IN PCTSTR Key, IN PBYTE Data, IN DWORD DataSize ) { PCBYTE OrgData; DWORD OrgSize; TCHAR Node[MEMDB_MAX];
wsprintf (Node, TEXT("%s\\%s"), S_EXCLUDE, Key);
if (MemDbGetValue (Node, NULL)) { return; }
if (!DiffMode) {
MemDbSetBinaryValueEx ( S_ZERO, Group, Key, Data, DataSize, NULL ); }
else { //
// Compare against original data
//
wsprintf (Node, TEXT("0\\%s\\%s"), Group, Key); OrgData = MemDbGetBinaryValue (Node, &OrgSize);
if (!OrgData) { //
// Data has been added
//
wsprintf (Node, TEXT("%s\\%s\\%s"), S_ADDED, Group, Key); MemDbSetValue (Node, 0); }
else {
//
// Delete memdb key, so remaining items will provide list of data
// that was deleted.
//
if (OrgSize != DataSize || !pCompareData (OrgData, Data, DataSize)) { //
// Data has changed
//
MemDbDeleteValue (Node);
wsprintf (Node, TEXT("%s\\%s\\%s"), S_CHANGED, Group, Key); MemDbSetValue (Node, 0); } else { //
// Data has not changed
//
MemDbDeleteValue (Node); } } } }
VOID pConvertWin32FindData ( IN PWIN32_FIND_DATA Data, OUT PFILEINFO Info ) { Info->dwFileAttributes = Data->dwFileAttributes; Info->ftCreationTime = Data->ftCreationTime; Info->ftLastWriteTime = Data->ftLastWriteTime; Info->nFileSizeHigh = Data->nFileSizeHigh; Info->nFileSizeLow = Data->nFileSizeLow;
}
VOID pSetRegDataAndFreePtrs ( BOOL DiffMode, PBYTE Data, OPTIONAL PBYTE Data2, OPTIONAL DWORD Size, PCTSTR Key, PCTSTR Value OPTIONAL ) { PCTSTR Node;
if (Data2) { Node = CreateEncodedRegistryString (Key, Value);
pSetMemDbKey ( DiffMode, S_REG, Node, Data2, Size );
FreeEncodedRegistryString (Node);
if (Data) { MemFree (g_hHeap, 0, Data); }
MemFree (g_hHeap, 0, Data2); } }
BOOL pRegSnap ( BOOL DiffMode, PCTSTR Root )
{ REGTREE_ENUM Reg; REGVALUE_ENUM RegVal; PBYTE Data; PBYTE Data2; DWORD Size = 0; TCHAR SkipTree[MEMDB_MAX]; TCHAR TempNode[MEMDB_MAX]; UINT SkipTreeBytes = 0;
SkipTree[0] = 0;
wsprintf (TempNode, TEXT("%s\\%s"), S_EXCLUDE, Root); if (MemDbGetValue (TempNode, NULL)) { return TRUE; }
if (!g_Quiet) { _ftprintf (stderr, TEXT("Taking snapshot of %s\n"), Root); }
if (EnumFirstRegKeyInTree (&Reg, Root)) { do { //
// Key/key tree exclude processing
//
if (SkipTree[0]) { if (StringIMatchByteCount (SkipTree, Reg.FullKeyName, SkipTreeBytes)) { continue; }
SkipTree[0] = 0; }
wsprintf (TempNode, TEXT("%s\\%s"), S_EXCLUDE, Reg.FullKeyName); if (MemDbGetValue (TempNode, NULL)) { StringCopy (SkipTree, Reg.FullKeyName); SkipTreeBytes = ByteCount (SkipTree); continue; }
//
// Non-excluded key
//
Data = NULL;
if (EnumFirstRegValue (&RegVal, Reg.CurrentKey->KeyHandle)) { do { Data = GetRegValueData (RegVal.KeyHandle, RegVal.ValueName); Data2 = NULL;
if (Data) { Size = RegVal.DataSize + sizeof (DWORD); Data2 = MemAlloc (g_hHeap, 0, Size); MYASSERT (Data2);
CopyMemory ((PDWORD) Data2 + 1, Data, RegVal.DataSize); *((PDWORD) Data2) = RegVal.Type; }
pSetRegDataAndFreePtrs (DiffMode, Data, Data2, Size, Reg.FullKeyName, RegVal.ValueName);
} while (EnumNextRegValue (&RegVal));
} else { Size = sizeof (DWORD); Data2 = MemAlloc (g_hHeap, 0, Size); MYASSERT (Data2); *((PDWORD) Data2) = 0xffffffff;
pSetRegDataAndFreePtrs (DiffMode, Data, Data2, Size, Reg.FullKeyName, RegVal.ValueName); }
} while (EnumNextRegKeyInTree (&Reg)); }
return TRUE; }
DWORD pComputeChecksum ( PCTSTR FullPath ) { HANDLE File; HANDLE Map; PBYTE Data; UINT Size; UINT u; DWORD Checksum = 0;
Data = MapFileIntoMemory (FullPath, &File, &Map); if (!Data) { return 0xFFFFFFFF; }
Size = GetFileSize (File, NULL);
for (u = 0 ; u < Size ; u++) { Checksum = _rotl (Checksum, 3); Checksum ^= Data[u]; }
UnmapFile (Data, Map, File);
return Checksum; }
BOOL pDirAndIniSnap ( BOOL DiffMode, PCTSTR Root ) { TREE_ENUM Dir; PCTSTR p, q, r; TCHAR SectionNames[32768]; TCHAR KeyNames[32768]; TCHAR KeyValue[4096]; TCHAR Node[MEMDB_MAX]; TCHAR ExcludeNode[MEMDB_MAX]; UINT Count; FILEINFO fi; TCHAR SkipTree[MEMDB_MAX]; UINT SkipTreeBytes = 0; DWORD Checksum;
SkipTree[0] = 0;
wsprintf (ExcludeNode, TEXT("%s\\%s"), S_EXCLUDE, Root); if (MemDbGetValue (ExcludeNode, NULL)) { return TRUE; }
//
// Take a snapshot of all dirs in drive specified by Root
//
if (!g_Quiet) { _ftprintf (stderr, TEXT("Taking snapshot of %s\n"), Root); }
if (EnumFirstFileInTree (&Dir, Root, NULL, TRUE)) { do { //
// Exclude processing
//
if (SkipTree[0]) { if (StringIMatchByteCount (SkipTree, Dir.FullPath, SkipTreeBytes)) { continue; }
SkipTree[0] = 0; }
if (Dir.Directory) { wsprintf (ExcludeNode, TEXT("%s\\%s"), S_EXCLUDE, Dir.FullPath); if (MemDbGetValue (ExcludeNode, NULL)) { StringCopy (SkipTree, Dir.FullPath); AppendWack (SkipTree); SkipTreeBytes = ByteCount (SkipTree); continue; } }
//
// Non-excluded file
//
if (g_Thorough) { Checksum = pComputeChecksum (Dir.FullPath);
pSetMemDbKey ( DiffMode, S_FILES, Dir.FullPath, (PBYTE) &Checksum, sizeof (Checksum) );
} else { pConvertWin32FindData (Dir.FindData, &fi);
pSetMemDbKey ( DiffMode, S_FILES, Dir.FullPath, (PBYTE) &fi, sizeof (FILEINFO) ); }
p = _tcsrchr (Dir.Name, TEXT('.')); if (p) { p = _tcsinc (p); if (StringIMatch (p, TEXT("INI"))) { //
// Found INI file, take a snapshot of it
//
if (!g_Quiet) { _ftprintf (stderr, TEXT(" Taking snapshot of %s\n"), Dir.FullPath); }
Count = GetPrivateProfileString (NULL, NULL, TEXT("\0"), SectionNames, 32768, Dir.FullPath); SectionNames[Count] = 0; SectionNames[Count + 1] = 0;
p = SectionNames; while (*p) { //
// Filter out dup sections
//
r = SectionNames; while (r < p) { if (StringIMatch (p, r)) { break; }
r = GetEndOfString (r) + 1; }
if (r < p) { if (!g_Quiet) { _ftprintf (stderr, TEXT(" ***Duplicate section ignored: [%s]\n"), p); }
p = GetEndOfString (p) + 1; continue; }
//
// Process each key in the section
//
Count = GetPrivateProfileString ( p, NULL, TEXT("\0"), KeyNames, 32768, Dir.FullPath ); KeyNames[Count] = 0; KeyNames[Count + 1] = 0;
q = KeyNames;
while (*q) { //
// Ignore duplicate value names
//
r = KeyNames; while (r < q) { if (StringIMatch (q, r)) { break; }
r = GetEndOfString (r) + 1; }
if (r < q) { if (!g_Quiet) { _ftprintf (stderr, TEXT(" ***Duplicate key ignored: [%s] %s\n"), p, q); }
q = GetEndOfString (q) + 1; continue; }
GetPrivateProfileString ( p, q, TEXT(""), KeyValue, 4096, Dir.FullPath );
wsprintf (Node, TEXT("%s\\[%s]\\%s"), Dir.FullPath, p, q); pSetMemDbKey ( DiffMode, S_INIFILES, Node, (PBYTE) KeyValue, ByteCount (KeyValue) + sizeof (TCHAR) );
q = GetEndOfString (q) + 1; }
p = GetEndOfString (p) + 1; } } }
} while (EnumNextFileInTree (&Dir)); }
return TRUE; }
VOID pCreateSubst ( IN PCTSTR Src, IN PCTSTR Dest ) { DWORD Offset;
MemDbSetValueEx (S_SUBSTITUTIONS, S_DEST, Dest, NULL, 0, &Offset); MemDbSetValueEx (S_SUBSTITUTIONS, S_SRC, Src, NULL, Offset, NULL); }
BOOL pTakeSnapshot ( POPTIONS Options, BOOL DiffMode ) { HINF Inf; INFSTRUCT is = INITINFSTRUCT_POOLHANDLE; TCHAR Path[MAX_TCHAR_PATH]; PTSTR p, q; TCHAR Section[256]; UINT Dirs = 0; UINT RegRoots = 0; TCHAR WinDir[MAX_TCHAR_PATH]; TCHAR SystemDir[MAX_TCHAR_PATH]; TCHAR System32Dir[MAX_TCHAR_PATH]; TCHAR SystemDrive[8]; TCHAR ProgramFilesDir[MAX_TCHAR_PATH];
GetWindowsDirectory (WinDir, MAX_TCHAR_PATH); StringCopy (SystemDir, WinDir); StringCopy (AppendWack (SystemDir), TEXT("system")); StringCopy (System32Dir, SystemDir); StringCat (System32Dir, TEXT("32")); SystemDrive[0] = SystemDir[0]; SystemDrive[1] = TEXT(':'); SystemDrive[2] = 0; StringCopy (ProgramFilesDir, SystemDrive); StringCopy (AppendWack (ProgramFilesDir), TEXT("Program Files"));
pCreateSubst (WinDir, TEXT("%%WINDIR%%")); pCreateSubst (SystemDir, TEXT("%%SYSTEMDIR%%")); pCreateSubst (System32Dir, TEXT("%%SYSTEM32DIR%%")); pCreateSubst (SystemDrive, TEXT("%%SYSTEMDRIVE%%")); pCreateSubst (ProgramFilesDir, TEXT("%%PROGRAMFILES%%"));
if (Options->UseAppDiffInf) { GetModuleFileName (NULL, Path, MAX_TCHAR_PATH); p = _tcsrchr (Path, TEXT('\\')); MYASSERT (p); StringCopy (p + 1, TEXT("appdiff.inf"));
Inf = InfOpenInfFile (Path); } else { Inf = INVALID_HANDLE_VALUE; }
if (Inf == INVALID_HANDLE_VALUE) { //
// Take snapshot of file system and INI files
//
if (Options->FileSysRoot) { pDirAndIniSnap (DiffMode, Options->FileSysRoot); } else if (Options->NoRoots) { pDirAndIniSnap (DiffMode, TEXT("C:\\")); }
//
// Take snapshot of registry
//
if (Options->RegRoot) { pRegSnap (DiffMode, Options->RegRoot); } else if (Options->NoRoots) { pRegSnap (DiffMode, TEXT("HKLM")); pRegSnap (DiffMode, TEXT("HKU")); } }
else { //
// Fill in the [Exclude] section
//
if (InfFindFirstLine (Inf, S_EXCLUDE, NULL, &is)) { do { p = InfGetLineText (&is); MemDbSetValueEx (S_EXCLUDE, p, NULL, NULL, 0, NULL); } while (InfFindNextLine (&is)); }
InfResetInfStruct (&is);
if (Options->Name) { wsprintf (Section, TEXT("%s.%s"), Options->Name, S_EXCLUDE);
if (InfFindFirstLine (Inf, Section, NULL, &is)) { do { p = InfGetLineText (&is); MemDbSetValueEx (S_EXCLUDE, p, NULL, NULL, 0, NULL); } while (InfFindNextLine (&is)); }
InfResetInfStruct (&is); }
//
// Fill in the [Substitutions] section
//
if (InfFindFirstLine (Inf, S_SUBSTITUTIONS, NULL, &is)) { do { p = InfGetStringField (&is, 0); q = InfGetStringField (&is, 1);
pCreateSubst (p, q);
} while (InfFindNextLine (&is)); }
InfResetInfStruct (&is);
if (Options->Name) { wsprintf (Section, TEXT("%s.%s"), Options->Name, S_EXCLUDE);
if (InfFindFirstLine (Inf, Section, NULL, &is)) { do { p = InfGetLineText (&is); MemDbSetValueEx (S_EXCLUDE, p, NULL, NULL, 0, NULL); } while (InfFindNextLine (&is)); }
InfResetInfStruct (&is); }
//
// Enumerate the [Paths] section, use c:\ by default
//
if (InfFindFirstLine (Inf, S_PATHS, NULL, &is)) { do { p = InfGetLineText (&is); pDirAndIniSnap (DiffMode, p); Dirs++; } while (InfFindNextLine (&is));
InfResetInfStruct (&is); }
if (Options->Name) { wsprintf (Section, TEXT("%s.%s"), Options->Name, S_PATHS);
if (InfFindFirstLine (Inf, Section, NULL, &is)) { do { p = InfGetLineText (&is); pDirAndIniSnap (DiffMode, p); Dirs++; } while (InfFindNextLine (&is)); }
InfResetInfStruct (&is); }
if (!Dirs) { pDirAndIniSnap (DiffMode, TEXT("C:\\")); }
//
// Enumerate the [Registry] section, use HKLM and HKU by default
//
if (InfFindFirstLine (Inf, S_REGISTRY, NULL, &is)) { do { p = InfGetLineText (&is); pRegSnap (DiffMode, p); RegRoots++; } while (InfFindNextLine (&is));
InfResetInfStruct (&is); }
if (Options->Name) { wsprintf (Section, TEXT("%s.%s"), Options->Name, S_REGISTRY);
if (InfFindFirstLine (Inf, Section, NULL, &is)) { do { p = InfGetLineText (&is); pRegSnap (DiffMode, p); RegRoots++; } while (InfFindNextLine (&is));
InfResetInfStruct (&is); } }
if (!RegRoots) { pRegSnap (DiffMode, TEXT("HKLM")); pRegSnap (DiffMode, TEXT("HKU")); }
InfCloseInfFile (Inf); }
InfCleanUpInfStruct (&is); return TRUE; }
PCTSTR pPerformSubstitution ( PGROWLIST EnvVars, PCTSTR OrgStr ) { PCTSTR PathStr; PCTSTR NewPathString; UINT Count; UINT u; PCTSTR Src; PCTSTR Dest;
Count = GrowListGetSize (EnvVars);
PathStr = DuplicatePathString (OrgStr, 0); MYASSERT (PathStr);
for (u = 0 ; u < Count ; u += 2) { Src = GrowListGetString (EnvVars, u); Dest = GrowListGetString (EnvVars, u + 1);
NewPathString = StringSearchAndReplace (PathStr, Src, Dest); if (NewPathString) { FreePathString (PathStr); PathStr = NewPathString; } }
return PathStr; }
VOID pCreateEnvVars ( PGROWLIST EnvVars ) { MEMDB_ENUM e; TCHAR Dest[MEMDB_MAX]; UINT Count; UINT u; UINT Len;
//
// Enumerate source strings
//
Count = 0;
if (MemDbGetValueEx (&e, S_SUBSTITUTIONS, S_SRC, NULL)) { do { MemDbBuildKeyFromOffset (e.dwValue, Dest, 2, NULL);
Len = ByteCount (e.szName);
for (u = 0 ; u < Count ; u += 2) { if (ByteCount (GrowListGetString (EnvVars, u)) < Len) { break; } }
if (u < Count) { GrowListInsertString (EnvVars, u, e.szName); GrowListInsertString (EnvVars, u + 1, Dest); } else { GrowListAppendString (EnvVars, e.szName); GrowListAppendString (EnvVars, Dest); }
Count += 2;
} while (MemDbEnumNextValue (&e)); } }
VOID pDecodeRegStr ( IN PCTSTR RegStr, OUT PTSTR Key, OUT PCTSTR *ValuePtr ) { PTSTR p; PCTSTR Val = NULL;
StringCopy (Key, RegStr);
p = _tcschr (Key, TEXT('[')); if (p) { Val = _tcsinc (p); p = _tcsdec2 (Key, p); while (p) { if (_tcsnextc (p) != TEXT(' ')) { break; }
p = _tcsdec2 (Key, p); }
*p = 0; }
*ValuePtr = Val; }
BOOL pAreAllValuesInMemDb ( IN PCTSTR RegStr, IN BOOL Encoded, IN HKEY KeyHandle OPTIONAL ) { BOOL WeOpen = FALSE; REGVALUE_ENUM e; TCHAR Key[MAX_REGISTRY_KEY]; PCTSTR Value; BOOL b = TRUE;
//
// If encoded, decode first.
//
if (Encoded) { pDecodeRegStr (RegStr, Key, &Value); } else { StringCopy (Key, RegStr); Value = NULL; }
//
// If key not open, open now
//
if (!KeyHandle) { KeyHandle = OpenRegKeyStr (Key); WeOpen = TRUE;
if (!KeyHandle) { return TRUE; } }
//
// if there is at least one value remaining, fail
//
b = !EnumFirstRegValue (&e, KeyHandle);
if (WeOpen) { CloseRegKey (KeyHandle); }
return b; }
BOOL pIsEntireSubKeyGone ( IN PCTSTR RegStr, IN BOOL Encoded ) { TCHAR Key[MAX_REGISTRY_KEY]; PCTSTR Value; HKEY KeyHandle;
//
// If encoded, decode now
//
if (Encoded) { pDecodeRegStr (RegStr, Key, &Value); } else { StringCopy (Key, RegStr); Value = NULL; }
//
// Open key
//
KeyHandle = OpenRegKeyStr (Key); if (!KeyHandle) { return TRUE; }
CloseRegKey (KeyHandle); return FALSE; }
VOID pAppendThingsToDelete ( POPTIONS Options, HANDLE File ) { MEMDB_ENUM e; PCTSTR p; GROWLIST EnvVars = GROWLIST_INIT; TCHAR SkipKey[MEMDB_MAX]; UINT SkipKeyBytes = 0; BOOL RegFlag; BOOL AppendStar; BOOL RemoveVal; PCTSTR OutLine; TCHAR KeyBuf[MAX_REGISTRY_KEY]; PCTSTR DontCare;
SkipKey[0] = 0;
//
// Generate substitution mapping
//
pCreateEnvVars (&EnvVars);
//
// Write section name
//
if (!Options->Name) { return; }
WriteFileString (File, TEXT("[")); WriteFileString (File, Options->Name); WriteFileString (File, TEXT("]\r\n"));
//
// Write all the things in the deleted key
//
if (MemDbGetValueEx (&e, S_ZERO, NULL, NULL)) { do { p = _tcschr (e.szName, TEXT('\\')); MYASSERT (p);
if (StringIMatchAB (S_REG, e.szName, p)) { RegFlag = TRUE; } else { RegFlag = FALSE; }
//
// Skip if this node is a subkey of a deleted key
//
p = _tcsinc (p);
if (SkipKey[0]) { if (StringIMatchByteCount (SkipKey, p, SkipKeyBytes)) { continue; }
SkipKey[0] = 0; }
RemoveVal = FALSE; AppendStar = FALSE;
OutLine = p;
if (RegFlag) { //
// If this is a registry key, and everything in
// the registry key has been deleted, then
// just write the one key with a star after it.
//
if (pIsEntireSubKeyGone (p, TRUE)) { RemoveVal = TRUE; AppendStar = TRUE; }
//
// If it's a registry key, and all the subvalues
// are deleted, then just write the one key, but
// without a star.
//
else if (pAreAllValuesInMemDb (p, TRUE, NULL)) { RemoveVal = TRUE; } }
//
// The value spec needs to be removed from the reg key
//
if (RemoveVal) { pDecodeRegStr (p, KeyBuf, &DontCare); OutLine = CreateEncodedRegistryString (KeyBuf, NULL);
//
// Workaround: CreateEncodedRegistryString always appends
// an asterisk, and we want to control when the asterisk
// appears.
//
p = _tcsrchr (OutLine, TEXT('*')); if (p && p[1] == 0) { p = _tcsdec2 (OutLine, p); if (p) { *((PTSTR) p) = 0; } }
//
// If this entire key is going to be deleted, then
// turn on SkipKey so the memdb nodes will be skipped.
//
if (AppendStar && SkipKey[0] == 0) { StringCopy (SkipKey, OutLine); AppendWack (SkipKey); SkipKeyBytes = ByteCount (SkipKey); } }
//
// Perform substitution on the string
//
p = pPerformSubstitution (&EnvVars, OutLine); MYASSERT (p);
if (RemoveVal) { FreeEncodedRegistryString (OutLine); }
//
// Write the file/reg key to the file
//
WriteFileString (File, p);
if (AppendStar) { WriteFileString (File, TEXT("\\*")); }
WriteFileString (File, TEXT("\r\n"));
FreePathString (p);
} while (MemDbEnumNextValue (&e)); }
//
// Write blank line at the end
//
WriteFileString (File, TEXT("\r\n"));
FreeGrowList (&EnvVars); }
BOOL pDumpDiffs ( VOID ) { MEMDB_ENUM e; BOOL Changes = FALSE;
if (MemDbGetValueEx (&e, S_ZERO, NULL, NULL)) { _tprintf (TEXT("Deleted Items:\n")); Changes = TRUE;
do { _tprintf (TEXT(" %s\n"), e.szName); } while (MemDbEnumNextValue (&e)); }
if (MemDbGetValueEx (&e, S_ADDED, NULL, NULL)) { _tprintf (TEXT("Added Items:\n"));
do { _tprintf (TEXT(" %s\n"), e.szName); } while (MemDbEnumNextValue (&e)); }
if (MemDbGetValueEx (&e, S_CHANGED, NULL, NULL)) { _tprintf (TEXT("Changed Items:\n"));
do { _tprintf (TEXT(" %s\n"), e.szName); } while (MemDbEnumNextValue (&e)); }
return Changes; }
BOOL pGenerateInf ( POPTIONS Options ) { HANDLE File; BOOL DelChanges;
//
// Dump changes to stdout
//
DelChanges = pDumpDiffs();
if (Options->OutputFile) { //
// Write a section to our output file
//
File = CreateFile ( Options->OutputFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
if (File == INVALID_HANDLE_VALUE) { _ftprintf (stderr, TEXT("Cannot generate %s, error %u\n"), Options->OutputFile, GetLastError()); return FALSE; }
if (DelChanges) { pAppendThingsToDelete (Options, File); }
CloseHandle (File); }
return TRUE; }
BOOL DoSnapMode ( POPTIONS Options ) { DWORD Start;
Start = GetTickCount();
if (!pTakeSnapshot (Options, FALSE)) { return FALSE; }
MemDbSave (Options->SnapFile);
if (!g_Quiet) { _ftprintf (stderr, TEXT("Run time: %u seconds\n"), (GetTickCount() - Start) / 1000); }
return TRUE; }
BOOL DoDiffMode ( POPTIONS Options ) { DWORD Start;
Start = GetTickCount();
if (GetFileAttributes (Options->SnapFile) == 0xffffffff) { _ftprintf (stderr, TEXT("Bogus file arg: %s\n"), Options->SnapFile); }
if (!Options->SnapMode) { MemDbLoad (Options->SnapFile); }
if (!pTakeSnapshot (Options, TRUE)) { return FALSE; }
pGenerateInf (Options);
if (!g_Quiet) { _ftprintf (stderr, TEXT("Run time: %u seconds\n"), (GetTickCount() - Start) / 1000); }
return TRUE; }
|