windows-nt/Source/XPSP1/NT/base/ntsetup/win95upg/w95upg/sysmig/sysmig.c
2020-09-26 16:20:57 +08:00

3233 lines
84 KiB
C

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
sysmig.c
Abstract:
System migration functions for Win95
Author:
Jim Schmidt (jimschm) 13-Feb-1997
Revision History:
jimschm 09-Mar-2001 Redesigned file list code to support LDID enumeration in
a clear way
marcw 18-Mar-1999 Boot16 now set to BOOT16_YES unless it has been
explicitly set to BOOT16_NO or the partition will
be converted to NTFS.
jimschm 23-Sep-1998 Updated for new fileops code
jimschm 12-May-1998 Added .386 warning
calinn 19-Nov-1997 Added pSaveDosFiles, will move DOS files out of the way
during upgrade
marcw 21-Jul-1997 Added end-processing of special keys.
(e.g. HKLM\Software\Microsoft\CurrentVersion\RUN)
jimschm 20-Jun-1997 Hooked up user loop and saved user
names to memdb
--*/
#include "pch.h"
#include "sysmigp.h"
#include "progbar.h"
#include "regops.h"
#include "oleregp.h"
#include <mmsystem.h>
typedef struct TAG_DIRPATH {
struct TAG_DIRPATH *Next;
TCHAR DirPath[];
} DIRIDPATH, *PDIRIDPATH;
typedef struct TAG_DIRID {
struct TAG_DIRID *Next;
PDIRIDPATH FirstDirPath;
UINT DirId;
} DIRIDMAP, *PDIRIDMAP;
typedef struct {
PDIRIDPATH LastMatch;
PCTSTR SubPath;
PTSTR ResultBuffer;
} DIRNAME_ENUM, *PDIRNAME_ENUM;
UINT *g_Boot16;
UINT g_ProgressBarTime;
PDIRIDMAP g_HeadDirId;
PDIRIDMAP g_TailDirId;
POOLHANDLE g_DirIdPool;
PDIRIDMAP g_LastIdPtr;
BOOL
pWarnAboutOldDrivers (
VOID
);
VOID
pAddNtFile (
IN PCTSTR Dir, OPTIONAL
IN PCTSTR FileName, OPTIONAL
IN BOOL BackupThisFile,
IN BOOL CleanThisFile,
IN BOOL OsFile
);
BOOL
WINAPI
SysMig_Entry (
IN HINSTANCE hinstDLL,
IN DWORD dwReason,
IN LPVOID lpv
)
/*++
Routine Description:
SysMig_Entry is a DllMain-like init funciton, called by w95upg\dll.
This function is called at process attach and detach.
Arguments:
hinstDLL - (OS-supplied) instance handle for the DLL
dwReason - (OS-supplied) indicates attach or detatch from process or
thread
lpv - unused
Return Value:
Return value is always TRUE (indicating successful init).
--*/
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
g_DirIdPool = PoolMemInitNamedPool ("FileList");
break;
case DLL_PROCESS_DETACH:
TerminateCacheFolderTracking();
if (g_DirIdPool) {
PoolMemDestroyPool (g_DirIdPool);
}
break;
}
return TRUE;
}
BOOL
pPreserveShellIcons (
VOID
)
/*++
Routine Description:
This routine scans the Shell Icons for references to files that
are expected to be deleted. If a reference is found, the file is
removed from the deleted list, and marked to be moved to
%windir%\migicons\shl<n>.
Arguments:
none
Return Value:
none
--*/
{
REGVALUE_ENUM e;
HKEY ShellIcons;
PCTSTR Data;
TCHAR ArgZero[MAX_CMDLINE];
DWORD Binary = 0;
INT IconIndex;
PCTSTR p;
//
// Scan all ProgIDs, looking for default icons that are currently
// set for deletion. Once found, save the icon.
//
ShellIcons = OpenRegKeyStr (S_SHELL_ICONS_REG_KEY);
if (ShellIcons) {
if (EnumFirstRegValue (&e, ShellIcons)) {
do {
Data = (PCTSTR) GetRegValueDataOfType (ShellIcons, e.ValueName, REG_SZ);
if (Data) {
ExtractArgZero (Data, ArgZero);
if (FILESTATUS_UNCHANGED != GetFileStatusOnNt (ArgZero)) {
p = _tcschr (Data, TEXT(','));
if (p) {
IconIndex = _ttoi (_tcsinc (p));
} else {
IconIndex = 0;
}
//
// Extract will fail only if the icon is known good
//
if (ExtractIconIntoDatFile (
ArgZero,
IconIndex,
&g_IconContext,
NULL
)) {
DEBUGMSG ((DBG_SYSMIG, "Preserving shell icon file %s", ArgZero));
}
}
MemFree (g_hHeap, 0, Data);
}
} while (EnumNextRegValue (&e));
}
CloseRegKey (ShellIcons);
}
return TRUE;
}
BOOL
pMoveStaticFiles (
VOID
)
{
BOOL rSuccess = TRUE;
INFSTRUCT is = INITINFSTRUCT_POOLHANDLE;
PCTSTR from;
PCTSTR to;
PCTSTR fromExpanded;
PCTSTR toExpanded;
PCTSTR toFinalDest;
PTSTR Pattern;
FILE_ENUM e;
//
// Cycle through all of the entries in the static move files section.
//
if (InfFindFirstLine(g_Win95UpgInf,S_STATIC_MOVE_FILES,NULL,&is)) {
do {
//
// For each entry, check to see if the file exists. If it does,
// add it into the memdb move file section.
//
from = InfGetStringField(&is,0);
to = InfGetStringField(&is,1);
if (from && to) {
fromExpanded = ExpandEnvironmentText(from);
toExpanded = ExpandEnvironmentText(to);
Pattern = _tcsrchr (fromExpanded, TEXT('\\'));
//
// full path please
//
MYASSERT (Pattern);
if (!Pattern) {
continue;
}
*Pattern = 0;
Pattern++;
if (EnumFirstFile (&e, fromExpanded, Pattern)) {
do {
if (!StringIMatch (e.FileName, Pattern)) {
//
// pattern specified
//
toFinalDest = JoinPaths (toExpanded, e.FileName);
} else {
toFinalDest = toExpanded;
}
if (!IsFileMarkedAsHandled (e.FullPath)) {
//
// Remove general operations, then mark for move
//
RemoveOperationsFromPath (
e.FullPath,
OPERATION_FILE_DELETE|
OPERATION_FILE_MOVE|
OPERATION_FILE_MOVE_BY_NT|
OPERATION_FILE_MOVE_SHELL_FOLDER|
OPERATION_CREATE_FILE
);
MarkFileForMove (e.FullPath, toFinalDest);
}
if (toFinalDest != toExpanded) {
FreePathString (toFinalDest);
}
} while (EnumNextFile (&e));
}
--Pattern;
*Pattern = TEXT('\\');
FreeText (toExpanded);
FreeText (fromExpanded);
}
} while (InfFindNextLine(&is));
}
InfCleanUpInfStruct(&is);
return rSuccess;
}
DWORD
MoveStaticFiles (
IN DWORD Request
)
{
switch (Request) {
case REQUEST_QUERYTICKS:
return TICKS_MOVE_STATIC_FILES;
case REQUEST_RUN:
if (!pMoveStaticFiles ()) {
return GetLastError ();
}
else {
return ERROR_SUCCESS;
}
default:
DEBUGMSG ((DBG_ERROR, "Bad parameter in MoveStaticFiles."));
}
return 0;
}
BOOL
pCopyStaticFiles (
VOID
)
{
BOOL rSuccess = TRUE;
INFSTRUCT is = INITINFSTRUCT_POOLHANDLE;
PCTSTR from;
PCTSTR to;
PCTSTR fromExpanded;
PCTSTR toExpanded;
PCTSTR toFinalDest;
PTSTR Pattern;
FILE_ENUM e;
//
// Cycle through all of the entries in the static copy files section.
//
if (InfFindFirstLine(g_Win95UpgInf,S_STATIC_COPY_FILES,NULL,&is)) {
do {
//
// For each entry, check to see if the file exists. If it does,
// add it into the memdb copy file section.
//
from = InfGetStringField(&is,0);
to = InfGetStringField(&is,1);
if (from && to) {
fromExpanded = ExpandEnvironmentText(from);
toExpanded = ExpandEnvironmentText(to);
Pattern = _tcsrchr (fromExpanded, TEXT('\\'));
//
// full path please
//
MYASSERT (Pattern);
if (!Pattern) {
continue;
}
*Pattern = 0;
Pattern++;
if (EnumFirstFile (&e, fromExpanded, Pattern)) {
do {
if (!StringIMatch (e.FileName, Pattern)) {
//
// pattern specified
//
toFinalDest = JoinPaths (toExpanded, e.FileName);
} else {
toFinalDest = toExpanded;
}
if (!IsFileMarkedForOperation (e.FullPath, OPERATION_FILE_DELETE)) {
MarkFileForCopy (e.FullPath, toFinalDest);
}
if (toFinalDest != toExpanded) {
FreePathString (toFinalDest);
}
} while (EnumNextFile (&e));
}
--Pattern;
*Pattern = TEXT('\\');
FreeText (toExpanded);
FreeText (fromExpanded);
}
} while (InfFindNextLine(&is));
}
InfCleanUpInfStruct(&is);
return rSuccess;
}
DWORD
CopyStaticFiles (
IN DWORD Request
)
{
switch (Request) {
case REQUEST_QUERYTICKS:
return TICKS_COPY_STATIC_FILES;
case REQUEST_RUN:
if (!pCopyStaticFiles ()) {
return GetLastError ();
}
else {
return ERROR_SUCCESS;
}
default:
DEBUGMSG ((DBG_ERROR, "Bad parameter in CopyStaticFiles."));
}
return 0;
}
DWORD
PreserveShellIcons (
IN DWORD Request
)
{
switch (Request) {
case REQUEST_QUERYTICKS:
return TICKS_PRESERVE_SHELL_ICONS;
case REQUEST_RUN:
if (!pPreserveShellIcons ()) {
return GetLastError ();
}
else {
return ERROR_SUCCESS;
}
default:
DEBUGMSG ((DBG_ERROR, "Bad parameter in PreserveShellIcons"));
}
return 0;
}
PCTSTR
GetWindowsInfDir(
VOID
)
{
PTSTR WindowsInfDir = NULL;
/*
NTBUG9:419428 - This registry entry is a semi-colon list of INF paths, and
it can contain Win9x source media INFs on OEM machines.
WindowsInfDir = (PTSTR) GetRegData (S_WINDOWS_CURRENTVERSION, S_DEVICEPATH);
*/
if (!WindowsInfDir) {
WindowsInfDir = (PTSTR) MemAlloc (g_hHeap, 0, SizeOfString (g_WinDir) + sizeof (S_INF));
StringCopy (WindowsInfDir, g_WinDir);
StringCopy (AppendWack (WindowsInfDir), S_INF);
}
return WindowsInfDir;
}
#ifndef SM_CMONITORS
#define SM_CMONITORS 80
#endif
BOOL
pProcessMiscMessages (
VOID
)
/*++
Routine Description:
pProcessMiscMessages performs runtime tests for items that are
incompatible, and it adds messages when the tests succeed.
Arguments:
None.
Return Value:
Always TRUE.
--*/
{
PCTSTR Group;
PCTSTR Message;
OSVERSIONINFO Version;
WORD CodePage;
LCID Locale;
if (GetSystemMetrics (SM_CMONITORS) > 1) {
//
// On Win95 and OSR2, GetSystemMetrics returns 0.
//
Group = BuildMessageGroup (MSG_INSTALL_NOTES_ROOT, MSG_MULTI_MONITOR_UNSUPPORTED_SUBGROUP, NULL);
Message = GetStringResource (MSG_MULTI_MONITOR_UNSUPPORTED);
if (Message && Group) {
MsgMgr_ObjectMsg_Add (TEXT("*MultiMonitor"), Group, Message);
}
FreeText (Group);
FreeStringResource (Message);
}
pWarnAboutOldDrivers();
//
// Save platform info
//
Version.dwOSVersionInfoSize = sizeof (Version);
GetVersionEx (&Version);
MemDbSetValueEx (
MEMDB_CATEGORY_STATE,
MEMDB_ITEM_MAJOR_VERSION,
NULL,
NULL,
Version.dwMajorVersion,
NULL
);
MemDbSetValueEx (
MEMDB_CATEGORY_STATE,
MEMDB_ITEM_MINOR_VERSION,
NULL,
NULL,
Version.dwMinorVersion,
NULL
);
MemDbSetValueEx (
MEMDB_CATEGORY_STATE,
MEMDB_ITEM_BUILD_NUMBER,
NULL,
NULL,
Version.dwBuildNumber,
NULL
);
MemDbSetValueEx (
MEMDB_CATEGORY_STATE,
MEMDB_ITEM_PLATFORM_ID,
NULL,
NULL,
Version.dwPlatformId,
NULL
);
MemDbSetValueEx (
MEMDB_CATEGORY_STATE,
MEMDB_ITEM_VERSION_TEXT,
NULL,
Version.szCSDVersion,
0,
NULL
);
GetGlobalCodePage (&CodePage, &Locale);
MemDbSetValueEx (
MEMDB_CATEGORY_STATE,
MEMDB_ITEM_CODE_PAGE,
NULL,
NULL,
CodePage,
NULL
);
MemDbSetValueEx (
MEMDB_CATEGORY_STATE,
MEMDB_ITEM_LOCALE,
NULL,
NULL,
Locale,
NULL
);
//
// Bad hard disk warning
//
if (!g_ConfigOptions.GoodDrive && HwComp_ReportIncompatibleController()) {
//
// Turn on boot loader flag
//
WriteInfKey (WINNT_DATA, WINNT_D_WIN95UNSUPHDC, S_ONE);
}
return TRUE;
}
DWORD
ProcessMiscMessages (
IN DWORD Request
)
{
switch (Request) {
case REQUEST_QUERYTICKS:
return TICKS_MISC_MESSAGES;
case REQUEST_RUN:
if (!pProcessMiscMessages()) {
return GetLastError ();
}
else {
return ERROR_SUCCESS;
}
default:
DEBUGMSG ((DBG_ERROR, "Bad parameter in ProcessSpecialKeys"));
}
return 0;
}
BOOL
pDeleteWinDirWackInf (
VOID
)
{
PCTSTR WindowsInfDir;
FILE_ENUM e;
DWORD count = 0;
//
// Delete all contents of c:\windows\inf.
//
WindowsInfDir = GetWindowsInfDir();
if (!WindowsInfDir) {
return FALSE;
}
if (EnumFirstFile (&e, WindowsInfDir, NULL)) {
do {
MarkFileForDelete (e.FullPath);
count++;
if (!(count % 32)) {
TickProgressBar ();
}
} while (EnumNextFile (&e));
}
MemFree (g_hHeap, 0, WindowsInfDir);
return TRUE;
}
DWORD
DeleteWinDirWackInf (
IN DWORD Request
)
{
switch (Request) {
case REQUEST_QUERYTICKS:
return TICKS_DELETE_WIN_DIR_WACK_INF;
case REQUEST_RUN:
if (!pDeleteWinDirWackInf ()) {
return GetLastError ();
}
else {
return ERROR_SUCCESS;
}
default:
DEBUGMSG ((DBG_ERROR, "Bad parameter in DeleteWinDirWackInf"));
}
return 0;
}
BOOL
pMoveWindowsIniFiles (
VOID
)
{
WIN32_FIND_DATA fd;
HANDLE FindHandle;
TCHAR WinDirPattern[MAX_TCHAR_PATH];
TCHAR FullPath[MAX_TCHAR_PATH];
TCHAR Key[MEMDB_MAX];
INFCONTEXT context;
DWORD result;
BOOL b = FALSE;
//
// build suppression table
//
if (SetupFindFirstLine (g_Win95UpgInf, S_INI_FILES_IGNORE, NULL, &context)) {
do {
if (SetupGetStringField (&context, 0, Key, MEMDB_MAX, NULL)) {
MemDbSetValueEx (
MEMDB_CATEGORY_INIFILES_IGNORE,
Key,
NULL,
NULL,
0,
NULL
);
}
} while (SetupFindNextLine (&context, &context));
}
//
// Scan %windir% for files
//
wsprintf (WinDirPattern, TEXT("%s\\*.ini"), g_WinDir);
FindHandle = FindFirstFile (WinDirPattern, &fd);
if (FindHandle != INVALID_HANDLE_VALUE) {
__try {
do {
//
// don't move and process specific INI files
//
MemDbBuildKey (Key, MEMDB_CATEGORY_INIFILES_IGNORE, fd.cFileName, NULL, NULL);
if (!MemDbGetValue (Key, &result)) {
wsprintf (FullPath, TEXT("%s\\%s"), g_WinDir, fd.cFileName);
if (CanSetOperation (FullPath, OPERATION_TEMP_PATH)) {
//
// see bug 317646
//
#ifdef DEBUG
if (StringIMatch (fd.cFileName, TEXT("netcfg.ini"))) {
continue;
}
#endif
MarkFileForTemporaryMove (FullPath, FullPath, g_TempDir);
MarkFileForBackup (FullPath);
}
}
ELSE_DEBUGMSG ((DBG_NAUSEA, "Ini File Ignored : %s\\%s", g_WinDir, fd.cFileName));
} while (FindNextFile (FindHandle, &fd));
b = TRUE;
}
__finally {
FindClose (FindHandle);
}
}
return b;
}
DWORD
MoveWindowsIniFiles (
IN DWORD Request
)
{
switch (Request) {
case REQUEST_QUERYTICKS:
return TICKS_MOVE_INI_FILES;
case REQUEST_RUN:
if (!pMoveWindowsIniFiles ()) {
return GetLastError ();
}
else {
return ERROR_SUCCESS;
}
default:
DEBUGMSG ((DBG_ERROR, "Bad parameter in MoveWindowsIniFiles"));
}
return 0;
}
PTSTR
pFindDosFile (
IN PTSTR FileName
)
{
WIN32_FIND_DATA findFileData;
PTSTR fullPathName = NULL;
PTSTR fullFileName = NULL;
HANDLE findHandle;
fullPathName = AllocPathString (MAX_TCHAR_PATH);
fullFileName = AllocPathString (MAX_TCHAR_PATH);
_tcsncpy (fullPathName, g_WinDir, MAX_TCHAR_PATH/sizeof (fullPathName [0]));
fullFileName = JoinPaths (fullPathName, FileName);
findHandle = FindFirstFile (fullFileName, &findFileData);
if (findHandle != INVALID_HANDLE_VALUE) {
FindClose (&findFileData);
FreePathString (fullPathName);
return fullFileName;
}
FreePathString (fullFileName);
StringCat (fullPathName, S_BOOT16_COMMAND_DIR);
fullFileName = JoinPaths (fullPathName, FileName);
findHandle = FindFirstFile (fullFileName, &findFileData);
if (findHandle != INVALID_HANDLE_VALUE) {
FindClose (&findFileData);
FreePathString (fullPathName);
return fullFileName;
}
FreePathString (fullPathName);
FreePathString (fullFileName);
return NULL;
}
BOOL
pSaveDosFile (
IN PTSTR FileName,
IN PTSTR FullFileName,
IN PTSTR TempPath
)
{
PTSTR newFileName = NULL;
newFileName = JoinPaths (TempPath, FileName);
if (!CopyFile (FullFileName, newFileName, FALSE)) {
DEBUGMSG ((DBG_WARNING, "BOOT16 : Cannot copy %s to %s", FullFileName, newFileName));
}
FreePathString (newFileName);
return TRUE;
}
VOID
pReportNoBoot16 (
VOID
)
/*
This function will report that BOOT16 option will not be available because the file system is going
to be converted to NTFS.
*/
{
PCTSTR ReportEntry;
PCTSTR ReportTitle;
PCTSTR Message;
PCTSTR Group;
PTSTR argArray[1];
ReportEntry = GetStringResource (MSG_INSTALL_NOTES_ROOT);
if (ReportEntry) {
argArray [0] = g_Win95Name;
ReportTitle = (PCTSTR)ParseMessageID (MSG_NO_BOOT16_WARNING_SUBGROUP, argArray);
if (ReportTitle) {
Message = (PCTSTR)ParseMessageID (MSG_NO_BOOT16_WARNING, argArray);
if (Message) {
Group = JoinPaths (ReportEntry, ReportTitle);
if (Group) {
MsgMgr_ObjectMsg_Add (TEXT("*NoBoot16"), Group, Message);
FreePathString (Group);
}
FreeStringResourcePtrA (&Message);
}
FreeStringResourcePtrA (&ReportTitle);
}
FreeStringResource (ReportEntry);
}
}
#define S_IOFILE TEXT("IO.SYS")
#define S_MSDOSFILE TEXT("MSDOS.SYS")
#define S_CONFIG_SYS TEXT("CONFIG.SYS")
#define S_AUTOEXEC_BAT TEXT("AUTOEXEC.BAT")
VOID
pMarkDosFileForChange (
IN PCTSTR FileName
)
{
pAddNtFile (g_BootDrivePath, FileName, TRUE, TRUE, TRUE);
}
BOOL
pSaveDosFiles (
VOID
)
{
HINF WkstaMigInf = INVALID_HANDLE_VALUE;
PTSTR boot16TempPath = NULL;
INFCONTEXT infContext;
PTSTR fileName = NULL;
PTSTR fullFileName = NULL;
PTSTR wkstaMigSource = NULL;
PTSTR wkstaMigTarget = NULL;
DWORD result;
TCHAR dir[MAX_PATH];
//
// For restore purposes, mark MSDOS environment as a Win9x OS file
//
pMarkDosFileForChange (S_IOFILE);
pMarkDosFileForChange (S_MSDOSFILE);
pMarkDosFileForChange (S_AUTOEXEC_BAT);
pMarkDosFileForChange (S_CONFIG_SYS);
//
// Now create a backup dir
//
if ((*g_Boot16 == BOOT16_YES) && (*g_ForceNTFSConversion)) {
WriteInfKey (S_WIN9XUPGUSEROPTIONS, TEXT("boot16"), S_NO);
//
// We no longer report the no boot16 message.
//
//pReportNoBoot16 ();
//
return TRUE;
}
if (*g_Boot16 == BOOT16_NO) {
WriteInfKey (S_WIN9XUPGUSEROPTIONS, TEXT("boot16"), S_NO);
}
else
if (*g_Boot16 == BOOT16_YES) {
WriteInfKey (S_WIN9XUPGUSEROPTIONS, TEXT("boot16"), S_YES);
}
else {
WriteInfKey (S_WIN9XUPGUSEROPTIONS, TEXT("boot16"), S_BOOT16_AUTOMATIC);
}
__try {
//prepare our temporary directory for saving dos7 files
boot16TempPath = JoinPaths (g_TempDir, S_BOOT16_DOS_DIR);
if (!CreateDirectory (boot16TempPath, NULL) && (GetLastError()!=ERROR_ALREADY_EXISTS)) {
LOG ((LOG_ERROR,"BOOT16 : Unable to create temporary directory %s",boot16TempPath));
__leave;
}
fileName = AllocPathString (MAX_TCHAR_PATH);
//load the files needed for booting in a 16 bit environment. The files are listed
//in wkstamig.inf section [Win95-DOS files]
wkstaMigSource = JoinPaths (SOURCEDIRECTORY(0), S_WKSTAMIG_INF);
wkstaMigTarget = JoinPaths (g_TempDir, S_WKSTAMIG_INF);
result = SetupDecompressOrCopyFile (wkstaMigSource, wkstaMigTarget, 0);
if ((result != ERROR_SUCCESS) && (result != ERROR_ALREADY_EXISTS)) {
LOG ((LOG_ERROR,"BOOT16 : Unable to decompress WKSTAMIG.INF"));
__leave;
}
WkstaMigInf = InfOpenInfFile (wkstaMigTarget);
if (WkstaMigInf == INVALID_HANDLE_VALUE) {
LOG ((LOG_ERROR,"BOOT16 : WKSTAMIG.INF could not be opened"));
__leave;
}
//read the section, for every file we are trying to find it in either %windir% or
//%windir%\command. If we find it, we'll just copy it to a safe place
if (!SetupFindFirstLine (
WkstaMigInf,
S_BOOT16_SECTION,
NULL,
&infContext
)) {
LOG ((LOG_ERROR,"Cannot read from %s section (WKSTAMIG.INF)",S_BOOT16_SECTION));
return TRUE;
}
do {
if (SetupGetStringField (
&infContext,
0,
fileName,
MAX_TCHAR_PATH/sizeof(fileName[0]),
NULL
)) {
//see if we can find this file either in %windir% or in %windir%\command
fullFileName = pFindDosFile (fileName);
if (fullFileName != NULL) {
pSaveDosFile (fileName, fullFileName, boot16TempPath);
FreePathString (fullFileName);
fullFileName = NULL;
}
}
}
while (SetupFindNextLine (&infContext, &infContext));
//OK, now save io.sys.
fullFileName = AllocPathString (MAX_TCHAR_PATH);
StringCopy (fullFileName, g_BootDrivePath);
StringCat (fullFileName, S_IOFILE);
pSaveDosFile (S_IOFILE, fullFileName, boot16TempPath);
FreePathString (fullFileName);
fullFileName = NULL;
}
__finally {
if (WkstaMigInf != INVALID_HANDLE_VALUE) {
InfCloseInfFile (WkstaMigInf);
}
if (boot16TempPath) {
FreePathString (boot16TempPath);
}
if (wkstaMigSource) {
FreePathString (wkstaMigSource);
}
if (wkstaMigTarget) {
DeleteFile (wkstaMigTarget);
FreePathString (wkstaMigTarget);
}
if (fileName) {
FreePathString (fileName);
}
}
return TRUE;
}
DWORD
SaveDosFiles (
IN DWORD Request
)
{
if (REPORTONLY()) {
return 0;
}
switch (Request) {
case REQUEST_QUERYTICKS:
return TICKS_SAVE_DOS_FILES;
case REQUEST_RUN:
if (!pSaveDosFiles ()) {
return GetLastError ();
}
else {
return ERROR_SUCCESS;
}
default:
DEBUGMSG ((DBG_ERROR, "Bad parameter in SaveDosFiles"));
}
return 0;
}
DWORD
InitWin95Registry (
IN DWORD Request
)
{
switch (Request) {
case REQUEST_QUERYTICKS:
return TICKS_INIT_WIN95_REGISTRY;
case REQUEST_RUN:
return Win95RegInit (g_WinDir, ISMILLENNIUM());
default:
DEBUGMSG ((DBG_ERROR, "Bad parameter in InitWin95Registry"));
}
return 0;
}
PDIRIDMAP
pFindDirId (
IN UINT DirId,
IN PDIRIDMAP BestGuess, OPTIONAL
IN BOOL Create
)
{
PDIRIDMAP map;
MYASSERT (Create || (g_HeadDirId && g_TailDirId));
//
// Find the existing dir ID. Check the caller's best guess first.
//
if (BestGuess && BestGuess->DirId == DirId) {
return BestGuess;
}
map = g_HeadDirId;
while (map) {
if (map->DirId == DirId) {
return map;
}
map = map->Next;
}
if (!Create) {
return NULL;
}
//
// Insert a new dir ID struct at the end of the list
//
map = (PDIRIDMAP) PoolMemGetAlignedMemory (g_DirIdPool, sizeof (DIRIDMAP));
if (g_TailDirId) {
g_TailDirId->Next = map;
} else {
g_HeadDirId = map;
}
g_TailDirId = map;
map->Next = NULL;
map->FirstDirPath = NULL;
map->DirId = DirId;
return map;
}
VOID
pInsertDirIdPath (
IN UINT DirId,
IN PCTSTR DirPath,
IN OUT PDIRIDMAP *BestGuess
)
{
PDIRIDPATH pathStruct;
PDIRIDPATH existingPathStruct;
PDIRIDMAP dirIdMap;
//
// Locate the dir ID structure, then append the DirPath to the
// list of paths for the ID
//
dirIdMap = pFindDirId (DirId, *BestGuess, TRUE);
MYASSERT (dirIdMap);
*BestGuess = dirIdMap;
existingPathStruct = dirIdMap->FirstDirPath;
while (existingPathStruct) {
if (StringIMatch (existingPathStruct->DirPath, DirPath)) {
return;
}
existingPathStruct = existingPathStruct->Next;
}
pathStruct = (PDIRIDPATH) PoolMemGetAlignedMemory (
g_DirIdPool,
sizeof (DIRIDPATH) + SizeOfString (DirPath)
);
pathStruct->Next = dirIdMap->FirstDirPath;
dirIdMap->FirstDirPath = pathStruct;
StringCopy (pathStruct->DirPath, DirPath);
}
BOOL
pConvertFirstDirName (
OUT PDIRNAME_ENUM EnumPtr,
IN PCTSTR DirNameWithId,
OUT PTSTR DirNameWithPath,
IN OUT PDIRIDMAP *LastDirIdMatch,
IN BOOL Convert11To1501
)
{
UINT id;
PDIRIDMAP idToPath;
EnumPtr->ResultBuffer = DirNameWithPath;
EnumPtr->LastMatch = NULL;
//
// Find the dir ID in the list of all dir IDs
//
id = _tcstoul (DirNameWithId, (PTSTR *) (&EnumPtr->SubPath), 10);
if (!id) {
DEBUGMSG ((DBG_WARNING, "Dir ID %s is not valid", DirNameWithId));
return FALSE;
}
DEBUGMSG_IF ((
EnumPtr->SubPath[0] != TEXT('\\') && EnumPtr->SubPath[0],
DBG_WHOOPS,
"Error in filelist.dat: non-numeric characters following LDID: %s",
DirNameWithId
));
if (Convert11To1501 && id == 11) {
id = 1501;
}
idToPath = pFindDirId (id, *LastDirIdMatch, FALSE);
if (!idToPath || !(idToPath->FirstDirPath)) {
DEBUGMSG ((DBG_WARNING, "Dir ID %s is not in the list and might not exist on the system", DirNameWithId));
return FALSE;
}
*LastDirIdMatch = idToPath;
EnumPtr->LastMatch = idToPath->FirstDirPath;
wsprintf (EnumPtr->ResultBuffer, TEXT("%s%s"), EnumPtr->LastMatch->DirPath, EnumPtr->SubPath);
return TRUE;
}
BOOL
pConvertNextDirName (
IN OUT PDIRNAME_ENUM EnumPtr
)
{
if (EnumPtr->LastMatch) {
EnumPtr->LastMatch = EnumPtr->LastMatch->Next;
}
if (!EnumPtr->LastMatch) {
return FALSE;
}
wsprintf (EnumPtr->ResultBuffer, TEXT("%s%s"), EnumPtr->LastMatch->DirPath, EnumPtr->SubPath);
return TRUE;
}
typedef struct _KNOWN_DIRS {
PCSTR DirId;
PCSTR *Translation;
}
KNOWN_DIRS, *PKNOWN_DIRS;
KNOWN_DIRS g_KnownDirs [] = {
{"10" , &g_WinDir},
{"11" , &g_System32Dir},
{"12" , &g_DriversDir},
{"17" , &g_InfDir},
{"18" , &g_HelpDir},
{"20" , &g_FontsDir},
{"21" , &g_ViewersDir},
{"23" , &g_ColorDir},
{"24" , &g_WinDrive},
{"25" , &g_SharedDir},
{"30" , &g_BootDrive},
{"50" , &g_SystemDir},
{"51" , &g_SpoolDir},
{"52" , &g_SpoolDriversDir},
{"53" , &g_ProfileDirNt},
{"54" , &g_BootDrive},
{"55" , &g_PrintProcDir},
{"1501" , &g_SystemDir},
{"1501" , &g_System32Dir},
{"7523" , &g_ProfileDir},
{"7523" , &g_CommonProfileDir},
{"16422", &g_ProgramFilesDir},
{"16427", &g_ProgramFilesCommonDir},
{"66002", &g_System32Dir},
{"66003", &g_ColorDir},
{NULL, NULL}
};
typedef struct {
PCSTR ShellFolderName;
PCSTR DirId;
} SHELL_TO_DIRS, *PSHELL_TO_DIRS;
SHELL_TO_DIRS g_ShellToDirs[] = {
{"Administrative Tools", "7501"},
{"Common Administrative Tools", "7501"},
{"AppData", "7502"},
{"Common AppData", "7502"},
{"Cache", "7503"},
{"Cookies", "7504"},
{"Desktop", "7505"},
{"Common Desktop", "7505"},
{"Favorites", "7506"},
{"Common Favorites", "7506"},
{"Fonts", "7507"},
{"History", "7508"},
{"Local AppData", "7509"},
{"Local Settings", "7510"},
{"My Music", "7511"},
{"CommonMusic", "7511"},
{"My Pictures", "7512"},
{"CommonPictures", "7512"},
{"My Video", "7513"},
{"CommonVideo", "7513"},
{"NetHood", "7514"},
{"Personal", "7515"},
{"Common Personal", "7515"},
{"Common Documents", "7515"},
{"PrintHood", "7516"},
{"Programs", "7517"},
{"Common Programs", "7517"},
{"Recent", "7518"},
{"SendTo", "7519"},
{"Start Menu", "7520"},
{"Common Start Menu", "7520"},
{"Startup", "7521"},
{"Common Startup", "7521"},
{"Templates", "7522"},
{"Common Templates", "7522"},
{"Profiles", "7523"},
{"Common Profiles", "7523"},
{NULL, NULL}
};
VOID
pAddKnownShellFolder (
IN PCTSTR ShellFolderName,
IN PCTSTR SrcPath
)
{
PSHELL_TO_DIRS p;
//
// Translate shell folder name into a dir ID
//
for (p = g_ShellToDirs ; p->ShellFolderName ; p++) {
if (StringIMatch (ShellFolderName, p->ShellFolderName)) {
break;
}
}
if (!p->ShellFolderName) {
DEBUGMSG ((DBG_ERROR, "This system has an unsupported shell folder tag: %s", ShellFolderName));
return;
}
//
// Record dir ID to path match in grow list
//
pInsertDirIdPath (_tcstoul (p->DirId, NULL, 10), SrcPath, &g_LastIdPtr);
}
VOID
pInitKnownDirs (
VOID
)
{
USERENUM eUser;
SF_ENUM e;
PKNOWN_DIRS p;
//
// Add all fixed known dirs to grow lists
//
for (p = g_KnownDirs ; p->DirId ; p++) {
pInsertDirIdPath (_tcstoul (p->DirId, NULL, 10), *(p->Translation), &g_LastIdPtr);
}
//
// Enumerate all users and put their shell folders in a known dirs struct
//
if (EnumFirstUser (&eUser, ENUMUSER_ENABLE_NAME_FIX)) {
do {
if (!(eUser.AccountType & INVALID_ACCOUNT)) {
if (eUser.AccountType & NAMED_USER) {
//
// Process the shell folders for this migrated user
//
if (EnumFirstRegShellFolder (&e, &eUser)) {
do {
pAddKnownShellFolder (e.sfName, e.sfPath);
} while (EnumNextRegShellFolder (&e));
}
}
}
} while (!CANCELLED() && EnumNextUser (&eUser));
if (EnumFirstRegShellFolder (&e, NULL)) {
do {
pAddKnownShellFolder (e.sfName, e.sfPath);
} while (!CANCELLED() && EnumNextRegShellFolder (&e));
}
}
}
VOID
pCleanUpKnownDirs (
VOID
)
{
if (g_DirIdPool) {
PoolMemDestroyPool (g_DirIdPool);
g_DirIdPool = NULL;
g_HeadDirId = NULL;
g_TailDirId = NULL;
}
}
VOID
pAddNtFile (
IN PCTSTR Dir, OPTIONAL
IN PCTSTR FileName, OPTIONAL
IN BOOL BackupThisFile,
IN BOOL CleanThisFile,
IN BOOL OsFile
)
{
TCHAR copyOfFileName[MAX_PATH];
PTSTR p;
PCTSTR fullPath;
BOOL freePath = FALSE;
DWORD offset;
TCHAR key[MEMDB_MAX];
DWORD value;
if (!Dir || !FileName) {
if (!Dir) {
MYASSERT (FileName);
fullPath = FileName;
} else {
fullPath = Dir;
}
StringCopy (copyOfFileName, fullPath);
p = _tcsrchr (copyOfFileName, TEXT('\\'));
if (p) {
*p = 0;
Dir = copyOfFileName;
FileName = p + 1;
} else {
DEBUGMSG ((DBG_WHOOPS, "Incomplete file name passed as NT OS file: %s", fullPath));
return;
}
} else {
fullPath = NULL;
}
MYASSERT (Dir);
MYASSERT (FileName);
if (OsFile) {
MemDbSetValueEx (
MEMDB_CATEGORY_NT_DIRS,
Dir,
NULL,
NULL,
0,
&offset
);
MemDbSetValueEx (
MEMDB_CATEGORY_NT_FILES,
FileName,
NULL,
NULL,
offset,
NULL
);
}
if (BackupThisFile || CleanThisFile) {
if (!fullPath) {
fullPath = JoinPaths (Dir, FileName);
freePath = TRUE;
}
if (BackupThisFile) {
//
// If the file exists, back it up (and don't clean it)
//
if (DoesFileExist (fullPath)) {
MarkFileForBackup (fullPath);
CleanThisFile = FALSE;
}
}
if (CleanThisFile) {
//
// Clean will cause the NT-installed file to be deleted
//
if (!DoesFileExist (fullPath)) {
MemDbBuildKey (
key,
MEMDB_CATEGORY_CLEAN_OUT,
fullPath,
NULL,
NULL
);
if (MemDbGetValue (key, &value)) {
if (value) {
DEBUGMSG ((
DBG_WARNING,
"File %s already in uninstall cleanout list with type %u",
fullPath,
value
));
}
return;
}
MemDbSetValue (key, 0);
}
}
if (freePath) {
FreePathString (fullPath);
}
}
}
VOID
pAddNtPath (
IN PCTSTR DirName,
IN BOOL ForceAsOsFile,
IN BOOL WholeTree,
IN BOOL ForceDirClean,
IN PCTSTR FilePattern, OPTIONAL
IN BOOL ForceFileClean OPTIONAL
)
{
TREE_ENUM e;
TCHAR rootDir[MAX_PATH];
PTSTR p;
BOOL b;
UINT type;
TCHAR key[MEMDB_MAX];
DWORD value;
MYASSERT (!_tcschr (DirName, TEXT('*')));
if (IsDriveExcluded (DirName)) {
DEBUGMSG ((DBG_VERBOSE, "Skipping %s because it is excluded", DirName));
return;
}
if (!IsDriveAccessible (DirName)) {
DEBUGMSG ((DBG_VERBOSE, "Skipping %s because it is not accessible", DirName));
return;
}
if (!WholeTree) {
b = EnumFirstFileInTreeEx (&e, DirName, FilePattern, FALSE, FALSE, 1);
} else {
b = EnumFirstFileInTree (&e, DirName, FilePattern, FALSE);
}
if (b) {
do {
if (e.Directory) {
continue;
}
StringCopy (rootDir, e.FullPath);
p = _tcsrchr (rootDir, TEXT('\\'));
if (p) {
*p = 0;
//
// Limit the file size to 5MB
//
if (e.FindData->nFileSizeHigh == 0 &&
e.FindData->nFileSizeLow <= 5242880
) {
pAddNtFile (rootDir, e.Name, TRUE, ForceFileClean, ForceAsOsFile);
}
ELSE_DEBUGMSG ((
DBG_WARNING,
"Not backing up big file %s. It is %I64u bytes.",
e.FullPath,
(ULONGLONG) e.FindData->nFileSizeHigh << 32 | (ULONGLONG) e.FindData->nFileSizeLow
));
}
} while (EnumNextFileInTree (&e));
}
if (ForceDirClean) {
type = WholeTree ? BACKUP_AND_CLEAN_TREE : BACKUP_AND_CLEAN_SUBDIR;
} else if (WholeTree) {
type = BACKUP_SUBDIRECTORY_TREE;
} else {
type = BACKUP_SUBDIRECTORY_FILES;
}
MemDbBuildKey (
key,
MEMDB_CATEGORY_CLEAN_OUT,
DirName,
NULL,
NULL
);
if (MemDbGetValue (key, &value)) {
if (!value && type) {
DEBUGMSG ((
DBG_WARNING,
"NT File %s already in uninstall cleanout list, overriding with type %u",
DirName,
type
));
} else {
if (value != type) {
DEBUGMSG ((
DBG_WARNING,
"NT File %s already in uninstall cleanout list with type %u",
DirName,
value
));
}
return;
}
}
MemDbSetValue (key, type);
}
VOID
pAddEmptyDirsTree (
IN PCTSTR RootDir
)
{
TREE_ENUM e;
DWORD attribs;
TCHAR key[MEMDB_MAX];
DWORD value;
if (IsDriveExcluded (RootDir)) {
DEBUGMSG ((DBG_VERBOSE, "Skipping empty dir tree of %s because it is excluded", RootDir));
return;
}
if (!IsDriveAccessible (RootDir)) {
DEBUGMSG ((DBG_VERBOSE, "Skipping empty dir tree of %s because it is not accessible", RootDir));
return;
}
if (DoesFileExist (RootDir)) {
if (EnumFirstFileInTreeEx (
&e,
RootDir,
NULL,
FALSE,
FALSE,
FILE_ENUM_ALL_LEVELS
)) {
do {
if (e.Directory) {
AddDirPathToEmptyDirsCategory (e.FullPath, TRUE, FALSE);
}
} while (EnumNextFileInTree (&e));
} else {
attribs = GetFileAttributes (RootDir);
if (attribs == FILE_ATTRIBUTE_DIRECTORY ||
attribs == INVALID_ATTRIBUTES
) {
attribs = 0;
}
MemDbBuildKey (
key,
MEMDB_CATEGORY_EMPTY_DIRS,
RootDir,
NULL,
NULL
);
if (MemDbGetValue (key, &value)) {
if (value) {
DEBUGMSG_IF ((
value != attribs,
DBG_ERROR,
"Ignoring conflict in empty dirs for %s",
RootDir
));
return;
}
}
MemDbSetValue (key, attribs);
}
}
ELSE_DEBUGMSG ((DBG_SYSMIG, "Uninstall: dir does not exist: %s", RootDir));
}
BOOL
ReadNtFilesEx (
IN PCSTR FileListName, //optional, if null default is opened
IN BOOL ConvertPath
)
{
PCSTR fileListName = NULL;
PCSTR fileListTmp = NULL;
HANDLE fileHandle = NULL;
HANDLE mapHandle = NULL;
PCSTR filePointer = NULL;
PCSTR dirPointer = NULL;
PCSTR filePtr = NULL;
DWORD offset;
DWORD version;
BOOL result = FALSE;
CHAR dirName [MEMDB_MAX];
PSTR p;
UINT u;
INFSTRUCT is = INITINFSTRUCT_POOLHANDLE;
PCTSTR fileName;
PCTSTR fileLoc;
PCTSTR dirId;
PCTSTR field3;
PCTSTR field4;
BOOL forceAsOsFile;
BOOL forceDirClean;
DIRNAME_ENUM nameEnum;
BOOL treeMode;
HINF drvIndex;
MEMDB_ENUM memdbEnum;
DWORD fileAttributes;
PCTSTR fullPath;
PCTSTR systemPath;
BOOL b;
PDIRIDMAP lastMatch = NULL;
UINT ticks = 0;
__try {
pInitKnownDirs();
//
// add to this list the dirs listed in [WinntDirectories] section of txtsetup.sif
//
if (InfFindFirstLine(g_TxtSetupSif, S_WINNTDIRECTORIES, NULL, &is)) {
//
// all locations are relative to %windir%
// prepare %windir%\
//
StringCopy (dirName, g_WinDir);
p = GetEndOfString (dirName);
*p++ = TEXT('\\');
do {
ticks++;
if ((ticks & 255) == 0) {
if (!TickProgressBarDelta (TICKS_READ_NT_FILES / 50)) {
__leave;
}
}
//
// For each entry, add the dir in memdb
//
fileLoc = InfGetStringField(&is, 1);
//
// ignore special entry "\"
//
if (fileLoc && !StringMatch(fileLoc, TEXT("\\"))) {
StringCopy (p, fileLoc);
MemDbSetValueEx (
MEMDB_CATEGORY_NT_DIRS,
dirName,
NULL,
NULL,
0,
NULL
);
pAddNtFile (NULL, dirName, FALSE, TRUE, FALSE);
}
} while (InfFindNextLine(&is));
}
if (FileListName != NULL) {
filePointer = MapFileIntoMemory (FileListName, &fileHandle, &mapHandle);
}
else {
for (u = 0 ; !fileListName && u < SOURCEDIRECTORYCOUNT() ; u++) {
fileListName = JoinPaths (SOURCEDIRECTORY(u), S_FILELIST_UNCOMPRESSED);
if (DoesFileExist (fileListName)) {
break;
}
FreePathString (fileListName);
fileListName = JoinPaths (SOURCEDIRECTORY(u), S_FILELIST_COMPRESSED);
if (DoesFileExist (fileListName)) {
fileListTmp = JoinPaths (g_TempDir, S_FILELIST_UNCOMPRESSED);
if (SetupDecompressOrCopyFile (fileListName, fileListTmp, 0) == NO_ERROR) {
FreePathString (fileListName);
fileListName = fileListTmp;
break;
}
DEBUGMSG ((DBG_ERROR, "Can't copy %s to %s", fileListName, fileListTmp));
__leave;
}
FreePathString (fileListName);
fileListName = NULL;
}
if (!fileListName) {
SetLastError (ERROR_FILE_NOT_FOUND);
DEBUGMSG ((DBG_ERROR, "Can't find %s", fileListName));
__leave;
}
filePointer = MapFileIntoMemory (fileListName, &fileHandle, &mapHandle);
if (!fileListTmp) {
FreePathString (fileListName);
}
}
filePtr = filePointer;
if (filePointer == NULL) {
DEBUGMSG ((DBG_ERROR, "Invalid file format: %s", fileListName));
__leave;
}
version = *((PDWORD) filePointer);
filePointer += sizeof (DWORD);
__try {
if (version >= 1) {
while (*filePointer != 0) {
ticks++;
if ((ticks & 255) == 0) {
if (!TickProgressBarDelta (TICKS_READ_NT_FILES / 50)) {
__leave;
}
}
dirPointer = filePointer;
filePointer = GetEndOfString (filePointer) + 1;
if (ConvertPath) {
//
// First loop: add the OS file exactly as it is in filelist.dat
//
if (pConvertFirstDirName (&nameEnum, dirPointer, dirName, &lastMatch, FALSE)) {
do {
pAddNtFile (dirName, filePointer, FALSE, FALSE, TRUE);
} while (pConvertNextDirName (&nameEnum));
}
//
// Second loop: add the file for backup, implementing the special system/system32 hack
//
if (pConvertFirstDirName (&nameEnum, dirPointer, dirName, &lastMatch, TRUE)) {
do {
pAddNtFile (dirName, filePointer, TRUE, FALSE, FALSE);
} while (pConvertNextDirName (&nameEnum));
}
} else {
pAddNtFile (dirPointer, filePointer, TRUE, FALSE, TRUE);
}
filePointer = GetEndOfString (filePointer) + 1;
}
if (version >= 2) {
filePointer ++;
while (*filePointer != 0) {
ticks++;
if ((ticks & 255) == 0) {
if (!TickProgressBarDelta (TICKS_READ_NT_FILES / 50)) {
__leave;
}
}
MemDbSetValueEx (
MEMDB_CATEGORY_NT_FILES_EXCEPT,
filePointer,
NULL,
NULL,
0,
NULL
);
filePointer = GetEndOfString (filePointer) + 1;
}
if (version >= 3) {
ticks++;
if ((ticks & 255) == 0) {
if (!TickProgressBarDelta (TICKS_READ_NT_FILES / 50)) {
__leave;
}
}
filePointer ++;
while (*filePointer != 0) {
dirPointer = filePointer;
filePointer = GetEndOfString (filePointer) + 1;
if (ConvertPath) {
if (pConvertFirstDirName (&nameEnum, dirPointer, dirName, &lastMatch, TRUE)) {
do {
pAddNtFile (dirName, filePointer, TRUE, FALSE, FALSE);
} while (pConvertNextDirName (&nameEnum));
}
} else {
pAddNtFile (dirPointer, filePointer, TRUE, FALSE, FALSE);
}
filePointer = GetEndOfString (filePointer) + 1;
}
}
}
}
}
__except (EXCEPTION_EXECUTE_HANDLER){
LOG ((LOG_ERROR, "Access violation while reading NT file list."));
__leave;
}
if (CANCELLED()) {
__leave;
}
// so far so good. Let's read static installed section from win95upg.inf
MYASSERT (g_Win95UpgInf);
//
// Cycle through all of the entries in the StaticInstalledFiles section.
//
if (InfFindFirstLine(g_Win95UpgInf,S_STATIC_INSTALLED_FILES,NULL,&is)) {
do {
ticks++;
if ((ticks & 255) == 0) {
if (!TickProgressBarDelta (TICKS_READ_NT_FILES / 50)) {
__leave;
}
}
//
// For each entry, add the file with it's location in memdb
//
fileName = InfGetStringField(&is,1);
fileLoc = InfGetStringField(&is,2);
if (fileName && fileLoc) {
if (ConvertPath) {
if (pConvertFirstDirName (&nameEnum, fileLoc, dirName, &lastMatch, FALSE)) {
do {
pAddNtFile (dirName, fileName, TRUE, FALSE, TRUE);
} while (pConvertNextDirName (&nameEnum));
}
} else {
pAddNtFile (fileLoc, fileName, TRUE, FALSE, TRUE);
}
}
} while (InfFindNextLine(&is));
}
//
// Add the files in drvindex.inf
//
drvIndex = InfOpenInfInAllSources (TEXT("drvindex.inf"));
if (drvIndex == INVALID_HANDLE_VALUE) {
LOG ((LOG_ERROR, "Can't open drvindex.inf."));
return FALSE;
}
if (InfFindFirstLine (drvIndex, TEXT("driver"), NULL, &is)) {
do {
ticks++;
if ((ticks & 255) == 0) {
if (!TickProgressBarDelta (TICKS_READ_NT_FILES / 50)) {
__leave;
}
}
fileName = InfGetStringField (&is, 1);
//
// Is this drive file already listed in the file list?
//
wsprintf (dirName, MEMDB_CATEGORY_NT_FILES TEXT("\\%s"), fileName);
if (MemDbGetValue (dirName, NULL)) {
DEBUGMSG ((DBG_SYSMIG, "%s is listed in drivers and in filelist.dat", fileName));
} else {
//
// Add this file
//
pAddNtFile (g_DriversDir, fileName, TRUE, TRUE, TRUE);
}
} while (InfFindNextLine (&is));
}
InfCloseInfFile (drvIndex);
//
// This code marks files to be backed up, because they aren't being caught
// through the regular mechanisms of setup.
//
if (InfFindFirstLine (g_Win95UpgInf, TEXT("Backup"), NULL, &is)) {
do {
ticks++;
if ((ticks & 255) == 0) {
if (!TickProgressBarDelta (TICKS_READ_NT_FILES / 50)) {
__leave;
}
}
InfResetInfStruct (&is);
dirId = InfGetStringField (&is, 1);
fileName = InfGetStringField (&is, 2);
field3 = InfGetStringField (&is, 3);
field4 = InfGetStringField (&is, 4);
if (dirId && *dirId == 0) {
dirId = NULL;
}
if (fileName && *fileName == 0) {
fileName = NULL;
}
if (field3 && *field3 == 0) {
field3 = NULL;
}
if (field4 && *field4 == 0) {
field4 = NULL;
}
if (!dirId) {
continue;
}
#ifdef DEBUG
if (!fileName) {
p = _tcsrchr (dirId, TEXT('\\'));
if (!p) {
p = (PTSTR) dirId;
}
p = _tcschr (p, TEXT('.'));
if (p) {
DEBUGMSG ((DBG_WHOOPS, "%s should be a dir spec, but it looks like it has a file.", dirId));
}
}
#endif
if (field3) {
forceAsOsFile = _ttoi (field3) != 0;
} else {
forceAsOsFile = FALSE;
}
if (field4) {
forceDirClean = _ttoi (field4) != 0;
} else {
forceDirClean = FALSE;
}
treeMode = FALSE;
p = _tcsrchr (dirId, TEXT('\\'));
if (p && p[1] == TEXT('*') && !p[2]) {
*p = 0;
treeMode = TRUE;
} else {
p = NULL;
}
if (ConvertPath) {
if (pConvertFirstDirName (&nameEnum, dirId, dirName, &lastMatch, FALSE)) {
do {
if (fileName && !treeMode) {
if (_tcsrchr (fileName, TEXT('*')) || _tcsrchr (fileName, TEXT('?'))) {
//
//Add files that match "fileName" pattern from "dirName" directory only
//
pAddNtPath (dirName, forceAsOsFile, FALSE, FALSE, fileName, TRUE);
} else {
//
//Add only one file "fileName"
//
pAddNtFile (dirName, fileName, TRUE, TRUE, forceAsOsFile);
}
} else {
if (INVALID_ATTRIBUTES == GetFileAttributes (dirName)) {
if (dirName[0] && dirName[1] == TEXT(':')) {
pAddNtPath (dirName, FALSE, treeMode, forceDirClean, NULL, FALSE);
}
} else {
//
//Add all files that match "fileName" pattern from whole tree starting from "dirName"
//
pAddNtPath (dirName, forceAsOsFile, treeMode, forceDirClean, fileName, FALSE);
}
}
} while (pConvertNextDirName (&nameEnum));
}
}
} while (InfFindNextLine (&is));
}
//
// In some cases, NT components create empty directories for future use.
// Some of them aren't ever used. Because setup does not know about
// them, we list the special cases in a win95upg.inf section called
// [Uninstall.Delete].
//
// For each entry, record the files or empty directories that need to be
// removed in an uninstall. If an directory is specified but is not empty,
// then it won't be altered during uninstall.
//
if (InfFindFirstLine (g_Win95UpgInf, TEXT("Uninstall.Delete"), NULL, &is)) {
do {
ticks++;
if ((ticks & 255) == 0) {
if (!TickProgressBarDelta (TICKS_READ_NT_FILES / 50)) {
__leave;
}
}
dirId = InfGetStringField (&is, 1);
fileName = InfGetStringField (&is, 2);
if (!dirId || *dirId == 0) {
continue;
}
if (fileName && *fileName == 0) {
fileName = NULL;
}
if (ConvertPath) {
if (pConvertFirstDirName (&nameEnum, dirId, dirName, &lastMatch, FALSE)) {
do {
pAddNtFile (dirName, fileName, FALSE, TRUE, FALSE);
} while (pConvertNextDirName (&nameEnum));
}
}
} while (InfFindNextLine (&is));
}
if (InfFindFirstLine (g_Win95UpgInf, TEXT("Uninstall.KeepEmptyDirs"), NULL, &is)) {
do {
ticks++;
if ((ticks & 255) == 0) {
if (!TickProgressBarDelta (TICKS_READ_NT_FILES / 50)) {
__leave;
}
}
dirId = InfGetStringField (&is, 1);
if (!dirId || *dirId == 0) {
continue;
}
if (ConvertPath) {
if (pConvertFirstDirName (&nameEnum, dirId, dirName, &lastMatch, FALSE)) {
do {
pAddEmptyDirsTree (dirName);
} while (pConvertNextDirName (&nameEnum));
}
}
} while (InfFindNextLine (&is));
}
result = TRUE;
}
__finally {
UnmapFile ((PVOID)filePtr, fileHandle, mapHandle);
if (fileListTmp) {
DeleteFile (fileListTmp);
FreePathString (fileListTmp);
fileListTmp = NULL;
}
InfCleanUpInfStruct(&is);
pCleanUpKnownDirs();
}
return CANCELLED() ? FALSE : result;
}
DWORD
ReadNtFiles (
IN DWORD Request
)
{
DWORD ticks = 0;
switch (Request) {
case REQUEST_QUERYTICKS:
return TICKS_READ_NT_FILES;
case REQUEST_RUN:
ProgressBar_SetComponentById (MSG_PREPARING_LIST);
ProgressBar_SetSubComponent (NULL);
if (!ReadNtFilesEx (NULL, TRUE)) {
return GetLastError ();
}
else {
return ERROR_SUCCESS;
}
default:
DEBUGMSG ((DBG_ERROR, "Bad parameter in ReadNtFiles"));
}
return 0;
}
BOOL
pIsDriverKnown (
IN PCTSTR DriverFileName,
IN PCTSTR FullPath,
IN BOOL DeleteMeansKnown
)
{
HANDLE h;
DWORD Status;
//
// Does DriverFileName have an extension? We require one.
// If no dot exists, then we assume this is something an OEM added.
//
if (!_tcschr (DriverFileName, TEXT('.'))) {
return TRUE;
}
//
// Is this file in migdb?
//
if (IsKnownMigDbFile (DriverFileName)) {
return TRUE;
}
//
// Is it going to be processed?
//
Status = GetFileStatusOnNt (FullPath);
if (Status != FILESTATUS_UNCHANGED) {
//
// If marked for delete, and DeleteMeansKnown is FALSE, then
// we consider the file unknown because it is simply being
// deleted as a cleanup step.
//
// If DeleteMeansKnown is TRUE, then the caller assumes that
// a file marked for delete is a known driver.
//
if (!(Status == FILESTATUS_DELETED) || DeleteMeansKnown) {
return TRUE;
}
}
//
// Make sure this is a NE header (or the more common case, the LE
// header)
//
h = OpenNeFile (FullPath);
if (!h) {
DEBUGMSG ((DBG_WARNING, "%s is not a NE file", FullPath));
//
// Is this a PE file? If so, the last error will be
// ERROR_BAD_EXE_FORMAT.
//
if (GetLastError() == ERROR_BAD_EXE_FORMAT) {
return FALSE;
}
DEBUGMSG ((DBG_WARNING, "%s is not a PE file", FullPath));
return TRUE;
}
CloseNeFile (h);
return FALSE;
}
BOOL
pWarnAboutOldDrivers (
VOID
)
{
HINF Inf;
TCHAR Path[MAX_TCHAR_PATH];
INFSTRUCT is = INITINFSTRUCT_GROWBUFFER;
BOOL b = FALSE;
PCTSTR Data;
PCTSTR DriverFile;
BOOL OldDriverFound = FALSE;
PCTSTR Group;
PCTSTR Message;
TCHAR FullPath[MAX_TCHAR_PATH];
GROWBUFFER FileList = GROWBUF_INIT;
PTSTR p;
wsprintf (Path, TEXT("%s\\system.ini"), g_WinDir);
Inf = InfOpenInfFile (Path);
if (Inf != INVALID_HANDLE_VALUE) {
if (InfFindFirstLine (Inf, TEXT("386Enh"), NULL, &is)) {
do {
Data = InfGetStringField (&is, 1);
if (Data) {
//
// Determine if device driver is known
//
if (_tcsnextc (Data) != TEXT('*')) {
DriverFile = GetFileNameFromPath (Data);
if (!_tcschr (Data, TEXT(':'))) {
if (!SearchPath (
NULL,
DriverFile,
NULL,
MAX_TCHAR_PATH,
FullPath,
NULL
)) {
_tcssafecpy (FullPath, Data, MAX_TCHAR_PATH);
}
} else {
_tcssafecpy (FullPath, Data, MAX_TCHAR_PATH);
}
if (!pIsDriverKnown (DriverFile, FullPath, TRUE)) {
//
// Unidentified driver; log it and turn on
// incompatibility message.
//
p = (PTSTR) GrowBuffer (&FileList, ByteCount (FullPath) + 7 * sizeof (TCHAR));
if (p) {
wsprintf (p, TEXT(" %s\r\n"), FullPath);
FileList.End -= sizeof (TCHAR);
}
OldDriverFound = TRUE;
MsgMgr_LinkObjectWithContext (TEXT("*386ENH"), Data);
} else {
DEBUGMSG ((DBG_NAUSEA, "Driver %s is known", Data));
}
}
}
} while (InfFindNextLine (&is));
}
ELSE_DEBUGMSG ((DBG_ERROR, "pWarnAboutOldDrivers: Cannot open %s", Path));
InfCloseInfFile (Inf);
InfCleanUpInfStruct (&is);
b = TRUE;
}
/*NTBUG9:155050
if (OldDriverFound) {
LOG ((LOG_INFORMATION, (PCSTR)MSG_386ENH_DRIVER_LOG, FileList.Buf));
Group = BuildMessageGroup (MSG_INCOMPATIBLE_HARDWARE_ROOT, MSG_OLD_DRIVER_FOUND_SUBGROUP, NULL);
Message = GetStringResource (MSG_OLD_DRIVER_FOUND_MESSAGE);
if (Message && Group) {
MsgMgr_ContextMsg_Add (TEXT("*386ENH"), Group, Message);
}
FreeText (Group);
FreeStringResource (Message);
}
*/
FreeGrowBuffer (&FileList);
return b;
}
DWORD
MoveSystemRegistry (
IN DWORD Request
)
{
PCTSTR path = NULL;
switch (Request) {
case REQUEST_QUERYTICKS:
return TICKS_MOVE_SYSTEMREGISTRY;
case REQUEST_RUN:
path = JoinPaths (g_WinDir, S_SYSTEMDAT);
MarkHiveForTemporaryMove (path, g_TempDir, NULL, TRUE, FALSE);
FreePathString (path);
//
// on Millennium, also save classes.dat hive
//
path = JoinPaths (g_WinDir, S_CLASSESDAT);
MarkHiveForTemporaryMove (path, g_TempDir, NULL, TRUE, FALSE);
FreePathString (path);
return ERROR_SUCCESS;
}
return 0;
}
VOID
pProcessJoystick (
PJOYSTICK_ENUM EnumPtr
)
{
PCTSTR Group;
TCHAR FullPath[MAX_TCHAR_PATH];
//
// Is this joystick compatible?
//
if (!_tcschr (EnumPtr->JoystickDriver, TEXT('\\'))) {
if (!SearchPath (NULL, EnumPtr->JoystickDriver, NULL, MAX_TCHAR_PATH, FullPath, NULL)) {
StringCopy (FullPath, EnumPtr->JoystickDriver);
}
} else {
StringCopy (FullPath, EnumPtr->JoystickDriver);
}
if (!pIsDriverKnown (GetFileNameFromPath (FullPath), FullPath, FALSE)) {
LOG ((
LOG_INFORMATION,
"Joystick driver for %s is not known: %s",
EnumPtr->JoystickName,
FullPath
));
Group = BuildMessageGroup (
MSG_INCOMPATIBLE_HARDWARE_ROOT,
MSG_JOYSTICK_SUBGROUP,
EnumPtr->JoystickName
);
MsgMgr_ObjectMsg_Add (
FullPath,
Group,
NULL
);
FreeText (Group);
}
}
DWORD
ReportIncompatibleJoysticks (
IN DWORD Request
)
{
JOYSTICK_ENUM e;
switch (Request) {
case REQUEST_QUERYTICKS:
return TICKS_JOYSTICK_DETECTION;
case REQUEST_RUN:
if (EnumFirstJoystick (&e)) {
do {
pProcessJoystick (&e);
} while (EnumNextJoystick (&e));
}
return ERROR_SUCCESS;
}
return 0;
}
DWORD
TwainCheck (
DWORD Request
)
{
TWAINDATASOURCE_ENUM e;
PCTSTR Group;
if (Request == REQUEST_QUERYTICKS) {
return TICKS_TWAIN;
} else if (Request != REQUEST_RUN) {
return 0;
}
if (EnumFirstTwainDataSource (&e)) {
do {
if (!TreatAsGood (e.DataSourceModule) &&
!pIsDriverKnown (
GetFileNameFromPath (e.DataSourceModule),
e.DataSourceModule,
FALSE
)) {
//
// Nobody handled the file. Generate a warning.
//
Group = BuildMessageGroup (
MSG_INCOMPATIBLE_HARDWARE_ROOT,
MSG_TWAIN_SUBGROUP,
e.DisplayName
);
MsgMgr_ObjectMsg_Add (
e.DataSourceModule,
Group,
NULL
);
MarkFileForDelete (e.DataSourceModule);
FreeText (Group);
}
} while (EnumNextTwainDataSource (&e));
}
return ERROR_SUCCESS;
}
DWORD
ProcessRecycleBins (
DWORD Request
)
{
ACCESSIBLE_DRIVE_ENUM e;
TREE_ENUM eFiles;
BOOL recycleFound;
UINT filesDeleted;
TCHAR recycledInfo[] = TEXT("x:\\recycled\\INFO");
TCHAR recyclerInfo[] = TEXT("x:\\recycler\\INFO");
TCHAR recycledInfo2[] = TEXT("x:\\recycled\\INFO2");
TCHAR recyclerInfo2[] = TEXT("x:\\recycler\\INFO2");
TCHAR recycled[] = TEXT("x:\\recycled");
TCHAR recycler[] = TEXT("x:\\recycler");
PTSTR dir;
PCTSTR args[1];
PCTSTR message;
PCTSTR group;
if (Request == REQUEST_QUERYTICKS) {
return TICKS_RECYCLEBINS;
}
else if (Request != REQUEST_RUN) {
return 0;
}
recycleFound = FALSE;
filesDeleted = 0;
//
// Enumerate through each of the accessible drives looking for
// a directory called RECYCLED or RECYCLER on the root.
//
if (GetFirstAccessibleDriveEx (&e, TRUE)) {
do {
dir = NULL;
//
// See if there is any recycle information to examine on
// this drive.
//
recycledInfo[0] = *e->Drive;
recyclerInfo[0] = *e->Drive;
recycledInfo2[0] = *e->Drive;
recyclerInfo2[0] = *e->Drive;
recycler[0] = *e->Drive;
recycled[0] = *e->Drive;
if (DoesFileExist (recycledInfo) || DoesFileExist (recycledInfo2)) {
dir = recycled;
}
else if (DoesFileExist(recyclerInfo) || DoesFileExist (recyclerInfo2)) {
dir = recycler;
}
if (dir) {
if (IsDriveExcluded (dir)) {
DEBUGMSG ((DBG_VERBOSE, "Skipping recycle dir %s because it is excluded", dir));
dir = NULL;
} else if (!IsDriveAccessible (dir)) {
DEBUGMSG ((DBG_VERBOSE, "Skipping recycle dir %s because it is not accessible", dir));
dir = NULL;
}
}
if (dir && EnumFirstFileInTree (&eFiles, dir, NULL, FALSE)) {
//
// We have work to do, Enumerate the files and mark them for
// deletion.
//
do {
//
// Mark the file for deletion, tally up the saved bytes, and free the space on the drive.
//
filesDeleted++;
FreeSpace (eFiles.FullPath,(eFiles.FindData->nFileSizeHigh * MAXDWORD) + eFiles.FindData->nFileSizeLow);
//
// only display Recycle Bin warning if there are visible files there
//
if (!(eFiles.FindData->dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)) {
recycleFound = TRUE;
}
} while (EnumNextFileInTree (&eFiles));
//
// We are going to delete all of this directory.
//
MemDbSetValueEx (MEMDB_CATEGORY_FULL_DIR_DELETES, dir, NULL, NULL, 0, NULL);
}
} while (GetNextAccessibleDrive (&e));
}
if (recycleFound) {
//
// We need to provide the user with a message.
//
wsprintf(recycled,"%d",filesDeleted);
args[0] = recycled;
group = BuildMessageGroup (MSG_INSTALL_NOTES_ROOT, MSG_RECYCLE_BIN_SUBGROUP, NULL);
message = ParseMessageID (MSG_RECYCLED_FILES_WILL_BE_DELETED, args);
if (message && group) {
MsgMgr_ObjectMsg_Add (TEXT("*RECYCLEBIN"), group, message);
FreeText (group);
FreeStringResource (message);
}
}
return 0;
}
DWORD
AnswerFileDetection (
IN DWORD Request
)
{
INFSTRUCT is = INITINFSTRUCT_GROWBUFFER;
TCHAR KeyStr[MAX_REGISTRY_KEY];
TCHAR EncodedKeyStr[MAX_ENCODED_RULE];
TCHAR ValueName[MAX_REGISTRY_VALUE_NAME];
TCHAR EncodedValueName[MAX_ENCODED_RULE];
PTSTR ValueDataPattern = NULL;
PBYTE ValueData = NULL;
PTSTR ValueDataStr = NULL;
PCTSTR p;
PTSTR q;
HKEY Key = NULL;
BOOL DefaultValue;
TCHAR SectionName[MAX_INF_SECTION_NAME];
TCHAR InfKey[MAX_INF_KEY_NAME];
TCHAR InfKeyData[MAX_INF_KEY_NAME];
DWORD Type;
DWORD Size;
BOOL Match;
UINT u;
switch (Request) {
case REQUEST_QUERYTICKS:
return TICKS_ANSWER_FILE_DETECTION;
case REQUEST_RUN:
if (InfFindFirstLine (g_Win95UpgInf, S_ANSWER_FILE_DETECTION, NULL, &is)) {
do {
__try {
//
// The first field has the key and optional value, encoded
// in the standard usermig.inf and wkstamig.inf syntax
//
DefaultValue = FALSE;
p = InfGetStringField (&is, 1);
if (!p || *p == 0) {
continue;
}
StackStringCopy (EncodedKeyStr, p);
q = _tcschr (EncodedKeyStr, TEXT('['));
if (q) {
StringCopy (EncodedValueName, SkipSpace (q + 1));
*q = 0;
q = _tcschr (EncodedValueName, TEXT(']'));
if (q) {
*q = 0;
}
ELSE_DEBUGMSG ((
DBG_WHOOPS,
"Unmatched square brackets in %s (see [%s])",
p,
S_ANSWER_FILE_DETECTION
));
if (*EncodedValueName == 0) {
DefaultValue = TRUE;
} else {
q = (PTSTR) SkipSpaceR (EncodedValueName, NULL);
if (q) {
*_mbsinc (q) = 0;
}
}
} else {
*EncodedValueName = 0;
}
q = (PTSTR) SkipSpaceR (EncodedKeyStr, NULL);
if (q) {
*_mbsinc (q) = 0;
}
DecodeRuleChars (KeyStr, EncodedKeyStr);
DecodeRuleChars (ValueName, EncodedValueName);
//
// The second field has the optional value data. If it
// is empty, then the value data is not tested.
//
p = InfGetStringField (&is, 2);
if (p && *p) {
ValueDataPattern = AllocText (CharCount (p) + 1);
StringCopy (ValueDataPattern, p);
} else {
ValueDataPattern = NULL;
}
//
// The third field has the section name
//
p = InfGetStringField (&is, 3);
if (!p || *p == 0) {
DEBUGMSG ((DBG_WHOOPS, "Section %s lacks a section name", S_ANSWER_FILE_DETECTION));
continue;
}
StackStringCopy (SectionName, p);
//
// The fourth field gives the INF key name
//
p = InfGetStringField (&is, 4);
if (!p || *p == 0) {
DEBUGMSG ((DBG_WHOOPS, "Section %s lacks an INF key", S_ANSWER_FILE_DETECTION));
continue;
}
StackStringCopy (InfKey, p);
//
// The fifth field is optional and gives the INF value name.
// The default is 1.
//
p = InfGetStringField (&is, 5);
if (p && *p != 0) {
StackStringCopy (InfKeyData, p);
} else {
StringCopy (InfKeyData, TEXT("1"));
}
//
// Data is gathered. Now test the rule.
//
DEBUGMSG ((
DBG_NAUSEA,
"Testing answer file setting.\n"
"Key: %s\n"
"Value Name: %s\n"
"Value Data: %s\n"
"Section: %s\n"
"Key: %s\n"
"Key Value: %s",
KeyStr,
*ValueName ? ValueName : DefaultValue ? TEXT("<default>") : TEXT("<unspecified>"),
ValueDataPattern ? ValueDataPattern : TEXT("<unspecified>"),
SectionName,
InfKey,
InfKeyData
));
Match = FALSE;
Key = OpenRegKeyStr (KeyStr);
if (Key) {
//
// Test the value name
//
if (*ValueName || DefaultValue) {
if (GetRegValueTypeAndSize (Key, ValueName, &Type, &Size)) {
//
// Test the value data
//
if (ValueDataPattern) {
//
// Get the data
//
ValueData = GetRegValueData (Key, ValueName);
if (!ValueData) {
MYASSERT (FALSE);
continue;
}
//
// Create the string
//
switch (Type) {
case REG_SZ:
case REG_EXPAND_SZ:
ValueDataStr = DuplicateText ((PCTSTR) ValueData);
break;
case REG_DWORD:
ValueDataStr = AllocText (11);
wsprintf (ValueDataStr, TEXT("0x%08X"), *((PDWORD) ValueData));
break;
default:
ValueDataStr = AllocText (3 * (max (1, Size)));
q = ValueDataStr;
for (u = 0 ; u < Size ; u++) {
if (u) {
*q++ = TEXT(' ');
}
wsprintf (q, TEXT("%02X"), ValueData[u]);
q += 2;
}
*q = 0;
break;
}
//
// Pattern-match the string
//
if (IsPatternMatch (ValueDataPattern, ValueDataStr)) {
DEBUGMSG ((DBG_NAUSEA, "Key, value name and value data found"));
Match = TRUE;
}
ELSE_DEBUGMSG ((
DBG_NAUSEA,
"Value data %s did not match %s",
ValueDataStr,
ValueDataPattern
));
} else {
DEBUGMSG ((DBG_NAUSEA, "Key and value name found"));
Match = TRUE;
}
}
ELSE_DEBUGMSG ((DBG_NAUSEA, "Value name not found, rc=%u", GetLastError()));
} else {
DEBUGMSG ((DBG_NAUSEA, "Key found"));
Match = TRUE;
}
}
ELSE_DEBUGMSG ((DBG_NAUSEA, "Key not found, rc=%u", GetLastError()));
if (Match) {
WriteInfKey (SectionName, InfKey, InfKeyData);
}
}
__finally {
if (Key) {
CloseRegKey (Key);
Key = NULL;
}
FreeText (ValueDataPattern);
ValueDataPattern = NULL;
if (ValueData) {
MemFree (g_hHeap, 0, ValueData);
ValueData = NULL;
}
FreeText (ValueDataStr);
ValueDataStr = NULL;
}
} while (InfFindNextLine (&is));
}
InfCleanUpInfStruct (&is);
return ERROR_SUCCESS;
}
return 0;
}
VOID
pAppendIniFiles (
IN HINF Inf,
IN PCTSTR Section,
IN PCTSTR MemDbCategory
)
/*++
Routine Description:
pAppendIniFiles reads from the specified INF from given section and appends
INI patterns to the multisz list IniFiles.
Arguments:
Inf - Specifies the source INF handle
Section - Specifies the section in that INF
MemDbCategory - Specifies the category in which to store INI patterns from that section
Return Value:
none
--*/
{
INFCONTEXT ctx;
TCHAR Field[MEMDB_MAX];
TCHAR IniPattern[MAX_PATH];
PTSTR IniPath;
if (SetupFindFirstLine (Inf, Section, NULL, &ctx)) {
do {
//
// INI file name is in the first value
//
if (SetupGetStringField (&ctx, 1, Field, MEMDB_MAX, NULL) && Field[0]) {
//
// now convert env vars
//
if (ExpandEnvironmentStrings (Field, IniPattern, MAX_PATH) > MAX_PATH) {
DEBUGMSG ((
DBG_ERROR,
"pAppendIniFiles: Invalid INI dir name in wkstamig.inf section [%s]; name too long",
Section
));
MYASSERT (FALSE);
continue;
}
IniPath = IniPattern;
//
// to speed up things while scanning file system, only check filenames
// with extension .INI; that means this section should only contain
// filenames with .INI extension (if a file with a different extension
// is needed, GatherIniFiles needs to be modified together
// with this function, i.e. to create here a list of extensions to be
// searched for)
//
MYASSERT (StringIMatch(GetDotExtensionFromPath (IniPattern), TEXT(".INI")));
//
// check for empty directory name
//
if (!_tcschr (IniPattern, TEXT('\\'))) {
//
// no dir name provided, assume %windir%
// reuse Field
//
StringCopy (Field, g_WinDir);
//
// construct new path
//
StringCopy (AppendWack (Field), IniPattern);
IniPath = Field;
}
//
// append filename to provided grow buffer
//
MemDbSetValueEx (MemDbCategory, IniPath, NULL, NULL, 0, NULL);
}
} while (SetupFindNextLine (&ctx, &ctx));
}
}
BOOL
pCreateIniCategories (
)
/*++
Routine Description:
pCreateIniCategories appends to multisz buffers that will
hold the patterns of INI files on which actions will be later performed on NT.
Arguments:
none
Return Value:
TRUE if success, FALSE if failure.
--*/
{
HINF WkstaMigInf = INVALID_HANDLE_VALUE;
PTSTR wkstaMigSource = NULL;
PTSTR wkstaMigTarget = NULL;
DWORD result;
BOOL b = FALSE;
__try {
wkstaMigSource = JoinPaths (SOURCEDIRECTORY(0), S_WKSTAMIG_INF);
wkstaMigTarget = JoinPaths (g_TempDir, S_WKSTAMIG_INF);
result = SetupDecompressOrCopyFile (wkstaMigSource, wkstaMigTarget, 0);
if ((result != ERROR_SUCCESS) && (result != ERROR_ALREADY_EXISTS)) {
LOG ((LOG_ERROR, "INI ACTIONS: Unable to decompress %s", wkstaMigSource));
__leave;
}
WkstaMigInf = InfOpenInfFile (wkstaMigTarget);
if (WkstaMigInf == INVALID_HANDLE_VALUE) {
LOG ((LOG_ERROR, "INI ACTIONS: %s could not be opened", wkstaMigTarget));
__leave;
}
pAppendIniFiles (WkstaMigInf, S_INIFILES_ACTIONS_FIRST, MEMDB_CATEGORY_INIFILES_ACT_FIRST);
pAppendIniFiles (WkstaMigInf, S_INIFILES_ACTIONS_LAST, MEMDB_CATEGORY_INIFILES_ACT_LAST);
b = TRUE;
}
__finally {
result = GetLastError ();
if (WkstaMigInf != INVALID_HANDLE_VALUE) {
InfCloseInfFile (WkstaMigInf);
}
if (wkstaMigTarget) {
DeleteFile (wkstaMigTarget);
FreePathString (wkstaMigTarget);
}
if (wkstaMigSource) {
FreePathString (wkstaMigSource);
}
SetLastError (result);
}
return b;
}
DWORD
InitIniProcessing (
IN DWORD Request
)
{
switch (Request) {
case REQUEST_QUERYTICKS:
return TICKS_INITINIPROCESSING;
case REQUEST_RUN:
if (!pCreateIniCategories ()) {
return GetLastError ();
}
return ERROR_SUCCESS;
}
return 0;
}