windows-nt/Source/XPSP1/NT/base/ntsetup/textmode/kernel/spntupg.c
2020-09-26 16:20:57 +08:00

2204 lines
65 KiB
C

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
Spntupg.c
Abstract:
initializing and maintaining list of nts to upgrade
Author:
Sunil Pai (sunilp) 10-Nov-1993
Revision History:
--*/
#include "spprecmp.h"
#pragma hdrstop
//
// Major/minor version numbers of the system we're upgrading *from*
// if upgrading.
//
ULONG OldMajorVersion,OldMinorVersion;
//**************************************************************
// S E L E C T I N G N T T O U P G R A D E S T U F F
//**************************************************************
#define MENU_LEFT_X 3
#define MENU_WIDTH (VideoVars.ScreenWidth-(2*MENU_LEFT_X))
#define MENU_INDENT 4
VOID
pSpStepUpValidate(
VOID //IN BOOLEAN Server
);
BOOLEAN
SpGetStepUpMode(
IN PWSTR PidExtraData,
BOOLEAN *StepUpMode
);
BOOLEAN
pSpGetCurrentInstallVariation(
IN PWSTR szPid20,
OUT LPDWORD CurrentInstallVariation
);
VOID
SpGetUpgDriveLetter(
IN WCHAR DriveLetter,
IN PWCHAR Buffer,
IN ULONG BufferSize,
IN BOOL AddColon
);
VOID
SpCantFindBuildToUpgrade(
VOID
);
#ifdef _X86_
BOOLEAN
SpIsWin9xMsdosSys(
IN PDISK_REGION Region,
OUT PSTR* Win9xPath
);
#endif
VOID
SpGetFileVersion(
IN PVOID ImageBase,
OUT PULONGLONG Version
);
ENUMUPGRADETYPE
SpFindNtToUpgrade(
IN PVOID SifHandle,
OUT PDISK_REGION *TargetRegion,
OUT PWSTR *TargetPath,
OUT PDISK_REGION *SystemPartitionRegion,
OUT PWSTR *SystemPartitionDirectory
)
/*++
Routine Description:
This goes through the list of NTs on the system and finds out which are
upgradeable. Presents the information to the user and selects if he
wishes to upgrade an installed NT / install a fresh NT into the same
directory / select a different location for Windows NT.
If the chosen target is too full user is offered to exit setup to create
space/ choose new target.
Arguments:
SifHandle: Handle the txtsetup.sif
TargetRegion: Variable to receive the partition of the Windows NT to install
NULL if not chosen. Caller should not free.
TargetPath: Variable to receive the target path of Windows NT. NULL if
not decided. Caller can free.
SystemPartitionRegion:
Variable to receive the system partition of the Windows NT
NULL if not chosen. Caller should not free.
Return Value:
UpgradeFull: If user chooses to upgrade an NT
UpgradeInstallFresh: If user chooses to install fresh into an existing NT
tree.
DontUpgrade: If user chooses to cancel upgrade and choose a fresh
tree for installation
--*/
{
ENUMUPGRADETYPE UpgradeType;
UPG_PROGRESS_TYPE UpgradeProgressValue;
NTSTATUS NtStatus;
ULONG i,j;
ULONG UpgradeBootSets;
ULONG PidIndex;
PSP_BOOT_ENTRY BootEntry;
PSP_BOOT_ENTRY ChosenBootEntry;
PSP_BOOT_ENTRY MatchedSet = NULL;
ULONG UpgradeOnlyBootSets;
PVOID p;
PWSTR Pid;
ULONG TotalSizeOfFilesOnOsWinnt = 0;
PWSTR UniqueIdFromSif;
PWSTR UniqueIdFromReg;
BOOLEAN Compliant;
BOOLEAN WindowsUpgrade;
BOOLEAN ComplianceChecked;
PWSTR EulaComplete;
DWORD Version = 0, BuildNumber = 0;
DetermineSourceVersionInfo(&Version, &BuildNumber);
//
// If we know we're upgrading NT (chosen during winnt32) then fetch the
// unique id from the parameters file. This will be used later to
// find the system to be upgraded.
//
UniqueIdFromSif = NULL;
p = SpGetSectionKeyIndex(WinntSifHandle,SIF_DATA,WINNT_D_NTUPGRADE_W,0);
if(p && !_wcsicmp(p,WINNT_A_YES_W)) {
UniqueIdFromSif = SpGetSectionKeyIndex(WinntSifHandle,SIF_DATA,SIF_UNIQUEID,0);
if(!UniqueIdFromSif) {
SpFatalSifError(WinntSifHandle,SIF_DATA,SIF_UNIQUEID,0,0);
}
}
//
// Go through all boot sets, looking for upgradeable ones.
//
SpDetermineUniqueAndPresentBootEntries();
UpgradeBootSets = 0;
UpgradeOnlyBootSets = 0;
PidIndex = 0;
for(BootEntry = SpBootEntries; BootEntry != NULL; BootEntry = BootEntry->Next) {
//
// The set's upgradeable flag might already be 0, such as it if was
// a duplicate entry in boot.ini/nv-ram.
// After we've checked for this reset the upgradeable flag for this
// boot set to FALSE in preparation for validating upgreadeability below.
//
if (!BootEntry->Processable) {
continue;
}
BootEntry->Processable = FALSE;
Pid = NULL;
BootEntry->LangId = -1;
//
// Determine various things about the build identified by the
// current boot set (product type -- srv, wks, etc; version and
// build numbers, upgrade progress value, unique id winnt32 put
// in there if any, etc).
//
// Based on the information, we will update the UpgradeableList and
// initialize FailedUpgradeList.
//
NtStatus = SpDetermineProduct(
BootEntry->OsPartitionDiskRegion,
BootEntry->OsDirectory,
&BootEntry->ProductType,
&BootEntry->MajorVersion,
&BootEntry->MinorVersion,
&BootEntry->BuildNumber,
&BootEntry->ProductSuiteMask,
&UpgradeProgressValue,
&UniqueIdFromReg,
&Pid,
NULL, // ignore eval variation flag
&BootEntry->LangId,
&BootEntry->ServicePack
);
if(!NT_SUCCESS(NtStatus)) {
continue;
}
//
// Determine if this installation matches the one we're supposed
// to upgrade (the one the user ran winnt32 on). If this is
// a winnt32 based installation, there is no need to do a
// compliance test as this was already completed during winnt32.
//
if(UniqueIdFromReg) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpFindNtToUpgrade: BootEntry = %p, RegId = %S, UniqueId = %S\n", BootEntry, UniqueIdFromReg, UniqueIdFromSif));
if(UniqueIdFromSif && (MatchedSet == NULL)
&& !wcscmp(UniqueIdFromSif,UniqueIdFromReg)) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpFindNtToUpgrade: found a match!\n"));
MatchedSet = BootEntry;
BootEntry->Processable = TRUE;
}
SpMemFree(UniqueIdFromReg);
UniqueIdFromReg = NULL;
}
if (BootEntry->Processable == FALSE) {
//
// this is set to TRUE if this is the build we ran winnt32 upgrade
// from -- in all other cases we need to do a compliance test
// to determine if this is a valid build to upgrade
//
Compliant = pSpIsCompliant( Version,
BuildNumber,
BootEntry->OsPartitionDiskRegion,
BootEntry->OsDirectory,
&BootEntry->UpgradeOnlyCompliance );
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpFindNtToUpgrade says UpgradeableList[%p] compliance test is %s, upgrade only : %s\n",
BootEntry,
Compliant ? "TRUE" : "FALSE" ,
BootEntry->UpgradeOnlyCompliance ? "TRUE" : "FALSE"
));
BootEntry->Processable = Compliant;
if (BootEntry->UpgradeOnlyCompliance) {
UpgradeOnlyBootSets++;
}
}
if(BootEntry->Processable) {
UpgradeBootSets++;
//
// Save the Pid only if it is Pid20
//
if(wcslen(Pid) == 20) {
BootEntry->Pid20Array = Pid;
} else {
SpMemFree(Pid);
}
} else {
SpMemFree(Pid);
}
BootEntry->FailedUpgrade = (UpgradeProgressValue == UpgradeInProgress);
}
//
// Winnt32 displays the EULA which signifies that compliance checking has been
// completed
//
EulaComplete = SpGetSectionKeyIndex(WinntSifHandle, SIF_DATA,WINNT_D_EULADONE_W, 0);
if(EulaComplete && SpStringToLong(EulaComplete, NULL, 10)) {
ComplianceChecked = TRUE;
} else {
ComplianceChecked = FALSE;
}
//
// don't try to validate if we are upgrading a Win3.X or Win9X installation
//
#ifdef _X86_
WindowsUpgrade = SpIsWindowsUpgrade(WinntSifHandle);
#else
WindowsUpgrade = FALSE;
#endif // _X86_
//
// In step-up mode, we need to ensure that the user has a qualifiying product.
//
//
// If we couldn't find it on the machine, go perform additional validation
// steps.
//
if(StepUpMode && !UpgradeBootSets && !WindowsUpgrade && !ComplianceChecked) {
pSpStepUpValidate();
}
//
// If we are supposed to be upgrading NT then make sure we found
// the system we're supposed to upgrade.
//
if(UniqueIdFromSif) {
if(MatchedSet == NULL) {
SpCantFindBuildToUpgrade();
}
ChosenBootEntry = MatchedSet;
UpgradeType = UpgradeFull;
OldMajorVersion = ChosenBootEntry->MajorVersion;
OldMinorVersion = ChosenBootEntry->MinorVersion;
#ifndef _X86_
//
// On non-x86 platforms, especially alpha machines that in general
// have small system partitions (~3 MB), we compute the size
// of the files on \os\winnt (ie osloader.exe and hal.dll),
// and consider this size as available disk space. We can do this
// since these files will be overwritten by the new ones.
// This fixes the problem that we see on Alpha, when the system
// partition is too full.
//
SpFindSizeOfFilesInOsWinnt(
SifHandle,
ChosenBootEntry->LoaderPartitionDiskRegion,
&TotalSizeOfFilesOnOsWinnt
);
//
// Transform the size into KB
//
TotalSizeOfFilesOnOsWinnt /= 1024;
#endif
//
// If a previous upgrade attempt on this build failed
// (say the power went out in the middle) then we will try to
// upgrade it again. We can't offer to install a fresh build
// because we're not sure we can reliably complete it
// (for example winnt32.exe might copy down only a subset of files
// across the net when it knows the user ios upgrading and so
// initial install could fail because of missing files, etc).
//
// If the disk is too full then the user is hosed. Tell him and exit.
//
if(ChosenBootEntry->FailedUpgrade) {
SppResumingFailedUpgrade(
ChosenBootEntry->OsPartitionDiskRegion,
ChosenBootEntry->OsDirectory,
ChosenBootEntry->FriendlyName,
FALSE
);
}
} else {
//
// Not upgrading. However for PSS we allow the user to upgrade a build
// "in place" as a sort of emergency repair thing. The build has to be
// the same build number as the one we're installing.
//
UpgradeType = DontUpgrade;
//
// Also, if the user is upgrading Windows 95 or we're in unattended mode
// then we don't ask the user anything.
//
p = SpGetSectionKeyIndex(WinntSifHandle,SIF_DATA,WINNT_D_WIN95UPGRADE_W,0);
if(!UnattendedOperation && (!p || _wcsicmp(p,WINNT_A_YES_W))) {
//
// Eliminate from the upgradeable list those builds which
// don't match.
//
j = 0;
for(BootEntry = SpBootEntries; BootEntry != NULL; BootEntry = BootEntry->Next) {
if(BootEntry->Processable) {
if (!SpDoBuildsMatch(
SifHandle,
BootEntry->BuildNumber,
BootEntry->ProductType,
BootEntry->ProductSuiteMask,
AdvancedServer,
SuiteType,
BootEntry->LangId)) {
BootEntry->Processable = FALSE;
j++;
}
}
}
UpgradeBootSets -= j;
if(UpgradeBootSets) {
//
// Find out if the user wants to "upgrade" one of these.
//
UpgradeType = SppSelectNTToRepairByUpgrade(
&ChosenBootEntry
);
#ifndef _X86_
SpFindSizeOfFilesInOsWinnt(
SifHandle,
ChosenBootEntry->LoaderPartitionDiskRegion,
&TotalSizeOfFilesOnOsWinnt
);
TotalSizeOfFilesOnOsWinnt /= 1024;
#endif
if(UpgradeType == UpgradeFull) {
//
// Check for resume case and inform user.
//
if(ChosenBootEntry->FailedUpgrade) {
//
// If user cancelled then lets try to do a
// clean install
//
if (!SppResumingFailedUpgrade(
ChosenBootEntry->OsPartitionDiskRegion,
ChosenBootEntry->OsDirectory,
ChosenBootEntry->FriendlyName,
TRUE
)) {
UpgradeType = DontUpgrade;
}
} else {
//
// Everything is OK.
//
OldMajorVersion = ChosenBootEntry->MajorVersion;
OldMinorVersion = ChosenBootEntry->MinorVersion;
}
}
}
}
}
//
// Depending on upgrade selection made do the setup needed before
// we do the upgrade
//
if(UpgradeType == UpgradeFull) {
PWSTR p1,p2,p3;
//
// Set the upgrade status to upgrading in the current system hive
//
SpSetUpgradeStatus(
ChosenBootEntry->OsPartitionDiskRegion,
ChosenBootEntry->OsDirectory,
UpgradeInProgress
);
//
// Return the region we are installing onto
//
*TargetRegion = ChosenBootEntry->OsPartitionDiskRegion;
*TargetPath = SpDupStringW(ChosenBootEntry->OsDirectory);
*SystemPartitionRegion = ChosenBootEntry->LoaderPartitionDiskRegion;
StandardServerUpgrade = ( AdvancedServer &&
( ChosenBootEntry->ProductType == NtProductWinNt ) ||
( ChosenBootEntry->ProductType == NtProductServer )
);
//
// Process the osloader variable to extract the system partition path.
// The var could be of the form ...partition(1)\os\nt\... or
// ...partition(1)os\nt\...
// So we search forward for the first \ and then backwards for
// the closest ) to find the start of the directory. We then
// search backwards in the resulting string for the last \ to find
// the end of the directory.
//
p1 = ChosenBootEntry->LoaderFile;
p2 = wcsrchr(p1, L'\\');
if (p2 == NULL) {
p2 = p1;
}
i = (ULONG)(p2 - p1);
if(i == 0) {
*SystemPartitionDirectory = SpDupStringW(L"");
} else {
p2 = p3 = SpMemAlloc((i+2)*sizeof(WCHAR));
ASSERT(p3);
if(*p1 != L'\\') {
*p3++ = L'\\';
}
wcsncpy(p3, p1, i);
p3[i] = 0;
*SystemPartitionDirectory = p2;
}
}
//
// Clean up and return,
//
CLEAR_CLIENT_SCREEN();
return(UpgradeType);
}
BOOLEAN
pSpGetCdInstallType(
IN PWSTR PathToCd,
OUT PULONG CdInstallType,
OUT PULONG CdInstallVersion
)
{
#define BuildMatch(_filename_,_type_,_ver_) \
FileName = _filename_; \
b = SpNFilesExist(PathToCd,&FileName,1,FALSE); \
if (b) { \
*CdInstallType = _type_; \
*CdInstallVersion = _ver_; \
} \
//return(TRUE); \
BOOLEAN b;
//
// Directories that are present on all known NT CD-ROM's.
//
//
// ISSUE:2000/27/07:vijayj: this code seems really busted. In looking at a handful of cd's, none
// of the nt cd's seem to conform to these rules listed
// also looks like there might be "per architecture" tag files as well.
//
//Check for both dirs to exist? Definitely nt4 has these. Some pre RTM w2k cds have them
PWSTR ListAllPreNT5[] = { L"alpha", L"i386" };
//wk2 RTM , whistler and nt4 have thse two dirs. They differ by tag file.
PWSTR ListAllNT5[] = { L"i386", L"support" };
PWSTR ListAllNec98[] = { L"pc98",L"support" }; //NEC98
PWSTR ListAllEntNT4[] = { L"alpha", L"i386", L"SP3" };
//
// Directories which must be present if a CD is a 3.51 or a 4.0 CD-ROM,
// workstation or server. Note that the ppc directory distinguishes
// 3.51 from 3.5.
//
PWSTR List351_40[] = { L"mips", L"ppc" };
//
// directories which must be present if a CD is a win95 or win98 cd-rom.
//
PWSTR ListWin95[] = { L"win95", L"drivers" };
PWSTR ListWin98[] = { L"win98", L"drivers" };
PWSTR ListWinME[] = { L"win9x", L"drivers" };
PWSTR FileName;
//
// check for NT4 enterprise
//
b = SpNFilesExist(
PathToCd,
ListAllEntNT4,
sizeof(ListAllEntNT4)/sizeof(ListAllEntNT4[0]),
TRUE
);
if (b) {
BuildMatch(L"cdrom_s.40", COMPLIANCE_INSTALLTYPE_NTSE, 400);
if (b) {
return(TRUE);
}
}
//
// check for various subsets of NT < NT5
//
b = SpNFilesExist(
PathToCd,
(!IsNEC_98) ? ListAllPreNT5 : ListAllNec98, //NEC98
(!IsNEC_98) ? sizeof(ListAllPreNT5)/sizeof(ListAllPreNT5[0]) : sizeof(ListAllNec98)/sizeof(ListAllNec98[0]), //NEC98
TRUE
);
if(b) {
//
// hydra (terminal server) is a special case (since it does not
// have mips and ppc directory).
//
BuildMatch(L"cdrom_ts.40", COMPLIANCE_INSTALLTYPE_NTS, 400);
if (b) {
return TRUE;
}
//
// OK, it could be an NT CD of some kind, but it could be
// 3.1, 3.5, 3.51, 4.0. It could also be
// server or workstation. Narrow down to 3.51/4.0.
//
b = SpNFilesExist(PathToCd,List351_40,
sizeof(List351_40)/sizeof(List351_40[0]),TRUE);
if(b) {
//
// If we get here, we know it can only be either 3.51 or 4.0.
// Look for 3.51.
//
BuildMatch(L"cdrom.s", COMPLIANCE_INSTALLTYPE_NTS, 351);
if (b) {
return(TRUE);
}
BuildMatch(L"cdrom.w", COMPLIANCE_INSTALLTYPE_NTW, 351);
if (b) {
return(TRUE);
}
//
// Look for 4.0.
//
BuildMatch(L"cdrom_s.40", COMPLIANCE_INSTALLTYPE_NTS, 400);
if (b) {
return(TRUE);
}
BuildMatch(L"cdrom_w.40", COMPLIANCE_INSTALLTYPE_NTW, 400);
if (b) {
return(TRUE);
}
} else {
//
// Find out if its one of the NT 4.0 service pack CDs
//
BuildMatch(L"cdrom_s.40", COMPLIANCE_INSTALLTYPE_NTS, 400);
if (b) {
return(TRUE);
}
BuildMatch(L"cdrom_w.40", COMPLIANCE_INSTALLTYPE_NTW, 400);
if (b) {
return(TRUE);
}
//
// Not 3.51 or 4.0. Check for 5.0 beta 1 and beta2
//
//How is this possible to be 5.0 unless alpha dir exists on cd.
//
// Post beta 1 the tag files changed to support per architecture tags
// but beta 2 still has alpha directories
//
// We could possibly just check to see if cdrom_w.50 isn't
// there, but the NT3.1 CD would then pass so we need to
// check explicitly for the 5.0 beta CDs.
//
BuildMatch(L"cdrom_s.5b1", COMPLIANCE_INSTALLTYPE_NTS, 500);
if (b) {
return(FALSE); //eval
}
BuildMatch(L"cdrom_w.5b1", COMPLIANCE_INSTALLTYPE_NTW, 500);
if (b) {
return(FALSE); //eval
}
BuildMatch(L"cdrom_s.5b2", COMPLIANCE_INSTALLTYPE_NTS, 500);
if (b) {
return(FALSE); //eval
}
BuildMatch(L"cdrom_w.5b2", COMPLIANCE_INSTALLTYPE_NTW, 500);
if (b) {
return(FALSE); //eval
}
BuildMatch(L"cdrom_s.5b3", COMPLIANCE_INSTALLTYPE_NTS, 500);
if (b) {
return(FALSE); //eval
}
BuildMatch(L"cdrom_w.5b3", COMPLIANCE_INSTALLTYPE_NTW, 500);
if (b) {
return(FALSE); //eval
}
BuildMatch(L"cdrom_is.5b2", COMPLIANCE_INSTALLTYPE_NTS, 500);
if (b) {
return(FALSE); //eval
}
BuildMatch(L"cdrom_iw.5b2", COMPLIANCE_INSTALLTYPE_NTW, 500);
if (b) {
return(FALSE); //eval
}
BuildMatch(L"cdrom_ie.5b2", COMPLIANCE_INSTALLTYPE_NTSE, 500);
if (b) {
return(FALSE); //eval
}
//Do we need to check for eval nt5.1 here? No since alpha dir doesnt exist on the cds.
//
// if we made it this far, it must be nt 3.1/3.5
//
// we just mark the version as 3.5 since we don't allow upgradescd o
// from either type of install.
//
*CdInstallType = COMPLIANCE_INSTALLTYPE_NTW;
*CdInstallVersion = 350;
return(TRUE);
}
}
//
// look for various nt5 beta cds.
// // Could also be nt5.1 since cd also contains same dir.
//
// note that we don't check 5.0 retail since that would allow the retail CD to
// validate itself, which defeats the purpose entirely.
//
// Post NT5 beta 1 the tag files changed to support per architecture tags so we have
// a massive ifdef below
//
//
b = SpNFilesExist(
PathToCd,
ListAllNT5,
sizeof(ListAllNT5)/sizeof(ListAllNT5[0]),
TRUE
);
if (b) {
//
// we might have some flavour of NT5 beta cd, but we're not sure which one
//
BuildMatch(L"cdrom_s.5b1", COMPLIANCE_INSTALLTYPE_NTS, 500);
if (b) {
return(FALSE); //eval
}
BuildMatch(L"cdrom_w.5b1", COMPLIANCE_INSTALLTYPE_NTW, 500);
if (b) {
return(FALSE); //eval
}
BuildMatch(L"cdrom_is.5b2", COMPLIANCE_INSTALLTYPE_NTS, 500);
if (b) {
return(FALSE); //eval
}
BuildMatch(L"cdrom_iw.5b2", COMPLIANCE_INSTALLTYPE_NTW, 500);
if (b) {
return(FALSE); //eval
}
BuildMatch(L"cdrom_ie.5b2", COMPLIANCE_INSTALLTYPE_NTSE, 500);
if (b) {
return(FALSE); //eval
}
BuildMatch(L"cdrom_is.5b3", COMPLIANCE_INSTALLTYPE_NTS, 500);
if (b) {
return(FALSE); //eval
}
BuildMatch(L"cdrom_iw.5b3", COMPLIANCE_INSTALLTYPE_NTW, 500);
if (b) {
return(FALSE); //eval
}
BuildMatch(L"cdrom_ie.5b3", COMPLIANCE_INSTALLTYPE_NTSE, 500);
if (b) {
return(FALSE); //eval
}
BuildMatch(L"cdrom_nt.51", COMPLIANCE_INSTALLTYPE_NTW, 501);
if (b) {
return(FALSE); //pre beta1 whistler
}
BuildMatch(L"wen51.b1", COMPLIANCE_INSTALLTYPE_NTW, 501);
if (b) {
return(FALSE); //beta 1 whistler
}
BuildMatch(L"win51.b2", COMPLIANCE_INSTALLTYPE_NTW, 501);
if (b) {
return(FALSE); //beta 1 whistler
}
BuildMatch(L"win51.rc1", COMPLIANCE_INSTALLTYPE_NTW, 501);
if (b) {
return(FALSE); //rc1 whistler
}
}
//
// check for win95
//
b = SpNFilesExist(PathToCd, ListWin95, sizeof(ListWin95)/sizeof(ListWin95[0]),TRUE );
if (b) {
*CdInstallType = COMPLIANCE_INSTALLTYPE_WIN9X;
*CdInstallVersion = 950;
return TRUE;
}
//
// check for win98
//
b = SpNFilesExist(PathToCd, ListWin98, sizeof(ListWin98)/sizeof(ListWin98[0]),TRUE );
if (b) {
*CdInstallType = COMPLIANCE_INSTALLTYPE_WIN9X;
*CdInstallVersion = 1998;
return TRUE;
}
//
// check for winME
//
b = SpNFilesExist(PathToCd, ListWinME, sizeof(ListWinME)/sizeof(ListWinME[0]),TRUE );
if (b) {
*CdInstallType = COMPLIANCE_INSTALLTYPE_WIN9X;
*CdInstallVersion = 3000;
return TRUE;
}
//At this point we have rejected w2k beta cds. However we need to reject wk2 eval cds.
//We should accept w2k stepup media so the next check is only for 5.1
//Need to accept nt5.1 eval cds.!!Ask rajj to verify.
// Need to reject nt5.1 step-up cds.
// Need to reject nt5.1 rtm cds? Looks like we accept RTM FPP?
//
// could be NT 5.1 CD-ROM (make sure its not eval media)
//
if (!b) { //check is not needed.
NTSTATUS Status;
CCMEDIA MediaObj;
WCHAR InfDir[MAX_PATH];
wcscpy(InfDir, PathToCd);
SpConcatenatePaths(InfDir, (IsNEC_98 ? ListAllNec98[0] : ListAllNT5[0]));
Status = SpGetMediaDetails(InfDir, &MediaObj);
if (NT_SUCCESS(Status)) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "Type=%lx, Variation=%lx, Version=%lx, Build=%lx, SetupMedia=%s\n",
MediaObj.SourceType, MediaObj.SourceVariation, MediaObj.Version,
MediaObj.BuildNumber,
(MediaObj.StepUpMedia ? L"True" : L"False")));
if( (MediaObj.Version == 500) &&
(MediaObj.SourceVariation != COMPLIANCE_INSTALLVAR_EVAL) &&
(MediaObj.BuildNumber == 2195)) {
*CdInstallType = MediaObj.SourceType;
*CdInstallVersion = MediaObj.Version;
return TRUE;
}
// At this point we should be current media 5.1
if( MediaObj.Version == 501 ) {
if( MediaObj.SourceVariation != COMPLIANCE_INSTALLVAR_EVAL) {
if( MediaObj.StepUpMedia == FALSE) {
*CdInstallType = MediaObj.SourceType;
*CdInstallVersion = MediaObj.Version;
return TRUE;
} else {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "pSpGetCdInstallType: SpGetMediaDetails succeeded but STEPUP media"
" cannot be used for validation\n", Status));
}
} else {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "pSpGetCdInstallType: SpGetMediaDetails succeeded but Eval media\n",
Status));
}
} else {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "pSpGetCdInstallType: SpGetMediaDetails succeeded but unrecognized version\n",
Status));
}
} else {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "pSpGetCdInstallType: SpGetMediaDetails failed with %lx error code\n",
Status));
}
}
//
// not any system CD that we know about
//
return(FALSE);
}
VOID
pSpStepUpValidate(
VOID
)
{
ULONG CdCount;
ULONG i;
BOOLEAN b;
ULONG Prompt,SecondaryPrompt;
ULONG ValidKeys[3] = { ASCI_CR, KEY_F3, 0 };
LARGE_INTEGER DelayTime;
PWSTR FileName;
ULONG SourceSkuId;
ULONG DontCare;
ULONG CdInstallType;
ULONG CdInstallVersion;
//
// Directories that are present on all known NT CD-ROM's.
//
PWSTR ListAll[] = { L"alpha", L"i386" };
PWSTR ListAllNec98[] = { L"pc98",L"support" }; //NEC98
//
// Directories which must be present if a CD is a 3.51 or a 4.0 CD-ROM,
// workstation or server. Note that the ppc directory distinguishes
// 3.51 from 3.5.
//
PWSTR List351_40[] = { L"mips", L"ppc" };
PWSTR ListWin95[] = { L"win95", L"autorun" };
PWSTR ListWin98[] = { L"win98", L"autorun" };
SourceSkuId = DetermineSourceProduct(&DontCare,NULL);
Prompt = SP_SCRN_STEP_UP_NO_QUALIFY;
switch (SourceSkuId) {
case COMPLIANCE_SKU_NTW32U:
SecondaryPrompt = SP_SCRN_STEP_UP_PROMPT_WKS;
break;
case COMPLIANCE_SKU_NTSU:
SecondaryPrompt = SP_SCRN_STEP_UP_PROMPT_SRV;
break;
case COMPLIANCE_SKU_NTSEU:
SecondaryPrompt = SP_SCRN_STEP_UP_PROMPT_ENT;
break;
default:
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "setup: Unexpected SKU %x, defaulting to workstation\n", SourceSkuId));
SecondaryPrompt = SP_SCRN_STEP_UP_PROMPT_WKS;
break;
}
#if 0
//
// ntw upgrade is a special case because you have either win95 or an old NTW to
// upgrade from
//
// might have to prompt for floppies
//
if (SourceSkuId == COMPLIANCE_SKU_NTWU) {
}
//
// See if there is a CD-ROM drive. If not we can't continue.
//
else
#endif
if(CdCount = IoGetConfigurationInformation()->CdRomCount) {
do {
//
// Tell the user what's going on. This screen also contains
// a prompt to insert a qualifying CD-ROM.
//
while(1) {
SpStartScreen(Prompt,3,HEADER_HEIGHT+1,FALSE,FALSE,DEFAULT_ATTRIBUTE);
SpContinueScreen(
SecondaryPrompt,
3,
1,
FALSE,
DEFAULT_ATTRIBUTE
);
SpContinueScreen(SP_SCRN_STEP_UP_INSTRUCTIONS,3,1,FALSE,DEFAULT_ATTRIBUTE);
SpDisplayStatusOptions(
DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_ENTER_EQUALS_CONTINUE,
SP_STAT_F3_EQUALS_EXIT,
0
);
if(SpWaitValidKey(ValidKeys,NULL,NULL) == KEY_F3) {
SpConfirmExit();
} else {
break;
}
}
CLEAR_CLIENT_SCREEN();
SpDisplayStatusText(SP_STAT_PLEASE_WAIT,DEFAULT_STATUS_ATTRIBUTE);
//
// Wait 5 sec for the CD to become ready
//
DelayTime.HighPart = -1;
DelayTime.LowPart = (ULONG)(-50000000);
KeDelayExecutionThread(KernelMode,FALSE,&DelayTime);
//
// Check for relevent files/dirs on each CD-ROM drive.
//
for(i=0; i<CdCount; i++) {
swprintf(TemporaryBuffer,L"\\Device\\Cdrom%u",i);
if (pSpGetCdInstallType(TemporaryBuffer, &CdInstallType, &CdInstallVersion) ) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "cd type : %x cd version : %d\n", CdInstallType, CdInstallVersion ));
switch (SourceSkuId) {
case COMPLIANCE_SKU_NTWPU:
case COMPLIANCE_SKU_NTW32U:
if ( (CdInstallType == COMPLIANCE_INSTALLTYPE_WIN9X) ||
( ((CdInstallType == COMPLIANCE_INSTALLTYPE_NTW) ||
(CdInstallType == COMPLIANCE_INSTALLTYPE_NTWP)) &&
(CdInstallVersion > 350)) ) {
return;
}
break;
case COMPLIANCE_SKU_NTSU:
if ( (CdInstallType == COMPLIANCE_INSTALLTYPE_NTS) &&
(CdInstallVersion > 350) ) {
return;
}
break;
case COMPLIANCE_SKU_NTSEU:
if (CdInstallType == COMPLIANCE_INSTALLTYPE_NTSE) {
return;
}
break;
default:
return;
}
}
}
//
// If we get here then the CD the user inserted is bogus
// or the user didn't insert a CD. Reprompt. The while loop
// condition makes this essentially an infinite loop.
//
} while(Prompt = SP_SCRN_STEP_UP_BAD_CD);
}
SpStartScreen(
SP_SCRN_STEP_UP_FATAL,
3,
HEADER_HEIGHT+1,
FALSE,
FALSE,
DEFAULT_ATTRIBUTE
);
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_F3_EQUALS_EXIT,0);
SpInputDrain();
while(SpInputGetKeypress() != KEY_F3);
SpDone(0,FALSE,FALSE);
}
BOOLEAN
SppResumingFailedUpgrade(
IN PDISK_REGION Region,
IN LPCWSTR OsLoadFileName,
IN LPCWSTR LoadIdentifier,
IN BOOLEAN AllowCancel
)
/*++
Routine Description:
Simple routine to inform the user that setup noticed that the build
chosen for upgrade had been upgraded before, but the upgrade attempt
failed. The user can continue or exit. If he continues the build will be
upgraded (again).
Arguments:
Region - supplies region containing the build being upgraded
OsLoadFileName - supplies ARC OSLOADFILENAME var for the build (ie, sysroot)
LoadIdentifier - supplies ARC LOADIDENTIFIER for the build (ie, human-
readable description).
AllowCancel - Indicates whether user can cancel out of this or not
Return Value:
TRUE, if the user wants to continue and attempt to upgrade again else
FALSE.
--*/
{
ULONG ValidKeys[] = { KEY_F3, ASCI_CR, 0, 0 };
ULONG c;
DRIVELTR_STRING UpgDriveLetter;
ULONG MsgId;
ULONG EscStatusId;
BOOLEAN AllowUpgrade = TRUE;
ASSERT(Region->PartitionedSpace);
ASSERT(wcslen(OsLoadFileName) >= 2);
SpGetUpgDriveLetter(Region->DriveLetter,
UpgDriveLetter,
sizeof(UpgDriveLetter),
FALSE);
if (AllowCancel) {
ValidKeys[2] = ASCI_ESC;
MsgId = SP_SCRN_WINNT_FAILED_UPGRADE_ESC;
EscStatusId = SP_STAT_ESC_EQUALS_CLEAN_INSTALL;
} else {
MsgId = SP_SCRN_WINNT_FAILED_UPGRADE;
EscStatusId = 0;
}
do {
SpStartScreen(
MsgId,
3,
HEADER_HEIGHT+1,
FALSE,
FALSE,
DEFAULT_ATTRIBUTE,
UpgDriveLetter,
OsLoadFileName,
LoadIdentifier
);
SpDisplayStatusOptions(
DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_F3_EQUALS_EXIT,
SP_STAT_ENTER_EQUALS_UPGRADE,
EscStatusId,
0
);
c = SpWaitValidKey(ValidKeys, NULL, NULL);
switch (c) {
case KEY_F3:
SpConfirmExit();
break;
case ASCI_ESC:
AllowUpgrade = FALSE;
break;
default:
break;
}
} while (c == KEY_F3);
return AllowUpgrade;
}
#define MAX_INT_STRING 30
VOID
SppUpgradeDiskFull(
IN PDISK_REGION OsRegion,
IN LPCWSTR OsLoadFileName,
IN LPCWSTR LoadIdentifier,
IN PDISK_REGION SysPartRegion,
IN ULONG MinOsFree,
IN ULONG MinSysFree,
IN BOOLEAN Fatal
)
/*++
Routine Description:
Inform the user that the nt tree chosen for upgrade can't be upgraded
because the partition is too full.
Arguments:
OsRegion - supplies region containing the nt tree.
OsLoadFileName - supplies ARC OSLOADFILENAME var for the build (ie, sysroot)
LoadIdentifier - supplies ARC LOADIDENTIFIER for the build (ie, human-
readable description).
SysPartRegion - supplies the region that is the ARC system partition
for the build being upgraded
MinOsFree - supplies the size in KB of the minimum amount of free space
we require before attempting upgrade
MinSysFree - supplies the size in KB of the minimum amount of free space
we require on the system partition before attempting upgrade.
Fatal - if TRUE then the only option is exit. If FALSE then this routine
can return to its caller.
Return Value:
None. MAY NOT RETURN, depending on Fatal.
--*/
{
ULONG ValidKeys[] = { KEY_F3,0,0 };
PWCHAR Drive1, Drive2;
DRIVELTR_STRING OsRgnDrive, OsRgnDriveFull, SysRgnDriveFull;
WCHAR Drive1Free[MAX_INT_STRING], Drive1FreeNeeded[MAX_INT_STRING];
WCHAR Drive2Free[MAX_INT_STRING], Drive2FreeNeeded[MAX_INT_STRING];
BOOLEAN FirstDefined = FALSE, SecondDefined = FALSE;
ASSERT(OsRegion->PartitionedSpace);
ASSERT(SysPartRegion->PartitionedSpace);
ASSERT(wcslen(OsLoadFileName) >= 2);
SpGetUpgDriveLetter(OsRegion->DriveLetter,OsRgnDrive,sizeof(OsRgnDrive),FALSE);
if((OsRegion == SysPartRegion) || (OsRegion->FreeSpaceKB < MinOsFree)) {
//
// Then we'll be needing the full (colon added) version of
// the drive letter
//
SpGetUpgDriveLetter(OsRegion->DriveLetter,OsRgnDriveFull,sizeof(OsRgnDrive),TRUE);
}
if(OsRegion == SysPartRegion) {
Drive1 = OsRgnDriveFull;
swprintf(Drive1Free,L"%d",OsRegion->FreeSpaceKB);
swprintf(Drive1FreeNeeded,L"%d",MinOsFree);
FirstDefined = TRUE;
} else {
if(SysPartRegion->FreeSpaceKB < MinSysFree) {
SpGetUpgDriveLetter(SysPartRegion->DriveLetter,SysRgnDriveFull,sizeof(SysRgnDriveFull),TRUE);
Drive1 = SysRgnDriveFull;
swprintf(Drive1Free,L"%d",SysPartRegion->FreeSpaceKB);
swprintf(Drive1FreeNeeded,L"%d",MinSysFree);
FirstDefined = TRUE;
}
if(OsRegion->FreeSpaceKB < MinOsFree) {
if(!FirstDefined) {
Drive1 = OsRgnDriveFull;
swprintf(Drive1Free,L"%d",OsRegion->FreeSpaceKB);
swprintf(Drive1FreeNeeded,L"%d",MinOsFree);
FirstDefined = TRUE;
} else {
Drive2 = OsRgnDriveFull;
swprintf(Drive2Free,L"%d",OsRegion->FreeSpaceKB);
swprintf(Drive2FreeNeeded,L"%d",MinOsFree);
SecondDefined = TRUE;
}
}
}
if(!Fatal) {
ValidKeys[1] = ASCI_CR;
}
while(1) {
SpStartScreen(
Fatal ? SP_SCRN_WINNT_DRIVE_FULL_FATAL : SP_SCRN_WINNT_DRIVE_FULL,
3,
HEADER_HEIGHT+1,
FALSE,
FALSE,
DEFAULT_ATTRIBUTE,
OsRgnDrive,
OsLoadFileName,
LoadIdentifier,
FirstDefined ? Drive1 : L"",
FirstDefined ? Drive1FreeNeeded : L"",
FirstDefined ? Drive1Free : L"",
SecondDefined ? Drive2 : L"",
SecondDefined ? Drive2FreeNeeded : L"",
SecondDefined ? Drive2Free : L""
);
SpDisplayStatusOptions(
DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_F3_EQUALS_EXIT,
Fatal ? 0 : SP_STAT_ENTER_EQUALS_CONTINUE,
0
);
if(SpWaitValidKey(ValidKeys,NULL,NULL) == KEY_F3) {
if(Fatal) {
SpDone(0,FALSE,TRUE);
} else {
SpConfirmExit();
}
} else {
//
// User hit CR in non-fatal case
//
return;
}
}
}
ENUMUPGRADETYPE
SppSelectNTToRepairByUpgrade(
OUT PSP_BOOT_ENTRY *BootEntryChosen
)
{
PVOID Menu;
ULONG MenuTopY;
ULONG ValidKeys[] = { KEY_F3,ASCI_ESC,0 };
ULONG Mnemonics[] = {MnemonicRepair,0 };
ULONG Keypress;
PSP_BOOT_ENTRY BootEntry,FirstUpgradeSet;
BOOL bDone;
ENUMUPGRADETYPE ret;
//
// Build up array of drive letters for all menu options
//
for(BootEntry = SpBootEntries; BootEntry != NULL; BootEntry = BootEntry->Next) {
if (BootEntry->Processable) {
SpGetUpgDriveLetter(
BootEntry->OsPartitionDiskRegion->DriveLetter,
BootEntry->DriveLetterString,
sizeof(DRIVELTR_STRING),
FALSE
);
}
}
bDone = FALSE;
while(!bDone) {
//
// Display the text that goes above the menu on the partitioning screen.
//
SpDisplayScreen(SP_SCRN_WINNT_REPAIR_BY_UPGRADE,3,CLIENT_TOP+1);
//
// Calculate menu placement. Leave one blank line
// and one line for a frame.
//
MenuTopY = NextMessageTopLine+2;
//
// Create a menu.
//
Menu = SpMnCreate(
MENU_LEFT_X,
MenuTopY,
MENU_WIDTH,
VideoVars.ScreenHeight-MenuTopY-2-STATUS_HEIGHT
);
ASSERT(Menu);
//
// Build up a menu of partitions and free spaces.
//
FirstUpgradeSet = NULL;
for(BootEntry = SpBootEntries; BootEntry != NULL; BootEntry = BootEntry->Next) {
if(BootEntry->Processable) {
swprintf(
TemporaryBuffer,
L"%ws:%ws %ws",
BootEntry->DriveLetterString,
BootEntry->OsDirectory,
BootEntry->FriendlyName
);
SpMnAddItem(
Menu,
TemporaryBuffer,
MENU_LEFT_X+MENU_INDENT,
MENU_WIDTH-(2*MENU_INDENT),
TRUE,
(ULONG_PTR)BootEntry
);
if(FirstUpgradeSet == NULL) {
FirstUpgradeSet = BootEntry;
}
}
}
//
// Initialize the status line.
//
SpDisplayStatusOptions(
DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_F3_EQUALS_EXIT,
SP_STAT_R_EQUALS_REPAIR,
SP_STAT_ESC_EQUALS_NO_REPAIR,
0
);
//
// Display the menu
//
SpMnDisplay(
Menu,
(ULONG_PTR)FirstUpgradeSet,
TRUE,
ValidKeys,
Mnemonics,
NULL,
&Keypress,
(PULONG_PTR)BootEntryChosen
);
//
// Now act on the user's selection.
//
switch(Keypress) {
case KEY_F3:
SpConfirmExit();
break;
case ASCI_ESC:
ret = DontUpgrade;
bDone = TRUE;
break;
default:
//
// Must be r=repair
//
ret = UpgradeFull;
bDone = TRUE;
break;
}
SpMnDestroy(Menu);
}
return(ret);
}
VOID
SpGetUpgDriveLetter(
IN WCHAR DriveLetter,
IN PWCHAR Buffer,
IN ULONG BufferSize,
IN BOOL AddColon
)
/*++
Routine Description:
This returns a unicode string containing the drive letter specified by
DriveLetter (if nonzero). If DriveLetter is 0, then we assume that we
are looking at a mirrored partition, and retrieve a localized string of
the form '(Mirror)'. If 'AddColon' is TRUE, then drive letters get a
colon appended (eg, "C:").
Arguments:
DriveLetter: Unicode drive letter, or 0 to denote a mirrored partition.
Buffer: Buffer to receive the unicode string
BufferSize: Size of the buffer.
AddColon: Boolean specifying whether colon should be added (has no
effect if DriveLetter is 0).
Returns:
Buffer contains the formatted Unicode string.
--*/
{
if(DriveLetter) {
if(BufferSize >= 2) {
*(Buffer++) = DriveLetter;
if(AddColon && BufferSize >= 3) {
*(Buffer++) = L':';
}
}
*Buffer = 0;
} else {
SpFormatMessage(Buffer, BufferSize, SP_UPG_MIRROR_DRIVELETTER);
}
}
BOOLEAN
SppWarnUpgradeWorkstationToServer(
IN ULONG MsgId
)
/*++
Routine Description:
Inform a user that that the installation that he/she selected to upgrade
is an NT Workstation, and that after the upgrade it will become a
Standard Server.
The user has the option to upgrade this or specify that he wants to
install Windows NT fresh.
Arguments:
MsgId - Screen to be displayed to the user.
Return Value:
BOOLEAN - Returns TRUE if the user wants to continue the upgrade, or
FALSE if the user wants to select another system to upgrade or
install fress.
--*/
{
ULONG ValidKeys[] = { ASCI_CR, ASCI_ESC, 0 };
ULONG c;
while(1) {
SpStartScreen(
MsgId,
3,
HEADER_HEIGHT+1,
FALSE,
FALSE,
DEFAULT_ATTRIBUTE
);
SpDisplayStatusOptions(
DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_ENTER_EQUALS_CONTINUE,
SP_STAT_ESC_EQUALS_CANCEL,
0
);
switch(c=SpWaitValidKey(ValidKeys,NULL,NULL)) {
case KEY_F3:
SpConfirmExit();
break;
case ASCI_ESC:
return( FALSE );
case ASCI_CR:
return(TRUE);
default:
break;
}
}
}
VOID
SpCantFindBuildToUpgrade(
VOID
)
/*++
Routine Description:
Inform the user that we were unable to locate the build from which
he initiated unattended installation via winnt32.
This is a fatal condition.
Arguments:
None.
Return Value:
Does not return.
--*/
{
ULONG ValidKeys[2] = { KEY_F3, 0 };
CLEAR_CLIENT_SCREEN();
SpDisplayScreen(SP_SCRN_CANT_FIND_UPGRADE,3,HEADER_HEIGHT+1);
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_F3_EQUALS_EXIT,0);
SpWaitValidKey(ValidKeys,NULL,NULL);
SpDone(0,FALSE,FALSE);
}
void
SpUpgradeToNT50FileSystems(
PVOID SifHandle,
PDISK_REGION SystemPartitionRegion,
PDISK_REGION NTPartitionRegion,
PWSTR SetupSourceDevicePath,
PWSTR DirectoryOnSetupSource
)
/*++
Routine Description:
Perform any necessary upgrades of the file systems
for the NT40 to NT50 upgrade case.
Arguments:
SystemPartitionRegion - Pointer to the structure that describes the
system partition.
NTPartitionRegion - Pointer to the structure that describes the
NT partition.
SetupSourceDevicePath - NT device path where autochk.exe is located
DirectoryOnSourceDevice - Local source directory.
Return Value:
None.
--*/
{
NTSTATUS Status;
PDISK_REGION Region;
PUCHAR Win9xPath;
ULONG i,j,k;
PSP_BOOT_ENTRY BootEntry;
PWSTR NtPath;
BOOLEAN DoConvert = TRUE;
OBJECT_ATTRIBUTES Obja;
IO_STATUS_BLOCK IoStatusBlock;
PVOID ImageBase;
HANDLE SectionHandle;
ULONGLONG SourceVersion;
HANDLE SourceHandle;
UNICODE_STRING UnicodeString;
BOOLEAN IssueWarning = FALSE;
WCHAR SourceFile[MAX_PATH];
PWSTR MediaShortName;
PWSTR MediaDirectory;
UCHAR SysId;
#if defined(REMOTE_BOOT)
//
// If this is a remote boot installation, do not try to convert -- the
// NT partition in this case is on the remote boot server.
//
if (RemoteBootSetup && !RemoteInstallSetup) {
ConvertNtVolumeToNtfs = FALSE;
return;
}
#endif // defined(REMOTE_BOOT)
SpDetermineUniqueAndPresentBootEntries();
for(BootEntry = SpBootEntries; BootEntry != NULL; BootEntry = BootEntry->Next) {
if (!BootEntry->Processable) {
continue;
}
BootEntry->Processable = FALSE;
wcscpy( TemporaryBuffer, BootEntry->OsPartitionNtName );
SpConcatenatePaths( TemporaryBuffer, BootEntry->OsDirectory );
SpConcatenatePaths( TemporaryBuffer, L"\\system32\\ntoskrnl.exe" );
INIT_OBJA( &Obja, &UnicodeString, TemporaryBuffer );
Status = ZwCreateFile(
&SourceHandle,
FILE_GENERIC_READ,
&Obja,
&IoStatusBlock,
NULL,
0,
0,
FILE_OPEN,
FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0
);
if (NT_SUCCESS(Status)) {
Status = SpMapEntireFile( SourceHandle, &SectionHandle, &ImageBase, FALSE );
if (NT_SUCCESS(Status)) {
SpGetFileVersion( ImageBase, &BootEntry->KernelVersion );
BootEntry->Processable = TRUE;
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP: SpUpgradeToNT50FileSystems: Kernel %p: NT%d.%d(Build %d) %d\n",
BootEntry,
(USHORT)(BootEntry->KernelVersion>>48),
(USHORT)(BootEntry->KernelVersion>>32),
(USHORT)(BootEntry->KernelVersion>>16),
(USHORT)(BootEntry->KernelVersion)));
SpUnmapFile( SectionHandle, ImageBase );
} else {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpUpgradeToNT50FileSystems() could not map kernel image [%ws], %lx\n", TemporaryBuffer, Status ));
}
ZwClose(SourceHandle);
} else {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpUpgradeToNT50FileSystems() corrupt boot config [%ws], %lx\n", TemporaryBuffer, Status ));
}
}
//
// count the number of "real" entries
//
k = 0;
for(BootEntry = SpBootEntries; BootEntry != NULL; BootEntry = BootEntry->Next) {
if (BootEntry->Processable) {
k += 1;
}
}
//
// check to see if a warning is necessary.
//
// If we're doing an upgrade, and there's only 1
// boot set, then we don't need a warning. However,
// if we're doing a clean install and there's at least
// 1 boot set, then warn (given the existing OS is
// old enough).
//
if( ( ((NTUpgrade == UpgradeFull) && (k > 1)) ||
((NTUpgrade == DontUpgrade) && (k > 0)) ) &&
( !UnattendedOperation ) && (!SpDrEnabled())) {
for(BootEntry = SpBootEntries; BootEntry != NULL && IssueWarning == FALSE; BootEntry = BootEntry->Next) {
if (!BootEntry->Processable || (BootEntry->KernelVersion == 0)) {
//
// bogus boot entry
//
} else if ((BootEntry->KernelVersion >> 48) < 4) {
IssueWarning = TRUE;
} else if ((BootEntry->KernelVersion >> 48) == 4 && (BootEntry->KernelVersion & 0xffff) <= 4) {
IssueWarning = TRUE;
}
}
}
// If there's any existing NT4.0 with servicepack less than 5 then warn.
if( k > 0) {
for(BootEntry = SpBootEntries; BootEntry != NULL && IssueWarning == FALSE; BootEntry = BootEntry->Next) {
if (!BootEntry->Processable || (BootEntry->KernelVersion == 0)) {
//
// bogus boot entry
//
} else if (BootEntry->MajorVersion == 4 && BootEntry->MinorVersion == 0 && BootEntry->BuildNumber == 1381 && BootEntry->ServicePack < 500) {
IssueWarning = TRUE;
}
}
}
if (IssueWarning) {
ULONG WarnKeys[] = { KEY_F3, 0 };
ULONG MnemonicKeys[] = { MnemonicContinueSetup, 0 };
while (IssueWarning) {
SpDisplayScreen(SP_SCRN_FSWARN,3,CLIENT_TOP+1);
SpDisplayStatusOptions(
DEFAULT_STATUS_ATTRIBUTE,
SP_STAT_C_EQUALS_CONTINUE_SETUP,
SP_STAT_F3_EQUALS_EXIT,
0
);
SpInputDrain();
switch(SpWaitValidKey(WarnKeys,NULL,MnemonicKeys)) {
case KEY_F3:
SpConfirmExit();
return;
default:
IssueWarning = FALSE;
break;
}
}
}
#if 0
//
// now lets upgrade any nt40+sp3 ntfs file systems
//
MediaShortName = SpLookUpValueForFile(
SifHandle,
L"ntfs40.sys",
INDEX_WHICHMEDIA,
TRUE
);
SpGetSourceMediaInfo( SifHandle, MediaShortName, NULL, NULL, &MediaDirectory );
wcscpy( SourceFile, SetupSourceDevicePath );
SpConcatenatePaths( SourceFile, DirectoryOnSetupSource );
SpConcatenatePaths( SourceFile, MediaDirectory );
SpConcatenatePaths( SourceFile, L"ntfs40.sys" );
//
// Initialize the diamond decompression engine.
// This needs to be done, because SpCopyFileUsingNames() uses
// the decompression engine.
//
SpdInitialize();
for(BootEntry = SpBootEntries; BootEntry != NULL; BootEntry = BootEntry->Next) {
if (BootEntry->Processable &&
((BootEntry->KernelVersion >> 48) == 4) &&
((BootEntry->KernelVersion & 0xffff) == 4)) {
wcscpy( TemporaryBuffer, BootEntry->OsPartitionNtName );
SpConcatenatePaths( TemporaryBuffer, BootEntry->OsDirectory );
SpConcatenatePaths( TemporaryBuffer, L"\\system32\\drivers\\ntfs.sys" );
Status = SpCopyFileUsingNames(
SourceFile,
TemporaryBuffer,
0,
COPY_NOVERSIONCHECK
);
if (!NT_SUCCESS(Status)) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpUpgradeToNT50FileSystems() could not copy nt40 ntfs.sys driver, %lx\n", Status ));
}
SpMemFree(NtPath);
}
}
// Terminate diamond
SpdTerminate();
#endif
return;
}
BOOLEAN
SpDoBuildsMatch(
IN PVOID SifHandle,
ULONG TestBuildNum,
NT_PRODUCT_TYPE TestBuildType,
ULONG TestBuildSuiteMask,
BOOLEAN CurrentProductIsServer,
ULONG CurrentSuiteMask,
IN LCID LangId
)
/*++
Routine Description:
Checks if the current build the user is installing matches the build we're
checking against.
We check:
1. do the build numbers match?
2. do the build types match? (nt server and nt professional don't match)
3. do the product suites match? (nt advanced server vs. data center)
Arguments:
SifHandle - Handle to txtsetup.sif to find the source language
TestBuildNum - The build number of the build we're checking against
TestBuildType - The type of build we're checking against
TestBuildSuiteMask - Type of product suite as mask we're checking against
CurrentProductIsServer - If TRUE, the current build is NT Server
CurrentSuiteMask - Type of suite mask
LangId - System Language Id of the installation to check. If -1, Lang Id
check is ignored.
Return Value:
BOOLEAN - Returns TRUE if the builds match.
--*/
{
#define PRODUCTSUITES_TO_MATCH (( VER_SUITE_SMALLBUSINESS \
| VER_SUITE_ENTERPRISE \
| VER_SUITE_BACKOFFICE \
| VER_SUITE_COMMUNICATIONS \
| VER_SUITE_SMALLBUSINESS_RESTRICTED \
| VER_SUITE_EMBEDDEDNT \
| VER_SUITE_DATACENTER \
| VER_SUITE_PERSONAL))
BOOLEAN retval;
LANGID DefLangId = -1;
DWORD Version = 0, BuildNumber = 0;
if (!DetermineSourceVersionInfo(&Version, &BuildNumber)) {
retval = FALSE;
goto exit;
}
if(TestBuildNum != BuildNumber) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP: SpDoBuildsMatch() has build mismatch, %d != %d\n",
TestBuildNum, BuildNumber));
retval = FALSE;
goto exit;
}
//
// build number test passed. now check for server vs. professional
//
if (((TestBuildType == NtProductWinNt) && CurrentProductIsServer) ||
((TestBuildType == NtProductServer) && !CurrentProductIsServer)) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP: SpDoBuildsMatch() has server/professional mismatch\n" ));
retval = FALSE;
goto exit;
}
//
// now check product suites.
// note that we don't check for all product suites, only
// suites that have their own SKU
//
if ((CurrentSuiteMask & PRODUCTSUITES_TO_MATCH) != (TestBuildSuiteMask & PRODUCTSUITES_TO_MATCH)) {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL,
"SETUP: SpDoBuildsMatch() has suite mismatch (dest = %x) (source = %x\n",
TestBuildSuiteMask,CurrentSuiteMask ));
retval = FALSE;
goto exit;
}
//
// language IDs should also match (if requested)
//
if (LangId != -1) {
PWSTR LangIdStr = SpGetSectionKeyIndex(SifHandle, SIF_NLS, SIF_DEFAULTLAYOUT, 0);
PWSTR EndChar;
if (LangIdStr)
DefLangId = (LANGID)SpStringToLong(LangIdStr, &EndChar, 16);
//
// note : currently we are only interested in primary language IDs
//
retval = (PRIMARYLANGID(DefLangId) == PRIMARYLANGID(LangId)) ? TRUE : FALSE;
goto exit;
}
retval = TRUE;
exit:
return(retval);
}
NTSTATUS
SpGetMediaDetails(
IN PWSTR CdInfDirPath,
OUT PCCMEDIA MediaObj
)
/*++
Routine Description:
Gets the details of the current CD in CCMEDIA structure
Arguments:
CdInfDirPath - The path to the inf directories on CD-ROM drive
MediaObj - The pointer to the media object in which the details
are returned
Return Value:
Returns STATUS_SUCCESS if success otherwise appropriate status error code.
--*/
{
NTSTATUS Status = STATUS_INVALID_PARAMETER;
WCHAR DosNetPath[MAX_PATH];
WCHAR SetuppIniPath[MAX_PATH];
PVOID SetuppIniHandle = 0;
PVOID DosNetHandle = 0;
ULONG ErrorLine = 0;
WCHAR Pid[32] = {0};
WCHAR PidData[256] = {0};
PWSTR TempPtr;
BOOLEAN UpgradeMode = FALSE;
DWORD Type = COMPLIANCE_INSTALLTYPE_UNKNOWN;
DWORD Variation = COMPLIANCE_INSTALLVAR_UNKNOWN;
DWORD Version = 0, BuildNumber = 0;
if (CdInfDirPath && MediaObj) {
BOOLEAN VersionDetected = FALSE;
wcscpy(DosNetPath, CdInfDirPath);
wcscpy(SetuppIniPath, CdInfDirPath);
SpConcatenatePaths(DosNetPath, L"dosnet.inf");
SpConcatenatePaths(SetuppIniPath, L"setupp.ini");
//
// load setupp.ini file and parse it
//
Status = SpLoadSetupTextFile(
SetuppIniPath,
NULL, // No image already in memory
0, // Image size is empty
&SetuppIniHandle,
&ErrorLine,
TRUE,
FALSE
);
if(NT_SUCCESS(Status)) {
Status = STATUS_FILE_INVALID;
//
// get the PID
//
TempPtr = SpGetSectionKeyIndex(SetuppIniHandle, L"Pid", L"Pid", 0);
if (TempPtr) {
wcscpy(Pid, TempPtr);
//
// get PID ExtraData
//
TempPtr = SpGetSectionKeyIndex(SetuppIniHandle, L"Pid", L"ExtraData", 0);
if (TempPtr) {
wcscpy(PidData, TempPtr);
//
// Get stepup mode & install variation based on PID
//
if (SpGetStepUpMode(PidData, &UpgradeMode) &&
pSpGetCurrentInstallVariation(Pid, &Variation)) {
Status = STATUS_SUCCESS;
} else {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SpGetMediaDetails: Could "
"not find StepUp mode or variation of install CD\n"));
}
} else {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SpGetMediaDetails: Could not get "
"PidExtraData from Setupp.ini\n"));
}
} else {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SpGetMediaDetails: Could not get Pid from Setupp.ini\n"));
}
} else {
//
// Silently fail if unable to read setupp.ini
//
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SpGetMediaDetails: Unable to read setupp.ini. "
"Status = %lx \n", Status));
}
if (SetuppIniHandle)
SpFreeTextFile(SetuppIniHandle);
if (NT_SUCCESS(Status)) {
//
// load and parse dosnet.inf
//
Status = SpLoadSetupTextFile(
DosNetPath,
NULL, // No image already in memory
0, // Image size is empty
&DosNetHandle,
&ErrorLine,
TRUE,
FALSE
);
if (NT_SUCCESS(Status)) {
Status = STATUS_FILE_INVALID;
//
// get ProductType from Miscellaneous section
//
TempPtr = SpGetSectionKeyIndex(DosNetHandle, L"Miscellaneous",
L"ProductType", 0);
if (TempPtr) {
UNICODE_STRING UnicodeStr;
ULONG Value = -1;
RtlInitUnicodeString(&UnicodeStr, TempPtr);
Status = RtlUnicodeStringToInteger(&UnicodeStr, 10, &Value);
switch (Value) {
case 0:
Type = COMPLIANCE_INSTALLTYPE_NTW;
break;
case 1:
Type = COMPLIANCE_INSTALLTYPE_NTS;
break;
case 2:
Type = COMPLIANCE_INSTALLTYPE_NTSE;
break;
case 3:
Type = COMPLIANCE_INSTALLTYPE_NTSDTC;
break;
case 4:
Type = COMPLIANCE_INSTALLTYPE_NTWP;
break;
default:
break;
}
//
// Get the version also off from driverver in dosnet.inf
//
TempPtr = SpGetSectionKeyIndex(DosNetHandle, L"Version",
L"DriverVer", 1);
if (TempPtr) {
if (NT_SUCCESS(SpGetVersionFromStr(TempPtr,
&Version, &BuildNumber))) {
VersionDetected = TRUE;
}
Status = STATUS_SUCCESS;
}
if (Type != COMPLIANCE_INSTALLTYPE_UNKNOWN) {
Status = STATUS_SUCCESS;
} else {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpGetMediaDetails: Could not get product type"
" from dosnet.inf\n"));
}
} else {
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpGetMediaDetails: "
"Could not get ProductType from dosnet.inf\n"));
}
} else {
//
// Silently fail if unable to read dosnet.inf
//
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SpGetMediaDetails: Unable to read dosnet.inf. "
"Status = %lx \n", Status ));
}
}
if (DosNetHandle)
SpFreeTextFile(DosNetHandle);
//
// Fall back to old way of finding version, if we failed
// to get one from dosnet.inf
//
if (NT_SUCCESS(Status) && !VersionDetected) {
if (!DetermineSourceVersionInfo(&Version, &BuildNumber))
Status = STATUS_FILE_INVALID;
}
//
// fill in the media details
//
if (NT_SUCCESS(Status) &&
! CCMediaInitialize(MediaObj, Type, Variation, UpgradeMode, Version, BuildNumber)) {
Status = STATUS_FILE_INVALID;
}
}
return Status;
}