windows-nt/Source/XPSP1/NT/base/ntsetup/winnt32/dll/inspect.c

1606 lines
39 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
#include "precomp.h"
#pragma hdrstop
#include <stdio.h>
BOOL
LoadInfs(
IN HWND hdlg
);
BOOL
BuildCopyList(
IN HWND hdlg
);
BOOL
LoadAndRunMigrationDlls (
HWND hDlg
);
BOOL
ProcessCompatibilityData(
HWND hDlg
);
DWORD
ProcessCompatibilitySection(
LPVOID InfHandle,
LPTSTR SectionName
);
DWORD
InspectAndLoadThread(
IN PVOID ThreadParam
)
{
HWND hdlg;
BOOL b;
//
// Thread parameter is the handle of the page in the wizard.
//
hdlg = ThreadParam;
b = FALSE;
//
// If we're running the upgrade checker, fixup the title
// right away.
//
if (CheckUpgradeOnly) {
FixUpWizardTitle(GetParent(hdlg));
PropSheet_SetTitle(GetParent(hdlg),0,UIntToPtr( IDS_APPTITLE_CHECKUPGRADE ));
}
//
// Step 1: delete existing local sources.
//
CleanUpOldLocalSources(hdlg);
#ifdef _X86_ //NEC98
//
// If NEC98, Backup NT4 files
// boot.ini, NTLDR, NTDETECT
//
if (IsNEC98() && Floppyless)
{
SaveRestoreBootFiles_NEC98(NEC98SAVEBOOTFILES);
}
#endif //NEC98
//
// Step 2: inspect for HPFS, etc.
//
if(!InspectFilesystems(hdlg)) {
Cancelled = TRUE;
} else {
//
// Step 3: load inf(s).
//
if(LoadInfs(hdlg)) {
//
// Put in an "|| CheckUpgradeOnly" on these
// function calls because if we're really only
// checking the ability to upgrade, we want
// to continue even if one of these guys fails.
//
//
// Step 4: Check memory resources.
//
if( EnoughMemory( hdlg, FALSE ) || CheckUpgradeOnly ) {
//
// check for services to disable
//
ProcessCompatibilityData(hdlg);
#if defined(UNICODE) && defined(_X86_)
//
// Run Migration DLLs.
//
LoadAndRunMigrationDlls (hdlg);
#endif
//
// migrate any important data in boot.ini (like the countdown)
//
if (Upgrade) {
if (IsArc()) {
MigrateBootVarData();
} else {
#ifdef _X86_
MigrateBootIniData();
#endif
}
}
//
// Step 5: build the master file copy list.
//
if(CheckUpgradeOnly || BuildCopyList(hdlg)) {
//
// Step 6: look for a valid local source and check disk space.
//
if(FindLocalSourceAndCheckSpace(hdlg, FALSE, 0) || CheckUpgradeOnly) {
//
// Step 7:
//
// At this point we actually know everything we need to know
// in order to pass parameters to text mode setup.
//
if( CheckUpgradeOnly ) {
b = TRUE;
} else {
b = WriteParametersFile(hdlg);
if (IsArc()) {
#ifdef UNICODE // Always true for ARC, never true for Win9x upgrade
if(b) {
TCHAR Text[128];
LoadString(hInst,IDS_SETTING_NVRAM,Text,sizeof(Text)/sizeof(TCHAR));
SendMessage(hdlg,WMX_SETPROGRESSTEXT,0,(LPARAM)Text);
b = SetUpNvRam(hdlg);
}
#endif // UNICODE
} // if (IsArc())
}
#ifdef UNICODE
if( b && Upgrade
#ifdef _X86_
&& Floppyless
#endif
) {
//
// Do the migration of unsupported NT drivers.
// We can ignore the return code, since the fuction will inform the user if
// migration could not be done.
//
MigrateUnsupportedNTDrivers( hdlg, TxtsetupSif );
}
#endif // UNICODE
}
}
if(!b) {
UnloadInfFile(MainInf);
MainInf = NULL;
if(TxtsetupSif) {
UnloadInfFile(TxtsetupSif);
TxtsetupSif = NULL;
}
}
}
}
}
PostMessage(hdlg,WMX_INSPECTRESULT,(CheckUpgradeOnly ? TRUE : b),0);
return(0);
}
#if defined(UNICODE) && defined(_X86_)
LIST_ENTRY g_HandledData;
TCHAR g_MigDllAnswerFilePath[MAX_PATH];
DWORD GlobalCompFlags;
UINT g_MigDllIndex = 0;
#define HANDLED_REGISTRY 1
#define HANDLED_FILE 2
#define HANDLED_SERVICE 3
typedef struct {
LIST_ENTRY ListEntry;
LONG Type;
PCTSTR RegKey;
PCTSTR RegValue;
PCTSTR File;
PCTSTR Service;
} HANDLED_DATA, *PHANDLED_DATA;
BOOL
ResolveHandledIncompatibilities (
VOID
)
{
//
// At this point, all incompatibilities that will exist in the list are in place.
// we can now compare this with our list of handled data and remove
// anything a migration dll is taking care of.
//
PLIST_ENTRY nextHandled;
PLIST_ENTRY nextCompData;
PHANDLED_DATA handledData;
PCOMPATIBILITY_DATA compData;
BOOL remove;
nextHandled = g_HandledData.Flink;
if (!nextHandled) {
return TRUE;
}
while ((ULONG_PTR)nextHandled != (ULONG_PTR)&g_HandledData) {
handledData = CONTAINING_RECORD (nextHandled, HANDLED_DATA, ListEntry);
nextHandled = handledData->ListEntry.Flink;
nextCompData = CompatibilityData.Flink;
if (!nextCompData) {
return TRUE;
}
while ((ULONG_PTR)nextCompData != (ULONG_PTR)&CompatibilityData) {
compData = CONTAINING_RECORD (nextCompData, COMPATIBILITY_DATA, ListEntry);
nextCompData = compData->ListEntry.Flink;
remove = FALSE;
if (handledData->Type == HANDLED_REGISTRY && compData->RegKey && *compData->RegKey) {
if (!lstrcmpi (compData->RegKey, handledData->RegKey)) {
if (!handledData->RegValue || !lstrcmpi (compData->RegValue, handledData->RegValue)) {
remove = TRUE;
}
}
}
if (handledData->Type == HANDLED_SERVICE && compData->ServiceName && *compData->ServiceName) {
if (!lstrcmpi (compData->ServiceName, handledData->Service)) {
remove = TRUE;
}
}
if (handledData->Type == HANDLED_FILE && compData->FileName && *compData->FileName) {
if (!lstrcmpi (compData->FileName, handledData->File)) {
remove = TRUE;
}
}
//
// Migration dll has handled something. Remove it from the compatibility list.
//
if (remove) {
RemoveEntryList (&compData->ListEntry);
}
}
}
return TRUE;
}
BOOL
CallMigDllEntryPoints (
PMIGDLLENUM Enum
)
{
MIGRATIONDLL dll;
LONG rc;
if (!MigDllOpen (&dll, Enum->Properties->DllPath, GATHERMODE, FALSE, SOURCEOS_WINNT)) {
return FALSE;
}
__try {
rc = ERROR_SUCCESS;
if (!MigDllInitializeSrc (
&dll,
Enum->Properties->WorkingDirectory,
NativeSourcePaths[0],
Enum->Properties->SourceMedia,
NULL,
0
)) {
rc = GetLastError ();
}
if (rc != ERROR_SUCCESS) {
return FALSE;
}
if (!MigDllGatherSystemSettings (
&dll,
g_MigDllAnswerFilePath,
NULL,
0
)) {
rc = GetLastError ();
}
if (rc != ERROR_SUCCESS) {
return FALSE;
}
}
__finally {
MigDllClose (&dll);
}
return TRUE;
}
BOOL
ParseMigrateInf (
PCWSTR MigInfPath
)
{
PVOID migInf = NULL;
LONG lineCount;
LONG i;
PCTSTR type;
PHANDLED_DATA data;
PCTSTR regKey;
PCTSTR regValue;
PCTSTR file;
PCTSTR service;
if (LoadInfFile (MigInfPath, FALSE, &migInf) != ERROR_SUCCESS) {
return FALSE;
}
__try {
//
// Add any compatibility items to the list.
//
if( !CompatibilityData.Flink ) {
InitializeListHead( &CompatibilityData );
}
GlobalCompFlags = COMPFLAG_STOPINSTALL;
CompatibilityCount += ProcessCompatibilitySection (migInf, TEXT("ServicesToStopInstallation") );
if (CompatibilityCount) {
IncompatibilityStopsInstallation = TRUE;
}
GlobalCompFlags = 0;
CompatibilityCount += ProcessCompatibilitySection (migInf, TEXT("ServicesToDisable") );
//
// Add Handled compatibility items to the list.
//
lineCount = InfGetSectionLineCount (migInf, TEXT("Handled"));
if (lineCount && lineCount != -1) {
for (i=0; i < lineCount; i++) {
type = InfGetFieldByIndex (migInf, TEXT("Handled"), i, 0);
if (!type) {
continue;
}
if (!lstrcmpi (type, TEXT("Registry"))) {
regKey = InfGetFieldByIndex (migInf, TEXT("Handled"), i, 1);
regValue = InfGetFieldByIndex (migInf, TEXT("Handled"), i, 2);
if (regKey && *regKey) {
data = (PHANDLED_DATA) MALLOC (sizeof(HANDLED_DATA));
if (data == NULL) {
return FALSE;
}
ZeroMemory (data, sizeof (HANDLED_DATA));
data->Type = HANDLED_REGISTRY;
data->RegKey = regKey;
data->RegValue = regValue;
InsertTailList (&g_HandledData, &data->ListEntry);
}
}
else if (!lstrcmpi (type, TEXT("File"))) {
file = InfGetFieldByIndex (migInf, TEXT("Handled"), i, 1);
if (file && *file) {
data = (PHANDLED_DATA) MALLOC (sizeof(HANDLED_DATA));
if (data == NULL) {
return FALSE;
}
ZeroMemory (data, sizeof (HANDLED_DATA));
data->Type = HANDLED_FILE;
data->File = file;
InsertTailList (&g_HandledData, &data->ListEntry);
}
}
else if (!lstrcmpi (type, TEXT("Service"))) {
service = InfGetFieldByIndex (migInf, TEXT("Handled"), i, 1);
if (service && *service) {
data = (PHANDLED_DATA) MALLOC (sizeof(HANDLED_DATA));
if (data == NULL) {
return FALSE;
}
ZeroMemory (data, sizeof (HANDLED_DATA));
data->Type = HANDLED_SERVICE;
data->Service = service;
InsertTailList (&g_HandledData, &data->ListEntry);
}
}
}
}
}
__finally {
UnloadInfFile (migInf);
}
return TRUE;
}
VOID
SearchDirForMigDlls (
PCTSTR SearchDir,
PCTSTR BaseDir,
DLLLIST List
)
{
HANDLE findHandle;
WIN32_FIND_DATA findData;
MIGRATIONDLL dll;
WCHAR path[MAX_PATH];
PWSTR p;
WCHAR searchPath[MAX_PATH];
PMIGRATIONINFO migInfo;
PMIGDLLPROPERTIES dllProps = NULL;
WCHAR workingDir[MAX_PATH];
lstrcpy (searchPath, SearchDir);
ConcatenatePaths (searchPath, TEXT("*"), MAX_PATH);
findHandle = FindFirstFile (searchPath, &findData);
if (findHandle != INVALID_HANDLE_VALUE) {
lstrcpy (path, SearchDir);
p = _tcschr (path, 0);
if (p) {
do {
if (!lstrcmpi (findData.cFileName, TEXT("migrate.dll"))) {
*p = 0;
ConcatenatePaths (path, findData.cFileName, MAX_PATH);
if (!MigDllOpen (&dll, path, GATHERMODE, FALSE, SOURCEOS_WINNT)) {
continue;
}
if (!MigDllQueryMigrationInfo (&dll, TEXT("c:\\"), &migInfo)) {
MigDllClose (&dll);
continue;
}
if (migInfo->SourceOs == OS_WINDOWS9X || migInfo->TargetOs != OS_WINDOWSWHISTLER) {
continue;
}
//
// Do we already have a version of this migration dll?
//
dllProps = MigDllFindDllInList (List, migInfo->StaticProductIdentifier);
if (dllProps && dllProps->Info.DllVersion >= migInfo->DllVersion) {
MigDllClose (&dll);
continue;
}
else if (dllProps) {
MigDllRemoveDllFromList (List, migInfo->StaticProductIdentifier);
}
//
// Move dll locally.
//
wsprintf (workingDir, TEXT("%s\\mig%u"), BaseDir, g_MigDllIndex);
g_MigDllIndex++;
MigDllMoveDllLocally (&dll, workingDir);
//
// Add the dll to the list.
//
MigDllAddDllToList (List, &dll);
MigDllClose (&dll);
}
else if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && *findData.cFileName != TEXT('.')) {
*p = 0;
ConcatenatePaths (path, findData.cFileName, MAX_PATH);
SearchDirForMigDlls (path, BaseDir, List);
}
} while (FindNextFile (findHandle, &findData));
}
FindClose (findHandle);
}
}
#endif // UNICODE
#if defined(UNICODE) && defined(_X86_)
BOOL
LoadAndRunMigrationDlls (
HWND hDlg
)
{
HKEY regKey = NULL;
DWORD index;
DWORD nameSize;
DWORD valueSize;
DWORD type;
TCHAR valueName[MAX_PATH];
TCHAR value[MAX_PATH];
TCHAR baseDir[MAX_PATH];
TCHAR workingDir[MAX_PATH];
PTSTR p;
LONG rc;
DLLLIST list = NULL;
MIGRATIONDLL dll;
PMIGDLLPROPERTIES dllProps = NULL;
MIGDLLENUM e;
PMIGRATIONINFO migInfo;
TCHAR migInfPath[MAX_PATH];
HANDLE migInf;
TCHAR searchDir[MAX_PATH];
TCHAR tempDir[MAX_PATH];
*g_MigDllAnswerFilePath = 0;
//
// NT Upgrades only.
//
if (!ISNT() || !Upgrade) {
return TRUE;
}
/*NTBUG9:394164
//
// Win2k > Upgrades only.
//
if (BuildNumber <= NT40) {
return TRUE;
}
*/
__try {
if (!MigDllInit ()) {
return TRUE;
}
list = MigDllCreateList ();
if (!list) {
return TRUE;
}
InitializeListHead (&g_HandledData);
MyGetWindowsDirectory (baseDir, MAX_PATH);
ConcatenatePaths (baseDir, TEXT("Setup"), MAX_PATH);
lstrcpy (g_MigDllAnswerFilePath, baseDir);
lstrcpy (tempDir, baseDir);
ConcatenatePaths (g_MigDllAnswerFilePath, TEXT("migdll.txt"), MAX_PATH);
if(ActualParamFile[0]){
CopyFile(ActualParamFile, g_MigDllAnswerFilePath, FALSE);
}
//
// Scan registry for migration dlls and load them.
//
if (RegOpenKeyEx (
HKEY_LOCAL_MACHINE,
S_REGKEY_MIGRATION_DLLS_WINNT,
0,
KEY_READ | KEY_WRITE,
&regKey
) == ERROR_SUCCESS) {
//
// Enumerate Values.
//
index = 0;
do {
nameSize = MAX_PATH;
valueSize = MAX_PATH * sizeof (TCHAR);
rc = RegEnumValue (
regKey,
index,
valueName,
&nameSize,
NULL,
&type,
(PBYTE) value,
&valueSize
);
index++;
if (rc == ERROR_MORE_DATA) {
continue;
}
if (rc == ERROR_NO_MORE_ITEMS) {
break;
}
if (rc != ERROR_SUCCESS) {
return TRUE;
}
if (!MigDllOpen (&dll, value, GATHERMODE, FALSE, SOURCEOS_WINNT)) {
continue;
}
if (!MigDllQueryMigrationInfo (&dll, tempDir, &migInfo)) {
MigDllClose (&dll);
continue;
}
if (migInfo->SourceOs == OS_WINDOWS9X || migInfo->TargetOs != OS_WINDOWSWHISTLER) {
continue;
}
//
// Do we already have a version of this migration dll?
//
dllProps = MigDllFindDllInList (list, migInfo->StaticProductIdentifier);
if (dllProps && dllProps->Info.DllVersion >= migInfo->DllVersion) {
MigDllClose (&dll);
continue;
}
else {
MigDllRemoveDllFromList (list, migInfo->StaticProductIdentifier);
}
//
// Move dll locally.
//
wsprintf (workingDir, TEXT("%s\\mig%u"), baseDir, g_MigDllIndex);
g_MigDllIndex++;
MigDllMoveDllLocally (&dll, workingDir);
//
// Add the dll to the list.
//
MigDllAddDllToList (list, &dll);
MigDllClose (&dll);
} while (1);
}
//
// Now, look for dlls shipped with the source.
//
GetModuleFileName (NULL, searchDir, MAX_PATH);
p = _tcsrchr (searchDir, TEXT('\\'));
if (p) {
p++;
lstrcpy (p, TEXT("WINNTMIG"));
}
SearchDirForMigDlls (searchDir, baseDir, list);
//
// All dlls are now in the list. Lets run them.
//
ConcatenatePaths (baseDir, TEXT("dlls.inf"), MAX_PATH);
if (MigDllEnumFirst (&e, list)) {
WritePrivateProfileString (
TEXT("Version"),
TEXT("Signature"),
TEXT("\"$Windows NT$\""),
baseDir
);
do {
wsprintf (migInfPath, TEXT("%s\\migrate.inf"), e.Properties->WorkingDirectory);
migInf = CreateFile (
migInfPath,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (migInf == INVALID_HANDLE_VALUE) {
continue;
}
CloseHandle (migInf);
WritePrivateProfileString (
TEXT("Version"),
TEXT("Signature"),
TEXT("\"$Windows NT$\""),
migInfPath
);
if (!CallMigDllEntryPoints (&e)) {
MigDllRemoveDllInEnumFromList (list, &e);
}
else {
ParseMigrateInf (migInfPath);
WritePrivateProfileString (
TEXT("DllsToLoad"),
e.Properties->Info.StaticProductIdentifier,
e.Properties->DllPath,
baseDir
);
}
} while (MigDllEnumNext (&e));
WritePrivateProfileString (NULL, NULL, NULL, baseDir);
//
// Get rid of compatibility messages handled by migration dlls.
//
ResolveHandledIncompatibilities ();
}
}
__finally {
if (regKey) {
RegCloseKey (regKey);
}
if (list) {
MigDllFreeList (list);
}
}
return TRUE;
}
#endif
VOID
CleanUpOldLocalSources(
IN HWND hdlg
)
/*++
Routine Description:
Locate and delete old local source trees. All local fixed drives
are scanned for \$win_nt$.~ls, and if present, delnoded.
On x86, we also check the system partition for \$win_nt$.~bt
and give it the same treatment.
Arguments:
Return Value:
--*/
{
TCHAR Drive;
TCHAR Text[250];
TCHAR Filename[128];
LoadString(hInst,IDS_INSPECTING,Text,sizeof(Text)/sizeof(TCHAR));
SendMessage(hdlg,WMX_SETPROGRESSTEXT,0,(LPARAM)Text);
for(Drive=TEXT('A'); Drive<=TEXT('Z'); Drive++) {
if(MyGetDriveType(Drive) != DRIVE_FIXED) {
continue;
}
Filename[0] = Drive;
Filename[1] = TEXT(':');
Filename[2] = 0;
ConcatenatePaths(Filename,LOCAL_SOURCE_DIR,sizeof(Filename)/sizeof(TCHAR));
if(FileExists(Filename, NULL)) {
LoadString(hInst,IDS_REMOVING_OLD_TEMPFILES,Text,sizeof(Text)/sizeof(TCHAR));
SendMessage(hdlg,WMX_SETPROGRESSTEXT,0,(LPARAM)Text);
MyDelnode(Filename);
LoadString(hInst,IDS_INSPECTING,Text,sizeof(Text)/sizeof(TCHAR));
SendMessage(hdlg,WMX_SETPROGRESSTEXT,0,(LPARAM)Text);
}
}
if (!IsArc()) {
#ifdef _X86_
MYASSERT (SystemPartitionDriveLetter);
Filename[0] = SystemPartitionDriveLetter;
Filename[1] = TEXT(':');
Filename[2] = TEXT('\\');
lstrcpy(Filename+3,LOCAL_BOOT_DIR);
LoadString(hInst,IDS_REMOVING_OLD_TEMPFILES,Text,sizeof(Text)/sizeof(TCHAR));
SendMessage(hdlg,WMX_SETPROGRESSTEXT,0,(LPARAM)Text);
MyDelnode(Filename);
//
// Clean up backup directory, if it exists.
//
if(IsNEC98() && Floppyless) {
Filename[0] = SystemPartitionDriveLetter;
Filename[1] = TEXT(':');
Filename[2] = TEXT('\\');
lstrcpy(Filename+3,LOCAL_BACKUP_DIR);
MyDelnode(Filename);
}
#endif // _X86_
} // if (!IsArc())
}
BOOL
InspectSources(
HWND ParentWnd
)
/*++
Routine Description:
Check all sources given to ensure that they contain a valid
windows NT distribution. We do this simply by looking for
DOSNET.INF on each source.
Arguments:
ParentWnd - Specifies the handle of the parent window for any
error messages.
Return Value:
None.
--*/
{
UINT i,j;
TCHAR Filename[MAX_PATH];
TCHAR Text[512];
UINT OriginalCount;
HCURSOR OldCursor;
BOOL b = TRUE;
OldCursor = SetCursor (LoadCursor (NULL, IDC_WAIT));
OriginalCount = SourceCount;
//
// if we have a good alternate path then there
// is no need to verify the source paths
//
if (AlternateSourcePath[0]) {
lstrcpy(Filename,AlternateSourcePath);
ConcatenatePaths(Filename,InfName,MAX_PATH);
if(FileExists (Filename, NULL)) {
SetCursor (OldCursor);
return TRUE;
}
}
//
// verify each path
//
for (i=0; i<SourceCount; ) {
lstrcpy(Filename,NativeSourcePaths[i]);
ConcatenatePaths(Filename,InfName,MAX_PATH);
if(!FileExists (Filename, NULL)) {
//
// Source doesn't exist or isn't valid.
// Adjust the list.
//
for(j=i+1; j<SourceCount; j++) {
lstrcpy(NativeSourcePaths[j-1],NativeSourcePaths[j]);
lstrcpy(SourcePaths[j-1],SourcePaths[j]);
}
SourceCount--;
} else {
i++;
}
}
if (!SourceCount) {
//
// No sources are valid.
//
MessageBoxFromMessage(
ParentWnd,
(OriginalCount == 1) ? MSG_INVALID_SOURCE : MSG_INVALID_SOURCES,
FALSE,
AppTitleStringId,
MB_OK | MB_ICONWARNING | MB_TASKMODAL,
NativeSourcePaths[0]
);
//
// Set it to look like one source that is the empty string,
// so logic elsewhere will work correctly without special casing.
//
SourceCount = 1;
NativeSourcePaths[0][0] = 0;
SourcePaths[0][0] = 0;
b = FALSE;
}
SetCursor (OldCursor);
return b;
}
BOOL
LoadInfs(
IN HWND hdlg
)
/*++
Routine Description:
Load dosnet.inf from source 0. If upgrading and we're running
on NT then also load txtsetup.sif. If running on NT, load ntcompat.inf
Arguments:
hdlg - supplies handle of dialog to which progress messages
should be directed.
Return Value:
Boolean value indicating outcome. If FALSE then the user
will have been informed.
--*/
{
BOOL b;
LPCTSTR p;
TCHAR szPath[MAX_PATH];
if (!MainInf) {
b = LoadInfWorker(hdlg,InfName,&MainInf, TRUE);
if(!b) {
MessageBoxFromMessage(
NULL,
MSG_INVALID_INF_FILE,
FALSE,
AppTitleStringId,
MB_OK | MB_ICONINFORMATION | MB_TASKMODAL,
InfName
);
DebugLog( Winnt32LogError, TEXT("ERROR: Could not load dosnet.inf!"), 0);
goto c0;
}
} else {
b = TRUE;
}
if(p = InfGetFieldByKey(MainInf,TEXT("Miscellaneous"),TEXT("ProductType"),0)) {
ProductFlavor = _tcstoul(p,NULL,10);
Server = (ProductFlavor != PROFESSIONAL_PRODUCTTYPE && ProductFlavor != PERSONAL_PRODUCTTYPE);
UpgradeProductType = Server ? NT_SERVER : NT_WORKSTATION;
if( CheckUpgradeOnly ) {
AppTitleStringId = IDS_APPTITLE_CHECKUPGRADE;
} else if( ProductFlavor == PROFESSIONAL_PRODUCTTYPE ) {
AppTitleStringId = IDS_APPTITLE_WKS;
} else if( ProductFlavor == SERVER_PRODUCTTYPE ) {
AppTitleStringId = IDS_APPTITLE_SRV;
} else if( ProductFlavor == ADVANCEDSERVER_PRODUCTTYPE ) {
AppTitleStringId = IDS_APPTITLE_ASRV;
} else if( ProductFlavor == DATACENTER_PRODUCTTYPE ) {
AppTitleStringId = IDS_APPTITLE_DAT;
} else if( ProductFlavor == BLADESERVER_PRODUCTTYPE ) {
AppTitleStringId = IDS_APPTITLE_BLADE;
}
// AppTitleStringId = Server ? IDS_APPTITLE_SRV : IDS_APPTITLE_WKS;
FixUpWizardTitle(GetParent(hdlg));
PropSheet_SetTitle(GetParent(hdlg),0,UIntToPtr( AppTitleStringId ));
}
if(Upgrade && ISNT()) {
//
// If upgrading NT, pull in txtsetup.sif.
//
b = LoadInfWorker(hdlg,TEXTMODE_INF,&TxtsetupSif, FALSE);
if(!b) {
MessageBoxFromMessage(
NULL,
MSG_INVALID_INF_FILE,
FALSE,
AppTitleStringId,
MB_OK | MB_ICONINFORMATION | MB_TASKMODAL,
TEXTMODE_INF
);
TxtsetupSif = NULL;
DebugLog( Winnt32LogError, TEXT("ERROR: Could not load txtsetup.sif!"), 0);
goto c1;
}
}
if( ISNT()) {
b = FindPathToWinnt32File(NTCOMPAT_INF, szPath, MAX_PATH);
if(!b) {
NtcompatInf = NULL;
DebugLog( Winnt32LogError, TEXT("ERROR: Could not find ntcompat.inf!"), 0);
goto c2;
}
if(LoadInfFile( szPath,TRUE, &NtcompatInf) != NO_ERROR) {
MessageBoxFromMessage(
NULL,
MSG_INVALID_INF_FILE,
FALSE,
AppTitleStringId,
MB_OK | MB_ICONINFORMATION | MB_TASKMODAL,
szPath
);
b = FALSE;
NtcompatInf = NULL;
DebugLog( Winnt32LogError, TEXT("ERROR: Could not load ntcompat.inf!"), 0);
goto c2;
}
DebugLog (Winnt32LogInformation, TEXT("NTCOMPAT: Using %1"), 0, szPath);
}
return(b);
c2:
if( TxtsetupSif) {
UnloadInfFile(TxtsetupSif);
TxtsetupSif = NULL;
}
c1:
UnloadInfFile(MainInf);
MainInf = NULL;
c0:
return(b);
}
BOOL
BuildCopyList(
IN HWND hdlg
)
{
TCHAR Text[256];
LoadString(hInst,IDS_BUILDING_COPY_LIST,Text,sizeof(Text)/sizeof(TCHAR));
SendMessage(hdlg,WMX_SETPROGRESSTEXT,0,(LPARAM)Text);
SaveLanguageDirs();
return(BuildCopyListWorker(hdlg));
}
BOOL
FindLocalSourceAndCheckSpace(
IN HWND hdlg,
IN BOOL QuickTest,
IN LONGLONG AdditionalPadding
)
{
TCHAR Text[256];
if (!QuickTest) {
LoadString(hInst,IDS_CHECKING_SPACE,Text,sizeof(Text)/sizeof(TCHAR));
SendMessage(hdlg,WMX_SETPROGRESSTEXT,0,(LPARAM)Text);
}
return FindLocalSourceAndCheckSpaceWorker(hdlg, QuickTest, AdditionalPadding);
}
BOOL
EnoughMemory(
IN HWND hdlg,
IN BOOL QuickTest
)
{
LPCTSTR p;
MEMORYSTATUS MemoryStatus;
DWORD RequiredMemory;
SIZE_T RequiredMB, AvailableMB;
TCHAR buffer[64];
UpgRequiredMb = 0;
UpgAvailableMb = 0;
//
// Load the minimum memory requirements from the inf
//
if(GetMainInfValue (TEXT("Miscellaneous"),TEXT("MinimumMemory"), 0, buffer, 64)) {
RequiredMemory = _tcstoul(buffer,NULL,10);
//
// Got it. Now figure out how much we've got.
//
GlobalMemoryStatus( &MemoryStatus );
//
// Convert to MB, rounding up to nearest 4MB boundary...
//
RequiredMB = ((RequiredMemory + ((4*1024*1024)-1)) >> 22) << 2;
AvailableMB = ((MemoryStatus.dwTotalPhys + ((4*1024*1024)-1)) >> 22) << 2;
//
// Allow for UMA machine which may reservce 8MB for video
//
if( AvailableMB < (RequiredMB-8) ) {
if (!QuickTest) {
UpgRequiredMb = (DWORD)RequiredMB;
UpgAvailableMb = (DWORD)AvailableMB;
//
// Fail.
//
DebugLog( Winnt32LogInformation,
NULL,
MSG_NOT_ENOUGH_MEMORY,
AvailableMB,
RequiredMB );
SendMessage(hdlg,WMX_ERRORMESSAGEUP,TRUE,0);
MessageBoxFromMessage(
hdlg,
MSG_NOT_ENOUGH_MEMORY,
FALSE,
AppTitleStringId,
MB_OK | MB_ICONWARNING,
AvailableMB,
RequiredMB );
SendMessage(hdlg,WMX_ERRORMESSAGEUP,FALSE,0);
}
return( FALSE );
} else {
if (!QuickTest) {
TCHAR Buffer[MAX_PATH];
_stprintf( Buffer, TEXT("Detected %dMB of RAM.\n"), AvailableMB );
DebugLog( Winnt32LogInformation,
Buffer,
0 );
}
}
}
return( TRUE );
}
BOOL
LoadInfWorker(
IN HWND hdlg,
IN LPCTSTR FilenamePart,
OUT PVOID *InfHandle,
IN BOOL Winnt32File
)
{
DWORD d;
UINT u;
UINT Id;
TCHAR infPath[MAX_PATH];
TCHAR FormatString[128];
TCHAR Text[MAX_PATH+128];
BOOL b;
LoadString(hInst,IDS_LOADINGINF,Text,sizeof(Text)/sizeof(TCHAR));
SendMessage(hdlg,WMX_SETPROGRESSTEXT,0,(LPARAM)Text);
//
// use standard searching algorithm to get to the right INF
//
if (Winnt32File) {
b = FindPathToWinnt32File (FilenamePart, infPath, MAX_PATH);
} else {
b = FindPathToInstallationFile (FilenamePart, infPath, MAX_PATH);
}
if (b) {
d = LoadInfFile(infPath,TRUE,InfHandle);
if (d == NO_ERROR) {
return TRUE;
}
} else {
d = ERROR_FILE_NOT_FOUND;
}
switch(d) {
case NO_ERROR:
Id = 0;
break;
case ERROR_NOT_ENOUGH_MEMORY:
Id = MSG_OUT_OF_MEMORY;
break;
case ERROR_READ_FAULT:
//
// I/O error.
//
Id = MSG_CANT_LOAD_INF_IO;
break;
case ERROR_INVALID_DATA:
Id = MSG_CANT_LOAD_INF_SYNTAXERR;
break;
default:
Id = MSG_CANT_LOAD_INF_GENERIC;
break;
}
if(Id) {
SendMessage(hdlg,WMX_ERRORMESSAGEUP,TRUE,0);
MessageBoxFromMessage(
hdlg,
Id,
FALSE,
AppTitleStringId,
MB_OK | MB_ICONERROR | MB_TASKMODAL,
infPath
);
SendMessage(hdlg,WMX_ERRORMESSAGEUP,FALSE,0);
return(FALSE);
}
return(TRUE);
}
BOOL
WriteFileToLog(
const PTCHAR pszFileMetaName,
const PTCHAR pszActualFileName
)
{
HANDLE hActualFile = INVALID_HANDLE_VALUE;
BOOL fResult = FALSE;
DWORD cbBootIniSize, cbReadBootIniSize;
PUCHAR pszBuffer = NULL;
PTCHAR pszActualBuffer = NULL;
//
// Open the boot.ini file, get its size, convert it to the proper
// string type internally, and then log it out.
//
hActualFile = CreateFile(
pszActualFileName,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0,
NULL);
if ( hActualFile == INVALID_HANDLE_VALUE )
goto Exit;
cbBootIniSize = GetFileSize( hActualFile, NULL );
//
// Buffer we'll be reading the boot.ini into
//
if ((pszBuffer = MALLOC(cbBootIniSize)) == NULL) {
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto Exit;
}
if ( !ReadFile( hActualFile, pszBuffer, cbBootIniSize, &cbReadBootIniSize, NULL ) )
goto Exit;
//
// Ensure that we read as much as we really wanted.
//
if ( cbBootIniSize != cbReadBootIniSize ) {
DebugLog( Winnt32LogError,
TEXT("Error: %1 unable to be read entirely.\n"),
0,
pszFileMetaName);
goto Exit;
}
#ifdef UNICODE
pszActualBuffer = MALLOC( (cbBootIniSize + 3) * sizeof(TCHAR) );
MultiByteToWideChar(
CP_ACP,
0,
pszBuffer,
cbBootIniSize,
pszActualBuffer,
cbBootIniSize );
#else
pszActualBuffer = pszBuffer;
#endif
pszActualBuffer[cbBootIniSize] = 0;
//
// And write it out
//
DebugLog(
Winnt32LogInformation,
TEXT("%1 ----\n%2\n---- (from %3)\n"),
0,
pszFileMetaName,
pszActualBuffer,
pszActualFileName);
fResult = TRUE;
SetLastError(ERROR_SUCCESS);
Exit:
if ( hActualFile != INVALID_HANDLE_VALUE )
{
CloseHandle( hActualFile );
hActualFile = INVALID_HANDLE_VALUE;
}
#ifdef UNICODE
if ( pszActualBuffer != NULL )
#else
if ( ( pszActualBuffer != pszBuffer ) && ( pszActualBuffer != NULL ) )
#endif
{
FREE(pszActualBuffer);
pszActualBuffer = NULL;
}
if ( pszBuffer != NULL ) {
FREE(pszBuffer);
pszBuffer = NULL;
}
return fResult;
}
BOOL
InspectFilesystems(
IN HWND hdlg
)
{
TCHAR DriveRoot[4];
BOOL b;
TCHAR VolumeName[MAX_PATH];
DWORD SerialNumber;
DWORD MaxComponent;
BOOL Bogus[26];
TCHAR Filesystem[100];
TCHAR Drive;
DWORD Flags;
int i;
DriveRoot[1] = TEXT(':');
DriveRoot[2] = TEXT('\\');
DriveRoot[3] = 0;
ZeroMemory(Bogus,sizeof(Bogus));
for(Drive=TEXT('A'); Drive<=TEXT('Z'); Drive++) {
if(MyGetDriveType(Drive) != DRIVE_FIXED) {
continue;
}
DriveRoot[0] = Drive;
b = GetVolumeInformation(
DriveRoot,
VolumeName,MAX_PATH,
&SerialNumber,
&MaxComponent,
&Flags,
Filesystem,
sizeof(Filesystem)/sizeof(TCHAR)
);
if(b) {
//
// On NT, we want to warn about HPFS.
// On Win9x, we want to warn about doublespace/drivespace.
//
if(ISNT()) {
if(!lstrcmpi(Filesystem,TEXT("HPFS"))) {
Bogus[Drive-TEXT('A')] = TRUE;
}
} else {
if(Flags & FS_VOL_IS_COMPRESSED) {
Bogus[Drive-TEXT('A')] = TRUE;
}
}
}
}
#ifdef _X86_
if(ISNT()) {
TCHAR BootIniName[16];
DWORD dwAttributes;
//
// Disallow HPFS system partition. If someone figured out how
// to get an HPFS system partition on an ARC machine, more power
// to 'em.
//
MYASSERT (SystemPartitionDriveLetter);
if(SystemPartitionDriveLetter && Bogus[SystemPartitionDriveLetter-TEXT('A')]) {
MessageBoxFromMessage(
hdlg,
MSG_SYSPART_IS_HPFS,
FALSE,
AppTitleStringId,
MB_OK | MB_ICONERROR | MB_TASKMODAL,
SystemPartitionDriveLetter
);
return(FALSE);
}
/*
If we're upgrading NT, then log the existing boot.ini to the
logfiles for this pass. However, if that failed, then there
was something wrong - a missing boot.ini during an upgrade
is really a bad thing that should be snipped in the bud before
we go much further and copy files down, change system state,
etc.
*/
#ifdef PRERELEASE
if (Upgrade)
{
_stprintf(BootIniName, TEXT("%c:\\BOOT.INI"), SystemPartitionDriveLetter);
if ( !WriteFileToLog( TEXT("Boot configuration file while inspecting filesystems"), BootIniName ) )
{
MessageBoxFromMessage(
hdlg,
MSG_UPGRADE_INSPECTION_MISSING_BOOT_INI,
FALSE,
AppTitleStringId,
MB_OK | MB_ICONERROR | MB_TASKMODAL,
BootIniName );
return FALSE;
}
}
#endif
}
#endif
//
// User cannot upgrade a system on an HPFS/DriveSpace drive
//
MyGetWindowsDirectory(VolumeName,MAX_PATH);
if(Upgrade && Bogus[VolumeName[0]-TEXT('A')]) {
MessageBoxFromMessage(
hdlg,
ISNT() ? MSG_SYSTEM_ON_HPFS : MSG_SYSTEM_ON_CVF,
FALSE,
AppTitleStringId,
MB_OK | MB_ICONERROR | MB_TASKMODAL
);
return(FALSE);
}
//
// General case, HPFS data partition/compressed drive.
//
for(b=FALSE,Drive=0; !b && (Drive<26); Drive++) {
if(Bogus[Drive]) {
b = TRUE;
}
}
if(b) {
i = MessageBoxFromMessage(
hdlg,
ISNT() ? MSG_HPFS_DRIVES_EXIST : MSG_CVFS_EXIST,
FALSE,
AppTitleStringId,
MB_YESNO | MB_ICONQUESTION | MB_TASKMODAL
);
if(i == IDNO) {
return(FALSE);
}
}
return(TRUE);
}