2571 lines
62 KiB
C
2571 lines
62 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1997-1999 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
dbaction.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This source implements action functions used by MigDb. There are two types
|
||
|
of action functions here as the third parameter of the macro list is TRUE
|
||
|
or FALSE.
|
||
|
First type of action function is called whenever an action is triggered
|
||
|
during file scanning. The second type of action function is called at the
|
||
|
end of file scanning if the associated action was not triggered during
|
||
|
file scanning phase.
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Calin Negreanu (calinn) 07-Jan-1998
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
jimschm 20-Nov-2000 Added MarkForBackup
|
||
|
marcw 31-Aug-1999 Added BlockingHardware
|
||
|
ovidiut 20-Jul-1999 Added Ignore
|
||
|
ovidiut 28-May-1999 Added IniFileMappings
|
||
|
marcw 23-Sep-1998 Added BlockingVirusScanner
|
||
|
jimschm 13-Aug-1998 Added CompatibleFiles
|
||
|
jimschm 19-May-1998 Added MinorProblems_NoLinkRequired
|
||
|
jimschm 27-Feb-1998 Added UninstallSections
|
||
|
calinn 18-Jan-1998 Added CompatibleModules action
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "pch.h"
|
||
|
#include "migdbp.h"
|
||
|
#include "migappp.h"
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Macro Expansion List Description:
|
||
|
|
||
|
GATHER_DATA_FUNCTIONS and ACTION_FUNCTIONS lists all valid actions to be performed
|
||
|
by migdb when a context is met. Meeting a context means that all the sections
|
||
|
associated with the context are satisfied (usually there is only one section).
|
||
|
The difference is that GATHER_DATA_FUNCTIONS are called even if some function already
|
||
|
handles a file.
|
||
|
|
||
|
Line Syntax:
|
||
|
|
||
|
DEFMAC(ActionFn, ActionName, CallWhenTriggered, CanHandleVirtualFiles)
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
ActionFn - This is a boolean function that returnes TRUE if the specified action
|
||
|
could be performed. It should return FALSE only if a serious error
|
||
|
occures. You must implement a function with this name and required
|
||
|
parameters.
|
||
|
|
||
|
ActionName - This is the string that identifies the action function. It should
|
||
|
have the same value as listed in migdb.inf. This arg is declared
|
||
|
as both a macro and the migdb.inf section name string.
|
||
|
|
||
|
CallWhenTriggered - If the MigDbContext this action is associated with is triggered
|
||
|
the action will be called if this field is TRUE, otherwise we will call
|
||
|
the action at the end of file scan if the context was not triggered.
|
||
|
|
||
|
CanHandleVirtualFiles - This is for treating files that are supposed to be in a fixed place
|
||
|
but are not there (not installed or deleted). We need this in order to fix
|
||
|
registry or links that point to this kind of files. A good example is backup.exe
|
||
|
which is located in %ProgramFiles%\Accessories. The rules say that we should
|
||
|
use ntbackup.exe instead but since this file is not existent we don't normally fix
|
||
|
registry settings pointing to this file. We do now, with this new variable.
|
||
|
|
||
|
Variables Generated From List:
|
||
|
|
||
|
g_ActionFunctions - do not touch!
|
||
|
|
||
|
For accessing the array there are the following functions:
|
||
|
|
||
|
MigDb_GetActionAddr
|
||
|
MigDb_GetActionIdx
|
||
|
MigDb_GetActionName
|
||
|
|
||
|
--*/
|
||
|
|
||
|
|
||
|
/*
|
||
|
Declare the macro list of action functions. If you need to add a new action just
|
||
|
add a line in this list and implement the function.
|
||
|
*/
|
||
|
#define GATHER_DATA_FUNCTIONS \
|
||
|
DEFMAC1(CompatibleFiles, COMPATIBLEFILES, TRUE, FALSE) \
|
||
|
DEFMAC1(CompatibleShellModules, COMPATIBLESHELLMODULES, TRUE, FALSE) \
|
||
|
DEFMAC1(CompatibleRunKeyModules, COMPATIBLERUNKEYMODULES, TRUE, FALSE) \
|
||
|
DEFMAC1(CompatibleDosModules, COMPATIBLEDOSMODULES, TRUE, FALSE) \
|
||
|
DEFMAC1(CompatibleHlpFiles, COMPATIBLEHLPFILES, TRUE, FALSE) \
|
||
|
DEFMAC1(StoreMapi32Locations, MAPI32, TRUE, FALSE) \
|
||
|
DEFMAC1(IniFileMappings, INIFILEMAPPINGS, TRUE, FALSE) \
|
||
|
DEFMAC1(SilentUninstall, SILENTUNINSTALL, TRUE, FALSE) \
|
||
|
DEFMAC1(FileEdit, FILEEDIT, TRUE, FALSE) \
|
||
|
DEFMAC1(IgnoreInReport, IGNORE, TRUE, FALSE) \
|
||
|
DEFMAC1(MarkForBackup, MARKFORBACKUP, TRUE, FALSE) \
|
||
|
DEFMAC1(ShowInSimplifiedView, SHOWINSIMPLIFIEDVIEW, TRUE, FALSE) \
|
||
|
|
||
|
#define ACTION_FUNCTIONS \
|
||
|
DEFMAC2(UseNtFiles, USENTFILES, TRUE, TRUE ) \
|
||
|
DEFMAC2(ProductCollisions, PRODUCTCOLLISIONS, TRUE, FALSE) \
|
||
|
DEFMAC2(MinorProblems, MINORPROBLEMS, TRUE, FALSE) \
|
||
|
DEFMAC2(MinorProblems_NoLinkRequired, MINORPROBLEMS_NOLINKREQUIRED, TRUE, FALSE) \
|
||
|
DEFMAC2(Reinstall_AutoUninstall, REINSTALL_AUTOUNINSTALL, TRUE, FALSE) \
|
||
|
DEFMAC2(Reinstall, REINSTALL, TRUE, FALSE) \
|
||
|
DEFMAC2(Reinstall_NoLinkRequired, REINSTALL_NOLINKREQUIRED, TRUE, FALSE) \
|
||
|
DEFMAC2(Reinstall_SoftBlock, REINSTALL_SOFTBLOCK, TRUE, FALSE) \
|
||
|
DEFMAC2(Incompatible_AutoUninstall, INCOMPATIBLE_AUTOUNINSTALL, TRUE, FALSE) \
|
||
|
DEFMAC2(Incompatible, INCOMPATIBLE, TRUE, FALSE) \
|
||
|
DEFMAC2(Incompatible_NoLinkRequired, INCOMPATIBLE_NOLINKREQUIRED, TRUE, FALSE) \
|
||
|
DEFMAC2(Incompatible_PreinstalledUtilities, INCOMPATIBLE_PREINSTALLEDUTILITIES, TRUE, FALSE) \
|
||
|
DEFMAC2(Incompatible_SimilarOsFunctionality,INCOMPATIBLE_SIMILAROSFUNCTIONALITY,TRUE, FALSE) \
|
||
|
DEFMAC2(Incompatible_HardwareUtility, INCOMPATIBLE_HARDWAREUTILITY, TRUE, FALSE) \
|
||
|
DEFMAC1(BadFusion, BADFUSION, TRUE, FALSE) \
|
||
|
DEFMAC2(OsFiles, OSFILES, TRUE, FALSE) \
|
||
|
DEFMAC2(DosApps, DOSAPPS, TRUE, FALSE) \
|
||
|
DEFMAC2(NonPnpDrivers, NONPNPDRIVERS, TRUE, FALSE) \
|
||
|
DEFMAC2(NonPnpDrivers_NoMessage, NONPNPDRIVERS_NOMESSAGE, TRUE, FALSE) \
|
||
|
DEFMAC2(MigrationProcessing, MIGRATIONPROCESSING, TRUE, FALSE) \
|
||
|
DEFMAC2(BlockingVirusScanner, BLOCKINGVIRUSSCANNERS, TRUE, FALSE) \
|
||
|
DEFMAC2(BlockingFile, BLOCKINGFILES, TRUE, FALSE) \
|
||
|
DEFMAC2(BlockingHardware, BLOCKINGHARDWARE, TRUE, FALSE) \
|
||
|
DEFMAC2(RequiredOSFiles, REQUIREDOSFILES, FALSE,FALSE) \
|
||
|
|
||
|
/*
|
||
|
Declare the action functions
|
||
|
*/
|
||
|
#define DEFMAC1(fn,id,call,can) ACTION_PROTOTYPE fn;
|
||
|
#define DEFMAC2(fn,id,call,can) ACTION_PROTOTYPE fn;
|
||
|
GATHER_DATA_FUNCTIONS
|
||
|
ACTION_FUNCTIONS
|
||
|
#undef DEFMAC1
|
||
|
#undef DEFMAC2
|
||
|
|
||
|
|
||
|
/*
|
||
|
This is the structure used for handling action functions
|
||
|
*/
|
||
|
typedef struct {
|
||
|
PCSTR ActionName;
|
||
|
PACTION_PROTOTYPE ActionFunction;
|
||
|
BOOL CallWhenTriggered;
|
||
|
BOOL CanHandleVirtualFiles;
|
||
|
BOOL CallAlways;
|
||
|
} ACTION_STRUCT, *PACTION_STRUCT;
|
||
|
|
||
|
|
||
|
/*
|
||
|
Declare a global array of functions and name identifiers for action functions
|
||
|
*/
|
||
|
#define DEFMAC1(fn,id,call,can) {#id,fn,call,can,TRUE},
|
||
|
#define DEFMAC2(fn,id,call,can) {#id,fn,call,can,FALSE},
|
||
|
static ACTION_STRUCT g_ActionFunctions[] = {
|
||
|
GATHER_DATA_FUNCTIONS
|
||
|
ACTION_FUNCTIONS
|
||
|
{NULL, NULL, FALSE}
|
||
|
};
|
||
|
#undef DEFMAC1
|
||
|
#undef DEFMAC2
|
||
|
|
||
|
|
||
|
BOOL g_BadVirusScannerFound = FALSE;
|
||
|
BOOL g_BlockingFileFound = FALSE;
|
||
|
BOOL g_BlockingHardwareFound = FALSE;
|
||
|
BOOL g_UnknownOs = FALSE;
|
||
|
GROWLIST g_BadVirusScannerGrowList = GROWLIST_INIT;
|
||
|
DWORD g_BackupDirCount = 0;
|
||
|
extern BOOL g_IsFusionDir;
|
||
|
|
||
|
BOOL
|
||
|
pNoLinkRequiredWorker (
|
||
|
IN UINT GroupId,
|
||
|
IN UINT SubGroupId, OPTIONAL
|
||
|
IN DWORD ActionType,
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
);
|
||
|
|
||
|
|
||
|
PACTION_PROTOTYPE
|
||
|
MigDb_GetActionAddr (
|
||
|
IN INT ActionIdx
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
MigDb_GetActionAddr returns the address of the action function based on the action index
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
ActionIdx - Action index.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
Action function address. Note that no checking is made so the address returned could be invalid.
|
||
|
This is not a problem since the parsing code did the right job.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
return g_ActionFunctions[ActionIdx].ActionFunction;
|
||
|
}
|
||
|
|
||
|
|
||
|
INT
|
||
|
MigDb_GetActionIdx (
|
||
|
IN PCSTR ActionName
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
MigDb_GetActionIdx returns the action index based on the action name
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
ActionName - Action name.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
Action index. If the name is not found, the index returned is -1.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PACTION_STRUCT p = g_ActionFunctions;
|
||
|
INT i = 0;
|
||
|
while (p->ActionName != NULL) {
|
||
|
if (StringIMatch (p->ActionName, ActionName)) {
|
||
|
return i;
|
||
|
}
|
||
|
p++;
|
||
|
i++;
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
PCSTR
|
||
|
MigDb_GetActionName (
|
||
|
IN INT ActionIdx
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
MigDb_GetActionName returns the name of an action based on the action index
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
ActionIdx - Action index.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
Action name. Note that no checking is made so the returned pointer could be invalid.
|
||
|
This is not a problem since the parsing code did the right job.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
return g_ActionFunctions[ActionIdx].ActionName;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
MigDb_CallWhenTriggered (
|
||
|
IN INT ActionIdx
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
MigDb_CallWhenTriggered is called every time when an action is triggered. Will return
|
||
|
TRUE is the associated action function needs to be called, FALSE otherwise.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
ActionIdx - Action index.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
TRUE if the associated action function needs to be called, FALSE otherwise.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
return g_ActionFunctions[ActionIdx].CallWhenTriggered;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
MigDb_CanHandleVirtualFiles (
|
||
|
IN INT ActionIdx
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
MigDb_CanHandleVirtualFiles is called if a virtual file is passed to migdb
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
ActionIdx - Action index.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
TRUE if the associated action can handle virtual files, false if not.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
return g_ActionFunctions[ActionIdx].CanHandleVirtualFiles;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
MigDb_CallAlways (
|
||
|
IN INT ActionIdx
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
MigDb_CallAlways returnes if an action should be called regardless of handled state.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
ActionIdx - Action index.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
TRUE if the associated action should be called every time.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
return g_ActionFunctions[ActionIdx].CallAlways;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
IsMigrationPathEx (
|
||
|
IN PCTSTR Path,
|
||
|
OUT PBOOL IsWin9xOsPath OPTIONAL
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
IsMigrationPath checks to see if the given path is a "MigrationPath" (meaning
|
||
|
that the path belongs to the OS that we are currently upgrading). The MigrationPaths
|
||
|
category was previously created in filescan.c by pBuildMigrationPaths
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Path - Specifies the path to be checked.
|
||
|
IsWin9xOsPath - Receives a BOOL indicating if this path is a Win9x OS migration path
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
TRUE if the path is part of "Migration Paths", FALSE otherwise.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
TCHAR key [MEMDB_MAX];
|
||
|
PTSTR pathPtr;
|
||
|
DWORD depth = 0;
|
||
|
DWORD pathValue;
|
||
|
TCHAR path[MAX_TCHAR_PATH];
|
||
|
DWORD bIsWin9xOsPath;
|
||
|
|
||
|
StringCopyTcharCount (path, Path, MAX_TCHAR_PATH);
|
||
|
RemoveWackAtEnd (path);
|
||
|
|
||
|
MemDbBuildKey (key, MEMDB_CATEGORY_MIGRATION_PATHS, path, NULL, NULL);
|
||
|
|
||
|
pathPtr = GetEndOfString (key);
|
||
|
|
||
|
if (IsWin9xOsPath) {
|
||
|
*IsWin9xOsPath = FALSE;
|
||
|
}
|
||
|
|
||
|
while (pathPtr) {
|
||
|
*pathPtr = 0;
|
||
|
|
||
|
if ((MemDbGetValueAndFlags (key, &pathValue, &bIsWin9xOsPath)) &&
|
||
|
(pathValue >= depth)
|
||
|
) {
|
||
|
if (IsWin9xOsPath) {
|
||
|
*IsWin9xOsPath = bIsWin9xOsPath;
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
depth ++;
|
||
|
pathPtr = GetPrevChar (key, pathPtr, TEXT('\\'));
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
DeleteFileWithWarning (
|
||
|
IN PCTSTR FileName
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
DeleteFileWithWarning marks a file for deletion but checks to see if a warning
|
||
|
should be added in user report. We will generate a "backup files found" warning
|
||
|
if the file that's going to be deleted is outside "Migration Paths",
|
||
|
but not under %ProgramFiles%.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
FileName - file to be deleted.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
TRUE if the file was deleted successfully, FALSE otherwise.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PCTSTR filePtr;
|
||
|
TCHAR filePath [MEMDB_MAX];
|
||
|
TCHAR key [MEMDB_MAX];
|
||
|
INFCONTEXT ic;
|
||
|
|
||
|
RemoveOperationsFromPath (FileName, ALL_DEST_CHANGE_OPERATIONS);
|
||
|
|
||
|
filePtr = (PTSTR)GetFileNameFromPath (FileName);
|
||
|
if (!filePtr) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
filePtr = _tcsdec (FileName, filePtr);
|
||
|
if (!filePtr) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
StringCopyABA (filePath, FileName, filePtr);
|
||
|
|
||
|
if (!StringIMatchCharCount (filePath, g_ProgramFilesDirWack, g_ProgramFilesDirWackChars) &&
|
||
|
!IsMigrationPath (filePath)
|
||
|
) {
|
||
|
//
|
||
|
// exclude certain files from user's report,
|
||
|
// even if they are not in migration directories
|
||
|
//
|
||
|
if (!SetupFindFirstLine (g_Win95UpgInf, S_BACKUPFILESIGNORE, filePtr + 1, &ic)) {
|
||
|
|
||
|
//
|
||
|
// this file is not excluded; show it's dir in the report
|
||
|
//
|
||
|
MemDbBuildKey (key, MEMDB_CATEGORY_BACKUPDIRS, filePath, NULL, NULL);
|
||
|
if (!MemDbGetValue (key, NULL)) {
|
||
|
//
|
||
|
// write it in the log
|
||
|
//
|
||
|
DEBUGMSG ((DBG_WARNING, "BACKUPDIR: %s is considered a backup directory.", filePath));
|
||
|
|
||
|
MemDbSetValueEx (MEMDB_CATEGORY_BACKUPDIRS, filePath, NULL, NULL, 0 , NULL);
|
||
|
g_BackupDirCount++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (CanSetOperation (FileName, OPERATION_FILE_DELETE)) {
|
||
|
MarkFileForDelete (FileName);
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
OsFiles (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This is the action taken when an OS file is found. Basically the file gets deleted to
|
||
|
make room for NT version.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Context - See definition.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
TRUE - if operation was successful
|
||
|
FALSE - otherwise
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PCSTR newFileName;
|
||
|
DWORD fileStatus;
|
||
|
MULTISZ_ENUM fileEnum;
|
||
|
BOOL b = FALSE;
|
||
|
|
||
|
if (EnumFirstMultiSz (&fileEnum, Context->FileList.Buf)) {
|
||
|
do {
|
||
|
if (!g_IsFusionDir || !IsNtCompatibleModule (fileEnum.CurrentString)) {
|
||
|
//
|
||
|
// If this file is marked with any MOVE operations, remove those operations.
|
||
|
// we want this deletion to take precedence.
|
||
|
//
|
||
|
RemoveOperationsFromPath (
|
||
|
fileEnum.CurrentString,
|
||
|
ALL_MOVE_OPERATIONS
|
||
|
);
|
||
|
|
||
|
DeleteFileWithWarning (fileEnum.CurrentString);
|
||
|
MarkFileAsOsFile (fileEnum.CurrentString);
|
||
|
fileStatus = GetFileStatusOnNt (fileEnum.CurrentString);
|
||
|
|
||
|
if ((fileStatus & FILESTATUS_REPLACED) != 0) {
|
||
|
|
||
|
newFileName = GetPathStringOnNt (fileEnum.CurrentString);
|
||
|
|
||
|
if (StringIMatch (newFileName, fileEnum.CurrentString)) {
|
||
|
MarkFileForCreation (newFileName);
|
||
|
} else {
|
||
|
MarkFileForMoveByNt (fileEnum.CurrentString, newFileName);
|
||
|
}
|
||
|
|
||
|
FreePathString (newFileName);
|
||
|
}
|
||
|
b = TRUE;
|
||
|
}
|
||
|
}
|
||
|
while (EnumNextMultiSz (&fileEnum));
|
||
|
}
|
||
|
|
||
|
return b;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
UseNtFiles (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This is the action taken when NT uses another file for same functionality. We will
|
||
|
mark the file as deleted, moved and we will add it in RenameFile category
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Context - See definition.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
TRUE - if operation was successful
|
||
|
FALSE - otherwise
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
CHAR ntFilePath [MAX_MBCHAR_PATH];
|
||
|
MULTISZ_ENUM fileEnum;
|
||
|
TCHAR key [MEMDB_MAX];
|
||
|
DWORD set;
|
||
|
PCTSTR name;
|
||
|
|
||
|
if (EnumFirstMultiSz (&fileEnum, Context->FileList.Buf)) {
|
||
|
|
||
|
if (!GetNtFilePath (Context->Arguments, ntFilePath)) {
|
||
|
LOG((LOG_ERROR, "Cannot UseNTFile for %s", Context->Arguments));
|
||
|
return FALSE;
|
||
|
}
|
||
|
else {
|
||
|
do {
|
||
|
if (Context->VirtualFile) {
|
||
|
MarkFileForExternalDelete (fileEnum.CurrentString);
|
||
|
} else {
|
||
|
DeleteFileWithWarning (fileEnum.CurrentString);
|
||
|
}
|
||
|
MarkFileForMoveByNt (fileEnum.CurrentString, ntFilePath);
|
||
|
MarkFileAsOsFile (fileEnum.CurrentString);
|
||
|
if (Context->VirtualFile) {
|
||
|
continue;
|
||
|
}
|
||
|
//
|
||
|
// add this info to memdb to update commands that use these files
|
||
|
//
|
||
|
name = GetFileNameFromPath (fileEnum.CurrentString);
|
||
|
if (!g_UseNtFileHashTable) {
|
||
|
continue;
|
||
|
}
|
||
|
if (!HtFindStringAndData (g_UseNtFileHashTable, name, &set)) {
|
||
|
MYASSERT (FALSE);
|
||
|
continue;
|
||
|
}
|
||
|
//
|
||
|
// check if a file with this name, but not handled, was previously found
|
||
|
//
|
||
|
if (!set) {
|
||
|
MemDbBuildKey (
|
||
|
key,
|
||
|
MEMDB_CATEGORY_USE_NT_FILES,
|
||
|
name,
|
||
|
GetFileNameFromPath (ntFilePath),
|
||
|
NULL
|
||
|
);
|
||
|
if (!MemDbGetValue (key, NULL)) {
|
||
|
MemDbSetValue (key, 0);
|
||
|
}
|
||
|
} else {
|
||
|
DEBUGMSG ((
|
||
|
DBG_VERBOSE,
|
||
|
"Found [UseNtFiles] file %s, but there's already one that was not handled",
|
||
|
name
|
||
|
));
|
||
|
}
|
||
|
}
|
||
|
while (EnumNextMultiSz (&fileEnum));
|
||
|
}
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
Incompatible (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This is the action taken when a known incompatible file is found. The file gets marked
|
||
|
for external deletion (it will not be deleted but in all subsequent operation will be
|
||
|
considered as deleted) and if there is a link pointing to it an announcement is made
|
||
|
in LinkProcessing phase.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Context - See definition.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
TRUE - if operation was successful
|
||
|
FALSE - otherwise
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
MULTISZ_ENUM fileEnum;
|
||
|
PCTSTR extPtr;
|
||
|
BOOL result = FALSE;
|
||
|
|
||
|
if (EnumFirstMultiSz (&fileEnum, Context->FileList.Buf)) {
|
||
|
do {
|
||
|
if (!IsFileMarkedAsKnownGood (fileEnum.CurrentString)) {
|
||
|
result = TRUE;
|
||
|
extPtr = GetFileExtensionFromPath (fileEnum.CurrentString);
|
||
|
if (extPtr) {
|
||
|
if (StringIMatch (extPtr, TEXT("SCR"))) {
|
||
|
DisableFile (fileEnum.CurrentString);
|
||
|
}
|
||
|
}
|
||
|
MarkFileForExternalDelete (fileEnum.CurrentString);
|
||
|
if (!IsFileMarkedForAnnounce (fileEnum.CurrentString)) {
|
||
|
AnnounceFileInReport (fileEnum.CurrentString, (DWORD)Context, ACT_INC_NOBADAPPS);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
while (EnumNextMultiSz (&fileEnum));
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
Incompatible_PreinstalledUtilities (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This is the action taken when a known incompatible preinstalled utility is found.
|
||
|
The file gets marked for external deletion (it will not be deleted but in all
|
||
|
subsequent operation will be considered as deleted) and if there is a link
|
||
|
pointing to it an announcement is made in LinkProcessing phase.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Context - See definition.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
TRUE - if operation was successful
|
||
|
FALSE - otherwise
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
MULTISZ_ENUM fileEnum;
|
||
|
BOOL result = FALSE;
|
||
|
|
||
|
if (!Context->Arguments) {
|
||
|
if (EnumFirstMultiSz (&fileEnum, Context->FileList.Buf)) {
|
||
|
do {
|
||
|
if (!IsFileMarkedAsKnownGood (fileEnum.CurrentString)) {
|
||
|
result = TRUE;
|
||
|
MarkFileForExternalDelete (fileEnum.CurrentString);
|
||
|
if (!IsFileMarkedForAnnounce (fileEnum.CurrentString)) {
|
||
|
AnnounceFileInReport (fileEnum.CurrentString, (DWORD)Context, ACT_INC_PREINSTUTIL);
|
||
|
}
|
||
|
}
|
||
|
} while (EnumNextMultiSz (&fileEnum));
|
||
|
}
|
||
|
} else {
|
||
|
return pNoLinkRequiredWorker (
|
||
|
MSG_INCOMPATIBLE_ROOT,
|
||
|
MSG_INCOMPATIBLE_PREINSTALLED_UTIL_SUBGROUP,
|
||
|
ACT_INC_PREINSTUTIL,
|
||
|
Context
|
||
|
);
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
Incompatible_SimilarOsFunctionality (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This is the action taken when a known incompatible preinstalled utility is found.
|
||
|
The file gets marked for external deletion (it will not be deleted but in all
|
||
|
subsequent operation will be considered as deleted) and if there is a link
|
||
|
pointing to it an announcement is made in LinkProcessing phase.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Context - See definition.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
TRUE - if operation was successful
|
||
|
FALSE - otherwise
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
MULTISZ_ENUM fileEnum;
|
||
|
BOOL result = FALSE;
|
||
|
|
||
|
if (!Context->Arguments) {
|
||
|
if (EnumFirstMultiSz (&fileEnum, Context->FileList.Buf)) {
|
||
|
do {
|
||
|
if (!IsFileMarkedAsKnownGood (fileEnum.CurrentString)) {
|
||
|
result = TRUE;
|
||
|
MarkFileForExternalDelete (fileEnum.CurrentString);
|
||
|
if (!IsFileMarkedForAnnounce (fileEnum.CurrentString)) {
|
||
|
AnnounceFileInReport (fileEnum.CurrentString, (DWORD)Context, ACT_INC_SIMILAROSFUNC);
|
||
|
}
|
||
|
}
|
||
|
} while (EnumNextMultiSz (&fileEnum));
|
||
|
}
|
||
|
} else {
|
||
|
return pNoLinkRequiredWorker (
|
||
|
MSG_INCOMPATIBLE_ROOT,
|
||
|
MSG_INCOMPATIBLE_UTIL_SIMILAR_FEATURE_SUBGROUP,
|
||
|
ACT_INC_SIMILAROSFUNC,
|
||
|
Context
|
||
|
);
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
Incompatible_HardwareUtility (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This is the action taken when a known incompatible hardware
|
||
|
utility is found. The file gets marked for external deletion
|
||
|
(it will not be deleted but in all subsequent operation will
|
||
|
be considered as deleted) and if there is a link pointing to
|
||
|
it an announcement is made in LinkProcessing phase.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Context - See definition.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
TRUE - if operation was successful
|
||
|
FALSE - otherwise
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
MULTISZ_ENUM fileEnum;
|
||
|
BOOL result = FALSE;
|
||
|
|
||
|
if (!Context->Arguments) {
|
||
|
|
||
|
if (EnumFirstMultiSz (&fileEnum, Context->FileList.Buf)) {
|
||
|
do {
|
||
|
if (!IsFileMarkedAsKnownGood (fileEnum.CurrentString)) {
|
||
|
result = TRUE;
|
||
|
MarkFileForExternalDelete (fileEnum.CurrentString);
|
||
|
if (!IsFileMarkedForAnnounce (fileEnum.CurrentString)) {
|
||
|
AnnounceFileInReport (fileEnum.CurrentString, (DWORD)Context, ACT_INC_IHVUTIL);
|
||
|
}
|
||
|
}
|
||
|
} while (EnumNextMultiSz (&fileEnum));
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
return pNoLinkRequiredWorker (
|
||
|
MSG_INCOMPATIBLE_ROOT,
|
||
|
MSG_INCOMPATIBLE_HW_UTIL_SUBGROUP,
|
||
|
ACT_INC_IHVUTIL,
|
||
|
Context
|
||
|
);
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
MinorProblems (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This is the action taken when we found an app with known minor problems. If there is a link
|
||
|
pointing to one of these files an announcement is made in LinkProcessing phase.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Context - See definition.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
TRUE - if operation was successful
|
||
|
FALSE - otherwise
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
MULTISZ_ENUM fileEnum;
|
||
|
BOOL result = FALSE;
|
||
|
|
||
|
if (EnumFirstMultiSz (&fileEnum, Context->FileList.Buf)) {
|
||
|
do {
|
||
|
if (!IsFileMarkedAsKnownGood (fileEnum.CurrentString)) {
|
||
|
result = TRUE;
|
||
|
if (!IsFileMarkedForAnnounce (fileEnum.CurrentString)) {
|
||
|
AnnounceFileInReport (fileEnum.CurrentString, (DWORD)Context, ACT_MINORPROBLEMS);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
while (EnumNextMultiSz (&fileEnum));
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
Reinstall (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This is the action taken when we found an app that should be reinstalled on NT. If there
|
||
|
is a link pointing to one of these files an announcement is made in LinkProcessing phase.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Context - See definition.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
TRUE - if operation was successful
|
||
|
FALSE - otherwise
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
MULTISZ_ENUM fileEnum;
|
||
|
BOOL result = FALSE;
|
||
|
|
||
|
if (EnumFirstMultiSz (&fileEnum, Context->FileList.Buf)) {
|
||
|
do {
|
||
|
if (!IsFileMarkedAsKnownGood (fileEnum.CurrentString)) {
|
||
|
result = TRUE;
|
||
|
MarkFileForExternalDelete (fileEnum.CurrentString);
|
||
|
if (!IsFileMarkedForAnnounce (fileEnum.CurrentString)) {
|
||
|
AnnounceFileInReport (fileEnum.CurrentString, (DWORD)Context, ACT_REINSTALL);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
while (EnumNextMultiSz (&fileEnum));
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
DosApps (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This is the action taken when we found an DOS app that's either incompatible or has
|
||
|
minor problems (it's incompatible if Context has Message field NULL). We are forced
|
||
|
to add this now in the user report since DOS apps usually don't have PIF files
|
||
|
associated.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Context - See definition.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
TRUE - at least one file was announced
|
||
|
FALSE - no files were announced
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
MULTISZ_ENUM fileEnum;
|
||
|
BOOL AtLeastOneFile;
|
||
|
|
||
|
AtLeastOneFile = FALSE;
|
||
|
|
||
|
if (EnumFirstMultiSz (&fileEnum, Context->FileList.Buf)) {
|
||
|
do {
|
||
|
if (!IsFileMarkedAsKnownGood (fileEnum.CurrentString)) {
|
||
|
if (Context->Message != NULL) {
|
||
|
if (!IsFileMarkedForAnnounce (fileEnum.CurrentString)) {
|
||
|
AnnounceFileInReport (fileEnum.CurrentString, (DWORD)Context, ACT_MINORPROBLEMS);
|
||
|
}
|
||
|
} else {
|
||
|
MarkFileForExternalDelete (fileEnum.CurrentString);
|
||
|
if (!IsFileMarkedForAnnounce (fileEnum.CurrentString)) {
|
||
|
AnnounceFileInReport (fileEnum.CurrentString, (DWORD)Context, ACT_INCOMPATIBLE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
HandleDeferredAnnounce (NULL, fileEnum.CurrentString, TRUE);
|
||
|
|
||
|
AtLeastOneFile = TRUE;
|
||
|
|
||
|
if (*g_Boot16 == BOOT16_AUTOMATIC) {
|
||
|
*g_Boot16 = BOOT16_YES;
|
||
|
}
|
||
|
}
|
||
|
} while (EnumNextMultiSz (&fileEnum));
|
||
|
}
|
||
|
|
||
|
return AtLeastOneFile;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
pNoLinkRequiredWorker (
|
||
|
IN UINT GroupId,
|
||
|
IN UINT SubGroupId, OPTIONAL
|
||
|
IN DWORD ActionType,
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
{
|
||
|
MULTISZ_ENUM e;
|
||
|
PCTSTR Group;
|
||
|
PCTSTR RootGroup;
|
||
|
PCTSTR SubGroup;
|
||
|
PCTSTR GroupTemp;
|
||
|
BOOL result = FALSE;
|
||
|
|
||
|
if (EnumFirstMultiSz (&e, Context->FileList.Buf)) {
|
||
|
do {
|
||
|
if (!IsFileMarkedAsKnownGood (e.CurrentString)) {
|
||
|
result = TRUE;
|
||
|
}
|
||
|
} while (EnumNextMultiSz (&e));
|
||
|
}
|
||
|
if (!result) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Add the message using section name as the context
|
||
|
//
|
||
|
|
||
|
if (!Context->SectNameForDisplay) {
|
||
|
DEBUGMSG ((DBG_WHOOPS, "Rule for %s needs a localized app title", Context->SectName));
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
RootGroup = GetStringResource (GroupId);
|
||
|
|
||
|
if (!RootGroup) {
|
||
|
LOG((LOG_ERROR, "Cannot get resources while processing section %s", Context->SectNameForDisplay));
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now fetch the group string, and optional subgroup string,
|
||
|
// and join them together
|
||
|
//
|
||
|
|
||
|
if (SubGroupId) {
|
||
|
|
||
|
SubGroup = GetStringResource (SubGroupId);
|
||
|
MYASSERT (SubGroup);
|
||
|
|
||
|
GroupTemp = JoinPaths (RootGroup, SubGroup);
|
||
|
Group = JoinPaths (GroupTemp, Context->SectNameForDisplay);
|
||
|
FreePathString (GroupTemp);
|
||
|
|
||
|
} else {
|
||
|
|
||
|
Group = JoinPaths (RootGroup, Context->SectNameForDisplay);
|
||
|
}
|
||
|
|
||
|
FreeStringResource (RootGroup);
|
||
|
|
||
|
//
|
||
|
// Put the message in msgmgr
|
||
|
//
|
||
|
|
||
|
MsgMgr_ContextMsg_Add (
|
||
|
Context->SectName,
|
||
|
Group,
|
||
|
Context->Message
|
||
|
);
|
||
|
|
||
|
FreePathString (Group);
|
||
|
|
||
|
//
|
||
|
// Associate all files with the context
|
||
|
//
|
||
|
|
||
|
if (EnumFirstMultiSz (&e, Context->FileList.Buf)) {
|
||
|
do {
|
||
|
if (ActionType != ACT_MINORPROBLEMS) {
|
||
|
MarkFileForExternalDelete (e.CurrentString);
|
||
|
}
|
||
|
if (!IsFileMarkedForAnnounce (e.CurrentString)) {
|
||
|
AnnounceFileInReport (e.CurrentString, (DWORD)Context, ActionType);
|
||
|
}
|
||
|
MsgMgr_LinkObjectWithContext (
|
||
|
Context->SectName,
|
||
|
e.CurrentString
|
||
|
);
|
||
|
} while (EnumNextMultiSz (&e));
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
Reinstall_NoLinkRequired (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This is the action taken when we found an app that should be reinstalled on NT. The
|
||
|
message is added to the report whenever the action is triggered; no link is required.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Context - See definition.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
TRUE - if operation was successful
|
||
|
FALSE - otherwise
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
return pNoLinkRequiredWorker (
|
||
|
MSG_REINSTALL_ROOT,
|
||
|
Context->Message ? MSG_REINSTALL_DETAIL_SUBGROUP : MSG_REINSTALL_LIST_SUBGROUP,
|
||
|
ACT_REINSTALL,
|
||
|
Context
|
||
|
);
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
Reinstall_SoftBlock (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This is the action taken when we found an app that should be reinstalled on NT. The
|
||
|
message is added to the report whenever the action is triggered; no link is required.
|
||
|
In addition, the user must uninstall the app before proceeding.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Context - See definition.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
TRUE - if operation was successful
|
||
|
FALSE - otherwise
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
MULTISZ_ENUM e;
|
||
|
|
||
|
//
|
||
|
// Add all files to blocking hash table in msgmgr
|
||
|
//
|
||
|
|
||
|
if (EnumFirstMultiSz (&e, Context->FileList.Buf)) {
|
||
|
do {
|
||
|
if (!IsFileMarkedAsKnownGood (e.CurrentString)) {
|
||
|
AddBlockingObject (e.CurrentString);
|
||
|
}
|
||
|
} while (EnumNextMultiSz (&e));
|
||
|
}
|
||
|
return pNoLinkRequiredWorker (MSG_BLOCKING_ITEMS_ROOT, MSG_REINSTALL_BLOCK_ROOT, ACT_REINSTALL_BLOCK, Context);
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
Incompatible_NoLinkRequired (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This is the action taken when we found an app that is incompatible with NT. The
|
||
|
message is added to the report whenever the action is triggered; no link is required.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Context - See definition.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
TRUE - if operation was successful
|
||
|
FALSE - otherwise
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
return pNoLinkRequiredWorker (
|
||
|
MSG_INCOMPATIBLE_ROOT,
|
||
|
Context->Message ? MSG_INCOMPATIBLE_DETAIL_SUBGROUP : MSG_TOTALLY_INCOMPATIBLE_SUBGROUP,
|
||
|
ACT_INC_NOBADAPPS,
|
||
|
Context
|
||
|
);
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
MinorProblems_NoLinkRequired (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This is the action taken when we found an app that is incompatible with NT. The
|
||
|
message is added to the report whenever the action is triggered; no link is required.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Context - See definition.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
TRUE - if operation was successful
|
||
|
FALSE - otherwise
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
return pNoLinkRequiredWorker (
|
||
|
MSG_MINOR_PROBLEM_ROOT,
|
||
|
0,
|
||
|
ACT_MINORPROBLEMS,
|
||
|
Context
|
||
|
);
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
CompatibleShellModules (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This is the action taken when we found an "known good" shell module. Those modules are
|
||
|
therefore approved to be listed in SHELL= line in SYSTEM.INI.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Context - See definition.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
FALSE - this will allow other actions to handle this file
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
MULTISZ_ENUM fileEnum;
|
||
|
|
||
|
if (EnumFirstMultiSz (&fileEnum, Context->FileList.Buf)) {
|
||
|
do {
|
||
|
AddCompatibleShell (fileEnum.CurrentString, (DWORD)Context);
|
||
|
}
|
||
|
while (EnumNextMultiSz (&fileEnum));
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
CompatibleRunKeyModules (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This is the action taken when we found an "known good" RunKey module. Those modules are
|
||
|
therefore approved to be listed in Run key.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Context - Specifies a pointer to the migdb context
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
FALSE - this will allow other actions to handle this file
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
MULTISZ_ENUM fileEnum;
|
||
|
|
||
|
if (EnumFirstMultiSz (&fileEnum, Context->FileList.Buf)) {
|
||
|
do {
|
||
|
AddCompatibleRunKey (fileEnum.CurrentString, (DWORD)Context);
|
||
|
} while (EnumNextMultiSz (&fileEnum));
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
CompatibleDosModules (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This is the action taken when we found an "known good" Dos module. Those modules are
|
||
|
therefore approved to be loaded in autoexec and config files.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Context - Specifies a pointer to the migdb context
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
FALSE - this will allow other actions to handle this file
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
MULTISZ_ENUM fileEnum;
|
||
|
|
||
|
if (EnumFirstMultiSz (&fileEnum, Context->FileList.Buf)) {
|
||
|
do {
|
||
|
AddCompatibleDos (fileEnum.CurrentString, (DWORD)Context);
|
||
|
} while (EnumNextMultiSz (&fileEnum));
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
pCommonSectionProcess (
|
||
|
IN PMIGDB_CONTEXT Context,
|
||
|
IN BOOL MsgLink
|
||
|
)
|
||
|
{
|
||
|
MULTISZ_ENUM e;
|
||
|
TCHAR Path[MAX_TCHAR_PATH];
|
||
|
PTSTR p;
|
||
|
|
||
|
//
|
||
|
// Defer processing: add the section to memdb so the section is processed only once.
|
||
|
//
|
||
|
|
||
|
if (EnumFirstMultiSz (&e, Context->FileList.Buf)) {
|
||
|
|
||
|
do {
|
||
|
|
||
|
//
|
||
|
// Construct just the path
|
||
|
//
|
||
|
|
||
|
StringCopy (Path, e.CurrentString);
|
||
|
p = (PTSTR) GetFileNameFromPath (Path);
|
||
|
|
||
|
// Path is a full path so GetFileNameFromPath will always return something
|
||
|
if (p) {
|
||
|
|
||
|
p = _tcsdec2 (Path, p);
|
||
|
|
||
|
// p will always be not NULL and will point to the last wack
|
||
|
if (p && (*p == '\\')) {
|
||
|
|
||
|
*p = 0;
|
||
|
|
||
|
MemDbSetValueExA (
|
||
|
MEMDB_CATEGORY_MIGRATION_SECTION,
|
||
|
Context->Arguments,
|
||
|
Path,
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL
|
||
|
);
|
||
|
|
||
|
if (MsgLink) {
|
||
|
MsgMgr_LinkObjectWithContext (
|
||
|
Context->Arguments,
|
||
|
e.CurrentString
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} while (EnumNextMultiSz (&e));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
Incompatible_AutoUninstall (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Incompatible_AutoUninstall implements the action taken when we find a particular app and
|
||
|
need to process an uninstall section. The uninstall section removes files or
|
||
|
registry entries. This application will also be announced in the report as incompatible.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Context - See definition.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
TRUE - if operation was successful
|
||
|
FALSE - otherwise
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PCTSTR Group;
|
||
|
|
||
|
if (!Context->Arguments) {
|
||
|
DEBUGMSG ((DBG_WHOOPS, "Incompatible_AutoUninstall: ARG is required"));
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
Group = BuildMessageGroup (
|
||
|
MSG_INCOMPATIBLE_ROOT,
|
||
|
MSG_AUTO_UNINSTALL_SUBGROUP,
|
||
|
Context->SectNameForDisplay
|
||
|
);
|
||
|
if (Group) {
|
||
|
|
||
|
MsgMgr_ContextMsg_Add (
|
||
|
Context->Arguments,
|
||
|
Group,
|
||
|
S_EMPTY
|
||
|
);
|
||
|
|
||
|
FreeText (Group);
|
||
|
}
|
||
|
|
||
|
pCommonSectionProcess (Context, TRUE);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
Reinstall_AutoUninstall (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Reinstall_AutoUninstall implements the action taken when we find a particular app and
|
||
|
need to process an uninstall section. The uninstall section removes files or
|
||
|
registry entries. This application will also be announced in the report as reinstall.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Context - See definition.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
TRUE - if operation was successful
|
||
|
FALSE - otherwise
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PCTSTR Group;
|
||
|
|
||
|
if (!Context->Arguments) {
|
||
|
DEBUGMSG ((DBG_WHOOPS, "Reinstall_AutoUninstall: ARG is required"));
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
Group = BuildMessageGroup (
|
||
|
MSG_REINSTALL_ROOT,
|
||
|
Context->Message ? MSG_REINSTALL_DETAIL_SUBGROUP : MSG_REINSTALL_LIST_SUBGROUP,
|
||
|
Context->SectNameForDisplay
|
||
|
);
|
||
|
if (Group) {
|
||
|
|
||
|
MsgMgr_ContextMsg_Add (
|
||
|
Context->Arguments,
|
||
|
Group,
|
||
|
S_EMPTY
|
||
|
);
|
||
|
|
||
|
FreeText (Group);
|
||
|
}
|
||
|
|
||
|
pCommonSectionProcess (Context, TRUE);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
SilentUninstall (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
SilentUninstall implements the action taken when we find a particular app and
|
||
|
need to process an uninstall section. The uninstall section removes files or
|
||
|
registry entries. No message goes in the report.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Context - See definition.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
Always FALSE - other actions should be processed
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
if (!Context->Arguments) {
|
||
|
DEBUGMSG ((DBG_WHOOPS, "SilentUninstall: ARG is required"));
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Defer processing: add the section to memdb so the section is processed only once.
|
||
|
//
|
||
|
|
||
|
pCommonSectionProcess (Context, FALSE);
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
FileEdit (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
FileEdit triggers a file edit operation, allowing search/replace and path
|
||
|
updates.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Context - Specifies the context of the migdb.inf entry that triggered this
|
||
|
action
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Always FALSE - allow other actions to be called
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
MULTISZ_ENUM e;
|
||
|
INFSTRUCT is = INITINFSTRUCT_GROWBUFFER;
|
||
|
PCSTR Data;
|
||
|
GROWBUFFER SearchList = GROWBUF_INIT;
|
||
|
GROWBUFFER ReplaceList = GROWBUF_INIT;
|
||
|
GROWBUFFER TokenArgBuf = GROWBUF_INIT;
|
||
|
GROWBUFFER TokenSetBuf = GROWBUF_INIT;
|
||
|
GROWBUFFER DataBuf = GROWBUF_INIT;
|
||
|
UINT u;
|
||
|
PTOKENARG TokenArg;
|
||
|
PBYTE Dest;
|
||
|
PTOKENSET TokenSet;
|
||
|
PCSTR editSection = NULL;
|
||
|
PCSTR CharsToIgnore = NULL;
|
||
|
BOOL urlMode = FALSE;
|
||
|
BOOL result = FALSE;
|
||
|
|
||
|
__try {
|
||
|
//
|
||
|
// If no args, then this file is just supposed to get its paths updated
|
||
|
//
|
||
|
|
||
|
if (!Context->Arguments) {
|
||
|
if (EnumFirstMultiSz (&e, Context->FileList.Buf)) {
|
||
|
|
||
|
do {
|
||
|
MemDbSetValueEx (
|
||
|
MEMDB_CATEGORY_FILEEDIT,
|
||
|
e.CurrentString,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL
|
||
|
);
|
||
|
|
||
|
} while (EnumNextMultiSz (&e));
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Scan the args for EnableUrlMode
|
||
|
//
|
||
|
|
||
|
if (EnumFirstMultiSz (&e, Context->Arguments)) {
|
||
|
do {
|
||
|
if (StringIMatch (e.CurrentString, TEXT("EnableUrlMode"))) {
|
||
|
urlMode = TRUE;
|
||
|
} else if (!editSection) {
|
||
|
editSection = e.CurrentString;
|
||
|
DEBUGMSG ((DBG_NAUSEA, "FileEdit: EditSection is %s", editSection));
|
||
|
} else if (!CharsToIgnore) {
|
||
|
CharsToIgnore = e.CurrentString;
|
||
|
DEBUGMSG ((DBG_NAUSEA, "FileEdit: CharsToIgnore is %s", CharsToIgnore));
|
||
|
} else {
|
||
|
DEBUGMSG ((DBG_WHOOPS, "Ignoring extra file edit arg %s", e.CurrentString));
|
||
|
}
|
||
|
} while (EnumNextMultiSz (&e));
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Parse the edit section
|
||
|
//
|
||
|
|
||
|
if (editSection) {
|
||
|
if (InfFindFirstLine (g_MigDbInf, editSection, NULL, &is)) {
|
||
|
|
||
|
do {
|
||
|
|
||
|
ReplaceList.End = 0;
|
||
|
SearchList.End = 0;
|
||
|
|
||
|
//
|
||
|
// Get the search/replace strings
|
||
|
//
|
||
|
|
||
|
for (u = 3 ; ; u += 2) {
|
||
|
|
||
|
Data = InfGetStringField (&is, u + 1);
|
||
|
if (!Data) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
MYASSERT (*Data);
|
||
|
if (*Data == 0) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
MultiSzAppend (&ReplaceList, Data);
|
||
|
|
||
|
Data = InfGetStringField (&is, u);
|
||
|
MYASSERT (Data && *Data);
|
||
|
if (!Data || *Data == 0) {
|
||
|
__leave;
|
||
|
}
|
||
|
|
||
|
MultiSzAppend (&SearchList, Data);
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get the detection string
|
||
|
//
|
||
|
|
||
|
Data = InfGetStringField (&is, 1);
|
||
|
|
||
|
if (Data && *Data) {
|
||
|
//
|
||
|
// Save the token arg into an array
|
||
|
//
|
||
|
|
||
|
TokenArg = (PTOKENARG) GrowBuffer (&TokenArgBuf, sizeof (TOKENARG));
|
||
|
TokenArg->DetectPattern = (PCSTR) (DataBuf.End + TOKEN_BASE_OFFSET);
|
||
|
GrowBufCopyString (&DataBuf, Data);
|
||
|
|
||
|
if (SearchList.End) {
|
||
|
MultiSzAppend (&SearchList, TEXT(""));
|
||
|
|
||
|
TokenArg->SearchList = (PCSTR) (DataBuf.End + TOKEN_BASE_OFFSET);
|
||
|
Dest = GrowBuffer (&DataBuf, SearchList.End);
|
||
|
CopyMemory (Dest, SearchList.Buf, SearchList.End);
|
||
|
|
||
|
MultiSzAppend (&ReplaceList, TEXT(""));
|
||
|
|
||
|
TokenArg->ReplaceWith = (PCSTR) (DataBuf.End + TOKEN_BASE_OFFSET);
|
||
|
Dest = GrowBuffer (&DataBuf, ReplaceList.End);
|
||
|
CopyMemory (Dest, ReplaceList.Buf, ReplaceList.End);
|
||
|
|
||
|
} else {
|
||
|
|
||
|
TokenArg->SearchList = 0;
|
||
|
TokenArg->ReplaceWith = 0;
|
||
|
|
||
|
}
|
||
|
|
||
|
Data = InfGetStringField (&is, 2);
|
||
|
if (_tcstoul (Data, NULL, 10)) {
|
||
|
TokenArg->UpdatePath = TRUE;
|
||
|
} else {
|
||
|
TokenArg->UpdatePath = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} while (InfFindNextLine (&is));
|
||
|
}
|
||
|
ELSE_DEBUGMSG ((DBG_WHOOPS, "FileEdit action's section %s does not exist", editSection));
|
||
|
|
||
|
} else if (urlMode) {
|
||
|
//
|
||
|
// Create an argument that has a detect pattern of *
|
||
|
//
|
||
|
|
||
|
TokenArg = (PTOKENARG) GrowBuffer (&TokenArgBuf, sizeof (TOKENARG));
|
||
|
TokenArg->DetectPattern = (PCSTR) (DataBuf.End + TOKEN_BASE_OFFSET);
|
||
|
GrowBufCopyString (&DataBuf, TEXT("*"));
|
||
|
|
||
|
TokenArg->SearchList = NULL;
|
||
|
TokenArg->ReplaceWith = NULL;
|
||
|
TokenArg->UpdatePath = TRUE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Build a token set out of the token args
|
||
|
//
|
||
|
|
||
|
if (TokenArgBuf.End) {
|
||
|
TokenSet = (PTOKENSET) GrowBuffer (
|
||
|
&TokenSetBuf,
|
||
|
sizeof (TOKENSET) +
|
||
|
TokenArgBuf.End +
|
||
|
DataBuf.End
|
||
|
);
|
||
|
|
||
|
TokenSet->ArgCount = TokenArgBuf.End / sizeof (TOKENARG);
|
||
|
TokenSet->SelfRelative = TRUE;
|
||
|
TokenSet->UrlMode = urlMode;
|
||
|
|
||
|
if (CharsToIgnore) {
|
||
|
TokenSet->CharsToIgnore = (PCSTR) (DataBuf.End + TOKEN_BASE_OFFSET);
|
||
|
GrowBufCopyString (&TokenSetBuf, CharsToIgnore);
|
||
|
} else {
|
||
|
TokenSet->CharsToIgnore = NULL;
|
||
|
}
|
||
|
|
||
|
CopyMemory (TokenSet->Args, TokenArgBuf.Buf, TokenArgBuf.End);
|
||
|
CopyMemory (
|
||
|
(PBYTE) (TokenSet->Args) + TokenArgBuf.End,
|
||
|
DataBuf.Buf,
|
||
|
DataBuf.End
|
||
|
);
|
||
|
|
||
|
//
|
||
|
// Save TokenSet to memdb
|
||
|
//
|
||
|
|
||
|
if (EnumFirstMultiSz (&e, Context->FileList.Buf)) {
|
||
|
|
||
|
do {
|
||
|
MemDbSetBinaryValueEx (
|
||
|
MEMDB_CATEGORY_FILEEDIT,
|
||
|
e.CurrentString,
|
||
|
NULL,
|
||
|
TokenSetBuf.Buf,
|
||
|
TokenSetBuf.End,
|
||
|
NULL
|
||
|
);
|
||
|
|
||
|
if (g_ConfigOptions.EnableBackup) {
|
||
|
MarkFileForBackup (e.CurrentString);
|
||
|
}
|
||
|
|
||
|
} while (EnumNextMultiSz (&e));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
result = TRUE;
|
||
|
}
|
||
|
__finally {
|
||
|
InfCleanUpInfStruct (&is);
|
||
|
FreeGrowBuffer (&SearchList);
|
||
|
FreeGrowBuffer (&ReplaceList);
|
||
|
FreeGrowBuffer (&TokenArgBuf);
|
||
|
FreeGrowBuffer (&TokenSetBuf);
|
||
|
FreeGrowBuffer (&DataBuf);
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
MigrationProcessing (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
MigrationProcessing implements the action taken when we find a particular app and
|
||
|
we need some migration DLL like processing to go on.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Context - See definition.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
TRUE - if operation was successful
|
||
|
FALSE - otherwise
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
if (!Context->Arguments) {
|
||
|
DEBUGMSG ((DBG_WHOOPS, "MigrationProcessing: ARG is required"));
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Defer processing: add the section to memdb so the section is processed only once.
|
||
|
//
|
||
|
|
||
|
pCommonSectionProcess (Context, FALSE);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
NonPnpDrivers (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
NonPnpDrivers adds hardware incompatibility messages for incompatible
|
||
|
devices found by identifying drivers.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Context - Specifies the context of the file found.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Always TRUE.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PCTSTR Group;
|
||
|
PCTSTR GroupRoot;
|
||
|
MULTISZ_ENUM e;
|
||
|
TCHAR MsgMgrContext[256];
|
||
|
PCTSTR OtherDevices;
|
||
|
|
||
|
MYASSERT (Context->SectNameForDisplay);
|
||
|
|
||
|
//
|
||
|
// Add MemDb entry, so .386 check code knows about this file
|
||
|
//
|
||
|
|
||
|
NonPnpDrivers_NoMessage (Context);
|
||
|
|
||
|
//
|
||
|
// Add incompatibility message to Hardware. This involves decorating
|
||
|
// the device driver name and using a context prefix of NonPnpDrv.
|
||
|
//
|
||
|
|
||
|
OtherDevices = GetStringResource (MSG_UNKNOWN_DEVICE_CLASS);
|
||
|
if (!OtherDevices) {
|
||
|
MYASSERT (FALSE);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
GroupRoot = BuildMessageGroup (
|
||
|
MSG_INCOMPATIBLE_HARDWARE_ROOT,
|
||
|
MSG_INCOMPATIBLE_HARDWARE_PNP_SUBGROUP,
|
||
|
OtherDevices
|
||
|
);
|
||
|
|
||
|
FreeStringResource (OtherDevices);
|
||
|
|
||
|
if (!GroupRoot) {
|
||
|
MYASSERT (FALSE);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
Group = JoinPaths (GroupRoot, Context->SectNameForDisplay);
|
||
|
FreeText (GroupRoot);
|
||
|
|
||
|
MYASSERT (TcharCount (Context->SectName) < 240);
|
||
|
StringCopy (MsgMgrContext, TEXT("*NonPnpDrv"));
|
||
|
StringCat (MsgMgrContext, Context->SectName);
|
||
|
|
||
|
MsgMgr_ContextMsg_Add (MsgMgrContext, Group, NULL);
|
||
|
|
||
|
FreePathString (Group);
|
||
|
|
||
|
if (EnumFirstMultiSz (&e, Context->FileList.Buf)) {
|
||
|
do {
|
||
|
MsgMgr_LinkObjectWithContext (
|
||
|
MsgMgrContext,
|
||
|
e.CurrentString
|
||
|
);
|
||
|
|
||
|
} while (EnumNextMultiSz (&e));
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
NonPnpDrivers_NoMessage (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
NonPnpDrivers_NoMessage marks a device driver file as known, so the .386
|
||
|
warning does not appear because of it.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Context - Specifies the context of the file found.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Always TRUE.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
MULTISZ_ENUM e;
|
||
|
|
||
|
MYASSERT (Context->SectNameForDisplay);
|
||
|
|
||
|
//
|
||
|
// Add MemDb entry, so .386 check code knows about this file
|
||
|
//
|
||
|
|
||
|
if (EnumFirstMultiSz (&e, Context->FileList.Buf)) {
|
||
|
do {
|
||
|
DeleteFileWithWarning (e.CurrentString);
|
||
|
} while (EnumNextMultiSz (&e));
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
extern HWND g_Winnt32Wnd;
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
RequiredOSFiles (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This is for now the only action function that's called when the associated action was
|
||
|
not triggered during the file scan.
|
||
|
We need to know that we are upgrading a known OS so this function is called when none
|
||
|
of the required files were found. The action taken is warning the user and terminating
|
||
|
the upgrade.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Context - See definition.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
TRUE - Always
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PCTSTR group = NULL;
|
||
|
PCTSTR message = NULL;
|
||
|
|
||
|
|
||
|
if ((!g_ConfigOptions.AnyVersion) && (!CANCELLED ())) {
|
||
|
|
||
|
//
|
||
|
// Add a message to the Incompatibility Report.
|
||
|
//
|
||
|
|
||
|
g_UnknownOs = TRUE;
|
||
|
group = BuildMessageGroup (MSG_BLOCKING_ITEMS_ROOT, MSG_UNKNOWN_OS_WARNING_SUBGROUP, NULL);
|
||
|
message = GetStringResource (MSG_UNKNOWN_OS);
|
||
|
|
||
|
if (message && group) {
|
||
|
MsgMgr_ObjectMsg_Add (TEXT("*UnknownOs"), group, message);
|
||
|
}
|
||
|
FreeText (group);
|
||
|
FreeStringResource (message);
|
||
|
|
||
|
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
CompatibleHlpFiles (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This is the action taken when we found an "known good" HLP file. We do this to prevent
|
||
|
help file checking routines from announcing it as incompatible.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Context - See definition.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
FALSE - this will allow other actions to handle this file
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
MULTISZ_ENUM fileEnum;
|
||
|
|
||
|
if (EnumFirstMultiSz (&fileEnum, Context->FileList.Buf)) {
|
||
|
do {
|
||
|
AddCompatibleHlp (fileEnum.CurrentString, (DWORD)Context);
|
||
|
} while (EnumNextMultiSz (&fileEnum));
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
BlockingVirusScanner (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
{
|
||
|
MULTISZ_ENUM fileEnum;
|
||
|
PCTSTR message = NULL;
|
||
|
PCTSTR button1 = NULL;
|
||
|
PCTSTR button2 = NULL;
|
||
|
PCSTR args[1];
|
||
|
BOOL bStop;
|
||
|
|
||
|
if (EnumFirstMultiSz (&fileEnum, Context->FileList.Buf)) {
|
||
|
do {
|
||
|
|
||
|
//
|
||
|
// Inform the user of the problem.
|
||
|
//
|
||
|
args[0] = Context -> Message;
|
||
|
bStop = (Context->Arguments && StringIMatch (Context->Arguments, TEXT("1")));
|
||
|
|
||
|
if (bStop) {
|
||
|
|
||
|
ResourceMessageBox (
|
||
|
g_ParentWnd,
|
||
|
MSG_BAD_VIRUS_SCANNER_STOP,
|
||
|
MB_OK|MB_ICONSTOP|MB_SETFOREGROUND,
|
||
|
args
|
||
|
);
|
||
|
g_BadVirusScannerFound = TRUE;
|
||
|
|
||
|
} else {
|
||
|
message = ParseMessageID (MSG_BAD_VIRUS_SCANNER, args);
|
||
|
button1 = GetStringResource (MSG_KILL_APPLICATION);
|
||
|
button2 = GetStringResource (MSG_QUIT_SETUP);
|
||
|
if (!UNATTENDED() && IDBUTTON1 != TwoButtonBox (g_ParentWnd, message, button1, button2)) {
|
||
|
|
||
|
g_BadVirusScannerFound = TRUE;
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
//
|
||
|
// Add the string to the list of files to be
|
||
|
// to be terminated.
|
||
|
//
|
||
|
GrowListAppendString (
|
||
|
&g_BadVirusScannerGrowList,
|
||
|
Context->FileList.Buf
|
||
|
);
|
||
|
|
||
|
}
|
||
|
FreeStringResource (message);
|
||
|
FreeStringResource (button1);
|
||
|
FreeStringResource (button2);
|
||
|
}
|
||
|
}
|
||
|
while (EnumNextMultiSz (&fileEnum));
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
BlockingFile (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
{
|
||
|
|
||
|
MULTISZ_ENUM e;
|
||
|
PCTSTR group;
|
||
|
BOOL result = FALSE;
|
||
|
|
||
|
if (EnumFirstMultiSz (&e, Context->FileList.Buf)) {
|
||
|
do {
|
||
|
if (!IsFileMarkedAsKnownGood (e.CurrentString)) {
|
||
|
|
||
|
result = TRUE;
|
||
|
DEBUGMSG ((DBG_WARNING, "BLOCKINGFILE: Found file %s which blocks upgrade.", e.CurrentString));
|
||
|
group = BuildMessageGroup (MSG_BLOCKING_ITEMS_ROOT, MSG_MUST_UNINSTALL_ROOT, Context->SectNameForDisplay);
|
||
|
MsgMgr_ObjectMsg_Add (e.CurrentString, group, Context->Message);
|
||
|
FreeText (group);
|
||
|
|
||
|
g_BlockingFileFound = TRUE;
|
||
|
}
|
||
|
|
||
|
} while (EnumNextMultiSz (&e));
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
BlockingHardware (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
{
|
||
|
|
||
|
MULTISZ_ENUM e;
|
||
|
PCTSTR group;
|
||
|
|
||
|
if (EnumFirstMultiSz (&e, Context->FileList.Buf)) {
|
||
|
do {
|
||
|
|
||
|
DEBUGMSG ((DBG_WARNING, "BLOCKINGHARDWARE: Found file %s which blocks upgrade.", e.CurrentString));
|
||
|
|
||
|
group = BuildMessageGroup (MSG_BLOCKING_ITEMS_ROOT, MSG_BLOCKING_HARDWARE_SUBGROUP, Context->SectNameForDisplay);
|
||
|
MsgMgr_ObjectMsg_Add (e.CurrentString, group, Context->Message);
|
||
|
FreeText (group);
|
||
|
|
||
|
g_BlockingHardwareFound = TRUE;
|
||
|
|
||
|
} while (EnumNextMultiSz (&e));
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
CompatibleFiles (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This is the action taken when an application file is considered good. Later, if we find
|
||
|
a link that points to a file that's not in this section, we will announce the link as
|
||
|
"unknown".
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Context - See definition.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
FALSE - this will allow other actions to handle this file
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
MULTISZ_ENUM e;
|
||
|
|
||
|
if (EnumFirstMultiSz (&e, Context->FileList.Buf)) {
|
||
|
do {
|
||
|
MarkFileAsKnownGood (e.CurrentString);
|
||
|
} while (EnumNextMultiSz (&e));
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
StoreMapi32Locations (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
This is the action taken for files related to MAPI32. We keep the locations
|
||
|
in a list, so we can later detect whether MAPI is handled or not. If it
|
||
|
is not handled, then we must tell the user they will lose e-mail functionality.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Context - See definition.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
FALSE - this will allow other actions to handle this file
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
MULTISZ_ENUM e;
|
||
|
|
||
|
if (EnumFirstMultiSz (&e, Context->FileList.Buf)) {
|
||
|
|
||
|
do {
|
||
|
MemDbSetValueEx (
|
||
|
MEMDB_CATEGORY_MAPI32_LOCATIONS,
|
||
|
e.CurrentString,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL
|
||
|
);
|
||
|
|
||
|
} while (EnumNextMultiSz (&e));
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
ProductCollisions (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
ProductCollisions identifies files that are known good but match an NT
|
||
|
system file name. In this case, we want one file to be treated as an OS
|
||
|
file (the one in %windir% for example), while another file needs to be
|
||
|
treated as an application file (the one in the app dir for example). Here
|
||
|
we get called only when the application files are found.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Context - Specifies the current file context
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Always TRUE.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
MarkForBackup (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
MarkForBackup puts a backup operation on the file, unless backup is turned
|
||
|
off.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Context - Specifies the current file context
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Always TRUE.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
MULTISZ_ENUM e;
|
||
|
|
||
|
if (g_ConfigOptions.EnableBackup) {
|
||
|
if (EnumFirstMultiSz (&e, Context->FileList.Buf)) {
|
||
|
|
||
|
do {
|
||
|
MarkFileForBackup (e.CurrentString);
|
||
|
} while (EnumNextMultiSz (&e));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
ShowInSimplifiedView (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
ShowInSimplifiedView records the file with message manager, so that
|
||
|
the list view will show the incompatibility.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Context - Specifies the current file context
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Always FALSE, so other actions can process the file.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
MULTISZ_ENUM e;
|
||
|
|
||
|
if (g_ConfigOptions.ShowReport == TRISTATE_PARTIAL) {
|
||
|
if (EnumFirstMultiSz (&e, Context->FileList.Buf)) {
|
||
|
|
||
|
do {
|
||
|
ElevateObject (e.CurrentString);
|
||
|
DEBUGMSG ((DBG_VERBOSE, "Elevated %s to the short view", e.CurrentString));
|
||
|
} while (EnumNextMultiSz (&e));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
IniFileMappings (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
IniFileMappings records the locations of all INI files, so they
|
||
|
can be processed during GUI mode.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Context - See definition.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
FALSE - this will allow other actions to handle this file
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
MULTISZ_ENUM e;
|
||
|
|
||
|
if (EnumFirstMultiSz (&e, Context->FileList.Buf)) {
|
||
|
|
||
|
do {
|
||
|
MemDbSetValueEx (
|
||
|
MEMDB_CATEGORY_INIFILES_CONVERT,
|
||
|
e.CurrentString,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
0,
|
||
|
NULL
|
||
|
);
|
||
|
|
||
|
} while (EnumNextMultiSz (&e));
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
IgnoreInReport (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
IgnoreInReport handles a file so that it will not appear in the
|
||
|
upgrade report. Currently this action is only for Office FindFast
|
||
|
version 9 and higher. Random results are likely with any other
|
||
|
type of file.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Context - See definition.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
FALSE - this will allow other actions to handle this file
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
MULTISZ_ENUM e;
|
||
|
|
||
|
if (EnumFirstMultiSz (&e, Context->FileList.Buf)) {
|
||
|
|
||
|
do {
|
||
|
|
||
|
HandleObject (e.CurrentString, TEXT("Report"));
|
||
|
|
||
|
} while (EnumNextMultiSz (&e));
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
BadFusion (
|
||
|
IN PMIGDB_CONTEXT Context
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
BadFusion removes known bad library files found in fusion dirs.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Context - See definition.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
FALSE - this will allow other actions to handle this file
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
MULTISZ_ENUM e;
|
||
|
TCHAR exeName[MAX_TCHAR_PATH * 2];
|
||
|
TCHAR localFile[MAX_TCHAR_PATH * 2];
|
||
|
PTSTR filePtr;
|
||
|
HANDLE h;
|
||
|
WIN32_FIND_DATA fd;
|
||
|
DWORD type;
|
||
|
BOOL b = FALSE;
|
||
|
|
||
|
if (g_IsFusionDir) {
|
||
|
|
||
|
if (EnumFirstMultiSz (&e, Context->FileList.Buf)) {
|
||
|
|
||
|
do {
|
||
|
if (IsFileMarkedForDelete (e.CurrentString)) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (SizeOfString (e.CurrentString) > sizeof (exeName)) {
|
||
|
MYASSERT (FALSE);
|
||
|
continue;
|
||
|
}
|
||
|
StringCopy (exeName, e.CurrentString);
|
||
|
|
||
|
filePtr = (PTSTR)GetFileNameFromPath (exeName);
|
||
|
if (!filePtr) {
|
||
|
MYASSERT (FALSE);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// make full path to app
|
||
|
//
|
||
|
StringCopy (filePtr, Context->Arguments);
|
||
|
|
||
|
//
|
||
|
// and to .local
|
||
|
//
|
||
|
StringCopyAB (localFile, exeName, filePtr);
|
||
|
filePtr = GetEndOfString (localFile);
|
||
|
|
||
|
//
|
||
|
// check if this is really a fusion case;
|
||
|
// both a file "exeName" and a file or dir (bug?) "exeName.local"
|
||
|
// must be present
|
||
|
//
|
||
|
h = FindFirstFile (exeName, &fd);
|
||
|
if (h == INVALID_HANDLE_VALUE) {
|
||
|
continue;
|
||
|
}
|
||
|
do {
|
||
|
if (fd.cFileName[0] == TEXT('.') &&
|
||
|
(fd.cFileName[1] == 0 || fd.cFileName[1] == TEXT('.') && fd.cFileName[2] == 0)
|
||
|
) {
|
||
|
continue;
|
||
|
}
|
||
|
*filePtr = 0;
|
||
|
StringCopy (StringCat (filePtr, fd.cFileName), TEXT(".local"));
|
||
|
|
||
|
if (DoesFileExist (localFile)) {
|
||
|
type = GetExeType (localFile);
|
||
|
if ((type == EXE_WIN32_APP) || (type == EXE_WIN16_APP)) {
|
||
|
b = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} while (FindNextFile (h, &fd));
|
||
|
FindClose (h);
|
||
|
|
||
|
if (b) {
|
||
|
RemoveOperationsFromPath (e.CurrentString, ALL_OPERATIONS);
|
||
|
MarkFileForDelete (e.CurrentString);
|
||
|
LOG ((
|
||
|
LOG_WARNING,
|
||
|
"BadFusion: removed known bad component %s in fusion dir",
|
||
|
e.CurrentString
|
||
|
));
|
||
|
}
|
||
|
|
||
|
} while (EnumNextMultiSz (&e));
|
||
|
}
|
||
|
}
|
||
|
return b;
|
||
|
}
|