mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3221 lines
82 KiB
3221 lines
82 KiB
/*++
|
|
|
|
Copyright (c) 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
spsetup.c
|
|
|
|
Abstract:
|
|
|
|
Main module for character-base setup (ie, text setup).
|
|
|
|
Author:
|
|
|
|
Ted Miller (tedm) 29-July-1993
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
|
|
#include "spprecmp.h"
|
|
#pragma hdrstop
|
|
|
|
#ifdef _X86_
|
|
//
|
|
// BUGBUG - Remove this flag in the future
|
|
//
|
|
BOOLEAN DisableWin95Migration = TRUE;
|
|
#endif
|
|
|
|
// #if 0
|
|
|
|
//
|
|
// TRUE if setup should find only Cairo systems on upgrade mode.
|
|
// BUGBUG: THIS IS A TEMPORARY VARIABLE THAT SHOULD BE REMOVED WHEN
|
|
// NT AND CAIRO ARE MERGED. THIS VARIABLE WILL TELL SETUP NOT
|
|
// TO FIND NT 3.x INSTALLATIONS TO UPGRADE, WHEN IT INSTALLS CAIRO
|
|
//
|
|
BOOLEAN CairoSetup = FALSE;
|
|
|
|
// #endif
|
|
|
|
//
|
|
// TRUE if setup should run in the step-up upgrade mode.
|
|
// In this mode, setup is not allowed to do clean install,
|
|
// and is not allowed to upgrade workstation to server.
|
|
// Also, evaluation time in minutes, read from the setup hive.
|
|
// This value is passed through to GUI mode.
|
|
//
|
|
BOOLEAN StepUpMode;
|
|
DWORD EvaluationTime;
|
|
ULONG RestrictCpu;
|
|
|
|
//
|
|
// TRUE if user chose Custom Setup.
|
|
//
|
|
BOOLEAN CustomSetup = TRUE;
|
|
|
|
//
|
|
// Non-0 if gui setup is supposed to be restartable.
|
|
// This causes us to do special stuff with hives in spconfig.c.
|
|
//
|
|
BOOLEAN RestartableGuiSetup = TRUE;
|
|
|
|
//
|
|
// TRUE if user chose repair winnt
|
|
//
|
|
|
|
BOOLEAN RepairWinnt = FALSE;
|
|
|
|
//
|
|
// TRUE if repair from ER diskette
|
|
//
|
|
|
|
BOOLEAN RepairFromErDisk = TRUE;
|
|
|
|
//
|
|
// TRUE if this is advanced server we're setting up.
|
|
//
|
|
BOOLEAN AdvancedServer;
|
|
|
|
//
|
|
// Windows NT Version.
|
|
//
|
|
ULONG WinntMajorVer;
|
|
ULONG WinntMinorVer;
|
|
|
|
//
|
|
// NTUpgrade - Whether we are upgrading an existing NT and if we are
|
|
// what type of an upgrade it is. Valid values are:
|
|
//
|
|
// - DontUpgrade: If we are not upgrading
|
|
// - UpgradeFull: Full upgrade
|
|
// - UpgradeInstallFresh: There was a failed upgrade, so we want to install
|
|
// fresh into this, saving the hives
|
|
//
|
|
//
|
|
ENUMUPGRADETYPE NTUpgrade = DontUpgrade;
|
|
|
|
//
|
|
// TRUE if upgrading Workstation to Standard Server, or upgrading
|
|
// existing Standard Server
|
|
//
|
|
BOOLEAN StandardServerUpgrade = FALSE;
|
|
|
|
//
|
|
// Contains the type of windows upgrade, if any (win31 or win95)
|
|
//
|
|
ENUMNONNTUPRADETYPE WinUpgradeType = NoWinUpgrade;
|
|
|
|
//
|
|
// TRUE if this setup was started with winnt.exe.
|
|
//
|
|
BOOLEAN WinntSetup;
|
|
|
|
#ifdef _X86_
|
|
//
|
|
// TRUE if floppyless boot
|
|
//
|
|
BOOLEAN IsFloppylessBoot = FALSE;
|
|
#endif
|
|
|
|
//
|
|
// If this is an unattended setup, this value will be a non-NULL
|
|
// handle to the SIF file with setup parameters.
|
|
// *Note*: Before referencing UnattendedSifHandle, you must first check
|
|
// UnattendedOperation is not FALSE.
|
|
//
|
|
BOOLEAN UnattendedOperation = FALSE;
|
|
BOOLEAN UnattendedGuiOperation = FALSE;
|
|
PVOID UnattendedSifHandle = NULL;
|
|
PVOID WinntSifHandle = NULL;
|
|
//
|
|
// This is a handle to txtsetup.oem, used on pre-install mode.
|
|
//
|
|
PVOID PreinstallOemSifHandle = NULL;
|
|
|
|
//
|
|
// If this flag is true, we ignore files that are not present on the source
|
|
// when copying. This is used internally for people who don't build the
|
|
// entire system and don't care that a whole bunch of help files,
|
|
// device drivers, etc, aren't there.
|
|
//
|
|
BOOLEAN SkipMissingFiles;
|
|
|
|
//
|
|
// On unattended mode, indicates whether OEM files
|
|
// that have same name as Microsoft files released
|
|
// with the product should be overwritten.
|
|
//
|
|
BOOLEAN UnattendedOverwriteOem = TRUE;
|
|
|
|
#ifdef _FASTRECOVER_
|
|
//
|
|
// TRUE if operating in Fast Recover mode. This mode
|
|
// is set by adding the "FastRecover = yes" line in the
|
|
// [SetupData] section.
|
|
//
|
|
BOOLEAN FastRecoverOperation = FALSE;
|
|
|
|
//
|
|
// On unattended mode, indicates whether the
|
|
// automatic partition check (autochk) should be skipped.
|
|
// By skipping the autochk, significant time can be saved
|
|
// during the unattended fast recovery process.
|
|
//
|
|
BOOLEAN UnattendedSkipAutoCheck = FALSE;
|
|
|
|
//
|
|
// On unattended mode, indicates whether the
|
|
// partitioning should be interactive. This is done to
|
|
// allow all of text mode setup to run unattended,
|
|
// expect for partitioning.
|
|
//
|
|
BOOLEAN UnattendedPartitionInteract = FALSE;
|
|
|
|
//
|
|
// On unattended mode, indicates whether the user should
|
|
// be prompted with the REBOOT screen (normally displayed
|
|
// during attended operation), so that the user can be
|
|
// reminded to remove any floppy media left in the drive
|
|
// during unattended operation.
|
|
//
|
|
BOOLEAN UnattendedPromptForReboot = FALSE;
|
|
#endif
|
|
|
|
//
|
|
// On unattended mode, indicates that this is is
|
|
// an OEM pre-installation
|
|
//
|
|
BOOLEAN PreInstall = FALSE;
|
|
|
|
//
|
|
// On pre-install mode, indicates whether or not an OEM component needs
|
|
// to be pre-installed (txtsetup.oem needs to be loaded).
|
|
//
|
|
// BOOLEAN PreinstallOemComponents = FALSE;
|
|
|
|
//
|
|
// On pre-install mode, the variables below point to the various lists of
|
|
// drivers to pre-install
|
|
//
|
|
// PPREINSTALL_DRIVER_INFO PreinstallDisplayDriverList = NULL;
|
|
// PPREINSTALL_DRIVER_INFO PreinstallKeyboardDriverList = NULL;
|
|
// PPREINSTALL_DRIVER_INFO PreinstallPointingDeviceDriverList = NULL;
|
|
// PPREINSTALL_DRIVER_INFO PreinstallKeyboardLayout = NULL;
|
|
|
|
//
|
|
// On pre-install mode, points to the directory that contains the files
|
|
// that need to be copied during textmode setup
|
|
//
|
|
PWSTR PreinstallOemSourcePath = NULL;
|
|
|
|
//
|
|
// Gets set to TRUE if the user elects to convert or format to ntfs.
|
|
// And a flag indicating whether we are doing a dirty sleazy hack
|
|
// for oem preinstall.
|
|
//
|
|
BOOLEAN ConvertNtVolumeToNtfs = FALSE;
|
|
BOOLEAN ExtendingOemPartition = FALSE;
|
|
|
|
//
|
|
// Variable used during the repair process, that indicates that the
|
|
// system has no CD-ROM drive.
|
|
// This is a hack that we did for World Bank so that they can repair
|
|
// the hives even if they don't have a CD-ROM drive.
|
|
//
|
|
BOOLEAN RepairNoCDROMDrive = FALSE;
|
|
|
|
//
|
|
// Filename of local source directory.
|
|
//
|
|
PWSTR LocalSourceDirectory = L"\\$win_nt$.~ls";
|
|
|
|
//
|
|
// Platform-specific extension, used when creating names of sections
|
|
// in sif/inf files.
|
|
//
|
|
#if defined(_ALPHA_)
|
|
PWSTR PlatformExtension = L".alpha";
|
|
#elif defined(_MIPS_)
|
|
PWSTR PlatformExtension = L".mips";
|
|
#elif defined(_PPC_)
|
|
PWSTR PlatformExtension = L".ppc";
|
|
#elif defined(_X86_)
|
|
PWSTR PlatformExtension = L".x86";
|
|
#endif
|
|
|
|
UCHAR TemporaryBuffer[32768];
|
|
|
|
//
|
|
// This global structure contains non-pointer values passed to us by setupldr
|
|
// in the setup loader parameter block.
|
|
//
|
|
// This structure is initialized during SpInitialize0().
|
|
//
|
|
SETUP_LOADER_BLOCK_SCALARS SetupParameters;
|
|
|
|
//
|
|
// These values are set during SpInitialize0() and are the ARC pathname
|
|
// of the device from which we were started and the directory within the device.
|
|
// DirectoryOnBootDevice will always be all uppercase.
|
|
//
|
|
PWSTR ArcBootDevicePath,DirectoryOnBootDevice;
|
|
|
|
//
|
|
// Representation of the boot device path in the nt namespace.
|
|
//
|
|
PWSTR NtBootDevicePath;
|
|
|
|
|
|
#ifdef _ALPHA_
|
|
//
|
|
// These values are retrieved from the setup loader parameter block and are non-NULL
|
|
// only if the user supplied an OEM PAL disk.
|
|
//
|
|
PWSTR OemPalFilename = NULL, OemPalDiskDescription;
|
|
|
|
#endif //def _ALPHA_
|
|
|
|
#ifdef _PPC_
|
|
//
|
|
// On PPC, we need to identify IBM Power Series 6050 and 6070, so that we can
|
|
// reconfigure atapi and atdisk.
|
|
//
|
|
BOOLEAN InstallingOnCarolinaMachine = FALSE;
|
|
|
|
#endif //def _PPC_
|
|
|
|
//
|
|
// Setupldr loads a text setup information file and passes us the buffer
|
|
// so that we don't have to reload it from disk. During SpInitialize0()
|
|
// we allocate some pool and store the image away for later use.
|
|
//
|
|
PVOID SetupldrInfoFile;
|
|
ULONG SetupldrInfoFileSize;
|
|
|
|
PDISK_SIGNATURE_INFORMATION DiskSignatureInformation;
|
|
|
|
|
|
BOOLEAN GeneralInitialized = FALSE;
|
|
|
|
BOOLEAN PcmciaLoaded = FALSE;
|
|
|
|
BOOLEAN AtapiLoaded = FALSE;
|
|
|
|
//
|
|
// Array with the PIDs of all NT greater than 4.x found in the machine (PID 2.0)
|
|
// The values in this array will be saved under Setup\PidList key in the registry,
|
|
// and will be used during GUI setup
|
|
//
|
|
PWSTR* Pid20Array = NULL;
|
|
|
|
//
|
|
// Product Id read from setupp.ini
|
|
//
|
|
PWSTR PidString = NULL;
|
|
|
|
//
|
|
// Routines required by rtl.lib
|
|
//
|
|
PRTL_ALLOCATE_STRING_ROUTINE RtlAllocateStringRoutine = SpMemAlloc;
|
|
PRTL_FREE_STRING_ROUTINE RtlFreeStringRoutine = SpMemFree;
|
|
|
|
VOID
|
|
SpTerminate(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
SpInitialize0a(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PVOID Context,
|
|
IN ULONG ReferenceCount
|
|
);
|
|
|
|
VOID
|
|
SpDetermineProductType(
|
|
IN PVOID SifHandle
|
|
);
|
|
|
|
VOID
|
|
SpAddInstallationToBootList(
|
|
IN PVOID SifHandle,
|
|
IN PDISK_REGION SystemPartitionRegion,
|
|
IN PWSTR SystemPartitionDirectory,
|
|
IN PDISK_REGION NtPartitionRegion,
|
|
IN PWSTR Sysroot,
|
|
IN BOOLEAN BaseVideoOption,
|
|
IN PWSTR OldOsLoadOptions OPTIONAL
|
|
);
|
|
|
|
VOID
|
|
SpRemoveInstallationFromBootList(
|
|
IN PDISK_REGION SysPartitionRegion, OPTIONAL
|
|
IN PDISK_REGION NtPartitionRegion, OPTIONAL
|
|
IN PWSTR SysRoot, OPTIONAL
|
|
IN PWSTR SystemLoadIdentifier, OPTIONAL
|
|
IN PWSTR SystemLoadOptions, OPTIONAL
|
|
IN ENUMARCPATHTYPE ArcPathType,
|
|
OUT PWSTR *OldOsLoadOptions OPTIONAL
|
|
);
|
|
|
|
BOOL
|
|
SpDetermineInstallationSource(
|
|
IN PVOID SifHandle,
|
|
OUT PWSTR *DevicePath,
|
|
OUT PWSTR *DirectoryOnDevice
|
|
);
|
|
|
|
VOID
|
|
SpGetWinntParams(
|
|
OUT PWSTR *DevicePath,
|
|
OUT PWSTR *DirectoryOnDevice
|
|
);
|
|
|
|
VOID
|
|
SpCompleteBootListConfig(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
SpInitializePidString(
|
|
IN HANDLE MasterSifHandle,
|
|
IN PWSTR SetupSourceDevicePath,
|
|
IN PWSTR DirectoryOnSourceDevice
|
|
);
|
|
|
|
NTSTATUS
|
|
SpInitialize0(
|
|
IN PDRIVER_OBJECT DriverObject
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize the setup device driver. This includes initializing
|
|
the memory allocator, saving away pieces of the os loader block,
|
|
and populating the registry with information about device drivers
|
|
that setupldr loaded for us.
|
|
|
|
Arguments:
|
|
|
|
DriverObject - supplies pointer to driver object for setupdd.sys.
|
|
|
|
Return Value:
|
|
|
|
Status is returned.
|
|
|
|
--*/
|
|
|
|
{
|
|
PLOADER_PARAMETER_BLOCK loaderBlock;
|
|
PSETUP_LOADER_BLOCK setupLoaderBlock;
|
|
PLIST_ENTRY nextEntry;
|
|
PBOOT_DRIVER_LIST_ENTRY bootDriver;
|
|
PWSTR ServiceName;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PWSTR imagePath;
|
|
|
|
//
|
|
// Initialize the memory allocator.
|
|
//
|
|
if(!SpMemInit()) {
|
|
return(STATUS_UNSUCCESSFUL);
|
|
}
|
|
|
|
//
|
|
// Fetch a pointer to the os loader block and setup loader block.
|
|
//
|
|
loaderBlock = *(PLOADER_PARAMETER_BLOCK *)KeLoaderBlock;
|
|
setupLoaderBlock = loaderBlock->SetupLoaderBlock;
|
|
|
|
//
|
|
// Phase 0 display initialization.
|
|
//
|
|
SpvidInitialize0(loaderBlock);
|
|
|
|
//
|
|
// Make a copy of the ARC pathname from which we booted.
|
|
// This is guaranteed to be the ARC equivalent of \systemroot.
|
|
//
|
|
ArcBootDevicePath = SpToUnicode(loaderBlock->ArcBootDeviceName);
|
|
DirectoryOnBootDevice = SpToUnicode(loaderBlock->NtBootPathName);
|
|
SpStringToUpper(DirectoryOnBootDevice);
|
|
|
|
//
|
|
// Make a copy if the image of the setup information file.
|
|
//
|
|
SetupldrInfoFileSize = setupLoaderBlock->IniFileLength;
|
|
SetupldrInfoFile = SpMemAlloc(SetupldrInfoFileSize);
|
|
RtlMoveMemory(SetupldrInfoFile,setupLoaderBlock->IniFile,SetupldrInfoFileSize);
|
|
|
|
//
|
|
// Make a copy of the scalar portions of the setup loader block.
|
|
//
|
|
SetupParameters = setupLoaderBlock->ScalarValues;
|
|
|
|
//
|
|
// Save away the hardware information passed to us by setupldr.
|
|
//
|
|
HardwareComponents[HwComponentDisplay] = SpSetupldrHwToHwDevice(&setupLoaderBlock->VideoDevice);
|
|
HardwareComponents[HwComponentKeyboard] = SpSetupldrHwToHwDevice(&setupLoaderBlock->KeyboardDevice);
|
|
HardwareComponents[HwComponentComputer] = SpSetupldrHwToHwDevice(&setupLoaderBlock->ComputerDevice);
|
|
ScsiHardware = SpSetupldrHwToHwDevice(setupLoaderBlock->ScsiDevices);
|
|
|
|
#ifdef _ALPHA_
|
|
//
|
|
// If the user supplied an OEM PAL disk, then save away that info as well
|
|
//
|
|
if(setupLoaderBlock->OemPal) {
|
|
|
|
PWSTR CurChar;
|
|
|
|
OemPalFilename = SpToUnicode(setupLoaderBlock->OemPal->Files->Filename);
|
|
OemPalDiskDescription = SpToUnicode(setupLoaderBlock->OemPal->Files->DiskDescription);
|
|
|
|
//
|
|
// Strip out any trailing \n's and \r's from disk description (only leave 1st line)
|
|
//
|
|
for(CurChar = OemPalDiskDescription;
|
|
*CurChar && *CurChar != L'\n' && *CurChar != L'\r';
|
|
CurChar++);
|
|
*CurChar = UNICODE_NULL;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// For each driver loaded by setupldr, we need to go create a service list entry
|
|
// for that driver in the registry.
|
|
//
|
|
for( nextEntry = loaderBlock->BootDriverListHead.Flink;
|
|
nextEntry != &loaderBlock->BootDriverListHead;
|
|
nextEntry = nextEntry->Flink)
|
|
{
|
|
bootDriver = CONTAINING_RECORD(nextEntry,BOOT_DRIVER_LIST_ENTRY,Link);
|
|
|
|
//
|
|
// Get the image path.
|
|
//
|
|
imagePath = SpMemAlloc(bootDriver->FilePath.Length + sizeof(WCHAR));
|
|
|
|
wcsncpy(
|
|
imagePath,
|
|
bootDriver->FilePath.Buffer,
|
|
bootDriver->FilePath.Length / sizeof(WCHAR)
|
|
);
|
|
|
|
imagePath[bootDriver->FilePath.Length / sizeof(WCHAR)] = 0;
|
|
|
|
Status = SpCreateServiceEntry(imagePath,&ServiceName);
|
|
|
|
//
|
|
// If this operation fails, nothing to do about it here.
|
|
//
|
|
if(NT_SUCCESS(Status)) {
|
|
bootDriver->RegistryPath.MaximumLength =
|
|
bootDriver->RegistryPath.Length = wcslen(ServiceName)*sizeof(WCHAR);
|
|
bootDriver->RegistryPath.Buffer = ServiceName;
|
|
|
|
} else {
|
|
KdPrint(("SETUP: warning: unable to create service entry for %ws (%lx)\n",imagePath,Status));
|
|
}
|
|
|
|
SpMemFree(imagePath);
|
|
}
|
|
|
|
#ifdef FULL_DOUBLE_SPACE_SUPPORT
|
|
if(NT_SUCCESS(Status)) {
|
|
|
|
OBJECT_ATTRIBUTES Obja;
|
|
UNICODE_STRING UnicodeString;
|
|
HANDLE hKey;
|
|
ULONG val = 1;
|
|
|
|
//
|
|
// Make sure we are automounting DoubleSpace
|
|
//
|
|
|
|
INIT_OBJA(
|
|
&Obja,
|
|
&UnicodeString,
|
|
L"\\registry\\machine\\system\\currentcontrolset\\control\\doublespace"
|
|
);
|
|
|
|
Status = ZwCreateKey(
|
|
&hKey,
|
|
KEY_ALL_ACCESS,
|
|
&Obja,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
NULL
|
|
);
|
|
|
|
if(NT_SUCCESS(Status)) {
|
|
RtlInitUnicodeString(&UnicodeString,L"AutomountRemovable");
|
|
Status = ZwSetValueKey(hKey,&UnicodeString,0,REG_DWORD,&val,sizeof(ULONG));
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrint(("SETUP: init0: unable to create DoubleSpace automount value (%lx)\n",Status));
|
|
}
|
|
ZwClose(hKey);
|
|
} else {
|
|
KdPrint(("SETUP: init0: unable to create DoubleSpace key (%lx)\n",Status));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Save arc disk info
|
|
//
|
|
if(NT_SUCCESS(Status)) {
|
|
|
|
PARC_DISK_INFORMATION ArcInformation;
|
|
PARC_DISK_SIGNATURE DiskInfo;
|
|
PLIST_ENTRY ListEntry;
|
|
PDISK_SIGNATURE_INFORMATION myInfo,prev;
|
|
|
|
ArcInformation = loaderBlock->ArcDiskInformation;
|
|
ListEntry = ArcInformation->DiskSignatures.Flink;
|
|
|
|
prev = NULL;
|
|
|
|
while(ListEntry != &ArcInformation->DiskSignatures) {
|
|
|
|
DiskInfo = CONTAINING_RECORD(ListEntry,ARC_DISK_SIGNATURE,ListEntry);
|
|
|
|
myInfo = SpMemAlloc(sizeof(DISK_SIGNATURE_INFORMATION));
|
|
|
|
myInfo->Signature = DiskInfo->Signature;
|
|
myInfo->ArcPath = SpToUnicode(DiskInfo->ArcName);
|
|
myInfo->CheckSum = DiskInfo->CheckSum;
|
|
myInfo->ValidPartitionTable = DiskInfo->ValidPartitionTable;
|
|
myInfo->Next = NULL;
|
|
|
|
if(prev) {
|
|
prev->Next = myInfo;
|
|
} else {
|
|
DiskSignatureInformation = myInfo;
|
|
}
|
|
prev = myInfo;
|
|
|
|
ListEntry = ListEntry->Flink;
|
|
}
|
|
}
|
|
|
|
#ifdef _PPC_
|
|
if( NT_SUCCESS(Status) &&
|
|
(InstallingOnCarolinaMachine = SpIsCarolinaMachine()) ) {
|
|
//
|
|
// Change Services\atdisk\parameters and
|
|
// Services\atdisk\atapiparameters on setup registry
|
|
//
|
|
|
|
Status = SpFixSetupHiveForCarolinaMachine();
|
|
if(!NT_SUCCESS(Status)) {
|
|
KdPrint(("SETUP: init0: unable to change setup registry for Carolina machines (%lx)\n",Status));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Register for reinitialization.
|
|
//
|
|
if(NT_SUCCESS(Status)) {
|
|
IoRegisterDriverReinitialization(DriverObject,SpInitialize0a,loaderBlock);
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
VOID
|
|
SpInitialize0a(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PVOID Context,
|
|
IN ULONG ReferenceCount
|
|
)
|
|
{
|
|
PLOADER_PARAMETER_BLOCK LoaderBlock;
|
|
PLIST_ENTRY nextEntry;
|
|
PBOOT_DRIVER_LIST_ENTRY bootDriver;
|
|
PLDR_DATA_TABLE_ENTRY driverEntry;
|
|
PHARDWARE_COMPONENT pHw,pHwPrev,pHwTemp;
|
|
BOOLEAN ReallyLoaded;
|
|
PUNICODE_STRING name;
|
|
|
|
UNREFERENCED_PARAMETER(DriverObject);
|
|
UNREFERENCED_PARAMETER(ReferenceCount);
|
|
|
|
//
|
|
// Context points to the os loader block.
|
|
//
|
|
LoaderBlock = Context;
|
|
|
|
//
|
|
// Iterate all scsi hardware we think we detected
|
|
// and make sure the driver really initialized.
|
|
//
|
|
pHwPrev = NULL;
|
|
for(pHw=ScsiHardware; pHw; ) {
|
|
|
|
//
|
|
// Assume not really loaded.
|
|
//
|
|
ReallyLoaded = FALSE;
|
|
|
|
//
|
|
// Scan the boot driver list for this driver's entry.
|
|
//
|
|
nextEntry = LoaderBlock->BootDriverListHead.Flink;
|
|
while(nextEntry != &LoaderBlock->BootDriverListHead) {
|
|
|
|
bootDriver = CONTAINING_RECORD( nextEntry,
|
|
BOOT_DRIVER_LIST_ENTRY,
|
|
Link );
|
|
|
|
driverEntry = bootDriver->LdrEntry;
|
|
name = &driverEntry->BaseDllName;
|
|
|
|
if(!_wcsnicmp(name->Buffer,pHw->BaseDllName,name->Length/sizeof(WCHAR))) {
|
|
|
|
//
|
|
// This is the driver entry we need.
|
|
//
|
|
if(!(driverEntry->Flags & LDRP_FAILED_BUILTIN_LOAD)
|
|
) {
|
|
ReallyLoaded = TRUE;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
nextEntry = nextEntry->Flink;
|
|
}
|
|
|
|
//
|
|
// If the driver didn't initialize properly,
|
|
// then it's not really loaded.
|
|
//
|
|
if(ReallyLoaded) {
|
|
pHwPrev = pHw;
|
|
pHw = pHw->Next;
|
|
} else {
|
|
|
|
pHwTemp = pHw->Next;
|
|
|
|
if(pHwPrev) {
|
|
pHwPrev->Next = pHwTemp;
|
|
} else {
|
|
ScsiHardware = pHwTemp;
|
|
}
|
|
|
|
SpFreeHwComponent(&pHw,FALSE);
|
|
|
|
pHw = pHwTemp;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Find the pcmcia and atapi drivers and make sure these drivers really
|
|
// initialized
|
|
//
|
|
|
|
//
|
|
// Assume not really loaded.
|
|
//
|
|
PcmciaLoaded = FALSE;
|
|
AtapiLoaded = FALSE;
|
|
|
|
//
|
|
// Scan the boot driver list for this driver's entry.
|
|
//
|
|
nextEntry = LoaderBlock->BootDriverListHead.Flink;
|
|
while(nextEntry != &LoaderBlock->BootDriverListHead) {
|
|
|
|
bootDriver = CONTAINING_RECORD( nextEntry,
|
|
BOOT_DRIVER_LIST_ENTRY,
|
|
Link );
|
|
|
|
driverEntry = bootDriver->LdrEntry;
|
|
name = &driverEntry->BaseDllName;
|
|
|
|
if(!_wcsnicmp(name->Buffer,L"pcmcia.sys",name->Length/sizeof(WCHAR))) {
|
|
|
|
//
|
|
// This is the driver entry we need.
|
|
//
|
|
if(!(driverEntry->Flags & LDRP_FAILED_BUILTIN_LOAD)) {
|
|
PcmciaLoaded = TRUE;
|
|
}
|
|
} else if(!_wcsnicmp(name->Buffer,L"atapi.sys",name->Length/sizeof(WCHAR))) {
|
|
|
|
//
|
|
// This is the driver entry we need.
|
|
//
|
|
if(!(driverEntry->Flags & LDRP_FAILED_BUILTIN_LOAD)) {
|
|
AtapiLoaded = TRUE;
|
|
}
|
|
}
|
|
|
|
nextEntry = nextEntry->Flink;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
SpInitialize1(
|
|
VOID
|
|
)
|
|
{
|
|
ASSERT(!GeneralInitialized);
|
|
|
|
if(GeneralInitialized) {
|
|
return;
|
|
}
|
|
|
|
SpFormatMessage(TemporaryBuffer,sizeof(TemporaryBuffer),SP_MNEMONICS);
|
|
|
|
MnemonicValues = SpMemAlloc((wcslen((PWSTR)TemporaryBuffer)+1)*sizeof(WCHAR));
|
|
|
|
wcscpy(MnemonicValues,(PWSTR)TemporaryBuffer);
|
|
|
|
GeneralInitialized = TRUE;
|
|
}
|
|
|
|
|
|
VOID
|
|
SpTerminate(
|
|
VOID
|
|
)
|
|
{
|
|
ASSERT(GeneralInitialized);
|
|
|
|
if(GeneralInitialized) {
|
|
if(MnemonicValues) {
|
|
SpMemFree(MnemonicValues);
|
|
MnemonicValues = NULL;
|
|
}
|
|
GeneralInitialized = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
SpWelcomeScreen(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Display a screen welcoming the user and allow him to choose among
|
|
some options (help, exit, aux. menu, continue, repair).
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG WelcomeKeys[] = { KEY_F1, KEY_F3, ASCI_CR, ASCI_ESC, 0 };
|
|
ULONG MnemonicKeys[] = { MnemonicRepair, 0 };
|
|
BOOLEAN Welcoming;
|
|
|
|
//
|
|
// Welcome the user.
|
|
//
|
|
for(Welcoming = TRUE; Welcoming; ) {
|
|
|
|
SpDisplayScreen(SP_SCRN_WELCOME,3,4);
|
|
|
|
SpDisplayStatusOptions(
|
|
DEFAULT_STATUS_ATTRIBUTE,
|
|
SP_STAT_ENTER_EQUALS_CONTINUE,
|
|
SP_STAT_R_EQUALS_REPAIR,
|
|
//SP_STAT_ESC_EQUALS_AUX,
|
|
SP_STAT_F1_EQUALS_HELP,
|
|
SP_STAT_F3_EQUALS_EXIT,
|
|
0
|
|
);
|
|
|
|
//
|
|
// Wait for keypress. Valid keys:
|
|
//
|
|
// F1 = help
|
|
// F3 = exit
|
|
// ENTER = continue
|
|
// R = Repair Winnt
|
|
// ESC = auxillary menu.
|
|
//
|
|
|
|
SpkbdDrain();
|
|
|
|
switch(SpWaitValidKey(WelcomeKeys,NULL,MnemonicKeys)) {
|
|
|
|
case ASCI_ESC:
|
|
|
|
//
|
|
// User wants auxillary menu.
|
|
//
|
|
break;
|
|
|
|
case ASCI_CR:
|
|
|
|
//
|
|
// User wants to continue.
|
|
//
|
|
RepairWinnt = FALSE;
|
|
Welcoming = FALSE;
|
|
break;
|
|
|
|
case KEY_F1:
|
|
|
|
//
|
|
// User wants help.
|
|
//
|
|
SpHelp(SP_HELP_WELCOME, NULL, SPHELP_HELPTEXT);
|
|
break;
|
|
|
|
case KEY_F3:
|
|
|
|
//
|
|
// User wants to exit.
|
|
//
|
|
SpConfirmExit();
|
|
break;
|
|
|
|
default:
|
|
|
|
//
|
|
// must be repair mnemonic
|
|
//
|
|
|
|
RepairWinnt = TRUE;
|
|
Welcoming = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SpDisplayEula (
|
|
IN HANDLE MasterSifHandle,
|
|
IN PWSTR SetupSourceDevicePath,
|
|
IN PWSTR DirectoryOnSourceDevice
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Display the End User Licensing Agreement.
|
|
|
|
Arguments:
|
|
|
|
MasterSifHandle - Handle to txtsetup.sif.
|
|
|
|
SetupSourceDevicePath - Path to the device that contains the source media.
|
|
|
|
DirectoryOnSourceDevice - Directory on the media where EULA is located.
|
|
|
|
Return Value:
|
|
|
|
None. Does not return if user does not accept licensing agreement or if
|
|
the licensing agreement cannot be opened.
|
|
|
|
--*/
|
|
|
|
{
|
|
PWSTR MediaShortName;
|
|
PWSTR MediaDirectory;
|
|
PWSTR EulaPath;
|
|
NTSTATUS Status;
|
|
PVOID BaseAddress;
|
|
ULONG FileSize;
|
|
HANDLE hFile, hSection;
|
|
ULONG ValidKeys[2] = { KEY_F3,0 };
|
|
PWSTR Eula;
|
|
ULONG EulaSize;
|
|
|
|
if (PreInstall || UnattendedOperation) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Figure out the path to eula.txt
|
|
//
|
|
MediaShortName = SpLookUpValueForFile(
|
|
MasterSifHandle,
|
|
L"eula.txt",
|
|
INDEX_WHICHMEDIA,
|
|
TRUE
|
|
);
|
|
SpPromptForSetupMedia(
|
|
MasterSifHandle,
|
|
MediaShortName,
|
|
SetupSourceDevicePath
|
|
);
|
|
|
|
SpGetSourceMediaInfo(
|
|
MasterSifHandle,MediaShortName,NULL,NULL,&MediaDirectory);
|
|
|
|
wcscpy( (PWSTR)TemporaryBuffer, SetupSourceDevicePath );
|
|
SpConcatenatePaths( (PWSTR)TemporaryBuffer, DirectoryOnSourceDevice );
|
|
SpConcatenatePaths( (PWSTR)TemporaryBuffer, MediaDirectory );
|
|
SpConcatenatePaths( (PWSTR)TemporaryBuffer, L"eula.txt" );
|
|
EulaPath = SpDupStringW( (PWSTR)TemporaryBuffer );
|
|
|
|
//
|
|
// Open and map the file for read access.
|
|
//
|
|
hFile = 0; // use EulaPath instead
|
|
Status = SpOpenAndMapFile(
|
|
EulaPath,
|
|
&hFile,
|
|
&hSection,
|
|
&BaseAddress,
|
|
&FileSize,
|
|
FALSE
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
//
|
|
// Display a message indicating that there was a fatal error while trying
|
|
// to open the EULA file.
|
|
//
|
|
SpStartScreen(
|
|
SP_SCRN_FATAL_ERROR_EULA_NOT_FOUND,
|
|
3,
|
|
HEADER_HEIGHT+3,
|
|
FALSE,
|
|
FALSE,
|
|
DEFAULT_ATTRIBUTE
|
|
);
|
|
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_F3_EQUALS_EXIT,
|
|
0);
|
|
SpWaitValidKey(ValidKeys,NULL,NULL);
|
|
SpDone(FALSE,TRUE);
|
|
}
|
|
|
|
//
|
|
// Convert the text to Unicode.
|
|
//
|
|
Eula = SpMemAlloc ((FileSize+1) * sizeof(WCHAR));
|
|
ASSERT (Eula);
|
|
|
|
Status = RtlMultiByteToUnicodeN (
|
|
Eula,
|
|
FileSize * sizeof(WCHAR),
|
|
&EulaSize,
|
|
BaseAddress,
|
|
FileSize
|
|
);
|
|
ASSERT (NT_SUCCESS(Status));
|
|
Eula[EulaSize / sizeof(WCHAR)] = (WCHAR)'\0';
|
|
|
|
//
|
|
// Show text to user.
|
|
//
|
|
SpHelp(
|
|
0,
|
|
Eula,
|
|
SPHELP_LICENSETEXT
|
|
);
|
|
|
|
//
|
|
// Clean up
|
|
//
|
|
SpMemFree (EulaPath);
|
|
SpMemFree (Eula);
|
|
SpUnmapFile(hSection,BaseAddress);
|
|
ZwClose(hFile);
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
SpCustomExpressScreen(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allow the user to choose between custom and express setup.
|
|
|
|
The global variable CustomSetup is set according to the user's choice.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG ValidKeys[] = { KEY_F1, KEY_F3, ASCI_CR, 0 };
|
|
ULONG MnemonicKeys[] = { MnemonicCustom, 0 };
|
|
BOOLEAN Choosing;
|
|
ULONG c;
|
|
|
|
//
|
|
// See whether this parameter is specified for unattended operation.
|
|
//
|
|
if(UnattendedOperation) {
|
|
|
|
PWSTR p = SpGetSectionKeyIndex(UnattendedSifHandle,
|
|
SIF_UNATTENDED,WINNT_U_METHOD_W,0);
|
|
PWSTR q = SpGetSectionKeyIndex(UnattendedSifHandle,
|
|
SIF_UNATTENDED,WINNT_U_OVERWRITEOEM_W,0);
|
|
|
|
if( q && !_wcsicmp( q, L"no" ) ) {
|
|
UnattendedOverwriteOem = FALSE;
|
|
} else {
|
|
UnattendedOverwriteOem = TRUE;
|
|
}
|
|
|
|
//
|
|
// Default is custom. If user specified something
|
|
// else then use express.
|
|
//
|
|
if(p && _wcsicmp(p,L"custom")) {
|
|
CustomSetup = FALSE;
|
|
}
|
|
return;
|
|
}
|
|
|
|
#if 0
|
|
for(Choosing = TRUE; Choosing; ) {
|
|
|
|
SpDisplayScreen(SP_SCRN_CUSTOM_EXPRESS,3,4);
|
|
|
|
SpDisplayStatusOptions(
|
|
DEFAULT_STATUS_ATTRIBUTE,
|
|
SP_STAT_ENTER_EQUALS_EXPRESS,
|
|
SP_STAT_C_EQUALS_CUSTOM,
|
|
SP_STAT_F1_EQUALS_HELP,
|
|
SP_STAT_F3_EQUALS_EXIT,
|
|
0
|
|
);
|
|
|
|
//
|
|
// Wait for keypress. Valid keys:
|
|
//
|
|
// F1 = help
|
|
// F3 = exit
|
|
// ENTER = express setup
|
|
// <MnemonicCustom> = custom setup
|
|
//
|
|
|
|
SpkbdDrain();
|
|
|
|
switch(c=SpWaitValidKey(ValidKeys,NULL,MnemonicKeys)) {
|
|
|
|
case ASCI_CR:
|
|
|
|
//
|
|
// User wants express setup.
|
|
//
|
|
CustomSetup = FALSE;
|
|
Choosing = FALSE;
|
|
break;
|
|
|
|
case KEY_F1:
|
|
|
|
//
|
|
// User wants help.
|
|
//
|
|
SpHelp(SP_HELP_CUSTOM_EXPRESS, NULL, SPHELP_HELPTEXT);
|
|
break;
|
|
|
|
case KEY_F3:
|
|
|
|
//
|
|
// User wants to exit.
|
|
//
|
|
SpConfirmExit();
|
|
break;
|
|
|
|
default:
|
|
|
|
//
|
|
// must be custom mnemonic
|
|
//
|
|
ASSERT(c == (MnemonicCustom | KEY_MNEMONIC));
|
|
CustomSetup = TRUE;
|
|
Choosing = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#ifdef _FASTRECOVER_
|
|
VOID
|
|
SpFRExpressCustomScreen(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Allow the user to choose between express and custom fast recover mode setup.
|
|
|
|
The global variable CustomSetup is set according to the user's choice.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG ValidKeys[] = { KEY_F1, KEY_F3, ASCI_CR, 0 };
|
|
ULONG MnemonicKeys[] = { MnemonicCustom, 0 };
|
|
BOOLEAN Choosing;
|
|
ULONG c;
|
|
|
|
#if 0
|
|
//
|
|
// See whether this parameter is specified for unattended operation.
|
|
//
|
|
if(UnattendedOperation) {
|
|
|
|
PWSTR p = SpGetSectionKeyIndex(UnattendedSifHandle,
|
|
SIF_UNATTENDED,WINNT_U_METHOD_W,0);
|
|
PWSTR q = SpGetSectionKeyIndex(UnattendedSifHandle,
|
|
SIF_UNATTENDED,WINNT_U_OVERWRITEOEM_W,0);
|
|
|
|
if( q && !_wcsicmp( q, L"no" ) ) {
|
|
UnattendedOverwriteOem = FALSE;
|
|
} else {
|
|
UnattendedOverwriteOem = TRUE;
|
|
}
|
|
|
|
//
|
|
// Default is custom. If user specified something
|
|
// else then use express.
|
|
//
|
|
if(p && _wcsicmp(p,L"custom")) {
|
|
CustomSetup = FALSE;
|
|
}
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
for(Choosing = TRUE; Choosing; ) {
|
|
|
|
SpDisplayScreen(SP_SCRN_CUSTOM_EXPRESS,3,4);
|
|
|
|
SpDisplayStatusOptions(
|
|
DEFAULT_STATUS_ATTRIBUTE,
|
|
SP_STAT_ENTER_EQUALS_EXPRESS,
|
|
SP_STAT_C_EQUALS_CUSTOM,
|
|
SP_STAT_F1_EQUALS_HELP,
|
|
SP_STAT_F3_EQUALS_EXIT,
|
|
0
|
|
);
|
|
|
|
//
|
|
// Wait for keypress. Valid keys:
|
|
//
|
|
// F1 = help
|
|
// F3 = exit
|
|
// ENTER = express setup
|
|
// <MnemonicCustom> = custom setup
|
|
//
|
|
|
|
SpkbdDrain();
|
|
|
|
switch(c=SpWaitValidKey(ValidKeys,NULL,MnemonicKeys)) {
|
|
|
|
case ASCI_CR:
|
|
|
|
//
|
|
// User wants express setup.
|
|
//
|
|
CustomSetup = FALSE;
|
|
Choosing = FALSE;
|
|
break;
|
|
|
|
case KEY_F1:
|
|
|
|
//
|
|
// User wants help.
|
|
//
|
|
SpHelp(SP_HELP_CUSTOM_EXPRESS, NULL, SPHELP_HELPTEXT);
|
|
break;
|
|
|
|
case KEY_F3:
|
|
|
|
//
|
|
// User wants to exit.
|
|
//
|
|
SpConfirmExit();
|
|
break;
|
|
|
|
default:
|
|
|
|
//
|
|
// must be custom mnemonic
|
|
//
|
|
ASSERT(c == (MnemonicCustom | KEY_MNEMONIC));
|
|
CustomSetup = TRUE;
|
|
Choosing = FALSE;
|
|
UnattendedPartitionInteract = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
PVOID
|
|
SpLoadSetupInformationFile(
|
|
VOID
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG ErrLine;
|
|
PVOID SifHandle;
|
|
|
|
CLEAR_CLIENT_SCREEN();
|
|
|
|
//
|
|
// The image of txtsetup.sif has been passed to us
|
|
// by setupldr.
|
|
//
|
|
Status = SpLoadSetupTextFile(
|
|
NULL,
|
|
SetupldrInfoFile,
|
|
SetupldrInfoFileSize,
|
|
&SifHandle,
|
|
&ErrLine
|
|
);
|
|
|
|
//
|
|
// We're done with the image.
|
|
//
|
|
SpMemFree(SetupldrInfoFile);
|
|
SetupldrInfoFile = NULL;
|
|
SetupldrInfoFileSize = 0;
|
|
|
|
if(NT_SUCCESS(Status)) {
|
|
return(SifHandle);
|
|
}
|
|
|
|
//
|
|
// The file was already parsed once by setupldr.
|
|
// If we can't do it here, there's a serious problem.
|
|
// Assume it was a syntax error, because we didn't
|
|
// have to load it from disk.
|
|
//
|
|
SpStartScreen(
|
|
SP_SCRN_SIF_PROCESS_ERROR,
|
|
3,
|
|
HEADER_HEIGHT+1,
|
|
FALSE,
|
|
FALSE,
|
|
DEFAULT_ATTRIBUTE,
|
|
ErrLine
|
|
);
|
|
|
|
//
|
|
// Since we haven't yet loaded the keyboard layout, we can't prompt the
|
|
// user to press F3 to exit
|
|
//
|
|
SpDisplayStatusText(SP_STAT_KBD_HARD_REBOOT, DEFAULT_STATUS_ATTRIBUTE);
|
|
|
|
while(TRUE); // Loop forever
|
|
}
|
|
|
|
|
|
VOID
|
|
SpIsWinntOrUnattended(
|
|
VOID
|
|
)
|
|
{
|
|
PWSTR szZero = L"0";
|
|
NTSTATUS Status;
|
|
ULONG ErrorLine;
|
|
PWSTR p;
|
|
|
|
//
|
|
// Attempt to load winnt.sif. If the user is in the middle of
|
|
// a winnt setup, this file will be present.
|
|
//
|
|
Status = SpLoadSetupTextFile(
|
|
L"\\SystemRoot\\winnt.sif",
|
|
NULL,
|
|
0,
|
|
&WinntSifHandle,
|
|
&ErrorLine
|
|
);
|
|
|
|
if(NT_SUCCESS(Status)) {
|
|
|
|
//
|
|
// Check for winnt setup.
|
|
//
|
|
p = SpGetSectionKeyIndex(WinntSifHandle,SIF_DATA,
|
|
WINNT_D_MSDOS_W,0);
|
|
if(p && SpStringToLong(p,NULL,10)) {
|
|
|
|
WinntSetup = TRUE;
|
|
}
|
|
|
|
#ifdef _X86_
|
|
//
|
|
// Check for floppyless boot.
|
|
//
|
|
p = SpGetSectionKeyIndex(WinntSifHandle,SIF_DATA,
|
|
WINNT_D_FLOPPY_W,0);
|
|
if(p && SpStringToLong(p,NULL,10)) {
|
|
|
|
IsFloppylessBoot = TRUE;
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Check for ignore missing files.
|
|
//
|
|
p = SpGetSectionKeyIndex(WinntSifHandle,SIF_SETUPPARAMS,
|
|
WINNT_S_SKIPMISSING_W,0);
|
|
if(p && SpStringToLong(p,NULL,10)) {
|
|
|
|
SkipMissingFiles = TRUE;
|
|
}
|
|
|
|
//
|
|
// Now check for an unattended setup.
|
|
//
|
|
if(SpSearchTextFileSection(WinntSifHandle,SIF_UNATTENDED)) {
|
|
|
|
//
|
|
// Run in unattended mode. Leave the sif open
|
|
// and save away its handle for later use.
|
|
//
|
|
UnattendedSifHandle = WinntSifHandle;
|
|
UnattendedOperation = TRUE;
|
|
|
|
} else if(SpSearchTextFileSection(WinntSifHandle,SIF_GUI_UNATTENDED)) {
|
|
|
|
//
|
|
// Leave UnattendedOperation to FALSE (because it mainly uses to
|
|
// control text mode setup.) Store the handle of winnt.sif for later
|
|
// reference.
|
|
//
|
|
|
|
// UnattendedSifHandle = SifHandle;
|
|
UnattendedGuiOperation = TRUE;
|
|
#if 0
|
|
} else {
|
|
//
|
|
// Don't need this file any more.
|
|
//
|
|
SpFreeTextFile(WinntSifHandle);
|
|
#endif
|
|
}
|
|
|
|
if(UnattendedOperation) {
|
|
//
|
|
// If this is an unattended operation, find out if this is
|
|
// also an OEM pre-install
|
|
//
|
|
p = SpGetSectionKeyIndex(UnattendedSifHandle,
|
|
SIF_UNATTENDED,
|
|
WINNT_U_OEMPREINSTALL_W,
|
|
0);
|
|
|
|
if( p && !_wcsicmp( p, L"yes" ) ) {
|
|
PreInstall = TRUE;
|
|
}
|
|
|
|
}
|
|
} else {
|
|
// Case where there isn't an WINNT.SIF file to be found
|
|
|
|
//
|
|
// Create a handle to the new file
|
|
//
|
|
WinntSifHandle = SpNewSetupTextFile();
|
|
//
|
|
// Add a bunch of defaults which *should* of been there, but
|
|
// was not
|
|
SpAddLineToSection(WinntSifHandle,SIF_DATA,
|
|
WINNT_D_MSDOS_W,&szZero,1);
|
|
SpAddLineToSection(WinntSifHandle,SIF_DATA,
|
|
WINNT_D_FLOPPY_W,&szZero,1);
|
|
SpAddLineToSection(WinntSifHandle,SIF_SETUPPARAMS,
|
|
WINNT_S_SKIPMISSING_W,&szZero,1);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
SpCheckSufficientMemory(
|
|
IN PVOID SifHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine whether sufficient memory exists in the system
|
|
for installation to proceed. The required amount is specified
|
|
in the sif file.
|
|
|
|
Arguments:
|
|
|
|
SifHandle - supplies handle to open setup information file.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG RequiredBytes,AvailableBytes;
|
|
PWSTR p;
|
|
|
|
p = SpGetSectionKeyIndex(SifHandle,SIF_SETUPDATA,SIF_REQUIREDMEMORY,0);
|
|
|
|
if(!p) {
|
|
SpFatalSifError(SifHandle,SIF_SETUPDATA,SIF_REQUIREDMEMORY,0,0);
|
|
}
|
|
|
|
RequiredBytes = SpStringToLong(p,NULL,10);
|
|
|
|
AvailableBytes = SystemBasicInfo.NumberOfPhysicalPages * SystemBasicInfo.PageSize;
|
|
|
|
if(AvailableBytes < RequiredBytes) {
|
|
|
|
SpStartScreen(
|
|
SP_SCRN_INSUFFICIENT_MEMORY,
|
|
3,
|
|
HEADER_HEIGHT+1,
|
|
FALSE,
|
|
FALSE,
|
|
DEFAULT_ATTRIBUTE,
|
|
RequiredBytes / (1024*1024),
|
|
((RequiredBytes % (1024*1024)) * 100) / (1024*1024)
|
|
);
|
|
|
|
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_F3_EQUALS_EXIT,0);
|
|
|
|
SpkbdDrain();
|
|
while(SpkbdGetKeypress() != KEY_F3) ;
|
|
|
|
SpDone(FALSE,TRUE);
|
|
}
|
|
}
|
|
|
|
|
|
ULONG
|
|
SpStartSetup(
|
|
VOID
|
|
)
|
|
{
|
|
PVOID SifHandle, RepairSifHandle;
|
|
PDISK_REGION TargetRegion,SystemPartitionRegion;
|
|
PWSTR TargetPath,SystemPartitionDirectory=NULL,OriginalSystemPartitionDirectory=NULL;
|
|
PWSTR DefaultTarget;
|
|
PWSTR SetupSourceDevicePath,DirectoryOnSetupSource;
|
|
PWSTR OldOsLoadOptions;
|
|
#ifdef _FASTRECOVER_
|
|
PWSTR p;
|
|
#endif
|
|
BOOLEAN CdInstall, Status, HasErDisk;
|
|
|
|
SpInitialize1();
|
|
SpvidInitialize(); // initialize video first, so we can give err msg if keyboard error
|
|
SpkbdInitialize();
|
|
|
|
//
|
|
// Initialize ARC<==>NT name translations.
|
|
//
|
|
SpInitializeArcNames();
|
|
|
|
//
|
|
// Set up the boot device path, which we have stashed away
|
|
// from the os loader block.
|
|
//
|
|
NtBootDevicePath = SpArcToNt(ArcBootDevicePath);
|
|
if(!NtBootDevicePath) {
|
|
SpBugCheck(SETUP_BUGCHECK_BOOTPATH,0,0,0);
|
|
}
|
|
|
|
//
|
|
// Read SKU data, such as whether we are in stepmode or
|
|
// this is an evaluation unit. Fills in StepUpMode and
|
|
// EvaluationTime globals.
|
|
//
|
|
SpReadSKUStuff();
|
|
|
|
//
|
|
// Reinitialize video -- noop in western builds but switches into DBCS mode,
|
|
// etc, in Far Eastern builds.
|
|
//
|
|
if(NT_SUCCESS(SplangInitializeFontSupport(NtBootDevicePath,DirectoryOnBootDevice))) {
|
|
SpvidInitialize(); // reinitialize video in alternate mode for Far East
|
|
}
|
|
|
|
//
|
|
// Process the txtsetup.sif file, which the boot loader
|
|
// will have loaded for us.
|
|
//
|
|
SifHandle = SpLoadSetupInformationFile();
|
|
|
|
#ifdef _FASTRECOVER_
|
|
//wfc
|
|
// Check whether this setup is running in Fast Recover mode.
|
|
//
|
|
p = SpGetSectionKeyIndex(SifHandle,
|
|
SIF_SETUPDATA,
|
|
L"FastRecoverOperation",
|
|
0);
|
|
|
|
if( p && !_wcsicmp( p, L"yes" ) ) {
|
|
FastRecoverOperation = TRUE;
|
|
}
|
|
#endif
|
|
|
|
#ifdef _X86_
|
|
//
|
|
// BUGBUG - Remove this block after the Beta
|
|
//
|
|
{
|
|
PWSTR p;
|
|
p = SpGetSectionKeyIndex(
|
|
SifHandle,
|
|
SIF_SETUPDATA,
|
|
L"EnableWin95Migration",
|
|
0
|
|
);
|
|
if( p &&
|
|
(SpStringToLong(p,NULL,10) == 1)
|
|
) {
|
|
DisableWin95Migration = FALSE;
|
|
} else {
|
|
DisableWin95Migration = TRUE;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
SpkbdLoadLayoutDll(SifHandle,DirectoryOnBootDevice);
|
|
|
|
//
|
|
// Check for sufficient memory. Does not return if not enough.
|
|
//
|
|
SpCheckSufficientMemory(SifHandle);
|
|
|
|
//
|
|
// Determine whether this is a winnt (dos-initiated) setup
|
|
// and/or unattended setup. If unattended, the global variable
|
|
// UnattendedSifHandle will be filled in. If winnt, the global
|
|
// variable WinntSetup will be set to TRUE.
|
|
//
|
|
SpIsWinntOrUnattended();
|
|
|
|
#ifdef _FASTRECOVER_
|
|
//wfc
|
|
// Check for an unattended setup in TXTSETUP.SIF
|
|
//
|
|
if(SpSearchTextFileSection(SifHandle,SIF_UNATTENDED)) {
|
|
//
|
|
// Run in unattended mode. Leave the sif open
|
|
// and save away its handle for later use.
|
|
//
|
|
UnattendedSifHandle = SifHandle;
|
|
UnattendedOperation = TRUE;
|
|
|
|
//
|
|
// If this is an unattended operation, determine whether to skip
|
|
// automatic partition checking (autochk). Skipping autochk will
|
|
// save signficant time during unattended fast recovery.
|
|
//
|
|
p = SpGetSectionKeyIndex(UnattendedSifHandle,
|
|
SIF_UNATTENDED,
|
|
L"SkipAutoCheck",
|
|
0);
|
|
|
|
if( p && !_wcsicmp( p, L"yes" ) ) {
|
|
UnattendedSkipAutoCheck = TRUE;
|
|
}
|
|
|
|
//
|
|
// If this is an unattended operation, find out if partitioning
|
|
// should be interactive, thus allowing the text mode partitioning
|
|
// interface to be used during an unattended operation.
|
|
//
|
|
p = SpGetSectionKeyIndex(UnattendedSifHandle,
|
|
SIF_UNATTENDED,
|
|
L"PartitionInteract",
|
|
0);
|
|
|
|
if( p && !_wcsicmp( p, L"yes" ) ) {
|
|
UnattendedPartitionInteract = TRUE;
|
|
}
|
|
|
|
//
|
|
// If this is an unattended operation, check whether prompting before
|
|
// rebooting the system should be displayed, so that the user is
|
|
// reminded to remove any floppy media left in the drive during the
|
|
// unattended setup.
|
|
//
|
|
p = SpGetSectionKeyIndex(UnattendedSifHandle,
|
|
SIF_UNATTENDED,
|
|
L"PromptForReboot",
|
|
0);
|
|
|
|
if( p && !_wcsicmp( p, L"yes" ) ) {
|
|
UnattendedPromptForReboot = TRUE;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Determine whether this is advanced server.
|
|
//
|
|
SpDetermineProductType(SifHandle);
|
|
|
|
//
|
|
// Display the correct header text based on the product.
|
|
//
|
|
SpDisplayHeaderText(
|
|
AdvancedServer ? SP_HEAD_ADVANCED_SERVER_SETUP : SP_HEAD_WINDOWS_NT_SETUP,
|
|
DEFAULT_ATTRIBUTE
|
|
);
|
|
|
|
//
|
|
// Welcome the user and determine if this is for repairing.
|
|
//
|
|
DoWelcome:
|
|
|
|
if(!UnattendedOperation) {
|
|
SpWelcomeScreen();
|
|
}
|
|
|
|
if (RepairWinnt) {
|
|
|
|
//
|
|
// if repair, we want to ask user if he wants to skip scsi detection.
|
|
//
|
|
|
|
Status = SpDisplayRepairMenu();
|
|
if (Status == FALSE) {
|
|
|
|
//
|
|
// User pressed ESC to leave repair menu
|
|
//
|
|
|
|
goto DoWelcome;
|
|
}
|
|
WinntSetup = FALSE;
|
|
|
|
//
|
|
// Initialize CustomSetup to TRUE to display the SCSI detection warning
|
|
//
|
|
|
|
CustomSetup = TRUE;
|
|
} else {
|
|
|
|
#ifdef _FASTRECOVER_
|
|
//
|
|
// Choose custom vs. express setup.
|
|
//
|
|
if (FastRecoverOperation)
|
|
SpFRExpressCustomScreen();
|
|
else
|
|
SpCustomExpressScreen();
|
|
#else
|
|
//
|
|
// Choose custom vs. express setup.
|
|
//
|
|
SpCustomExpressScreen();
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Detect/load scsi miniports.
|
|
// WARNING WARNING WARNING
|
|
//
|
|
// Do NOT change the order of the actions carried out below without
|
|
// understanding EXACTLY what you are doing.
|
|
// There are many interdependencies...
|
|
//
|
|
SpConfirmScsiMiniports(SifHandle, NtBootDevicePath, DirectoryOnBootDevice);
|
|
|
|
//
|
|
// Load disk class drivers if necessary.
|
|
// Do this before loading scsi class drivers, because atdisks
|
|
// and the like 'come before' scsi disks in the load order.
|
|
//
|
|
SpLoadDiskDrivers(SifHandle,NtBootDevicePath,DirectoryOnBootDevice);
|
|
|
|
//
|
|
// Load scsi class drivers if necessary.
|
|
//
|
|
SpLoadScsiClassDrivers(SifHandle,NtBootDevicePath,DirectoryOnBootDevice);
|
|
|
|
//
|
|
// Reinitialize ARC<==>NT name translations.
|
|
// Do this after loading disk and scsi class drivers because doing so
|
|
// may bring additional devices on-line.
|
|
//
|
|
SpFreeArcNames();
|
|
SpInitializeArcNames();
|
|
|
|
//
|
|
// Initialize hard disk information.
|
|
// Do this after loading disk drivers so we can talk to all attached disks.
|
|
//
|
|
SpDetermineHardDisks(SifHandle);
|
|
|
|
//
|
|
// Figure out where we are installing from (cd-rom or floppy).
|
|
// BUGBUG (tedm, 12/8/93) there is a minor problem here.
|
|
// This only works because we currently only support scsi cd-rom drives,
|
|
// and we have loaded the scsi class drivers above.
|
|
// SpDetermineInstallationSource won't allow cd-rom installation
|
|
// it there are no cd-rom drives on-line -- but we haven't loaded
|
|
// non-scsi cd-rom drivers yet. What we really should do is
|
|
// allow cd-rom as a choice on all machines, and if the user selects
|
|
// it, not verify the presence of a drive until after we have called
|
|
// SpLoadCdRomDrivers().
|
|
//
|
|
// If winnt setup, defer this for now, because we will let the partitioning
|
|
// engine search for the local source directory when it initializes.
|
|
//
|
|
|
|
CdInstall = WinntSetup
|
|
? FALSE
|
|
: SpDetermineInstallationSource(
|
|
SifHandle,
|
|
&SetupSourceDevicePath,
|
|
&DirectoryOnSetupSource
|
|
);
|
|
|
|
//
|
|
// Load cd-rom drivers if necessary.
|
|
// Note that if we booted from CD (like on an ARC machine) then drivers
|
|
// will already have been loaded by setupldr. This call here catches the
|
|
// case where we booted from floppy or hard disk and the user chose
|
|
// 'install from cd' during SpDetermineInstallationSource.
|
|
//
|
|
// If we're in step-up mode then we load cd drivers, because the user
|
|
// might need to insert a CD to prove that he qualifies for the step-up.
|
|
//
|
|
if(StepUpMode || CdInstall) {
|
|
SpLoadCdRomDrivers(SifHandle,NtBootDevicePath,DirectoryOnBootDevice);
|
|
|
|
//
|
|
// Reinitialize ARC<==>NT name translations.
|
|
//
|
|
SpFreeArcNames();
|
|
SpInitializeArcNames();
|
|
}
|
|
|
|
//
|
|
// At this point, any and all drivers that are to be loaded
|
|
// are loaded -- we are done with the boot media and can switch over
|
|
// to the setup media
|
|
//
|
|
// Initialize the partitioning engine.
|
|
//
|
|
SpPtInitialize();
|
|
|
|
//
|
|
// If this is a winnt setup, the partition engine initialization
|
|
// will have attempted to locate the local source partition for us.
|
|
//
|
|
// WARNING: Do not use the SetupSourceDevicePath or DirectoryOnSetupSource
|
|
// variables in the winnt case until AFTER this bit of code has executed
|
|
// as they are not set until we get here!
|
|
//
|
|
if(WinntSetup) {
|
|
SpGetWinntParams(&SetupSourceDevicePath,&DirectoryOnSetupSource);
|
|
}
|
|
|
|
//
|
|
// Initialize the boot variables
|
|
//
|
|
|
|
SpInitBootVars();
|
|
|
|
//
|
|
// Ask user for emergency repair diskette
|
|
//
|
|
|
|
|
|
if (RepairWinnt) {
|
|
|
|
AskForRepairDisk:
|
|
|
|
//
|
|
// Display message to let user know he can either provide his
|
|
// own ER disk or let setup search for him.
|
|
//
|
|
|
|
HasErDisk = SpErDiskScreen();
|
|
RepairSifHandle = NULL;
|
|
|
|
if (HasErDisk) {
|
|
|
|
//
|
|
// Ask for emergency repair diskette until either we get it or
|
|
// user cancels the request.
|
|
//
|
|
|
|
SpRepairDiskette(&RepairSifHandle,
|
|
&TargetRegion,
|
|
&TargetPath,
|
|
&SystemPartitionRegion,
|
|
&SystemPartitionDirectory
|
|
);
|
|
}
|
|
|
|
if (!RepairSifHandle) {
|
|
|
|
BOOLEAN FoundRepairableSystem;
|
|
|
|
//
|
|
// If user has no emergency repair diskette, we need to find out
|
|
// if there is any NT to repair and which one to repair.
|
|
//
|
|
|
|
FoundRepairableSystem = FALSE;
|
|
Status = SpFindNtToRepair(SifHandle,
|
|
&TargetRegion,
|
|
&TargetPath,
|
|
&SystemPartitionRegion,
|
|
&SystemPartitionDirectory,
|
|
&FoundRepairableSystem
|
|
);
|
|
if (Status == TRUE) {
|
|
|
|
PWSTR p = (PWSTR)TemporaryBuffer;
|
|
PWSTR FullLogFileName;
|
|
BOOLEAN rc;
|
|
|
|
//
|
|
// Get the device path of the nt partition.
|
|
//
|
|
|
|
SpNtNameFromRegion(
|
|
TargetRegion,
|
|
p,
|
|
sizeof(TemporaryBuffer),
|
|
PartitionOrdinalCurrent
|
|
);
|
|
|
|
//
|
|
// Form the full NT path of the setup.log file
|
|
//
|
|
|
|
SpConcatenatePaths(p,TargetPath);
|
|
SpConcatenatePaths(p,SETUP_REPAIR_DIRECTORY);
|
|
SpConcatenatePaths(p,SETUP_LOG_FILENAME);
|
|
|
|
FullLogFileName = SpDupStringW(p);
|
|
|
|
//
|
|
// read and process the setup.log file.
|
|
//
|
|
|
|
rc = SpLoadRepairLogFile(FullLogFileName, &RepairSifHandle);
|
|
SpMemFree(FullLogFileName);
|
|
if (!rc) {
|
|
|
|
//
|
|
// Load setup.log failed. Ask user to insert a ER
|
|
// diskette again.
|
|
//
|
|
|
|
goto AskForRepairDisk;
|
|
} else {
|
|
RepairFromErDisk = FALSE;
|
|
}
|
|
} else {
|
|
|
|
if( FoundRepairableSystem ) {
|
|
//
|
|
// No WinNT installation was chosen. We will go back to
|
|
// ask ER diskette again.
|
|
//
|
|
goto AskForRepairDisk;
|
|
} else {
|
|
//
|
|
// Couldn't find any NT to repair
|
|
//
|
|
ULONG ValidKeys[] = { KEY_F3, ASCI_CR, 0 };
|
|
ULONG MnemonicKeys[] = { MnemonicCustom, 0 };
|
|
ULONG c;
|
|
|
|
SpStartScreen( SP_SCRN_REPAIR_NT_NOT_FOUND,
|
|
3,
|
|
HEADER_HEIGHT+1,
|
|
FALSE,
|
|
FALSE,
|
|
DEFAULT_ATTRIBUTE );
|
|
|
|
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
|
|
SP_STAT_ENTER_EQUALS_REPAIR,
|
|
SP_STAT_F3_EQUALS_EXIT,0);
|
|
|
|
SpkbdDrain();
|
|
switch(c=SpWaitValidKey(ValidKeys,NULL,NULL)) {
|
|
|
|
case KEY_F3:
|
|
|
|
//
|
|
// User wants to exit.
|
|
//
|
|
SpDone(TRUE,TRUE);
|
|
break;
|
|
|
|
default:
|
|
goto AskForRepairDisk;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Now proceed to repair
|
|
//
|
|
|
|
SpRepairWinnt(RepairSifHandle,
|
|
SifHandle,
|
|
SetupSourceDevicePath,
|
|
DirectoryOnSetupSource);
|
|
|
|
SpStringToUpper(TargetPath);
|
|
goto UpdateBootList;
|
|
|
|
} else {
|
|
//
|
|
// Display End User Licensing Agreement
|
|
//
|
|
|
|
SpDisplayEula (
|
|
SifHandle,
|
|
SetupSourceDevicePath,
|
|
DirectoryOnSetupSource);
|
|
|
|
//
|
|
// Read the product id from setupp.ini
|
|
//
|
|
|
|
SpInitializePidString( SifHandle,
|
|
SetupSourceDevicePath,
|
|
DirectoryOnSetupSource );
|
|
|
|
//
|
|
// Find out if there is any NT to upgrade and if the user wants us to
|
|
// upgrade it
|
|
//
|
|
|
|
NTUpgrade = SpFindNtToUpgrade(SifHandle,
|
|
&TargetRegion,
|
|
&TargetPath,
|
|
&SystemPartitionRegion,
|
|
&OriginalSystemPartitionDirectory);
|
|
|
|
}
|
|
|
|
if( PreInstall ) {
|
|
//
|
|
// In pre-install mode, get the information about the components
|
|
// to pre-install
|
|
//
|
|
wcscpy( (PWSTR)TemporaryBuffer, DirectoryOnSetupSource );
|
|
SpConcatenatePaths( (PWSTR)TemporaryBuffer, WINNT_OEM_TEXTMODE_DIR_W );
|
|
PreinstallOemSourcePath = SpDupStringW( ( PWSTR )TemporaryBuffer );
|
|
SpInitializePreinstallList(SifHandle,
|
|
SetupSourceDevicePath ,
|
|
PreinstallOemSourcePath);
|
|
}
|
|
|
|
|
|
//
|
|
// Detect/confirm hardware.
|
|
//
|
|
SpConfirmHardware(SifHandle);
|
|
//
|
|
// Reinitialize the keyboard layout dll. This is a no-op for western builds
|
|
// but in Far East builds this can cause a new keyboard layout dll to be loaded.
|
|
//
|
|
if(NTUpgrade != UpgradeFull) {
|
|
extern PVOID KeyboardTable;
|
|
//
|
|
// BUGBUG - jaimes - Fix this on OEM pre-install
|
|
//
|
|
SplangReinitializeKeyboard(
|
|
UnattendedOperation,
|
|
SifHandle,
|
|
DirectoryOnBootDevice,
|
|
&KeyboardTable,
|
|
HardwareComponents
|
|
);
|
|
}
|
|
|
|
#ifdef _X86_
|
|
if( NTUpgrade == DontUpgrade ) {
|
|
BOOLEAN Windows95;
|
|
|
|
//
|
|
// Take a gander on the hard drives, looking for win3.1.
|
|
//
|
|
if( SpLocateWin31(SifHandle,&TargetRegion,&TargetPath,&SystemPartitionRegion, &Windows95) ) {
|
|
WinUpgradeType = ( Windows95 )? UpgradeWin95 : UpgradeWin31;
|
|
} else {
|
|
WinUpgradeType = NoWinUpgrade;
|
|
}
|
|
//
|
|
// Note that on x86, it can happen that the machine has NT installed
|
|
// on top of Win31, and the user selects not to upgrade NT, but to
|
|
// install on top of Win3.1. In this case we need to delete some hives
|
|
//
|
|
if( (WinUpgradeType == UpgradeWin31) && SpIsNtInDirectory( TargetRegion, TargetPath ) ) {
|
|
NTUpgrade = UpgradeInstallFresh;
|
|
}
|
|
}
|
|
else {
|
|
//
|
|
// Just check to see if the target region also contains WIN31, Note
|
|
// that the MIN KB to check for is 0, since we already have done
|
|
// the space check
|
|
// Note also that if the directory contains Win95, then the Win95
|
|
// migration was already done when NT was installed, and we don't
|
|
// care about it now.
|
|
//
|
|
if( SpIsWin31Dir(TargetRegion,TargetPath,0) ) {
|
|
WinUpgradeType = UpgradeWin31;
|
|
} else {
|
|
WinUpgradeType = NoWinUpgrade;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Do partitioning and ask the user for the target path.
|
|
//
|
|
if((WinUpgradeType == NoWinUpgrade) && (NTUpgrade == DontUpgrade)) {
|
|
|
|
SpPtPrepareDisks(SifHandle,&TargetRegion,&SystemPartitionRegion,SetupSourceDevicePath,DirectoryOnSetupSource);
|
|
|
|
//
|
|
// Partitioning may have changed the partition ordinal of the local source
|
|
//
|
|
if(WinntSetup) {
|
|
SpMemFree(SetupSourceDevicePath);
|
|
SpGetWinntParams(&SetupSourceDevicePath,&DirectoryOnSetupSource);
|
|
}
|
|
|
|
DefaultTarget = SpGetSectionKeyIndex(
|
|
SifHandle,
|
|
SIF_SETUPDATA,
|
|
SIF_DEFAULTPATH,
|
|
0
|
|
);
|
|
|
|
if(!DefaultTarget) {
|
|
|
|
SpFatalSifError(
|
|
SifHandle,
|
|
SIF_SETUPDATA,
|
|
SIF_DEFAULTPATH,
|
|
0,
|
|
0
|
|
);
|
|
}
|
|
|
|
//
|
|
// Select the target path.
|
|
//
|
|
SpGetTargetPath(SifHandle,TargetRegion,DefaultTarget,&TargetPath);
|
|
}
|
|
|
|
//
|
|
// Form the SystemPartitionDirectory
|
|
//
|
|
#ifdef _X86_
|
|
//
|
|
// system partition directory is the root of C:.
|
|
//
|
|
SystemPartitionDirectory = L"";
|
|
#else
|
|
SystemPartitionDirectory = SpDetermineSystemPartitionDirectory(
|
|
SystemPartitionRegion,
|
|
OriginalSystemPartitionDirectory
|
|
);
|
|
#endif
|
|
|
|
SpStringToUpper(TargetPath);
|
|
|
|
#ifdef _FASTRECOVER_
|
|
if (!UnattendedSkipAutoCheck)
|
|
//
|
|
// Run autochk on Nt and system partitions
|
|
//
|
|
SpRunAutochkOnNtAndSystemPartitions( SifHandle,
|
|
TargetRegion,
|
|
SystemPartitionRegion,
|
|
SetupSourceDevicePath,
|
|
DirectoryOnSetupSource
|
|
);
|
|
#else
|
|
//
|
|
// Run autochk on Nt and system partitions
|
|
//
|
|
SpRunAutochkOnNtAndSystemPartitions( SifHandle,
|
|
TargetRegion,
|
|
SystemPartitionRegion,
|
|
SetupSourceDevicePath,
|
|
DirectoryOnSetupSource
|
|
);
|
|
#endif
|
|
|
|
//
|
|
// If we are installing into an existing tree we need to delete some
|
|
// files and backup some files
|
|
//
|
|
if(NTUpgrade != DontUpgrade) {
|
|
SpDeleteAndBackupFiles(
|
|
SifHandle,
|
|
TargetRegion,
|
|
TargetPath
|
|
);
|
|
}
|
|
|
|
//
|
|
// Copy the files that make up the product.
|
|
//
|
|
SpCopyFiles(
|
|
SifHandle,
|
|
SystemPartitionRegion,
|
|
TargetRegion,
|
|
TargetPath,
|
|
SystemPartitionDirectory,
|
|
SetupSourceDevicePath,
|
|
DirectoryOnSetupSource,
|
|
( PreInstall )? SetupSourceDevicePath : L"\\device\\floppy0"
|
|
);
|
|
|
|
|
|
//
|
|
// Configure the registry.
|
|
//
|
|
SpInitializeRegistry(
|
|
SifHandle,
|
|
TargetRegion,
|
|
TargetPath,
|
|
SetupSourceDevicePath,
|
|
DirectoryOnSetupSource,
|
|
wcsstr(DirectoryOnBootDevice,L"\\$WIN_NT$.~BT") ? NtBootDevicePath : NULL
|
|
);
|
|
|
|
UpdateBootList:
|
|
|
|
//
|
|
// If this is an upgrade we need to remove the entry which exists for
|
|
// this system right now, because we are using new entries. We can use
|
|
// this opportunity to also clean out the boot ini and remove all entries
|
|
// which point to the current nt partition and path
|
|
//
|
|
OldOsLoadOptions = NULL;
|
|
if(NTUpgrade == UpgradeFull || RepairItems[RepairNvram]) {
|
|
SpRemoveInstallationFromBootList(
|
|
NULL,
|
|
TargetRegion,
|
|
TargetPath,
|
|
NULL,
|
|
NULL,
|
|
PrimaryArcPath,
|
|
&OldOsLoadOptions
|
|
);
|
|
|
|
#ifdef _X86_
|
|
// call again to delete the secondary Arc name
|
|
SpRemoveInstallationFromBootList(
|
|
NULL,
|
|
TargetRegion,
|
|
TargetPath,
|
|
NULL,
|
|
NULL,
|
|
SecondaryArcPath,
|
|
&OldOsLoadOptions
|
|
);
|
|
#endif
|
|
}
|
|
|
|
|
|
#ifdef _X86_
|
|
//
|
|
// Lay NT boot code on C:. Do this before flushing boot vars
|
|
// because it may change the 'previous os' selection.
|
|
//
|
|
if (!RepairWinnt || RepairItems[RepairBootSect] ) {
|
|
SpLayBootCode(SystemPartitionRegion);
|
|
}
|
|
|
|
#ifdef _FASTRECOVER_
|
|
//
|
|
// Skip adding second boot set during Fast Recover operation.
|
|
//
|
|
if (!FastRecoverOperation && (!RepairWinnt || RepairItems[RepairNvram])) {
|
|
#else
|
|
if (!RepairWinnt || RepairItems[RepairNvram]) {
|
|
#endif
|
|
|
|
//
|
|
// Add a boot set for this installation with /BASEVIDEO for vga mode boot.
|
|
// Do this before adding the standard one because otherwise this one ends
|
|
// up as the default.
|
|
//
|
|
SpAddInstallationToBootList(
|
|
SifHandle,
|
|
SystemPartitionRegion,
|
|
SystemPartitionDirectory,
|
|
TargetRegion,
|
|
TargetPath,
|
|
TRUE,
|
|
OldOsLoadOptions
|
|
);
|
|
}
|
|
#endif
|
|
|
|
if (!RepairWinnt || RepairItems[RepairNvram]) {
|
|
|
|
//
|
|
// Add a boot set for this installation.
|
|
//
|
|
SpAddInstallationToBootList(
|
|
SifHandle,
|
|
SystemPartitionRegion,
|
|
SystemPartitionDirectory,
|
|
TargetRegion,
|
|
TargetPath,
|
|
FALSE,
|
|
OldOsLoadOptions
|
|
);
|
|
|
|
if(OldOsLoadOptions) {
|
|
SpMemFree(OldOsLoadOptions);
|
|
}
|
|
|
|
SpCleanSysPartOrphan();
|
|
SpCompleteBootListConfig();
|
|
}
|
|
|
|
//
|
|
// If system was repaired, and either the System Partition
|
|
// or the NT Partition is an FT partition, then set the
|
|
// appropriate flag in the registry, so that next time the
|
|
// system boots, it checks and updates the partition's image.
|
|
//
|
|
if( RepairWinnt ) {
|
|
UCHAR TmpSysId;
|
|
UCHAR TmpNtPartitionSysId;
|
|
PON_DISK_PTE pte;
|
|
BOOLEAN SystemPartitionIsFT;
|
|
BOOLEAN TargetPartitionIsFT;
|
|
|
|
pte = &SystemPartitionRegion->MbrInfo->OnDiskMbr.PartitionTable[SystemPartitionRegion->TablePosition];
|
|
ASSERT(pte->SystemId != PARTITION_ENTRY_UNUSED);
|
|
TmpSysId = pte->SystemId;
|
|
SystemPartitionIsFT = ((TmpSysId & VALID_NTFT) == VALID_NTFT) ||
|
|
((TmpSysId & PARTITION_NTFT) == PARTITION_NTFT);
|
|
|
|
pte = &TargetRegion->MbrInfo->OnDiskMbr.PartitionTable[TargetRegion->TablePosition];
|
|
ASSERT(pte->SystemId != PARTITION_ENTRY_UNUSED);
|
|
TmpSysId = pte->SystemId;
|
|
TargetPartitionIsFT = ((TmpSysId & VALID_NTFT) == VALID_NTFT) ||
|
|
((TmpSysId & PARTITION_NTFT) == PARTITION_NTFT);
|
|
|
|
#ifdef _X86_
|
|
if( ( SystemPartitionIsFT &&
|
|
( RepairItems[ RepairNvram ] || RepairItems[ RepairBootSect ] )
|
|
) ||
|
|
( TargetPartitionIsFT &&
|
|
( RepairItems[ RepairHives ] || RepairItems[ RepairFiles ] )
|
|
)
|
|
) {
|
|
SpSetDirtyShutdownFlag( TargetRegion, TargetPath );
|
|
}
|
|
#else
|
|
if( ( ( ( SystemPartitionIsFT || TargetPartitionIsFT ) && RepairItems[ RepairFiles ] ) ||
|
|
( TargetPartitionIsFT && RepairItems[ RepairHives ] )
|
|
)
|
|
) {
|
|
SpSetDirtyShutdownFlag( TargetRegion, TargetPath );
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#ifdef _FASTRECOVER_
|
|
//wfc
|
|
// Execute image specified in PostExecImage key. This
|
|
// allows a kernel application to be executed just prior to
|
|
// rebooting from kernel text mode setup.
|
|
p = SpGetSectionKeyIndex(SifHandle,
|
|
SIF_SETUPDATA,
|
|
L"PostExecImage",
|
|
0);
|
|
|
|
if (p)
|
|
{
|
|
SpNtNameFromRegion(
|
|
SystemPartitionRegion,
|
|
(PWSTR)TemporaryBuffer,
|
|
sizeof(TemporaryBuffer),
|
|
PartitionOrdinalOnDisk
|
|
);
|
|
|
|
SpRunImage(SifHandle,
|
|
TemporaryBuffer, //SetupSourceDevicePath,
|
|
p);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Done with boot variables and arc names.
|
|
//
|
|
SpFreeBootVars();
|
|
SpFreeArcNames();
|
|
|
|
//
|
|
// Done with setup log file
|
|
//
|
|
|
|
if (RepairWinnt && RepairSifHandle) {
|
|
SpFreeTextFile(RepairSifHandle);
|
|
}
|
|
#ifdef _FASTRECOVER_
|
|
if (UnattendedOperation && UnattendedPromptForReboot)
|
|
{
|
|
UnattendedOperation = FALSE;
|
|
SpDone(TRUE,TRUE);
|
|
UnattendedOperation = TRUE;
|
|
}
|
|
else
|
|
SpDone(TRUE,TRUE);
|
|
#else
|
|
SpDone(TRUE,TRUE);
|
|
#endif
|
|
|
|
//
|
|
// We never get here because SpDone doesn't return.
|
|
//
|
|
SpvidTerminate();
|
|
SpkbdTerminate();
|
|
SpTerminate();
|
|
return((ULONG)STATUS_SUCCESS);
|
|
}
|
|
|
|
VOID
|
|
SpRemoveInstallationFromBootList(
|
|
IN PDISK_REGION SysPartitionRegion, OPTIONAL
|
|
IN PDISK_REGION NtPartitionRegion, OPTIONAL
|
|
IN PWSTR SysRoot, OPTIONAL
|
|
IN PWSTR SystemLoadIdentifier, OPTIONAL
|
|
IN PWSTR SystemLoadOptions, OPTIONAL
|
|
IN ENUMARCPATHTYPE ArcPathType,
|
|
OUT PWSTR *OldOsLoadOptions OPTIONAL
|
|
)
|
|
{
|
|
PWSTR BootSet[MAXBOOTVARS];
|
|
BOOTVAR i;
|
|
WCHAR Drive[] = L"?:";
|
|
PWSTR tmp2;
|
|
|
|
//
|
|
// Tell the user what we are doing.
|
|
//
|
|
CLEAR_CLIENT_SCREEN();
|
|
SpDisplayStatusText(SP_STAT_CLEANING_FLEXBOOT,DEFAULT_STATUS_ATTRIBUTE);
|
|
|
|
//
|
|
// Set up the boot set
|
|
//
|
|
for(i = FIRSTBOOTVAR; i <= LASTBOOTVAR; i++) {
|
|
BootSet[i] = NULL;
|
|
}
|
|
|
|
tmp2 = (PWSTR)((PUCHAR)TemporaryBuffer + (sizeof(TemporaryBuffer)/2));
|
|
|
|
if( NtPartitionRegion ) {
|
|
SpArcNameFromRegion(NtPartitionRegion,tmp2,sizeof(TemporaryBuffer)/2,PartitionOrdinalOnDisk,ArcPathType);
|
|
BootSet[OSLOADPARTITION] = SpDupStringW(tmp2);
|
|
}
|
|
|
|
if( SysPartitionRegion ) {
|
|
SpArcNameFromRegion(SysPartitionRegion,tmp2,sizeof(TemporaryBuffer)/2,PartitionOrdinalOnDisk,ArcPathType);
|
|
BootSet[SYSTEMPARTITION] = SpDupStringW(tmp2);
|
|
}
|
|
|
|
BootSet[OSLOADFILENAME] = SysRoot;
|
|
BootSet[LOADIDENTIFIER] = SystemLoadIdentifier;
|
|
BootSet[OSLOADOPTIONS] = SystemLoadOptions;
|
|
|
|
//
|
|
// Delete the boot set
|
|
//
|
|
SpDeleteBootSet(BootSet, OldOsLoadOptions);
|
|
|
|
//
|
|
// To take care of the case where the OSLOADPARTITION is a DOS drive letter
|
|
// in the boot set, change the OSLOADPARTITION to a drive and retry
|
|
// deletion
|
|
//
|
|
if( BootSet[OSLOADPARTITION] != NULL ) {
|
|
SpMemFree(BootSet[OSLOADPARTITION]);
|
|
}
|
|
if( NtPartitionRegion && (ULONG)(Drive[0] = NtPartitionRegion->DriveLetter) != 0) {
|
|
BootSet[OSLOADPARTITION] = Drive;
|
|
SpDeleteBootSet(BootSet, OldOsLoadOptions);
|
|
}
|
|
|
|
#ifdef _X86_
|
|
//
|
|
// If OldOsLoadOptions contains "/scsiordinal:", then remove it
|
|
//
|
|
if( ( OldOsLoadOptions != NULL ) &&
|
|
( *OldOsLoadOptions != NULL ) ) {
|
|
|
|
PWSTR p, q;
|
|
WCHAR SaveChar;
|
|
|
|
SpStringToLower(*OldOsLoadOptions);
|
|
p = wcsstr( *OldOsLoadOptions, L"/scsiordinal:" );
|
|
if( p != NULL ) {
|
|
SaveChar = *p;
|
|
*p = (WCHAR)'\0';
|
|
wcscpy((PWSTR)TemporaryBuffer, *OldOsLoadOptions);
|
|
*p = SaveChar;
|
|
q = wcschr( p, (WCHAR)' ' );
|
|
if( q != NULL ) {
|
|
wcscat( (PWSTR)TemporaryBuffer, q );
|
|
}
|
|
SpMemFree( *OldOsLoadOptions );
|
|
*OldOsLoadOptions = SpDupStringW( ( PWSTR )TemporaryBuffer );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Cleanup
|
|
//
|
|
if( BootSet[SYSTEMPARTITION] != NULL ) {
|
|
SpMemFree(BootSet[SYSTEMPARTITION]);
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
SpAddInstallationToBootList(
|
|
IN PVOID SifHandle,
|
|
IN PDISK_REGION SystemPartitionRegion,
|
|
IN PWSTR SystemPartitionDirectory,
|
|
IN PDISK_REGION NtPartitionRegion,
|
|
IN PWSTR Sysroot,
|
|
IN BOOLEAN BaseVideoOption,
|
|
IN PWSTR OldOsLoadOptions OPTIONAL
|
|
)
|
|
{
|
|
PWSTR BootVars[MAXBOOTVARS];
|
|
PWSTR SystemPartitionArcName;
|
|
PWSTR TargetPartitionArcName;
|
|
PWSTR tmp;
|
|
PWSTR tmp2;
|
|
PWSTR SifKeyName;
|
|
BOOLEAN AddBaseVideo = FALSE;
|
|
WCHAR BaseVideoString[] = L"/basevideo";
|
|
WCHAR BaseVideoSosString[] = L"/sos";
|
|
BOOLEAN AddSosToBaseVideoString;
|
|
#ifdef _X86_
|
|
ENUMARCPATHTYPE ArcPathType = PrimaryArcPath;
|
|
#endif
|
|
|
|
//
|
|
// Tell the user what we are doing.
|
|
//
|
|
CLEAR_CLIENT_SCREEN();
|
|
SpDisplayStatusText(SP_STAT_INITING_FLEXBOOT,DEFAULT_STATUS_ATTRIBUTE);
|
|
|
|
tmp2 = (PWSTR)((PUCHAR)TemporaryBuffer + (sizeof(TemporaryBuffer)/2));
|
|
|
|
//
|
|
// Get an ARC name for the system partition.
|
|
//
|
|
SpArcNameFromRegion(SystemPartitionRegion,tmp2,sizeof(TemporaryBuffer)/2,PartitionOrdinalOnDisk,PrimaryArcPath);
|
|
SystemPartitionArcName = SpDupStringW(tmp2);
|
|
|
|
//
|
|
// Get an ARC name for the target partition.
|
|
//
|
|
#ifdef _X86_
|
|
//
|
|
// If the partition is on a SCSI disk that has more than 1024 cylinders
|
|
// and the partition has sectors located on cylinders beyond cylinder
|
|
// 1024, the get the arc name in the secondary format.
|
|
//
|
|
if( (*(HardDisks[NtPartitionRegion->DiskNumber].ScsiMiniportShortname) != 0 ) &&
|
|
SpIsRegionBeyondCylinder1024(NtPartitionRegion) ) {
|
|
ArcPathType = SecondaryArcPath;
|
|
}
|
|
SpArcNameFromRegion(NtPartitionRegion,tmp2,sizeof(TemporaryBuffer)/2,PartitionOrdinalOnDisk,ArcPathType);
|
|
#else
|
|
SpArcNameFromRegion(NtPartitionRegion,tmp2,sizeof(TemporaryBuffer)/2,PartitionOrdinalOnDisk,PrimaryArcPath);
|
|
#endif
|
|
|
|
TargetPartitionArcName = SpDupStringW(tmp2);
|
|
|
|
//
|
|
// OSLOADOPTIONS is specified in the setup information file.
|
|
//
|
|
tmp = SpGetSectionKeyIndex(
|
|
SifHandle,
|
|
SIF_SETUPDATA,
|
|
SIF_OSLOADOPTIONSVAR,
|
|
0
|
|
);
|
|
|
|
//
|
|
// If OsLoadOptionsVar wasn't specified, then we'll preserve any flags
|
|
// the user had specified.
|
|
//
|
|
if(!tmp && OldOsLoadOptions) {
|
|
tmp = OldOsLoadOptions;
|
|
}
|
|
|
|
AddSosToBaseVideoString = BaseVideoOption;
|
|
AddBaseVideo = BaseVideoOption;
|
|
|
|
if(tmp) {
|
|
//
|
|
// make sure we don't already have a /basevideo option, so we
|
|
// won't add another
|
|
//
|
|
wcscpy((PWSTR)TemporaryBuffer, tmp);
|
|
SpStringToLower((PWSTR)TemporaryBuffer);
|
|
if(wcsstr((PWSTR)TemporaryBuffer, BaseVideoString)) { // already have /basevideo
|
|
BaseVideoOption = TRUE;
|
|
AddBaseVideo = FALSE;
|
|
}
|
|
if(wcsstr((PWSTR)TemporaryBuffer, BaseVideoSosString)) { // already have /sos
|
|
AddSosToBaseVideoString = FALSE;
|
|
}
|
|
}
|
|
|
|
if(AddBaseVideo || AddSosToBaseVideoString) {
|
|
|
|
ULONG Length;
|
|
|
|
Length = ((tmp ? wcslen(tmp) + 1 : 0) * sizeof(WCHAR));
|
|
if( AddBaseVideo ) {
|
|
Length += sizeof(BaseVideoString);
|
|
}
|
|
if( AddSosToBaseVideoString ) {
|
|
Length += sizeof( BaseVideoSosString );
|
|
}
|
|
|
|
tmp2 = SpMemAlloc(Length);
|
|
|
|
*tmp2 = ( WCHAR )'\0';
|
|
if( AddBaseVideo ) {
|
|
wcscat(tmp2, BaseVideoString);
|
|
}
|
|
if( AddSosToBaseVideoString ) {
|
|
if( *tmp2 != (WCHAR)'\0' ) {
|
|
wcscat(tmp2, L" ");
|
|
}
|
|
wcscat(tmp2, BaseVideoSosString);
|
|
}
|
|
if(tmp) {
|
|
if( *tmp2 != (WCHAR)'\0' ) {
|
|
wcscat(tmp2, L" ");
|
|
}
|
|
wcscat(tmp2, tmp);
|
|
}
|
|
|
|
BootVars[OSLOADOPTIONS] = SpDupStringW(tmp2);
|
|
|
|
} else {
|
|
BootVars[OSLOADOPTIONS] = SpDupStringW(tmp ? tmp : L"");
|
|
}
|
|
|
|
//
|
|
// LOADIDENTIFIER is specified in the setup information file.
|
|
// We need to surround it in double quotes.
|
|
// Which value to use depends on the BaseVideo flag.
|
|
//
|
|
SifKeyName = BaseVideoOption ? SIF_BASEVIDEOLOADID : SIF_LOADIDENTIFIER;
|
|
|
|
tmp = SpGetSectionKeyIndex(SifHandle,SIF_SETUPDATA,SifKeyName,0);
|
|
|
|
if(!tmp) {
|
|
SpFatalSifError(SifHandle,SIF_SETUPDATA,SifKeyName,0,0);
|
|
}
|
|
|
|
#ifdef _X86_
|
|
//
|
|
// Need quotation marks around the description on x86.
|
|
//
|
|
BootVars[LOADIDENTIFIER] = SpMemAlloc((wcslen(tmp)+3)*sizeof(WCHAR));
|
|
BootVars[LOADIDENTIFIER][0] = L'\"';
|
|
wcscpy(BootVars[LOADIDENTIFIER]+1,tmp);
|
|
wcscat(BootVars[LOADIDENTIFIER],L"\"");
|
|
#else
|
|
BootVars[LOADIDENTIFIER] = SpDupStringW(tmp);
|
|
#endif
|
|
|
|
//
|
|
// OSLOADER is the system partition path + the system partition directory +
|
|
// osloader.exe. (ntldr on x86 machines).
|
|
//
|
|
tmp = (PWSTR)TemporaryBuffer;
|
|
wcscpy(tmp,SystemPartitionArcName);
|
|
SpConcatenatePaths(tmp,SystemPartitionDirectory);
|
|
SpConcatenatePaths(
|
|
tmp,
|
|
#ifdef _X86_
|
|
L"ntldr"
|
|
#else
|
|
L"osloader.exe"
|
|
#endif
|
|
);
|
|
|
|
BootVars[OSLOADER] = SpDupStringW(tmp);
|
|
|
|
//
|
|
// OSLOADPARTITION is the ARC name of the windows nt partition.
|
|
//
|
|
BootVars[OSLOADPARTITION] = TargetPartitionArcName;
|
|
|
|
//
|
|
// OSLOADFILENAME is sysroot.
|
|
//
|
|
BootVars[OSLOADFILENAME] = Sysroot;
|
|
|
|
//
|
|
// SYSTEMPARTITION is the ARC name of the system partition.
|
|
//
|
|
BootVars[SYSTEMPARTITION] = SystemPartitionArcName;
|
|
|
|
//
|
|
// Add the boot set and make it the default.
|
|
//
|
|
SpAddBootSet(BootVars, TRUE);
|
|
|
|
//
|
|
// Free memory allocated.
|
|
//
|
|
SpMemFree(BootVars[OSLOADOPTIONS]);
|
|
SpMemFree(BootVars[LOADIDENTIFIER]);
|
|
SpMemFree(BootVars[OSLOADER]);
|
|
|
|
SpMemFree(SystemPartitionArcName);
|
|
SpMemFree(TargetPartitionArcName);
|
|
}
|
|
|
|
|
|
VOID
|
|
SpCompleteBootListConfig(
|
|
VOID
|
|
)
|
|
{
|
|
|
|
#ifndef _X86_
|
|
BOOL b;
|
|
BOOTVAR i;
|
|
#endif
|
|
|
|
if(!RepairWinnt) {
|
|
#ifdef _X86_
|
|
SpSetTimeout(1);
|
|
#else
|
|
SpSetTimeout(5);
|
|
|
|
//
|
|
// If this is a winnt setup, there will be a boot set to start
|
|
// text setup ("Install/Upgrade Windows NT"). Remove it here.
|
|
//
|
|
if(WinntSetup) {
|
|
|
|
PWSTR BootVars[MAXBOOTVARS];
|
|
|
|
RtlZeroMemory(BootVars,sizeof(BootVars));
|
|
|
|
BootVars[OSLOADOPTIONS] = L"WINNT32";
|
|
|
|
SpDeleteBootSet(BootVars, NULL);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Flush boot vars.
|
|
// On some machines, NVRAM update takes a few seconds,
|
|
// so change the message to tell the user we are doing something different.
|
|
//
|
|
SpDisplayStatusText(SP_STAT_UPDATING_NVRAM,DEFAULT_STATUS_ATTRIBUTE);
|
|
if(!SpFlushBootVars()) {
|
|
|
|
//
|
|
// Fatal on x86 machines, nonfatal on arc machines.
|
|
//
|
|
#ifdef _X86_
|
|
SpDisplayScreen(SP_SCRN_CANT_INIT_FLEXBOOT,3,HEADER_HEIGHT+1);
|
|
SpDisplayStatusText(SP_STAT_F3_EQUALS_EXIT,DEFAULT_STATUS_ATTRIBUTE);
|
|
SpkbdDrain();
|
|
while(SpkbdGetKeypress() != KEY_F3) ;
|
|
SpDone(FALSE,TRUE);
|
|
}
|
|
#else
|
|
b = TRUE;
|
|
while(b) {
|
|
ULONG ValidKeys[3] = { ASCI_CR, KEY_F1, 0 };
|
|
|
|
SpStartScreen(
|
|
SP_SCRN_CANT_UPDATE_BOOTVARS,
|
|
3,
|
|
HEADER_HEIGHT+1,
|
|
FALSE,
|
|
FALSE,
|
|
DEFAULT_ATTRIBUTE,
|
|
NewBootVars[LOADIDENTIFIER],
|
|
NewBootVars[OSLOADER],
|
|
NewBootVars[OSLOADPARTITION],
|
|
NewBootVars[OSLOADFILENAME],
|
|
NewBootVars[OSLOADOPTIONS],
|
|
NewBootVars[SYSTEMPARTITION]
|
|
);
|
|
|
|
SpDisplayStatusOptions(
|
|
DEFAULT_STATUS_ATTRIBUTE,
|
|
SP_STAT_ENTER_EQUALS_CONTINUE,
|
|
SP_STAT_F1_EQUALS_HELP,
|
|
0
|
|
);
|
|
|
|
switch(SpWaitValidKey(ValidKeys,NULL,NULL)) {
|
|
case KEY_F1:
|
|
SpHelp(SP_HELP_NVRAM_FULL, NULL, SPHELP_HELPTEXT);
|
|
break;
|
|
case ASCI_CR:
|
|
b = FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Free all of the boot variable strings
|
|
for(i = FIRSTBOOTVAR; i <= LASTBOOTVAR; i++) {
|
|
SpMemFree(NewBootVars[i]);
|
|
NewBootVars[i] = NULL;
|
|
}
|
|
|
|
#endif
|
|
}
|
|
|
|
|
|
VOID
|
|
SpDetermineProductType(
|
|
IN PVOID SifHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine whether this is advanced server we are setting up,
|
|
as dictated by the ProductType value in [SetupData] section of
|
|
txtsetup.sif. A non-0 value indicates that we are running
|
|
advanced server.
|
|
|
|
Also determine product version.
|
|
|
|
The global variables:
|
|
|
|
- AdvancedServer
|
|
- MajorVersion
|
|
- MinorVersion
|
|
|
|
are modified
|
|
|
|
Arguments:
|
|
|
|
SifHandle - supplies handle to loaded txtsetup.sif.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PWSTR p;
|
|
|
|
//
|
|
// Assume Workstation product.
|
|
//
|
|
AdvancedServer = FALSE;
|
|
|
|
//
|
|
// Get the product type from the sif file.
|
|
//
|
|
p = SpGetSectionKeyIndex(SifHandle,SIF_SETUPDATA,SIF_PRODUCTTYPE,0);
|
|
if(p) {
|
|
|
|
//
|
|
// Convert to numeric value.
|
|
//
|
|
if(SpStringToLong(p,NULL,10)) {
|
|
AdvancedServer = TRUE;
|
|
}
|
|
} else {
|
|
SpFatalSifError(SifHandle,SIF_SETUPDATA,SIF_PRODUCTTYPE,0,0);
|
|
}
|
|
|
|
//
|
|
// Get the product major version
|
|
//
|
|
p = SpGetSectionKeyIndex(
|
|
SifHandle,
|
|
SIF_SETUPDATA,
|
|
SIF_MAJORVERSION,
|
|
0
|
|
);
|
|
|
|
if(!p) {
|
|
SpFatalSifError(SifHandle,SIF_SETUPDATA,SIF_MAJORVERSION,0,0);
|
|
}
|
|
WinntMajorVer = (ULONG)SpStringToLong(p,NULL,10);
|
|
|
|
//
|
|
// Get the product minor version
|
|
//
|
|
p = SpGetSectionKeyIndex(
|
|
SifHandle,
|
|
SIF_SETUPDATA,
|
|
SIF_MINORVERSION,
|
|
0
|
|
);
|
|
|
|
if(!p) {
|
|
SpFatalSifError(SifHandle,SIF_SETUPDATA,SIF_MINORVERSION,0,0);
|
|
}
|
|
WinntMinorVer = (ULONG)SpStringToLong(p,NULL,10);
|
|
|
|
//
|
|
// Build the string that contains the signature that
|
|
// identifies setup.log
|
|
// Allocate a buffer of reasonable size
|
|
//
|
|
SIF_NEW_REPAIR_NT_VERSION = SpMemAlloc( 30*sizeof(WCHAR) );
|
|
if( SIF_NEW_REPAIR_NT_VERSION == NULL ) {
|
|
KdPrint(("SETUP: Unable to allocate memory for SIF_NEW_REPAIR_NT_VERSION \n" ));
|
|
return;
|
|
}
|
|
swprintf( SIF_NEW_REPAIR_NT_VERSION,
|
|
SIF_NEW_REPAIR_NT_VERSION_TEMPLATE,
|
|
WinntMajorVer,WinntMinorVer );
|
|
|
|
// #if 0
|
|
//
|
|
// BUGBUG - To be removed when Cairo and NT 3.51 getmerged.
|
|
// Find out if this is a Cairo install.
|
|
// If it is, set the flag that prevents textmode setup
|
|
// from finding NT 3.x systems to upgrade.
|
|
//
|
|
p = SpGetSectionKeyIndex(
|
|
SifHandle,
|
|
L"CairoData",
|
|
L"UpgradeCairoOnly",
|
|
0
|
|
);
|
|
if( p &&
|
|
((ULONG)SpStringToLong(p,NULL,10) == 1) ) {
|
|
KdPrint(("SETUP: Installing a Cairo system. \n" ));
|
|
CairoSetup = TRUE;
|
|
}
|
|
// #endif
|
|
}
|
|
|
|
|
|
BOOL
|
|
SpDetermineInstallationSource(
|
|
IN PVOID SifHandle,
|
|
OUT PWSTR *DevicePath,
|
|
OUT PWSTR *DirectoryOnDevice
|
|
)
|
|
{
|
|
PWSTR p,q;
|
|
BOOLEAN CdInstall;
|
|
|
|
//
|
|
// Assume CD-ROM installation.
|
|
//
|
|
CdInstall = TRUE;
|
|
|
|
//
|
|
// See whether an override source device has been specified.
|
|
//
|
|
if(p = SpGetSectionKeyIndex(SifHandle,SIF_SETUPDATA,SIF_SETUPSOURCEDEVICE,0)) {
|
|
|
|
//
|
|
// Determine if the specified device is a cd-rom so we can set the
|
|
// cd-rom flag accordingly.
|
|
//
|
|
q = SpDupStringW(p);
|
|
SpStringToLower(q);
|
|
if(!wcsstr(q,L"\\device\\cdrom")) {
|
|
CdInstall = FALSE;
|
|
}
|
|
SpMemFree(q);
|
|
|
|
//
|
|
// Inform the caller of the device path.
|
|
//
|
|
*DevicePath = p;
|
|
|
|
} else {
|
|
//
|
|
// No override specified. There must be a CD-ROM drive in order for us
|
|
// to continue.
|
|
//
|
|
if(!IoGetConfigurationInformation()->CdRomCount) {
|
|
//
|
|
// If there is no CD-ROM drive, put a message informing the user
|
|
// that setup cannot continue.
|
|
// In the repair case, we pretend that there is a CD-ROM drive,
|
|
// so that the user can at least repar the hives, boot sector,
|
|
// and the boot variables (boot.ini on x86 case)
|
|
//
|
|
if(!RepairWinnt) {
|
|
SpDisplayScreen(SP_SCRN_NO_VALID_SOURCE,3,HEADER_HEIGHT+1);
|
|
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_F3_EQUALS_EXIT,0);
|
|
|
|
SpkbdDrain();
|
|
while(SpkbdGetKeypress() != KEY_F3) ;
|
|
|
|
SpDone(FALSE,TRUE);
|
|
} else {
|
|
//
|
|
// BUGBUG -
|
|
// We should warn the user that the system has no CD-ROM drive,
|
|
// and that because of that, the repair process won't be able
|
|
// to repair the system files.
|
|
//
|
|
RepairNoCDROMDrive = TRUE;
|
|
}
|
|
}
|
|
|
|
*DevicePath = L"\\device\\cdrom0";
|
|
}
|
|
|
|
//
|
|
// Fetch the directory on the source device.
|
|
//
|
|
if((p = SpGetSectionKeyIndex(SifHandle,SIF_SETUPDATA,SIF_SETUPSOURCEPATH,0)) == NULL) {
|
|
SpFatalSifError(SifHandle,SIF_SETUPDATA,SIF_SETUPSOURCEPATH,0,0);
|
|
}
|
|
|
|
*DirectoryOnDevice = p;
|
|
|
|
return(CdInstall);
|
|
}
|
|
|
|
|
|
VOID
|
|
SpGetWinntParams(
|
|
OUT PWSTR *DevicePath,
|
|
OUT PWSTR *DirectoryOnDevice
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determine the local source partition and directory on the partition.
|
|
|
|
The local source partition should have already been located for us
|
|
by the partitioning engine when it initialized. The directory name
|
|
within the partition is constant.
|
|
|
|
Note: this routine should only be called in the winnt.exe setup case!
|
|
|
|
Arguments:
|
|
|
|
DevicePath - receives the path to the local source partition
|
|
in the nt namespace. The caller should not attempt to free
|
|
this buffer.
|
|
|
|
DirectoryOnDevice - receives the directory name of the local source.
|
|
This is actually a fixed constant but is included here for future use.
|
|
|
|
Return Value:
|
|
|
|
None. If the local source was not located, setup cannot continue.
|
|
|
|
--*/
|
|
|
|
{
|
|
ASSERT(WinntSetup);
|
|
|
|
if(LocalSourceRegion) {
|
|
|
|
SpNtNameFromRegion(
|
|
LocalSourceRegion,
|
|
(PWSTR)TemporaryBuffer,
|
|
sizeof(TemporaryBuffer),
|
|
PartitionOrdinalCurrent
|
|
);
|
|
|
|
*DevicePath = SpDupStringW((PWSTR)TemporaryBuffer);
|
|
|
|
*DirectoryOnDevice = LocalSourceDirectory;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Error -- can't locate local source directory
|
|
// prepared by winnt.exe.
|
|
//
|
|
|
|
SpDisplayScreen(SP_SCRN_CANT_FIND_LOCAL_SOURCE,3,HEADER_HEIGHT+1);
|
|
|
|
SpDisplayStatusOptions(
|
|
DEFAULT_STATUS_ATTRIBUTE,
|
|
SP_STAT_F3_EQUALS_EXIT,
|
|
0
|
|
);
|
|
|
|
SpkbdDrain();
|
|
while(SpkbdGetKeypress() != KEY_F3) ;
|
|
|
|
SpDone(FALSE,TRUE);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
SpInitializePidString(
|
|
IN HANDLE MasterSifHandle,
|
|
IN PWSTR SetupSourceDevicePath,
|
|
IN PWSTR DirectoryOnSourceDevice
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Read th Pid20 from setupp.ini on the media, and save it on the global
|
|
variable PidString
|
|
|
|
Arguments:
|
|
|
|
MasterSifHandle - Handle to txtsetup.sif.
|
|
|
|
SetupSourceDevicePath - Path to the device that contains the source media.
|
|
|
|
DirectoryOnSourceDevice - Directory on the media where setupp.ini is located.
|
|
|
|
|
|
Return Value:
|
|
|
|
NONE.
|
|
|
|
--*/
|
|
|
|
{
|
|
PWSTR MediaShortName;
|
|
PWSTR MediaDirectory;
|
|
PWSTR SetupIniPath;
|
|
ULONG ErrorSubId;
|
|
ULONG ErrorLine;
|
|
PVOID SetupIniHandle;
|
|
PWSTR TmpPid;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// Prepair to run autofmt
|
|
//
|
|
MediaShortName = SpLookUpValueForFile(
|
|
MasterSifHandle,
|
|
L"setupp.ini",
|
|
INDEX_WHICHMEDIA,
|
|
TRUE
|
|
);
|
|
|
|
//
|
|
// Prompt the user to insert the setup media.
|
|
//
|
|
SpPromptForSetupMedia(
|
|
MasterSifHandle,
|
|
MediaShortName,
|
|
SetupSourceDevicePath
|
|
);
|
|
|
|
SpGetSourceMediaInfo(MasterSifHandle,MediaShortName,NULL,NULL,&MediaDirectory);
|
|
|
|
wcscpy( (PWSTR)TemporaryBuffer, SetupSourceDevicePath );
|
|
SpConcatenatePaths( (PWSTR)TemporaryBuffer, DirectoryOnSourceDevice );
|
|
SpConcatenatePaths( (PWSTR)TemporaryBuffer, MediaDirectory );
|
|
SpConcatenatePaths( (PWSTR)TemporaryBuffer, L"setupp.ini" );
|
|
SetupIniPath = SpDupStringW( (PWSTR)TemporaryBuffer );
|
|
|
|
CLEAR_CLIENT_SCREEN();
|
|
|
|
Status = SpLoadSetupTextFile(
|
|
SetupIniPath,
|
|
NULL, // No image already in memory
|
|
0, // Image size is empty
|
|
&SetupIniHandle,
|
|
&ErrorLine
|
|
);
|
|
|
|
if(!NT_SUCCESS(Status)) {
|
|
//
|
|
// Silently fail if unable to read setupp.ini
|
|
//
|
|
KdPrint(("SETUP: Unable to read setupp.ini. Status = %lx \n", Status ));
|
|
|
|
PidString = NULL;
|
|
return;
|
|
}
|
|
|
|
TmpPid = SpGetSectionKeyIndex (SetupIniHandle,
|
|
L"Pid",
|
|
L"Pid",
|
|
0);
|
|
|
|
PidString = ( TmpPid == NULL )? NULL : SpDupStringW(TmpPid);
|
|
SpFreeTextFile( SetupIniHandle );
|
|
return;
|
|
}
|