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