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.
4214 lines
127 KiB
4214 lines
127 KiB
/*++
|
|
Copyright (c) 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
spdr.c
|
|
|
|
Abstract:
|
|
Source file for Automated System Recovery (ASR) functions for text-mode
|
|
setup. The services defined in this module recreate the boot and system
|
|
partitions based on information obtained by reading records from a
|
|
configuration file, the asr.sif file (aka SIF).
|
|
|
|
|
|
Terminology
|
|
The following terms are used:
|
|
|
|
1. The "system" partition is the partition that contains the OS loader
|
|
programs (i.e., On amd64/x86 platforms these are the boot.ini. ntldr,
|
|
and ntdetect.com files, among others).
|
|
|
|
2. The "boot" (aka NT) partition is the partition that contains the %SystemRoot%
|
|
directory, i.e., the directory containing the NT system files. In the
|
|
text-mode setup sources, this directory is also called the
|
|
"TargetDirectory" since, when running normal textmode setup, this is the
|
|
directory into which NT gets installed.
|
|
|
|
3. Extended partition and Logical Disk Terminology
|
|
|
|
In the SIF file two kinds of extended partition records can be found. The
|
|
first kind, of which there may be zero, one, or more, are called Logical
|
|
Disk Descriptor records, or LDDs. LDDs describe a partition within an
|
|
extended partition. The second kind are called Container Partition
|
|
Descriptor records, or CPDs, because they describe extended partitions.
|
|
For any disk, at most one extended partition may exist and, therefore, only
|
|
one CPD per disk record may exist in the SIF file.
|
|
|
|
|
|
Extended partitions and logical disk support in Windows NT 5.0:
|
|
1) Windows NT 5.0 supports 0 or 1 extended partition per disk.
|
|
2) Logical disks only exist within extended partitions.
|
|
3) An extended partition may contain zero (0) or more logical disk
|
|
partitions.
|
|
|
|
|
|
Algorithm for Recovering the System and NT Partitions (see
|
|
SpDrPtPrepareDisks()):
|
|
For each disk
|
|
{
|
|
Check whether its capacity is sufficient to contain all the partitions
|
|
specified in the asr.sif file for that disk (ie the partition set).
|
|
|
|
if (Existing Physical Disk Partitions != asr.sif configuration)
|
|
{
|
|
- Remove disk's existing partitions;
|
|
- Recreate disk's partitions according to the asr.sif
|
|
specifications.
|
|
}
|
|
else
|
|
{
|
|
- Replace all corrupt boot and NT system files, excluding
|
|
registry files.
|
|
- Set Repaired Flag.
|
|
}
|
|
|
|
}
|
|
|
|
- Reinstall NT from CDROM into NT directory specified by asr.sif.
|
|
- If specified, copy 3rd-party files per asr.sif file.
|
|
- Reboot and execute gui-mode disaster recover.
|
|
|
|
ASR Restrictions:
|
|
For the boot and system volumes ASR requires that the restored (new)
|
|
system have:
|
|
Same number of drives as the old system.
|
|
Capacity of each new drive >= capacity of corresponding old drive.
|
|
|
|
Revision History:
|
|
Initial Code Michael Peterson (v-michpe) 13.May.1997
|
|
Code cleanup and changes Guhan Suriyanarayanan (guhans) 21.Aug.1999
|
|
|
|
--*/
|
|
#include "spprecmp.h"
|
|
#pragma hdrstop
|
|
#include <oemtypes.h>
|
|
|
|
//
|
|
// Defaults used for textmode ASR. The static ones aren't accessed from outside
|
|
// this file, and are grouped here so that it's easy to change them if need be.
|
|
//
|
|
static PWSTR ASR_CONTEXT_KEY = L"\\CurrentControlSet\\Control\\Session Manager\\Environment";
|
|
static PWSTR ASR_CONTEXT_VALUE = L"ASR_C_CONTEXT";
|
|
static PWSTR ASR_CONTEXT_DATA = L"AsrInProgress";
|
|
|
|
static PWSTR ASR_BOOT_PARTITION_VALUE = L"ASR_C_WINNT_PARTITION_DEVICE";
|
|
static PWSTR ASR_SYSTEM_PARTITION_VALUE = L"ASR_C_SYSTEM_PARTITION_DEVICE";
|
|
|
|
static PWSTR ASR_SIF_NAME = L"asr.sif";
|
|
static PWSTR ASR_SIF_PATH = L"\\Device\\Floppy0\\asr.sif";
|
|
static PWSTR ASR_SIF_TARGET_PATH = L"\\repair\\asr.sif";
|
|
|
|
static PWSTR ASR_SETUP_LOG_NAME = L"setup.log";
|
|
static PWSTR ASR_DEFAULT_SETUP_LOG_PATH = L"\\Device\\Floppy0\\Setup.log";
|
|
|
|
extern const PWSTR SIF_ASR_PARTITIONS_SECTION;
|
|
extern const PWSTR SIF_ASR_SYSTEMS_SECTION;
|
|
|
|
PWSTR ASR_FLOPPY0_DEVICE_PATH = L"\\Device\\Floppy0";
|
|
PWSTR ASR_CDROM0_DEVICE_PATH = L"\\Device\\CdRom0";
|
|
PWSTR ASR_TEMP_DIRECTORY_PATH = L"\\TEMP";
|
|
|
|
|
|
PWSTR ASR_SIF_SYSTEM_KEY = L"1"; // we only handle one system per sif
|
|
|
|
static PWSTR Gbl_SourceSetupLogFileName = NULL;
|
|
|
|
PWSTR Gbl_SystemPartitionName = NULL;
|
|
PWSTR Gbl_SystemPartitionDirectory = NULL;
|
|
PWSTR Gbl_BootPartitionName = NULL;
|
|
PWSTR Gbl_BootPartitionDirectory = NULL;
|
|
|
|
ULONG Gbl_FixedDiskCount = 0;
|
|
|
|
WCHAR Gbl_BootPartitionDriveLetter;
|
|
|
|
PVOID Gbl_HandleToSetupLog = NULL;
|
|
PVOID Gbl_SifHandle = NULL;
|
|
|
|
BOOLEAN Gbl_RepairWinntFast = FALSE; // Put in spdrfix.c
|
|
BOOLEAN Gbl_NtPartitionIntact = TRUE;
|
|
BOOLEAN Gbl_RepairFromErDisk = FALSE;
|
|
BOOLEAN Gbl_AsrSifOnInstallationMedia = FALSE;
|
|
|
|
ASRMODE Gbl_AsrMode = ASRMODE_NONE;
|
|
|
|
PDISK_REGION Gbl_BootPartitionRegion = NULL;
|
|
PDISK_REGION Gbl_SystemPartitionRegion = NULL;
|
|
|
|
PSIF_PARTITION_RECORD Gbl_SystemPartitionRecord = NULL;
|
|
DWORD Gbl_SystemDiskIndex = 0;
|
|
|
|
PSIF_PARTITION_RECORD Gbl_BootPartitionRecord = NULL;
|
|
DWORD Gbl_BootDiskIndex = 0;
|
|
|
|
PSIF_INSTALLFILE_LIST Gbl_3rdPartyFileList = NULL;
|
|
PCONFIGURATION_INFORMATION Gbl_IoDevices = NULL;
|
|
|
|
PWSTR RemoteBootAsrSifName = NULL;
|
|
|
|
|
|
//
|
|
// delay the driver cab opening until required
|
|
// (while repair is being performed)
|
|
//
|
|
PWSTR gszDrvInfDeviceName = 0;
|
|
PWSTR gszDrvInfDirName = 0;
|
|
HANDLE ghSif = 0;
|
|
|
|
//
|
|
// To Enable/Disable Emergency repair
|
|
//
|
|
BOOLEAN DisableER = TRUE;
|
|
|
|
|
|
// Module identification for debug traces
|
|
#define THIS_MODULE L" spdr.c"
|
|
#define THIS_MODULE_CODE L"A"
|
|
|
|
// Keys valid on various menu screens
|
|
|
|
#define ASCI_C 67
|
|
#define ASCI_c 99
|
|
|
|
#define ASCI_F 70
|
|
#define ASCI_f 102
|
|
|
|
#define ASCI_M 77
|
|
#define ASCI_m 109
|
|
|
|
#define ASCI_R 82
|
|
#define ASCI_r 114
|
|
|
|
// Useful macros
|
|
#define FilesystemNotApplicable ((FilesystemType) FilesystemMax)
|
|
|
|
// External functions and variables
|
|
extern BOOLEAN ForceConsole;
|
|
|
|
extern const PWSTR SIF_ASR_GPT_PARTITIONS_SECTION;
|
|
extern const PWSTR SIF_ASR_MBR_PARTITIONS_SECTION;
|
|
|
|
extern PWSTR NtBootDevicePath;
|
|
extern PWSTR DirectoryOnBootDevice;
|
|
|
|
extern VOID SpInitializePidString(
|
|
IN HANDLE MasterSifHandle,
|
|
IN PWSTR SetupSourceDevicePath,
|
|
IN PWSTR DirectoryOnSourceDevice
|
|
);
|
|
|
|
extern NTSTATUS SpOpenSetValueAndClose(
|
|
IN HANDLE hKeyRoot,
|
|
IN PWSTR SubKeyName, OPTIONAL
|
|
IN PWSTR ValueName,
|
|
IN ULONG ValueType,
|
|
IN PVOID Value,
|
|
IN ULONG ValueSize
|
|
);
|
|
|
|
extern BOOLEAN
|
|
SpPtnCreateLogicalDrive(
|
|
IN ULONG DiskNumber,
|
|
IN ULONGLONG StartSector,
|
|
IN ULONGLONG SizeInSectors,
|
|
IN BOOLEAN ForNT,
|
|
IN BOOLEAN AlignToCylinder,
|
|
IN ULONGLONG DesiredMB OPTIONAL,
|
|
IN PPARTITION_INFORMATION_EX PartInfo OPTIONAL,
|
|
OUT PDISK_REGION *ActualDiskRegion OPTIONAL
|
|
);
|
|
|
|
extern ULONG
|
|
SpPtnGetPartitionCountDisk(
|
|
IN ULONG DiskId
|
|
);
|
|
|
|
extern ULONG
|
|
SpPtnGetContainerPartitionCount(
|
|
IN ULONG DiskId
|
|
);
|
|
|
|
extern NTSTATUS
|
|
SpPtnZapSectors(
|
|
IN HANDLE DiskHandle,
|
|
IN ULONG BytesPerSector,
|
|
IN ULONGLONG StartSector,
|
|
IN ULONG SectorCount
|
|
);
|
|
|
|
extern PDISK_REGION
|
|
SpPtnLocateESP(
|
|
VOID
|
|
);
|
|
|
|
|
|
VOID
|
|
SpAsrInitIoDeviceCount(VOID)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Gets the IO Devices counts and updates Gbl_IoDevices. Prints out
|
|
debug information with the deves counts.
|
|
|
|
Arguments:
|
|
None
|
|
|
|
Return Value:
|
|
void
|
|
|
|
Side Effect:
|
|
Updates Gbl_IoDevices with configuration information
|
|
|
|
--*/
|
|
{
|
|
ULONG diskIndex;
|
|
|
|
Gbl_IoDevices = IoGetConfigurationInformation();
|
|
|
|
//!!review null?
|
|
|
|
DbgStatusMesg((_asrinfo, "----- I/O Device Configurations: -----\n"));
|
|
DbgMesg((_asrinfo, " SCSI ports: %lu\n", Gbl_IoDevices->ScsiPortCount));
|
|
DbgMesg((_asrinfo, " Floppy disk drives: %lu\n", Gbl_IoDevices->FloppyCount));
|
|
DbgMesg((_asrinfo, " CDROM disk drives: %lu\n", Gbl_IoDevices->CdRomCount));
|
|
|
|
if (Gbl_IoDevices->TapeCount) {
|
|
DbgMesg((_asrinfo, " Tape drives: %lu\n", Gbl_IoDevices->TapeCount));
|
|
}
|
|
|
|
if (Gbl_IoDevices->MediumChangerCount) {
|
|
DbgMesg((_asrinfo, " Media changers: %lu\n", Gbl_IoDevices->MediumChangerCount));
|
|
}
|
|
|
|
DbgMesg((_asrinfo, " Hard disk drives: %lu\n", Gbl_IoDevices->DiskCount));
|
|
|
|
for (diskIndex = 0; diskIndex < Gbl_IoDevices->DiskCount; diskIndex++) {
|
|
DbgMesg((_asrinfo, " %ws %s %ws\n",
|
|
(PWSTR) HardDisks[diskIndex].DevicePath,
|
|
DISK_IS_REMOVABLE(diskIndex) ? "(rmvable):" : "(fixed): ",
|
|
(PWSTR) HardDisks[diskIndex].Description));
|
|
}
|
|
DbgStatusMesg((_asrinfo, "----- End of I/O Device Configurations: -----\n\n"));
|
|
}
|
|
|
|
|
|
VOID
|
|
SpAsrDbgDumpRegion(
|
|
IN PDISK_REGION pRegion
|
|
)
|
|
{
|
|
UCHAR partitionType = 0;
|
|
PWSTR partitionPath = NULL;
|
|
|
|
if (!pRegion) {
|
|
KdPrintEx((_asrinfo, "pRegion is NULL. Cannot be examined.\n"));
|
|
return;
|
|
}
|
|
|
|
if (!SPPT_IS_REGION_PARTITIONED(pRegion)) {
|
|
KdPrintEx((_asrinfo, "[/]: non-partitioned region.\n"));
|
|
return;
|
|
}
|
|
else {
|
|
SpNtNameFromRegion(
|
|
pRegion,
|
|
TemporaryBuffer,
|
|
sizeof(TemporaryBuffer),
|
|
PartitionOrdinalCurrent
|
|
);
|
|
|
|
partitionPath = SpDupStringW(TemporaryBuffer);
|
|
|
|
partitionType = SPPT_GET_PARTITION_TYPE(pRegion);
|
|
|
|
KdPrintEx((_asrinfo, "[%ws]: partitioned. type:0x%x dynamicVol:%s\n",
|
|
partitionPath,
|
|
partitionType,
|
|
pRegion->DynamicVolume ? "Yes" : "No"));
|
|
|
|
SpMemFree(partitionPath);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
SpAsrDbgDumpDisk(IN ULONG Disk)
|
|
{
|
|
PDISK_REGION primaryRegion = NULL,
|
|
extRegion = NULL;
|
|
|
|
DbgMesg((_asrinfo,
|
|
"\n SpAsrDbgDumpDisk. Existing regions on disk %lu (sig:0x%x):\n",
|
|
Disk,
|
|
SpAsrGetActualDiskSignature(Disk)
|
|
));
|
|
|
|
primaryRegion = SPPT_GET_PRIMARY_DISK_REGION(Disk);
|
|
extRegion = SPPT_GET_EXTENDED_DISK_REGION(Disk);
|
|
|
|
if (!primaryRegion && !extRegion) {
|
|
DbgMesg((_asrinfo, "*** No Partitions ***\n"));
|
|
return;
|
|
}
|
|
|
|
while (primaryRegion) {
|
|
DbgMesg((_asrinfo, "(pri) "));
|
|
SpAsrDbgDumpRegion(primaryRegion);
|
|
primaryRegion = primaryRegion->Next;
|
|
}
|
|
|
|
while (extRegion) {
|
|
DbgMesg((_asrinfo, "(ext) "));
|
|
SpAsrDbgDumpRegion(extRegion);
|
|
extRegion = extRegion->Next;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
SpAsrDeletePartitions(
|
|
IN ULONG DiskNumber,
|
|
IN BOOLEAN PreserveInterestingPartitions, // ESP for GPT, InterestingPartitionType for MBR
|
|
IN UCHAR InterestingMbrPartitionType, // see above
|
|
OUT BOOLEAN *IsBlank // this is set FALSE if disk contains partitions that weren't deleted
|
|
)
|
|
{
|
|
PPARTITIONED_DISK pDisk = NULL;
|
|
PDISK_REGION CurrRegion = NULL;
|
|
|
|
BOOLEAN Changes = FALSE;
|
|
NTSTATUS Status, InitStatus;
|
|
BOOLEAN preserveThisPartition = FALSE;
|
|
|
|
*IsBlank = TRUE;
|
|
|
|
DbgStatusMesg((_asrinfo,
|
|
"Deleting partitions on DiskNumber %lu "
|
|
"(partition count: %lu + %lu)\n",
|
|
DiskNumber,
|
|
SpPtnGetPartitionCountDisk(DiskNumber),
|
|
SpPtnGetContainerPartitionCount(DiskNumber)
|
|
));
|
|
|
|
//
|
|
// Check if disk has any partitions
|
|
//
|
|
pDisk = &PartitionedDisks[DiskNumber];
|
|
if (!pDisk) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Mark partitions for deletion
|
|
//
|
|
CurrRegion = pDisk->PrimaryDiskRegions;
|
|
while (CurrRegion) {
|
|
if (!SPPT_IS_REGION_FREESPACE(CurrRegion)) {
|
|
|
|
preserveThisPartition = FALSE;
|
|
|
|
if (PreserveInterestingPartitions) {
|
|
if (SPPT_IS_GPT_DISK(DiskNumber)) {
|
|
|
|
if (SPPT_IS_REGION_EFI_SYSTEM_PARTITION(CurrRegion)) {
|
|
preserveThisPartition = TRUE;
|
|
}
|
|
|
|
//
|
|
// TODO: OEM partitions on GPT, do we preserve them?
|
|
//
|
|
}
|
|
else {
|
|
//
|
|
// Preserve the MBR partition, if it matches the OEM partition type
|
|
//
|
|
if ((PARTITION_ENTRY_UNUSED != InterestingMbrPartitionType) &&
|
|
(InterestingMbrPartitionType == SPPT_GET_PARTITION_TYPE(CurrRegion))) {
|
|
|
|
preserveThisPartition = TRUE;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
if (preserveThisPartition) {
|
|
|
|
DbgStatusMesg((_asrinfo, "Preserving partition with start sector: %I64u\n",
|
|
CurrRegion->StartSector));
|
|
|
|
*IsBlank = FALSE;
|
|
SPPT_SET_REGION_DELETED(CurrRegion, FALSE);
|
|
SPPT_SET_REGION_DIRTY(CurrRegion, TRUE);
|
|
|
|
}
|
|
else {
|
|
|
|
DbgStatusMesg((_asrinfo, "Deleting partition with start sector: %I64u\n",
|
|
CurrRegion->StartSector));
|
|
|
|
SPPT_SET_REGION_DELETED(CurrRegion, TRUE);
|
|
SPPT_SET_REGION_DIRTY(CurrRegion, TRUE);
|
|
|
|
//
|
|
// If this is a container partition, make sure we zero it
|
|
//
|
|
if (SPPT_IS_REGION_CONTAINER_PARTITION(CurrRegion)) {
|
|
WCHAR DiskPath[MAX_PATH];
|
|
HANDLE DiskHandle;
|
|
|
|
//
|
|
// form the name
|
|
//
|
|
DbgStatusMesg((_asrinfo,
|
|
"Zapping first sector for container partition with start sector: %I64u\n",
|
|
CurrRegion->StartSector
|
|
));
|
|
|
|
swprintf(DiskPath, L"\\Device\\Harddisk%u", DiskNumber);
|
|
Status = SpOpenPartition0(DiskPath, &DiskHandle, TRUE);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
SpPtnZapSectors(DiskHandle, SPPT_DISK_SECTOR_SIZE(DiskNumber), CurrRegion->StartSector, 2);
|
|
ZwClose(DiskHandle);
|
|
}
|
|
else {
|
|
DbgStatusMesg((_asrinfo,
|
|
"Could not open handle to disk %lu to zap sector: %I64u (0x%x)\n",
|
|
DiskNumber,
|
|
CurrRegion->StartSector,
|
|
Status
|
|
));
|
|
}
|
|
}
|
|
|
|
//
|
|
// Remove any boot sets pointing to this region.
|
|
//
|
|
SpPtDeleteBootSetsForRegion(CurrRegion);
|
|
|
|
//
|
|
// Get rid of the compressed drives, if any
|
|
//
|
|
if (CurrRegion->NextCompressed != NULL) {
|
|
SpDisposeCompressedDrives(CurrRegion->NextCompressed);
|
|
CurrRegion->NextCompressed = NULL;
|
|
CurrRegion->MountDrive = 0;
|
|
CurrRegion->HostDrive = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
CurrRegion = CurrRegion->Next;
|
|
}
|
|
|
|
//
|
|
// Commit the changes
|
|
//
|
|
Status = SpPtnCommitChanges(DiskNumber, &Changes);
|
|
|
|
//
|
|
// Initialize region structure for the disk again
|
|
//
|
|
InitStatus = SpPtnInitializeDiskDrive(DiskNumber);
|
|
|
|
if (!NT_SUCCESS(Status) || !Changes || !NT_SUCCESS(InitStatus)) {
|
|
|
|
DbgFatalMesg((_asrerr,
|
|
"Could not successfully delete partitions on disk %lu (0x%x)",
|
|
DiskNumber,
|
|
Status
|
|
));
|
|
|
|
//
|
|
// If this is going to be a serious problem, we will hit a fatal error
|
|
// when we try to create partitions on this disk. Let's defer
|
|
// any UI error messages till then.
|
|
//
|
|
|
|
}
|
|
else {
|
|
DbgStatusMesg((_asrinfo, "Deleted all partitions on disk %lu.\n", DiskNumber));
|
|
}
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
SpAsrProcessSetupLogFile(
|
|
PWSTR FullLogFileName,
|
|
BOOLEAN AllowRetry
|
|
)
|
|
{
|
|
|
|
PDISK_REGION region = NULL;
|
|
BOOLEAN result = FALSE;
|
|
|
|
DbgStatusMesg((_asrinfo, "ProcessSetupLogFile. (ER) Loading setup log file [%ws]\n", FullLogFileName));
|
|
|
|
result = SpLoadRepairLogFile(FullLogFileName, &Gbl_HandleToSetupLog);
|
|
|
|
if (!result) {
|
|
|
|
if (AllowRetry) {
|
|
|
|
DbgErrorMesg((_asrwarn,
|
|
"ProcessSetupLogFile. Error loading setup log file [%ws]. AllowRetry:TRUE. continuing.\n",
|
|
FullLogFileName));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
else {
|
|
|
|
DbgFatalMesg((_asrerr, "ProcessSetupLogFile. Error loading setup log file [%ws]. AllowRetry:FALSE. Terminating.\n",
|
|
FullLogFileName));
|
|
|
|
SpAsrRaiseFatalError(SP_TEXT_DR_NO_SETUPLOG, L"Setup.log file not loaded successfully");
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Determine the system partition, system partition directory, NT partition,
|
|
// and the NT partition directory from the setup.log file.
|
|
//
|
|
SppGetRepairPathInformation(Gbl_HandleToSetupLog,
|
|
&Gbl_SystemPartitionName,
|
|
&Gbl_SystemPartitionDirectory,
|
|
&Gbl_BootPartitionName,
|
|
&Gbl_BootPartitionDirectory);
|
|
|
|
if (!(Gbl_SystemPartitionName && Gbl_SystemPartitionDirectory
|
|
&& Gbl_BootPartitionName && Gbl_BootPartitionDirectory)) {
|
|
|
|
DbgFatalMesg((_asrerr,
|
|
"ProcessSetupLogFile. Invalid NULL value in one of the following: \n"
|
|
));
|
|
|
|
DbgMesg((_asrinfo,
|
|
"\tGbl_SystemPartitionName: %p Gbl_SystemPartitionDirectory: %p\n",
|
|
Gbl_SystemPartitionName,
|
|
Gbl_SystemPartitionDirectory
|
|
));
|
|
|
|
DbgMesg((_asrinfo,
|
|
"\tGbl_BootPartitionName: %p Gbl_BootPartitionDirectory: %p\n",
|
|
Gbl_BootPartitionName,
|
|
Gbl_BootPartitionDirectory
|
|
));
|
|
|
|
SpAsrRaiseFatalError(SP_TEXT_DR_BAD_SETUPLOG, L"One or more directory and partition names from setup.log were NULL.");
|
|
|
|
}
|
|
|
|
//
|
|
// Check whether the system and nt partition regions exist on this machine
|
|
//
|
|
Gbl_SystemPartitionRegion = SpRegionFromNtName(Gbl_SystemPartitionName, PartitionOrdinalCurrent);
|
|
if (!Gbl_SystemPartitionRegion) {
|
|
DbgStatusMesg((_asrinfo, "ProcessSetupLogFile. System partition [%ws] does not yet exist\n", Gbl_SystemPartitionName));
|
|
}
|
|
|
|
Gbl_BootPartitionRegion = SpRegionFromNtName(Gbl_BootPartitionName, PartitionOrdinalCurrent);
|
|
if (!Gbl_BootPartitionRegion) {
|
|
DbgStatusMesg((_asrinfo, "ProcessSetupLogFile. Boot partition [%ws] does not yet exist\n", Gbl_BootPartitionName));
|
|
}
|
|
|
|
DbgStatusMesg((_asrinfo, "ProcessSetupLogFile. (ER) DONE loading setup log file [%ws]\n",
|
|
FullLogFileName));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
SpAsrRegionCanBeFormatted(IN PDISK_REGION pRegion)
|
|
{
|
|
UCHAR partitionType = 0x0;
|
|
BOOLEAN canBeFormatted = FALSE;
|
|
|
|
partitionType = SPPT_GET_PARTITION_TYPE(pRegion);
|
|
|
|
switch (partitionType) {
|
|
case PARTITION_HUGE:
|
|
case PARTITION_FAT32:
|
|
case PARTITION_IFS:
|
|
canBeFormatted = TRUE;
|
|
break;
|
|
}
|
|
|
|
return canBeFormatted;
|
|
}
|
|
|
|
|
|
FilesystemType
|
|
SpAsrGetFsTypeFromPartitionType(
|
|
IN UCHAR PartitionType
|
|
)
|
|
{
|
|
FilesystemType fileSystemType = FilesystemUnknown;
|
|
|
|
// if this is an extended partition, or logical disk, skip it.
|
|
if (IsContainerPartition(PartitionType)) {
|
|
return FilesystemNotApplicable;
|
|
}
|
|
|
|
if (IsRecognizedFatPartition(PartitionType)) {
|
|
fileSystemType = FilesystemFat;
|
|
}
|
|
else if (IsRecognizedFat32Partition(PartitionType)) {
|
|
fileSystemType = FilesystemFat32;
|
|
}
|
|
else if (IsRecognizedNtfsPartition(PartitionType)) {
|
|
fileSystemType = FilesystemNtfs;
|
|
}
|
|
else {
|
|
fileSystemType = FilesystemUnknown;
|
|
}
|
|
return fileSystemType;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
SpAsrPartitionNeedsFormatting(
|
|
IN PDISK_REGION pRegion,
|
|
IN UCHAR NewFileSystemType
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
This routine is only called when checking whether an existing partition
|
|
needs to be [re]formatted.
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN needsFormatting = FALSE;
|
|
FilesystemType fsType;
|
|
|
|
ASSERT(pRegion);
|
|
|
|
// if (!SpAsrRegionCanBeFormatted(pRegion)) {
|
|
// return FALSE;
|
|
// }
|
|
|
|
// *NewFilesystemType = SpAsrGetFsTypeFromPartitionType(RequiredSysId);
|
|
|
|
fsType = SpIdentifyFileSystem(HardDisks[pRegion->DiskNumber].DevicePath,
|
|
HardDisks[pRegion->DiskNumber].Geometry.BytesPerSector,
|
|
SpPtGetOrdinal(pRegion,PartitionOrdinalCurrent));
|
|
|
|
switch (fsType) {
|
|
|
|
case FilesystemFat:
|
|
if (!IsRecognizedFatPartition(NewFileSystemType)) {
|
|
needsFormatting = TRUE;
|
|
}
|
|
break;
|
|
|
|
case FilesystemNtfs:
|
|
if (!IsRecognizedNtfsPartition(NewFileSystemType)) {
|
|
needsFormatting = TRUE;
|
|
}
|
|
break;
|
|
|
|
case FilesystemFat32:
|
|
if (!IsRecognizedFat32Partition(NewFileSystemType)) {
|
|
needsFormatting = TRUE;
|
|
}
|
|
break;
|
|
|
|
case FilesystemDoubleSpace:
|
|
needsFormatting = FALSE;
|
|
break;
|
|
|
|
case FilesystemUnknown:
|
|
case FilesystemNewlyCreated:
|
|
default:
|
|
needsFormatting = TRUE;
|
|
break;
|
|
}
|
|
|
|
DbgStatusMesg((_asrinfo, "SpAsrPartitionNeedsFormatting. DiskRegion %p Disk:%lu SS:%I64u SC:%I64u fsType:0x%x NewFsType:0x%x NeedsFmt:%s\n",
|
|
pRegion,
|
|
pRegion->DiskNumber,
|
|
pRegion->StartSector,
|
|
pRegion->SectorCount,
|
|
fsType,
|
|
NewFileSystemType,
|
|
needsFormatting ? "TRUE" : "FALSE"));
|
|
|
|
return needsFormatting;
|
|
}
|
|
|
|
|
|
//
|
|
// Called only for boot and system partitions.
|
|
//
|
|
BOOLEAN
|
|
SpAsrReformatPartition(
|
|
IN PDISK_REGION pRegion,
|
|
IN UCHAR PartitionType,
|
|
IN PVOID SifHandle,
|
|
IN DWORD ClusterSize,
|
|
IN PWSTR Local_SetupSourceDevicePath,
|
|
IN PWSTR Local_DirectoryOnSetupSource,
|
|
IN BOOL IsBootPartition // TRUE=>Boot, FALSE=>System
|
|
)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PWSTR partitionDeviceName = NULL;
|
|
FilesystemType Filesystem;
|
|
UNICODE_STRING UnicodeString;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
OBJECT_ATTRIBUTES Obja;
|
|
HANDLE Handle = NULL;
|
|
|
|
WCHAR formatStr[6]; // okay to hardcode "6".
|
|
|
|
//
|
|
// For the recognised partitions, ensure that the partition type matches the
|
|
// filesystem type. For other partitions, we cannot perform this check.
|
|
//
|
|
switch (PartitionType) {
|
|
|
|
case PARTITION_FAT32: {
|
|
wcscpy(formatStr, L"FAT32");
|
|
Filesystem = FilesystemFat32;
|
|
break;
|
|
}
|
|
|
|
case PARTITION_HUGE: {
|
|
wcscpy(formatStr, L"FAT");
|
|
Filesystem = FilesystemFat;
|
|
break;
|
|
}
|
|
|
|
case PARTITION_IFS: {
|
|
wcscpy(formatStr, L"NTFS");
|
|
Filesystem = FilesystemNtfs;
|
|
break;
|
|
}
|
|
|
|
default: {
|
|
//
|
|
// This is fatal, we need to format the boot and system drive.
|
|
//
|
|
DbgErrorMesg((_asrerr,
|
|
"Region %p, Partition Type 0x%x, SifHandle %p, SetupSrc [%ws], Dir [%ws], IsBoot %d\n",
|
|
pRegion, PartitionType, SifHandle, Local_SetupSourceDevicePath,
|
|
Local_DirectoryOnSetupSource, IsBootPartition
|
|
));
|
|
|
|
ASSERT(0 && "Cannot format boot or system partition");
|
|
|
|
swprintf(TemporaryBuffer, L"Partition type 0x%x for %s partition is not recognised\n",
|
|
PartitionType,
|
|
(IsBootPartition ? "boot" : "system")
|
|
);
|
|
|
|
SpAsrRaiseFatalError(
|
|
(IsBootPartition ? SP_TEXT_DR_UNKNOWN_NT_FILESYSTEM : SP_TEXT_DR_UNKNOWN_LOADER_FILESYSTEM),
|
|
TemporaryBuffer
|
|
);
|
|
}
|
|
}
|
|
|
|
if (SPPT_IS_MBR_DISK(pRegion->DiskNumber)) {
|
|
//
|
|
// This should only be set for MBR disks
|
|
//
|
|
SPPT_SET_PARTITION_TYPE(pRegion, PartitionType);
|
|
}
|
|
partitionDeviceName = SpAsrGetRegionName(pRegion);
|
|
|
|
DbgStatusMesg((_asrinfo, "About to format [%ws] for [%ws].\n", partitionDeviceName, formatStr));
|
|
|
|
//
|
|
// If automated ASR tests are in progress, we won't actually format the drives
|
|
//
|
|
if (ASRMODE_NORMAL != SpAsrGetAsrMode()) {
|
|
DbgStatusMesg((_asrerr, "ASR Quick Tests in Progress, skipping format\n"));
|
|
status = STATUS_SUCCESS;
|
|
|
|
}
|
|
else {
|
|
status = SpDoFormat(partitionDeviceName,
|
|
pRegion,
|
|
Filesystem,
|
|
TRUE, // IsFailureFatal
|
|
FALSE, // Check FAT Size, FALSE since we automatically convert if needed
|
|
#ifdef PRERELEASE
|
|
TRUE, // To reduce testing time, we can quick format in pre-release
|
|
#else
|
|
FALSE, // Quick Format
|
|
#endif
|
|
SifHandle,
|
|
ClusterSize,
|
|
Local_SetupSourceDevicePath,
|
|
Local_DirectoryOnSetupSource
|
|
);
|
|
}
|
|
|
|
//
|
|
// Won't get here if SpDoFormat failed, we set IsFailureFatal = TRUE.
|
|
//
|
|
ASSERT(NT_SUCCESS(status) && L"SpDoFormat returned on failure");
|
|
|
|
//
|
|
// To make sure the file system mounts, we'll open a handle to the
|
|
// partition and close it right back.
|
|
//
|
|
INIT_OBJA(&Obja, &UnicodeString, partitionDeviceName);
|
|
|
|
status = ZwCreateFile(
|
|
&Handle,
|
|
FILE_GENERIC_READ,
|
|
&Obja,
|
|
&IoStatusBlock,
|
|
NULL,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
FILE_SHARE_READ|FILE_SHARE_WRITE,
|
|
FILE_OPEN,
|
|
FILE_SYNCHRONOUS_IO_NONALERT,
|
|
NULL,
|
|
0
|
|
);
|
|
|
|
ZwClose(Handle);
|
|
ASSERT(NT_SUCCESS(status) && L"Couldn't open the partition after formatting it");
|
|
|
|
DbgStatusMesg((_asrinfo, "ReformatPartition. Done [%ws] for [%ws].\n", partitionDeviceName, formatStr));
|
|
SpMemFree(partitionDeviceName);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID
|
|
SpAsrRemoveDiskMountPoints(IN ULONG Disk)
|
|
/*++
|
|
|
|
Description:
|
|
For each partition on the specified disk, its drive letter (if
|
|
present) is removed.
|
|
|
|
Arguments:
|
|
Disk Specifies the disk containing the partitions whose drive letters
|
|
are to be removed.
|
|
|
|
Returns:
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PPARTITIONED_DISK pDisk = NULL;
|
|
PDISK_REGION pDiskRegion = NULL;
|
|
PWSTR partitionPath = NULL;
|
|
UCHAR partitionType = 0;
|
|
|
|
pDisk = &PartitionedDisks[Disk];
|
|
|
|
|
|
DbgStatusMesg((_asrinfo, "SpAsrRemoveDiskMountPoints. Removing mount points for Disk %lu.\n", Disk));
|
|
|
|
//
|
|
// We first delete the primary partitions (other than the container partition)
|
|
//
|
|
pDiskRegion = pDisk->PrimaryDiskRegions;
|
|
while (pDiskRegion) {
|
|
|
|
if (SPPT_IS_REGION_PARTITIONED(pDiskRegion)) {
|
|
//
|
|
// We don't want to delete the container partition yet
|
|
//
|
|
partitionType = SPPT_GET_PARTITION_TYPE(pDiskRegion);
|
|
if (!IsContainerPartition(partitionType)) {
|
|
|
|
partitionPath = SpAsrGetRegionName(pDiskRegion);
|
|
SpAsrDeleteMountPoint(partitionPath);
|
|
SpMemFree(partitionPath);
|
|
|
|
}
|
|
}
|
|
|
|
pDiskRegion = pDiskRegion->Next;
|
|
}
|
|
|
|
//
|
|
// Next, delete the extended region mount points
|
|
//
|
|
pDiskRegion = pDisk->ExtendedDiskRegions;
|
|
while (pDiskRegion) {
|
|
|
|
if (SPPT_IS_REGION_PARTITIONED(pDiskRegion)) {
|
|
|
|
partitionPath = SpAsrGetRegionName(pDiskRegion);
|
|
SpAsrDeleteMountPoint(partitionPath);
|
|
SpMemFree(partitionPath);
|
|
|
|
}
|
|
|
|
pDiskRegion = pDiskRegion->Next;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
SpAsrRemoveMountPoints(VOID)
|
|
{
|
|
ULONG driveCount;
|
|
|
|
// remove the mount points associated with all removable disk drives (Jaz, Zip, etc.,)
|
|
for (driveCount = 0; driveCount < Gbl_IoDevices->DiskCount; driveCount++) {
|
|
if (DISK_IS_REMOVABLE(driveCount)) {
|
|
swprintf(TemporaryBuffer, L"%ws\\Partition1", (PWSTR) HardDisks[driveCount].DevicePath);
|
|
SpAsrDeleteMountPoint(TemporaryBuffer);
|
|
}
|
|
}
|
|
|
|
// next, unlink CD-ROM drive letters.
|
|
// NB: the device name is case sensitive - Must be CdRom.
|
|
for (driveCount = 0; driveCount < Gbl_IoDevices->CdRomCount; driveCount++) {
|
|
swprintf(TemporaryBuffer, L"\\Device\\CdRom%u", driveCount);
|
|
SpAsrDeleteMountPoint(TemporaryBuffer);
|
|
}
|
|
|
|
// finally, remove the mount points for all partitions on all fixed
|
|
// disks attached to the system.
|
|
for (driveCount = 0; driveCount < HardDiskCount; driveCount++) {
|
|
if (Gbl_PartitionSetTable2[driveCount]) {
|
|
SpAsrRemoveDiskMountPoints(driveCount);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
SpAsrSetRegionMountPoint(
|
|
IN PDISK_REGION pRegion,
|
|
IN PSIF_PARTITION_RECORD pRec
|
|
)
|
|
{
|
|
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
|
PWSTR partitionDeviceName = NULL;
|
|
BOOLEAN isBoot = FALSE;
|
|
|
|
//
|
|
// Make sure that the input's okay ...
|
|
//
|
|
if (!pRec) {
|
|
DbgErrorMesg((_asrwarn,
|
|
"SpAsrSetRegionMountPoint. Rec %p is NULL!\n",
|
|
pRec
|
|
));
|
|
return;
|
|
}
|
|
|
|
if (!pRegion || !(SPPT_IS_REGION_PARTITIONED(pRegion))) {
|
|
DbgErrorMesg((_asrwarn,
|
|
"SpAsrSetRegionMountPoint. Region %p is NULL/unpartitioned for ptn-rec:[%ws].\n",
|
|
pRegion, pRec->CurrPartKey
|
|
));
|
|
return;
|
|
}
|
|
|
|
partitionDeviceName = SpAsrGetRegionName(pRegion);
|
|
|
|
//
|
|
// If this is the boot volume, set the drive letter
|
|
//
|
|
isBoot = SpAsrIsBootPartitionRecord(pRec->PartitionFlag);
|
|
if (isBoot) {
|
|
|
|
DbgStatusMesg((_asrinfo, "Setting [%ws] boot drive-letter to [%wc]\n",
|
|
partitionDeviceName,
|
|
Gbl_BootPartitionDriveLetter
|
|
));
|
|
|
|
status = SpAsrSetPartitionDriveLetter(pRegion, Gbl_BootPartitionDriveLetter);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
DbgErrorMesg((_asrwarn, "SpAsrSetRegionMountPoint. SpAsrSetPartitionDriveLetter failed for boot-drive. boot-ptn:[%ws], ptn-rec:[%ws]. (0x%x)\n",
|
|
partitionDeviceName,
|
|
pRec->CurrPartKey,
|
|
status
|
|
));
|
|
}
|
|
}
|
|
|
|
//
|
|
// And if the volume guid is present, set the volume guid
|
|
//
|
|
if ((pRec->VolumeGuid) && (wcslen(pRec->VolumeGuid) > 0)) {
|
|
|
|
DbgStatusMesg((_asrinfo,
|
|
"SpAsrSetRegionMountPoint. Setting [%ws] guid to [%ws]\n",
|
|
partitionDeviceName, pRec->VolumeGuid
|
|
));
|
|
|
|
status = SpAsrSetVolumeGuid(pRegion, pRec->VolumeGuid);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
DbgErrorMesg((_asrwarn,
|
|
"SpAsrSetRegionMountPoint. SpAsrSetVolumeGuid failed. device:[%ws], ptn-rec:[%ws]. (0x%x)\n",
|
|
partitionDeviceName, pRec->CurrPartKey, status
|
|
));
|
|
|
|
}
|
|
}
|
|
|
|
SpMemFree(partitionDeviceName);
|
|
}
|
|
|
|
|
|
VOID
|
|
SpAsrRestoreDiskMountPoints(IN ULONG DiskIndex)
|
|
{
|
|
PSIF_PARTITION_RECORD pRec = NULL;
|
|
PDISK_REGION pRegion = NULL;
|
|
|
|
//
|
|
// Make sure there is a partition list for the disk
|
|
//
|
|
if (Gbl_PartitionSetTable2[DiskIndex] == NULL ||
|
|
Gbl_PartitionSetTable2[DiskIndex]->pDiskRecord == NULL ||
|
|
Gbl_PartitionSetTable2[DiskIndex]->pDiskRecord->PartitionList == NULL) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Go through the paritions and set their mount points. This will also
|
|
// set the drive letter for the boot volume. (We have to set it now
|
|
// since we can't change it in GUI-mode Setup)
|
|
//
|
|
pRec = Gbl_PartitionSetTable2[DiskIndex]->pDiskRecord->PartitionList->First;
|
|
|
|
while (pRec) {
|
|
|
|
pRegion = SpAsrDiskPartitionExists(DiskIndex, pRec);
|
|
if (!pRegion) {
|
|
//
|
|
// We don't expect to find the regions for the non-critical disks.
|
|
//
|
|
DbgErrorMesg((_asrwarn,
|
|
"RestoreDiskMountPoints: Disk region not found, physical-disk %lu, ptn-rec-key %ws.\n",
|
|
DiskIndex,
|
|
pRec->CurrPartKey
|
|
));
|
|
|
|
}
|
|
else {
|
|
|
|
SpAsrSetRegionMountPoint(pRegion, pRec);
|
|
}
|
|
|
|
pRec = pRec->Next;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
SpAsrUpdatePartitionRecord(
|
|
IN ULONG Disk,
|
|
IN ULONGLONG NewStartSector,
|
|
IN ULONGLONG PrevStartSector,
|
|
IN ULONGLONG NewSectorCount
|
|
)
|
|
{
|
|
PSIF_PARTITION_RECORD pRecNew = NULL;
|
|
|
|
//
|
|
// Update the partition record whose disk and partition start sector
|
|
// match that of the Disk and PrevStartSector parameters.
|
|
//
|
|
pRecNew = Gbl_PartitionSetTable2[Disk]->pDiskRecord->PartitionList->First;
|
|
while (pRecNew) {
|
|
if (pRecNew->StartSector == PrevStartSector) {
|
|
pRecNew->StartSector = NewStartSector;
|
|
pRecNew->SectorCount = NewSectorCount;
|
|
break;
|
|
}
|
|
pRecNew = pRecNew->Next;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
SpAsrGetFirstFreespace(
|
|
IN ULONG DiskNumber,
|
|
IN BOOLEAN IsAPrimaryPartition,
|
|
OUT ULONGLONG *StartSector,
|
|
OUT ULONGLONG *FreeSectors,
|
|
OUT ULONGLONG *SizeMbFree,
|
|
IN CONST ULONGLONG MinimumSectorCount
|
|
)
|
|
{
|
|
PDISK_REGION pRegion = NULL;
|
|
ULONG NumPartitions = 0;
|
|
|
|
BOOLEAN extendedExists;
|
|
|
|
*StartSector = 0;
|
|
*FreeSectors = 0;
|
|
*SizeMbFree = 0;
|
|
|
|
NumPartitions = SpPtnGetPartitionCountDisk(DiskNumber)
|
|
+ SpPtnGetContainerPartitionCount(DiskNumber);
|
|
|
|
DbgStatusMesg((_asrinfo,
|
|
"SpAsrGetFirstFreespace. Dsk %lu. PartitionCount= %lu\n",
|
|
DiskNumber,
|
|
NumPartitions
|
|
));
|
|
|
|
pRegion = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
|
|
|
|
if (0 == NumPartitions) {
|
|
|
|
if (pRegion) {
|
|
*StartSector = pRegion->StartSector;
|
|
*FreeSectors = pRegion->SectorCount;
|
|
if ((*FreeSectors) < MinimumSectorCount) {
|
|
*FreeSectors = 0;
|
|
}
|
|
|
|
*SizeMbFree = SpAsrConvertSectorsToMB(*FreeSectors, SPPT_DISK_SECTOR_SIZE(DiskNumber));
|
|
return;
|
|
}
|
|
else {
|
|
//
|
|
// We have the whole disk at our disposal.
|
|
//
|
|
*FreeSectors = SpAsrGetTrueDiskSectorCount(DiskNumber);
|
|
if ((*FreeSectors) < MinimumSectorCount) {
|
|
*FreeSectors = 0;
|
|
}
|
|
|
|
*SizeMbFree = SpAsrConvertSectorsToMB(*FreeSectors, SPPT_DISK_SECTOR_SIZE(DiskNumber));
|
|
*StartSector = 0;
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
while (pRegion) {
|
|
DbgStatusMesg((_asrinfo,
|
|
"SpAsrGetFirstFreespace: MinSC: %I64u. Dsk %lu. Region: %p SS %I64u, SC %I64u, %spartitioned, %sfree-space \n",
|
|
MinimumSectorCount,
|
|
DiskNumber,
|
|
pRegion,
|
|
pRegion->StartSector,
|
|
pRegion->SectorCount,
|
|
(SPPT_IS_REGION_PARTITIONED(pRegion) ? "" : "non-"),
|
|
(SPPT_IS_REGION_FREESPACE(pRegion) ? "IS " : "not ")
|
|
));
|
|
|
|
if (SPPT_IS_REGION_FREESPACE(pRegion)) {
|
|
ULONGLONG AvailableSectors = 0;
|
|
BOOLEAN Found = (IsAPrimaryPartition ?
|
|
(!SPPT_IS_REGION_CONTAINER_PARTITION(pRegion) && !SPPT_IS_REGION_INSIDE_CONTAINER(pRegion)) :
|
|
(SPPT_IS_REGION_INSIDE_CONTAINER(pRegion))
|
|
);
|
|
|
|
AvailableSectors = pRegion->SectorCount;
|
|
//
|
|
// If we're trying to create a logical drive, we need to take into account that
|
|
// the size of the Free region is not fully available to us for use--the first
|
|
// track will be used for the EBR. So we must subtract out the first track
|
|
// from the AvailableSectors.
|
|
//
|
|
if (!IsAPrimaryPartition) {
|
|
AvailableSectors -= SPPT_DISK_TRACK_SIZE(DiskNumber);
|
|
}
|
|
|
|
DbgStatusMesg((_asrinfo,
|
|
"SpAsrGetFirstFreespace: For this region %p, AvailableSectors:%I64u, Found is %s kind of free space)\n",
|
|
pRegion,
|
|
AvailableSectors,
|
|
(Found ? "TRUE. (right" : "FALSE (wrong")
|
|
));
|
|
|
|
if ((Found) && (pRegion->StartSector > 0) && (AvailableSectors >= MinimumSectorCount)) {
|
|
*StartSector = pRegion->StartSector;
|
|
*FreeSectors = AvailableSectors;
|
|
*SizeMbFree = SpAsrConvertSectorsToMB(AvailableSectors, SPPT_DISK_SECTOR_SIZE(DiskNumber));
|
|
return;
|
|
}
|
|
}
|
|
pRegion = pRegion->Next;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
SpAsrRecreatePartition(
|
|
IN PSIF_PARTITION_RECORD pRec,
|
|
IN ULONG DiskNumber,
|
|
IN CONST BOOLEAN IsAligned
|
|
)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
BOOLEAN diskChanged = FALSE,
|
|
result = FALSE;
|
|
|
|
ULONGLONG sizeMbFree = 0,
|
|
freeSectors = 0,
|
|
oldStartSector = 0,
|
|
oldSectorCount = 0,
|
|
alignedSector = 0;
|
|
|
|
WCHAR DiskPath[MAX_PATH];
|
|
HANDLE DiskHandle = NULL;
|
|
|
|
PDISK_REGION pRegion = NULL;
|
|
PARTITION_INFORMATION_EX PartInfo;
|
|
|
|
DbgStatusMesg((_asrinfo,
|
|
"Recreating Ptn %p [%ws] (%s, SS %I64u, SC %I64u type 0x%x)\n",
|
|
pRec,
|
|
pRec->CurrPartKey,
|
|
pRec->IsPrimaryRecord ? "Pri" :
|
|
pRec->IsContainerRecord ? "Con" :
|
|
pRec->IsLogicalDiskRecord ? "Log" :
|
|
pRec->IsDescriptorRecord ? "Des" :"ERR",
|
|
pRec->StartSector,
|
|
pRec->SectorCount,
|
|
pRec->PartitionType
|
|
));
|
|
|
|
//
|
|
// Get needed parameters (start sector and remaining free space) from the
|
|
// first unpartitioned region on the disk.
|
|
//
|
|
SpAsrGetFirstFreespace(DiskNumber,
|
|
(pRec->IsPrimaryRecord || pRec->IsContainerRecord),
|
|
&pRec->StartSector,
|
|
&freeSectors, // Sector count of this free space
|
|
&sizeMbFree,
|
|
pRec->SectorCount
|
|
);
|
|
|
|
//
|
|
// We fail if the number of free sectors are less than the number
|
|
// of sectors required to create the partition.
|
|
//
|
|
if (!freeSectors) {
|
|
|
|
DbgFatalMesg((_asrerr,
|
|
"Ptn-record [%ws]: Disk %lu. reqSec %I64u > available sectors\n",
|
|
pRec->CurrPartKey,
|
|
DiskNumber,
|
|
pRec->SectorCount
|
|
));
|
|
|
|
SpAsrRaiseFatalError(
|
|
SP_TEXT_DR_INSUFFICIENT_CAPACITY,
|
|
L"Not enough free space left to create partition"
|
|
);
|
|
}
|
|
|
|
pRec->SizeMB = SpAsrConvertSectorsToMB(pRec->SectorCount, BYTES_PER_SECTOR(DiskNumber));
|
|
|
|
//
|
|
// Check if this is an LDM partition on the boot/sys disk. If so,
|
|
// all the 0x42 partitions on that disk need to be retyped to a basic
|
|
// type (6, 7 or B). This is to prevent LDM from getting confused on
|
|
// reboot. At the end of GUI-Setup, asr_ldm will do the needful to
|
|
// reset the partition types as needed.
|
|
//
|
|
if (pRec->NeedsLdmRetype) {
|
|
|
|
if (PARTITION_STYLE_MBR == pRec->PartitionStyle) {
|
|
if (!IsRecognizedPartition(pRec->FileSystemType)) {
|
|
//
|
|
// This is an 0x42 partition on the boot/sys disk, but it is
|
|
// not the boot or system partition. The FileSystemType is not
|
|
// recognised since it is set to be 0x42 as well. (The
|
|
// FileSystemType is only valid for the boot and system
|
|
// partitions--for all other partitions,
|
|
// it is set to be the same as the PartitionType)
|
|
//
|
|
// We set it to 0x7 for the time being. The actual file-system type
|
|
// will be set later in GUI-Setup by asr_ldm and asr_fmt.
|
|
//
|
|
DbgStatusMesg((_asrinfo,
|
|
"MBR ptn-rec %ws re-typed (0x%x->0x7) \n",
|
|
pRec->CurrPartKey, pRec->FileSystemType));
|
|
pRec->FileSystemType = PARTITION_IFS;
|
|
pRec->PartitionType = PARTITION_IFS;
|
|
}
|
|
else {
|
|
DbgStatusMesg((_asrinfo,
|
|
"MBR ptn-rec %ws re-typed (0x%x->0x%x).\n",
|
|
pRec->CurrPartKey, pRec->PartitionType,
|
|
pRec->FileSystemType));
|
|
pRec->PartitionType = pRec->FileSystemType;
|
|
}
|
|
}
|
|
else if (PARTITION_STYLE_GPT == pRec->PartitionStyle) {
|
|
|
|
DbgStatusMesg((_asrinfo,
|
|
"GPT ptn-rec %ws re-typed (%ws to basic).\n",
|
|
pRec->CurrPartKey, pRec->PartitionTypeGuid));
|
|
|
|
CopyMemory(&(pRec->PartitionTypeGuid),
|
|
&PARTITION_BASIC_DATA_GUID, sizeof(GUID));
|
|
|
|
}
|
|
else {
|
|
ASSERT(0 && L"Unrecognised partition style");
|
|
}
|
|
}
|
|
|
|
RtlZeroMemory(&PartInfo, sizeof(PARTITION_INFORMATION_EX));
|
|
|
|
//
|
|
// Fill out the PARTITION_INFORMATION_EX structure that SpPtnCreate uses
|
|
//
|
|
PartInfo.PartitionStyle = pRec->PartitionStyle;
|
|
|
|
if (PARTITION_STYLE_MBR == pRec->PartitionStyle) {
|
|
PartInfo.Mbr.PartitionType = pRec->PartitionType;
|
|
PartInfo.Mbr.BootIndicator =
|
|
SpAsrIsSystemPartitionRecord(pRec->PartitionFlag);
|
|
}
|
|
else if (PARTITION_STYLE_GPT == pRec->PartitionStyle) {
|
|
CopyMemory(&(PartInfo.Gpt.PartitionType), &(pRec->PartitionTypeGuid),
|
|
sizeof(GUID));
|
|
CopyMemory(&(PartInfo.Gpt.PartitionId), &(pRec->PartitionIdGuid),
|
|
sizeof(GUID));
|
|
PartInfo.Gpt.Attributes = pRec->GptAttributes;
|
|
wcscpy(PartInfo.Gpt.Name, pRec->PartitionName);
|
|
}
|
|
else {
|
|
//
|
|
// Unrecognised disk layout?
|
|
//
|
|
return;
|
|
}
|
|
|
|
DbgStatusMesg((_asrinfo,
|
|
"Recreating Ptn [%ws] (%s, Adjusted SS %I64u, type 0x%x)\n",
|
|
pRec->CurrPartKey, pRec->IsPrimaryRecord ? "Pri" :
|
|
pRec->IsContainerRecord ? "Con" :
|
|
pRec->IsLogicalDiskRecord ? "Log" :
|
|
pRec->IsDescriptorRecord ? "Des" :"ERR",
|
|
pRec->StartSector, pRec->PartitionType));
|
|
|
|
//
|
|
// Before creating the partition, let's zero out the first few
|
|
// sectors in that partition, so that we forcibly nuke any
|
|
// stale file-system or other information present
|
|
//
|
|
DbgStatusMesg((_asrinfo,
|
|
"Zeroing 2 sectors starting with sector: %I64u\n",pRec->StartSector));
|
|
|
|
swprintf(DiskPath, L"\\Device\\Harddisk%u", DiskNumber);
|
|
status = SpOpenPartition0(DiskPath, &DiskHandle, TRUE);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
status = SpPtnZapSectors(DiskHandle,
|
|
SPPT_DISK_SECTOR_SIZE(DiskNumber),
|
|
pRec->StartSector,
|
|
2);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
DbgStatusMesg((_asrwarn,
|
|
"Could not zero sector %I64u on disk %lu (0x%x)\n",
|
|
pRec->StartSector, DiskNumber, status));
|
|
}
|
|
|
|
//
|
|
// If the first partition we're creating is a container partition,
|
|
// SpPtnCreate will align it to a cylinder boundary. The problem
|
|
// is that since we haven't zero'ed that sector (at the first
|
|
// cylinder boundary), it may contain some stale EBR info, and we will
|
|
// end up thinking that that EBR is valid.
|
|
//
|
|
// So if this is a container partition, let's do one additional
|
|
// thing--check what the cylinder aligned boundary will be, and
|
|
// zero that out if needed.
|
|
//
|
|
if (IsAligned && pRec->IsContainerRecord) {
|
|
alignedSector = SpPtAlignStart(SPPT_GET_HARDDISK(DiskNumber), pRec->StartSector, TRUE);
|
|
|
|
if (alignedSector != pRec->StartSector) {
|
|
status = SpPtnZapSectors(DiskHandle,
|
|
SPPT_DISK_SECTOR_SIZE(DiskNumber),
|
|
alignedSector,
|
|
2);
|
|
if (!NT_SUCCESS(status)) {
|
|
DbgStatusMesg((_asrwarn,
|
|
"Could not zero aligned-sector %I64u on disk %lu (0x%x)\n",
|
|
alignedSector, DiskNumber, status));
|
|
}
|
|
}
|
|
}
|
|
|
|
ZwClose(DiskHandle);
|
|
}
|
|
else {
|
|
DbgStatusMesg((_asrwarn,
|
|
"Could not open handle to disk %lu to zap sector: %I64u (0x%x)\n",
|
|
DiskNumber,
|
|
pRec->StartSector,
|
|
status
|
|
));
|
|
}
|
|
|
|
//
|
|
// Create this partition on disk. If we aren't successful, we treat it as a fatal error.
|
|
//
|
|
if (pRec->IsLogicalDiskRecord) {
|
|
//
|
|
// For logical disks, we need to call SpPtnCreateLogicalDrive, which
|
|
// will take care of creating the descriptor records as needed.
|
|
//
|
|
result = SpPtnCreateLogicalDrive(
|
|
DiskNumber,
|
|
pRec->StartSector,
|
|
pRec->SectorCount,
|
|
TRUE,
|
|
IsAligned,
|
|
pRec->SizeMB,
|
|
&PartInfo,
|
|
&pRegion
|
|
);
|
|
|
|
}
|
|
else {
|
|
//
|
|
// If this is a container partition, make sure we zero the
|
|
// first sector of the partition before creating it
|
|
//
|
|
result = SpPtnCreate(
|
|
DiskNumber,
|
|
pRec->StartSector,
|
|
pRec->SectorCount,
|
|
pRec->SizeMB,
|
|
IsContainerPartition(pRec->PartitionType),
|
|
IsAligned,
|
|
&PartInfo,
|
|
&pRegion
|
|
);
|
|
|
|
}
|
|
|
|
if (!result) {
|
|
|
|
DbgFatalMesg((_asrerr, "SpPtnCreate failed for ptn-rec %ws at %p (Disk %lu, SS %I64u, Size %I64u)\n",
|
|
pRec->CurrPartKey,
|
|
pRec,
|
|
DiskNumber,
|
|
pRec->StartSector,
|
|
pRec->SizeMB
|
|
));
|
|
|
|
SpAsrRaiseFatalError(
|
|
SP_SCRN_DR_CREATE_ERROR_DISK_PARTITION,
|
|
TemporaryBuffer
|
|
);
|
|
|
|
// does not return
|
|
}
|
|
|
|
|
|
if (pRec->NeedsLdmRetype) {
|
|
|
|
pRec->NeedsLdmRetype = FALSE;
|
|
pRegion->DynamicVolume = TRUE;
|
|
pRegion->DynamicVolumeSuitableForOS = TRUE;
|
|
|
|
}
|
|
|
|
SpUpdateDoubleSpaceIni();
|
|
|
|
//
|
|
// If the new disk geometry is different, the start sector and sector count
|
|
// of the newly created region wil be different from the old values.
|
|
//
|
|
if ((pRec->StartSector != pRegion->StartSector) ||
|
|
(pRec->SectorCount != pRegion->SectorCount)) {
|
|
|
|
pRec->StartSector = pRegion->StartSector;
|
|
pRec->SectorCount = pRegion->SectorCount;
|
|
}
|
|
|
|
DbgStatusMesg((_asrinfo, "Created %ws at sector %I64u for key [%ws], type 0x%x, region %p.\n",
|
|
pRec->IsPrimaryRecord ? L"primary partition" :
|
|
pRec->IsContainerRecord ? L"container partition" :
|
|
pRec->IsLogicalDiskRecord ? L"logical disk partition" : L"LDM Partition",
|
|
pRegion->StartSector,
|
|
pRec->CurrPartKey,
|
|
pRec->PartitionType,
|
|
pRegion
|
|
));
|
|
}
|
|
|
|
|
|
ULONGLONG
|
|
RoundUp(
|
|
IN ULONGLONG Number,
|
|
IN ULONG MultipleOf
|
|
)
|
|
{
|
|
if (Number % MultipleOf) {
|
|
return (Number + (ULONGLONG) MultipleOf - (Number % (ULONGLONG) MultipleOf));
|
|
|
|
}
|
|
else {
|
|
return Number;
|
|
}
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
SpAsrRecreateDiskPartitions(
|
|
IN ULONG Disk,
|
|
IN BOOLEAN SkipSpecialPartitions, // OEM partitions for amd64/x86, ESP for ia64
|
|
IN UCHAR MbrOemPartitionType
|
|
)
|
|
{
|
|
ULONGLONG oldStartSector = 0,
|
|
oldSectorCount = 0;
|
|
PSIF_PARTITION_RECORD pRec = NULL;
|
|
PSIF_PARTITION_RECORD_LIST pList = NULL;
|
|
|
|
SIF_PARTITION_RECORD_LIST logicalDiskList;
|
|
SIF_PARTITION_RECORD_LIST primaryPartList;
|
|
ULONG count = 0,
|
|
SectorsPerCylinder = 0;
|
|
|
|
BOOLEAN isAligned = TRUE;
|
|
BOOLEAN moveToNext = TRUE;
|
|
|
|
ZeroMemory(&logicalDiskList, sizeof(SIF_PARTITION_RECORD_LIST));
|
|
ZeroMemory(&primaryPartList, sizeof(SIF_PARTITION_RECORD_LIST));
|
|
|
|
SectorsPerCylinder = HardDisks[Disk].SectorsPerCylinder;
|
|
|
|
if (!Gbl_PartitionSetTable1[Disk]->pDiskRecord->PartitionList) {
|
|
//
|
|
// No partitions to recreate
|
|
//
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Split the partitions into two lists, one containing
|
|
// just the primary partitions, and the second containing
|
|
// the logical drives. The primary partition list will
|
|
// also include the container record if any.
|
|
//
|
|
// pList = SpAsrCopyPartitionRecordList(Gbl_PartitionSetTable1[Disk]->pDiskRecord->PartitionList);
|
|
|
|
pList = Gbl_PartitionSetTable1[Disk]->pDiskRecord->PartitionList;
|
|
ASSERT(pList);
|
|
|
|
isAligned = Gbl_PartitionSetTable1[Disk]->IsAligned;
|
|
|
|
pRec = SpAsrPopNextPartitionRecord(pList);
|
|
while (pRec) {
|
|
if (pRec->IsPrimaryRecord || pRec->IsContainerRecord) {
|
|
//
|
|
// Primary records go into the primaryPartList
|
|
//
|
|
if (SkipSpecialPartitions) {
|
|
if ((PARTITION_STYLE_MBR == pRec->PartitionStyle) &&
|
|
(MbrOemPartitionType == pRec->PartitionType)) {
|
|
//
|
|
// This is an OEM partition that already exists on the
|
|
// target machine. Discard this record.
|
|
//
|
|
SpMemFree(pRec);
|
|
pRec = NULL;
|
|
}
|
|
else if ((PARTITION_STYLE_GPT == pRec->PartitionStyle) &&
|
|
(RtlEqualMemory(&(pRec->PartitionTypeGuid), &PARTITION_SYSTEM_GUID, sizeof(GUID)))
|
|
) {
|
|
//
|
|
// This is the EFI System Partition, and it already
|
|
// exists on the taget machine. Discard this
|
|
// record.
|
|
//
|
|
SpMemFree(pRec);
|
|
pRec = NULL;
|
|
}
|
|
}
|
|
|
|
if (pRec) {
|
|
SpAsrInsertPartitionRecord(&primaryPartList, pRec);
|
|
}
|
|
}
|
|
else if (pRec->IsLogicalDiskRecord) {
|
|
//
|
|
// LogicalDiskRecords go into the logicalDisklist
|
|
//
|
|
SpAsrInsertPartitionRecord(&logicalDiskList, pRec);
|
|
}
|
|
else if (pRec->IsDescriptorRecord) {
|
|
//
|
|
// Discard the descriptor records
|
|
//
|
|
SpMemFree(pRec);
|
|
}
|
|
else {
|
|
ASSERT(0 && L"Partition record has incorrect flags set");
|
|
SpMemFree(pRec);
|
|
}
|
|
pRec = SpAsrPopNextPartitionRecord(pList);
|
|
}
|
|
|
|
//
|
|
// Recreate the primary partitions first.
|
|
//
|
|
pRec = SpAsrPopNextPartitionRecord(&primaryPartList);
|
|
while (pRec) {
|
|
//
|
|
// If it's the container partition, we need to make sure it's big
|
|
// enough to hold all the logical drives
|
|
//
|
|
if (pRec->IsContainerRecord) {
|
|
ULONGLONG sectorCount = 0;
|
|
PSIF_PARTITION_RECORD pLogicalDiskRec = NULL;
|
|
|
|
pLogicalDiskRec = logicalDiskList.First;
|
|
while (pLogicalDiskRec) {
|
|
sectorCount += RoundUp(pLogicalDiskRec->SectorCount, SectorsPerCylinder);
|
|
pLogicalDiskRec = pLogicalDiskRec->Next;
|
|
}
|
|
|
|
if (pRec->SectorCount < sectorCount) {
|
|
pRec->SectorCount = sectorCount;
|
|
}
|
|
|
|
}
|
|
|
|
oldStartSector = pRec->StartSector;
|
|
oldSectorCount = pRec->SectorCount;
|
|
|
|
count = SpPtnGetPartitionCountDisk(Disk) + SpPtnGetContainerPartitionCount(Disk);
|
|
SpAsrRecreatePartition(pRec, Disk, isAligned);
|
|
|
|
if ((pRec->StartSector != oldStartSector) ||
|
|
(pRec->SectorCount != oldSectorCount)) {
|
|
|
|
SpAsrUpdatePartitionRecord(
|
|
Disk,
|
|
pRec->StartSector,
|
|
oldStartSector,
|
|
pRec->SectorCount
|
|
);
|
|
}
|
|
|
|
SpMemFree(pRec);
|
|
|
|
if (SpPtnGetPartitionCountDisk(Disk) + SpPtnGetContainerPartitionCount(Disk) > (count + 1)) {
|
|
// moveToNext = FALSE;
|
|
// pRec = NULL;
|
|
|
|
ASSERT(0 && L"Partition count differs from expected value (stale data?)");
|
|
}
|
|
// else {
|
|
|
|
pRec = SpAsrPopNextPartitionRecord(&primaryPartList);
|
|
// }
|
|
}
|
|
|
|
if (moveToNext) {
|
|
//
|
|
// Recreate the logical drives next
|
|
//
|
|
pRec = SpAsrPopNextPartitionRecord(&logicalDiskList);
|
|
while (pRec) {
|
|
|
|
oldStartSector = pRec->StartSector;
|
|
oldSectorCount = pRec->SectorCount;
|
|
|
|
count = SpPtnGetPartitionCountDisk(Disk);
|
|
SpAsrRecreatePartition(pRec, Disk, isAligned);
|
|
|
|
if ((pRec->StartSector != oldStartSector) ||
|
|
(pRec->SectorCount != oldSectorCount)) {
|
|
|
|
SpAsrUpdatePartitionRecord(
|
|
Disk,
|
|
pRec->StartSector,
|
|
oldStartSector,
|
|
pRec->SectorCount
|
|
);
|
|
}
|
|
|
|
|
|
SpMemFree(pRec);
|
|
|
|
if (SpPtnGetPartitionCountDisk(Disk) > (count + 1)) {
|
|
// moveToNext = FALSE;
|
|
// pRec = NULL;
|
|
|
|
ASSERT(0 && L".. Partition count differs from expected value .. (stale data?)");
|
|
|
|
}
|
|
// else {
|
|
pRec = SpAsrPopNextPartitionRecord(&logicalDiskList);
|
|
// }
|
|
}
|
|
}
|
|
|
|
return moveToNext;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
SpAsrAttemptRepair(
|
|
IN PVOID SifHandle,
|
|
IN PWSTR Local_SetupSourceDevicePath,
|
|
IN PWSTR Local_DirectoryOnSetupSource,
|
|
IN PWSTR AutoSourceDevicePath,
|
|
IN PWSTR AutoDirectoryOnSetupSource
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This routine attempts to replace any missing or corrupted system files with
|
|
their counterparts from an installation source (CDROM, Harddisk, etc). If
|
|
successful, a full-scale installation is not required and the recovery can
|
|
proceed much faster.
|
|
|
|
To accomplish this, AsrAttemptRepair() employs the following logic:
|
|
|
|
* If \Device\floppy0\setup.log cannot be opened, then repair can
|
|
not proceed and a full-scale install must be performed. Otherwise, the
|
|
repair is begun.
|
|
|
|
* The first step in the repair is to verify that the directories
|
|
forming the NT tree are present and accessible. If any of these
|
|
directories are missing or inaccessible, they are recreated and made
|
|
accessible.
|
|
|
|
* The second step is to copy any missing or corrupted files from
|
|
installation source. To accomplish this, SppRepairWinntFiles() is
|
|
called. This function checks whether each file enumerated in the
|
|
setup.log file is present on the disk AND that its checksum matches
|
|
that specified in setup.log. If either of these two conditions are
|
|
not met, a new version of the file is copied from the installation
|
|
source (e.g., the CDROM) to the disk.
|
|
|
|
|
|
Arguments:
|
|
SifHandle Handle to txtsetup.inf
|
|
|
|
SetupSourceDevicePath The physical device path of the media containing the
|
|
installation files.
|
|
|
|
DirectoryOnSetupSource The name of the directory on the source media (see
|
|
previous parameter) containing the installation files.
|
|
|
|
|
|
Returns:
|
|
TRUE if the attempted repair operation is successful.
|
|
FALSE if the setup.log file was not opened (ie it wasn't present
|
|
on the ASR/ER floppy), or the system or boot partitions were NULL
|
|
|
|
--*/
|
|
{
|
|
if (!(Gbl_HandleToSetupLog &&
|
|
Gbl_SystemPartitionRegion &&
|
|
Gbl_BootPartitionRegion)) {
|
|
return FALSE;
|
|
}
|
|
|
|
// run autochk on boot and system partitions
|
|
DbgStatusMesg((_asrinfo,
|
|
"AttemptRepair. Running AutoChk on boot and sys ptns\n"
|
|
));
|
|
|
|
SpRunAutochkOnNtAndSystemPartitions(
|
|
SifHandle,
|
|
Gbl_BootPartitionRegion,
|
|
Gbl_SystemPartitionRegion,
|
|
Local_SetupSourceDevicePath,
|
|
Local_DirectoryOnSetupSource,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// Verify and repair security of the directories that form the NT tree
|
|
// using the information obtained from the setup.log file.
|
|
//
|
|
DbgStatusMesg((_asrinfo,
|
|
"AttemptRepair. Verifying and repairing directory structure\n"
|
|
));
|
|
|
|
SppVerifyAndRepairNtTreeAccess(SifHandle,
|
|
Gbl_BootPartitionName,
|
|
Gbl_BootPartitionDirectory,
|
|
Gbl_SystemPartitionName,
|
|
Gbl_SystemPartitionDirectory
|
|
);
|
|
|
|
// initialize the diamond compression engine.
|
|
SpdInitialize();
|
|
|
|
//
|
|
// At this point, we are safe in assuming that the partition and directory
|
|
// structures required to recover the system are still intact. That being
|
|
// the case, replace the files whose state is preventing the system from
|
|
// booting.
|
|
//
|
|
if (RepairItems[RepairFiles]) {
|
|
|
|
//
|
|
// initialize PID only in case of normal ASR
|
|
//
|
|
if ((ASRMODE_NORMAL == SpAsrGetAsrMode()) && !RepairWinnt) {
|
|
SpInitializePidString(SifHandle,
|
|
Local_SetupSourceDevicePath,
|
|
Local_DirectoryOnSetupSource
|
|
);
|
|
}
|
|
|
|
SppRepairWinntFiles(Gbl_HandleToSetupLog,
|
|
SifHandle,
|
|
Local_SetupSourceDevicePath,
|
|
Local_DirectoryOnSetupSource,
|
|
Gbl_SystemPartitionName,
|
|
Gbl_SystemPartitionDirectory,
|
|
Gbl_BootPartitionName,
|
|
Gbl_BootPartitionDirectory
|
|
);
|
|
|
|
SppRepairStartMenuGroupsAndItems(Gbl_BootPartitionName, Gbl_BootPartitionDirectory);
|
|
}
|
|
|
|
//
|
|
// Repair the hives. This action is only available if the Fast Repair
|
|
// option was chosen.
|
|
//
|
|
if (Gbl_RepairWinntFast) {
|
|
|
|
PWSTR directoryOnHiveRepairSource = NULL;
|
|
BOOLEAN tmpRepairFromErDisk = Gbl_RepairFromErDisk;
|
|
|
|
//
|
|
// Create the complete hive repair path
|
|
//
|
|
wcscpy(TemporaryBuffer, Gbl_BootPartitionDirectory);
|
|
SpConcatenatePaths(TemporaryBuffer, SETUP_REPAIR_DIRECTORY);
|
|
directoryOnHiveRepairSource = SpDupStringW(TemporaryBuffer);
|
|
Gbl_RepairFromErDisk = FALSE;
|
|
|
|
SppRepairHives(SifHandle,
|
|
Gbl_BootPartitionName,
|
|
Gbl_BootPartitionDirectory,
|
|
Gbl_BootPartitionName,
|
|
directoryOnHiveRepairSource
|
|
);
|
|
|
|
SpMemFree(directoryOnHiveRepairSource);
|
|
Gbl_RepairFromErDisk = tmpRepairFromErDisk;
|
|
}
|
|
|
|
SpdTerminate();
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
SpDoRepair(
|
|
IN PVOID SifHandle,
|
|
IN PWSTR SetupSourceDevicePath,
|
|
IN PWSTR DirectoryOnSetupSource,
|
|
IN PWSTR AutoSourceDevicePath,
|
|
IN PWSTR AutoDirectoryOnSetupSource,
|
|
IN PWSTR RepairPath,
|
|
IN PULONG RepairOptions
|
|
)
|
|
{
|
|
|
|
ULONG count = 0;
|
|
ASRMODE prevMode = ASRMODE_NONE;
|
|
BOOLEAN returnValue = FALSE;
|
|
|
|
for (count = 0; count < RepairItemMax; count++) {
|
|
RepairItems[count] = RepairOptions[count];
|
|
}
|
|
|
|
prevMode = SpAsrSetAsrMode(TRUE);
|
|
Gbl_SourceSetupLogFileName = RepairPath;
|
|
SpAsrProcessSetupLogFile(Gbl_SourceSetupLogFileName, FALSE);
|
|
|
|
returnValue = SpAsrAttemptRepair(SifHandle,
|
|
SetupSourceDevicePath,
|
|
DirectoryOnSetupSource,
|
|
AutoSourceDevicePath,
|
|
AutoDirectoryOnSetupSource
|
|
);
|
|
|
|
SpAsrSetAsrMode(prevMode);
|
|
return returnValue;
|
|
}
|
|
|
|
|
|
VOID
|
|
SpAsrRepairOrDRMenu(VOID)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Display a screen allowing the user to choose among the repair
|
|
options: Recovery Console, Conventional Repair, ASR or Exit.
|
|
|
|
Arguments:
|
|
None.
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
Side Effects:
|
|
Sets the following global flags to indicate user's selection:
|
|
ForceConsole set to TRUE if user wants Recovery Console
|
|
RepairWinnt set to TRUE if user wants Conventional Repair
|
|
SpAsrSetAsrMode(ASRMODE_NORMAL) if user wants Conventional Repair or ASR
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG repairKeys[] = {KEY_F3, KEY_F10, 0};
|
|
ULONG mnemonicKeys[] = {MnemonicConsole, MnemonicRepair, 0};
|
|
BOOLEAN done = TRUE;
|
|
ULONG UserOption;
|
|
|
|
do {
|
|
done = TRUE;
|
|
|
|
if (SpIsERDisabled()) {
|
|
UserOption = (MnemonicConsole | KEY_MNEMONIC); // only Command console
|
|
} else {
|
|
// display the choice screen for the user.
|
|
SpDisplayScreen(SP_SCRN_DR_OR_REPAIR,3,4);
|
|
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
|
|
SP_STAT_C_EQUALS_CMDCONS,
|
|
SP_STAT_R_EQUALS_REPAIR,
|
|
SP_STAT_F3_EQUALS_EXIT,
|
|
0
|
|
);
|
|
|
|
// wait for keypress. Valid keys:
|
|
// F3 = exit
|
|
// F10,C = Recovery Console
|
|
// R = Repair Winnt
|
|
// A = Automated System Recovery (ASR)
|
|
SpInputDrain();
|
|
UserOption = SpWaitValidKey(repairKeys,NULL,mnemonicKeys);
|
|
}
|
|
|
|
switch(UserOption) {
|
|
case KEY_F3:
|
|
// User wants to exit.
|
|
SpConfirmExit();
|
|
done = FALSE;
|
|
break;
|
|
|
|
case KEY_F10:
|
|
case (MnemonicConsole | KEY_MNEMONIC):
|
|
// User wants the recovery console.
|
|
ForceConsole = TRUE;
|
|
SpAsrSetAsrMode(ASRMODE_NONE);
|
|
RepairWinnt = FALSE;
|
|
break;
|
|
|
|
case (MnemonicRepair | KEY_MNEMONIC):
|
|
// User wants conventional repair.
|
|
SpAsrSetAsrMode(ASRMODE_NORMAL);
|
|
RepairWinnt = TRUE;
|
|
break;
|
|
|
|
default:
|
|
// User doesn't want any of our choices. Show him the same screen again.
|
|
done = FALSE;
|
|
break;
|
|
|
|
}
|
|
} while (!done);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
SpAsrRepairManualOrFastMenu(VOID)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Display a screen allowing the user to choose between Manual and Fast
|
|
Repair modes. Manual--user will select options on next screen,
|
|
Fast--defaults are used
|
|
|
|
Arguments:
|
|
None.
|
|
|
|
Return Value:
|
|
TRUE if the user selected a repair mode
|
|
FALSE if the user hit <ESC> to cancel
|
|
|
|
Side Effect:
|
|
Gbl_RepairWinntFast is set to TRUE if user selects Fast Repair, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
ULONG repairKeys[] = {KEY_F3, ASCI_ESC, 0};
|
|
ULONG mnemonicKeys[] = {MnemonicFastRepair, MnemonicManualRepair, 0};
|
|
BOOLEAN done;
|
|
|
|
do {
|
|
done = TRUE;
|
|
|
|
//
|
|
// Display the choice screen for the user.
|
|
//
|
|
SpDisplayScreen(SP_SCRN_REPAIR_MANUAL_OR_FAST,3,4);
|
|
SpDisplayStatusOptions(
|
|
DEFAULT_STATUS_ATTRIBUTE,
|
|
SP_STAT_M_EQUALS_REPAIR_MANUAL,
|
|
SP_STAT_F_EQUALS_REPAIR_FAST,
|
|
SP_STAT_ESC_EQUALS_CANCEL,
|
|
SP_STAT_F3_EQUALS_EXIT,
|
|
0
|
|
);
|
|
|
|
//
|
|
// wait for keypress. Valid keys:
|
|
// F3 = exit
|
|
// ESC = cancel
|
|
// M = Manual Repair
|
|
// F = Fast Repair
|
|
//
|
|
SpInputDrain();
|
|
switch(SpWaitValidKey(repairKeys,NULL,mnemonicKeys)) {
|
|
case KEY_F3:
|
|
// User wants to exit.
|
|
SpConfirmExit();
|
|
break;
|
|
|
|
case (MnemonicManualRepair | KEY_MNEMONIC):
|
|
// User wants manual repair, i.e., choose from the list.
|
|
Gbl_RepairWinntFast = FALSE;
|
|
break;
|
|
|
|
case (MnemonicFastRepair | KEY_MNEMONIC):
|
|
// User wants fast repair, i.e., don't show the list.
|
|
Gbl_RepairWinntFast = TRUE;
|
|
break;
|
|
|
|
case ASCI_ESC:
|
|
// User wants to cancel
|
|
return FALSE;
|
|
|
|
default:
|
|
// User doesn't want any of our choices
|
|
done = FALSE;
|
|
break;
|
|
|
|
}
|
|
} while (!done);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// Returns true if this physical disk is to be skipped while
|
|
// repartitioning all the disks. (i.e., this disk is intact,
|
|
// or is removable, etc)
|
|
//
|
|
BOOLEAN
|
|
SpAsrpSkipDiskRepartition(
|
|
IN DWORD DiskIndex,
|
|
IN BOOLEAN SkipNonCritical // should we skip non-critical disks?
|
|
)
|
|
{
|
|
//
|
|
// Skip removable disks. They are not counted in the
|
|
// partition set table, hence their entry is NULL.
|
|
//
|
|
if (NULL == Gbl_PartitionSetTable1[DiskIndex]) {
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Skip disks for which no disk record exists in asr.sif
|
|
//
|
|
if (NULL == Gbl_PartitionSetTable1[DiskIndex]->pDiskRecord) {
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Skip disks for which a disk record may exist but no
|
|
// partition records reference that disk record.
|
|
//
|
|
if (NULL == Gbl_PartitionSetTable1[DiskIndex]->pDiskRecord->PartitionList) {
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Skip non-critical disks if told to.
|
|
//
|
|
if ((SkipNonCritical) && (FALSE == Gbl_PartitionSetTable1[DiskIndex]->pDiskRecord->IsCritical)) {
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Skip disks that are intact
|
|
//
|
|
if (Gbl_PartitionSetTable1[DiskIndex]->PartitionsIntact) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
VOID
|
|
SpAsrClobberDiskWarning(VOID)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Display a screen warning the user that when a partition on a disk is
|
|
to be recreated, *all* partitions on that disk are clobbered, and
|
|
allowing the user to abort.
|
|
|
|
Arguments:
|
|
None.
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ULONG validKeys[] = {KEY_F3, 0};
|
|
ULONG mnemonicKeys[] = {MnemonicContinueSetup, 0};
|
|
BOOLEAN done = FALSE,
|
|
skip = FALSE;
|
|
DWORD diskIndex = 0;
|
|
ULONG Keypress = 0;
|
|
PVOID Menu;
|
|
ULONG MenuTopY;
|
|
|
|
//
|
|
// Dummy variables for user selection data, we don't use these
|
|
//
|
|
ULONG_PTR FirstData = 0,
|
|
ReturnedData = 0;
|
|
|
|
|
|
if ((ASRMODE_NORMAL != SpAsrGetAsrMode()) || SpAsrGetSilentRepartitionFlag(ASR_SIF_SYSTEM_KEY)) {
|
|
//
|
|
// Automated tests; don't display warning menu
|
|
//
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// Display the "your disks will be repartitioned" warning message
|
|
//
|
|
SpDisplayScreen(SP_SCRN_DR_DISK_REFORMAT_WARNING,3,CLIENT_TOP+1);
|
|
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
|
|
SP_STAT_C_EQUALS_CONTINUE_SETUP,
|
|
SP_STAT_F3_EQUALS_EXIT,
|
|
0
|
|
);
|
|
|
|
//
|
|
// And generate the list of disks that will be repartitioned.
|
|
// Calculate menu placement. Leave one blank line and one
|
|
// line for a frame.
|
|
//
|
|
MenuTopY = NextMessageTopLine + 2;
|
|
|
|
//
|
|
// Create a menu.
|
|
//
|
|
Menu = SpMnCreate(3, MenuTopY, (VideoVars.ScreenWidth-6),
|
|
(VideoVars.ScreenHeight - MenuTopY -
|
|
(SplangQueryMinimizeExtraSpacing() ? 1 : 2) - STATUS_HEIGHT)
|
|
);
|
|
if (!Menu) {
|
|
SpAsrRaiseFatalError(SP_SCRN_OUT_OF_MEMORY, L"SpMnCreate failed");
|
|
}
|
|
|
|
for (diskIndex = 0; diskIndex < HardDiskCount; diskIndex++) {
|
|
|
|
skip = SpAsrpSkipDiskRepartition(diskIndex, FALSE);
|
|
|
|
if (!skip) {
|
|
PHARD_DISK Disk = SPPT_GET_HARDDISK(diskIndex);
|
|
|
|
if (!FirstData) {
|
|
FirstData = (ULONG_PTR)Disk;
|
|
}
|
|
|
|
if (!SpMnAddItem(Menu, Disk->Description, 3, (VideoVars.ScreenWidth-6), TRUE, (ULONG_PTR)Disk)) {
|
|
SpAsrRaiseFatalError(SP_SCRN_OUT_OF_MEMORY, L"SpMnAddItem failed");
|
|
}
|
|
}
|
|
}
|
|
|
|
SpInputDrain();
|
|
|
|
do {
|
|
|
|
//
|
|
// wait for keypress. Valid keys:
|
|
// C = continue
|
|
// F3 = exit
|
|
//
|
|
SpMnDisplay(Menu,
|
|
FirstData,
|
|
TRUE,
|
|
validKeys,
|
|
mnemonicKeys,
|
|
NULL, // no new highlight callback
|
|
NULL, // no selection callback
|
|
&Keypress,
|
|
&ReturnedData
|
|
);
|
|
|
|
|
|
switch(Keypress) {
|
|
case KEY_F3:
|
|
//
|
|
// User wants to exit--confirm.
|
|
//
|
|
SpConfirmExit();
|
|
break;
|
|
|
|
case (MnemonicContinueSetup | KEY_MNEMONIC):
|
|
//
|
|
// User wants to continue with Setup
|
|
//
|
|
done = TRUE;
|
|
break;
|
|
}
|
|
} while (!done);
|
|
|
|
SpMnDestroy(Menu);
|
|
}
|
|
|
|
|
|
VOID
|
|
SpAsrCannotDoER(VOID)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Display a screen informing the user that ER canot be performed on
|
|
the system because the boot partition in not intact, i.e., ASR
|
|
recreated/reformatted that partition.
|
|
|
|
Arguments:
|
|
None.
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ULONG warningKeys[] = { KEY_F3, 0 };
|
|
ULONG mnemonicKeys[] = { 0 };
|
|
|
|
// display the message screen
|
|
SpDisplayScreen(SP_SCRN_DR_CANNOT_DO_ER,3,4);
|
|
SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
|
|
SP_STAT_F3_EQUALS_EXIT,
|
|
0
|
|
);
|
|
|
|
// wait for keypress. Valid key:
|
|
// F3 = exit
|
|
SpInputDrain();
|
|
do {
|
|
switch(SpWaitValidKey(warningKeys,NULL,mnemonicKeys)) {
|
|
case KEY_F3:
|
|
// User wants to exit.
|
|
return;
|
|
}
|
|
} while (TRUE);
|
|
}
|
|
|
|
|
|
VOID
|
|
SpAsrQueryRepairOrDr()
|
|
/*++
|
|
|
|
-pending code description
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN done = TRUE;
|
|
|
|
do {
|
|
done = TRUE;
|
|
|
|
// ask the user if he wants repair or ASR
|
|
SpAsrRepairOrDRMenu();
|
|
|
|
if (RepairWinnt) {
|
|
// User wants to repair, check Manual or Fast
|
|
if (done = SpAsrRepairManualOrFastMenu()) {
|
|
if (Gbl_RepairWinntFast) { // Fast Repair
|
|
RepairItems[RepairNvram] = 1;
|
|
RepairItems[RepairFiles] = 1;
|
|
#if defined(_AMD64_) || defined(_X86_)
|
|
RepairItems[RepairBootSect] = 1;
|
|
#endif // defined(_AMD64_) || defined(_X86_)
|
|
}
|
|
else { // Manual Repair
|
|
done = SpDisplayRepairMenu();
|
|
}
|
|
}
|
|
}
|
|
} while (!done);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
SpAsrOpenAsrStateFile(ULONG *ErrorLine, PWSTR AsrSifPath)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
ASSERT(ErrorLine);
|
|
*ErrorLine = 0;
|
|
|
|
// load asr.sif
|
|
status = SpLoadSetupTextFile(
|
|
AsrSifPath,
|
|
NULL,
|
|
0,
|
|
&Gbl_HandleToDrStateFile,
|
|
ErrorLine,
|
|
TRUE,
|
|
FALSE
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
DbgErrorMesg((_asrerr, "SpAsrOpenAsrStateFile. Unable to open %ws. status:0x%x ErrorLine:%lu\n",
|
|
AsrSifPath,
|
|
status,
|
|
*ErrorLine));
|
|
|
|
Gbl_HandleToDrStateFile = NULL;
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
SpAsrLoadAsrDiskette(VOID)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This routine checks for a floppy drive. If one is not found, this routine
|
|
never returns, Setup terminates with an error. If a floppy drive is found,
|
|
this routine prompts for the ASR disk. If the disk is loaded, it reads and
|
|
parses the asr.sif file.
|
|
|
|
Arguments:
|
|
None.
|
|
|
|
Return Values:
|
|
TRUE if disk was loaded successfully
|
|
DOES NOT RETURN if no floppy drive was found, or if asr.sif is corrupt.
|
|
|
|
--*/
|
|
{
|
|
ULONG errorAtLine = 0,
|
|
diskIndex = 0;
|
|
|
|
PWSTR diskName = NULL;
|
|
PWSTR diskDeviceName = NULL;
|
|
PWSTR localAsrSifPath = NULL;
|
|
|
|
BOOLEAN result = FALSE;
|
|
|
|
if (!RemoteBootSetup) {
|
|
//
|
|
// Look for the asr.sif in the boot directory. If it isn't present
|
|
// in the boot directory, we'll look for it on the floppy drive.
|
|
//
|
|
localAsrSifPath = SpMemAlloc((wcslen(NtBootDevicePath)+wcslen(ASR_SIF_NAME)+2) * sizeof(WCHAR));
|
|
|
|
if (localAsrSifPath) {
|
|
localAsrSifPath[0] = UNICODE_NULL;
|
|
wcscpy(localAsrSifPath,NtBootDevicePath);
|
|
SpConcatenatePaths(localAsrSifPath,ASR_SIF_NAME);
|
|
|
|
result = SpAsrOpenAsrStateFile(&errorAtLine, localAsrSifPath);
|
|
Gbl_AsrSifOnInstallationMedia = result;
|
|
|
|
SpMemFree(localAsrSifPath);
|
|
localAsrSifPath = NULL;
|
|
}
|
|
|
|
if (!result) {
|
|
//
|
|
// Check if the machine has a floppy drive. This is kind of redundant,
|
|
// since he couldn't have got this far if there isn't a floppy drive.
|
|
// However, we've had cases where setupldr recognises the floppy drive,
|
|
// but we then loose the floppy by the time we get here.
|
|
//
|
|
if (SpGetFloppyDriveType(0) == FloppyTypeNone) {
|
|
SpAsrRaiseFatalError(
|
|
SP_TEXT_DR_NO_FLOPPY_DRIVE,
|
|
L"Floppy drive does not exist"
|
|
);
|
|
// does not return
|
|
}
|
|
|
|
SpFormatMessage(TemporaryBuffer, sizeof(TemporaryBuffer), SP_TEXT_DR_DISK_NAME);
|
|
diskName = SpDupStringW(TemporaryBuffer);
|
|
diskDeviceName = SpDupStringW(ASR_FLOPPY0_DEVICE_PATH);
|
|
|
|
//
|
|
// Prompt for the disk. We don't allow him to hit ESC to cancel,
|
|
// since he can't quit out of ASR at this point.
|
|
//
|
|
SpPromptForDisk(
|
|
diskName,
|
|
diskDeviceName,
|
|
ASR_SIF_NAME,
|
|
FALSE, // no ignore disk in drive
|
|
FALSE, // no allow escape
|
|
FALSE, // no warn multiple prompts
|
|
NULL // don't care about redraw flag
|
|
);
|
|
|
|
DbgStatusMesg((_asrinfo,
|
|
"SpAsrLoadAsrDiskette. Disk [%ws] loaded successfully on %ws\n",
|
|
diskName, diskDeviceName
|
|
));
|
|
|
|
SpMemFree(diskName);
|
|
SpMemFree(diskDeviceName);
|
|
|
|
//
|
|
// Open asr.sif from the floppy. If we can't read it, it's a fatal
|
|
// error.
|
|
//
|
|
result = SpAsrOpenAsrStateFile(&errorAtLine, ASR_SIF_PATH);
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// open the file from the remote location
|
|
//
|
|
RemoteBootAsrSifName = SpGetSectionKeyIndex(
|
|
WinntSifHandle,
|
|
L"OSChooser",
|
|
L"ASRINFFile",
|
|
0);
|
|
|
|
if (!RemoteBootAsrSifName) {
|
|
SpAsrRaiseFatalError(
|
|
SP_TEXT_DR_NO_ASRSIF_RIS,
|
|
L"Couldn't get ASRINFFile from winnt.sif in RIS case"
|
|
);
|
|
// does not return
|
|
}
|
|
|
|
result = SpAsrOpenAsrStateFile(&errorAtLine, RemoteBootAsrSifName);
|
|
}
|
|
|
|
if (!result) {
|
|
|
|
swprintf(TemporaryBuffer, L"Failed to load/parse asr.sif at line %lu\n",
|
|
errorAtLine);
|
|
|
|
if (errorAtLine > 0) {
|
|
SpAsrRaiseFatalErrorLu(SP_TEXT_DR_STATEFILE_BAD_LINE,
|
|
TemporaryBuffer,
|
|
errorAtLine
|
|
);
|
|
}
|
|
else {
|
|
SpAsrRaiseFatalError(SP_TEXT_DR_STATEFILE_ERROR, TemporaryBuffer);
|
|
}
|
|
// does not return
|
|
}
|
|
|
|
//
|
|
// Set Gbl_FixedDiskCount
|
|
//
|
|
for (diskIndex = 0; diskIndex < HardDiskCount; diskIndex++) {
|
|
Gbl_FixedDiskCount += DISK_IS_REMOVABLE(diskIndex) ? 0 : 1;
|
|
}
|
|
|
|
AutoPartitionPicker = FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
SpAsrLoadErDiskette(VOID)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This routine checks for a floppy drive, and prompts for the ER
|
|
Diskette if a drive is found. If a floppy drive is not found,
|
|
this routine never returns, Setup terminates with an error.
|
|
|
|
Arguments:
|
|
None.
|
|
|
|
Return Values:
|
|
TRUE if disk was loaded successfully
|
|
FALSE otherwise (user hit cancel, or there was no floppy drive present)
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN diskLoaded = FALSE;
|
|
PWSTR diskName = NULL,
|
|
diskDeviceName = NULL;
|
|
|
|
// check if an A: drive exists.
|
|
if (SpGetFloppyDriveType(0) == FloppyTypeNone) {
|
|
SpAsrRaiseFatalError(
|
|
SP_TEXT_DR_NO_FLOPPY_DRIVE,
|
|
L"Floppy drive does not exist"
|
|
);
|
|
// does not return
|
|
}
|
|
|
|
SpFormatMessage(TemporaryBuffer, sizeof(TemporaryBuffer),
|
|
SP_TEXT_REPAIR_OR_DR_DISK_NAME);
|
|
diskName = SpDupStringW(TemporaryBuffer);
|
|
diskDeviceName = SpDupStringW(ASR_FLOPPY0_DEVICE_PATH);
|
|
|
|
// prompt for the disk.
|
|
diskLoaded = SpPromptForDisk(
|
|
diskName,
|
|
diskDeviceName,
|
|
ASR_SETUP_LOG_NAME,
|
|
TRUE,
|
|
TRUE,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
|
|
DbgStatusMesg((_asrinfo, "SpAsrLoadErDiskette. ER disk [%ws] %s loaded successfully on %s\n",
|
|
diskName, diskLoaded?"":"NOT", diskDeviceName));
|
|
|
|
SpMemFree(diskName);
|
|
SpMemFree(diskDeviceName);
|
|
|
|
return diskLoaded;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
SpAsrGetErFromHardDrive(
|
|
IN PVOID MasterSifHandle,
|
|
OUT PVOID *RepairSifHandle,
|
|
OUT PWSTR *FullLogFileName
|
|
)
|
|
/*++
|
|
|
|
-pending code description
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOLEAN foundRepairableSystem = FALSE,
|
|
result = FALSE;
|
|
|
|
DbgStatusMesg((_asrinfo, "SpAsrGetErFromHardDrive. ER: Attempting to load ER data from Hard drive"));
|
|
|
|
//
|
|
// If user has no emergency repair diskette, we need to find out
|
|
// if there is any NT to repair and which one to repair.
|
|
//
|
|
result = SpFindNtToRepair(MasterSifHandle,
|
|
&Gbl_BootPartitionRegion,
|
|
&Gbl_BootPartitionDirectory,
|
|
&Gbl_SystemPartitionRegion,
|
|
&Gbl_SystemPartitionDirectory,
|
|
&foundRepairableSystem
|
|
);
|
|
|
|
if (result) {
|
|
|
|
//
|
|
// Repairable systems were found, and the user selected one to repair
|
|
//
|
|
|
|
//
|
|
// Get the device path of the system and boot partitions.
|
|
//
|
|
SpNtNameFromRegion(Gbl_SystemPartitionRegion,
|
|
TemporaryBuffer,
|
|
sizeof(TemporaryBuffer),
|
|
PartitionOrdinalCurrent
|
|
);
|
|
Gbl_SystemPartitionName = SpDupStringW(TemporaryBuffer);
|
|
|
|
SpNtNameFromRegion(Gbl_BootPartitionRegion,
|
|
TemporaryBuffer,
|
|
sizeof(TemporaryBuffer),
|
|
PartitionOrdinalCurrent
|
|
);
|
|
Gbl_BootPartitionName = SpDupStringW(TemporaryBuffer);
|
|
|
|
//
|
|
// Form the full NT path of the setup.log file in the chosen
|
|
// system on the hard drive.
|
|
//
|
|
SpConcatenatePaths(TemporaryBuffer, Gbl_BootPartitionDirectory);
|
|
SpConcatenatePaths(TemporaryBuffer, SETUP_REPAIR_DIRECTORY);
|
|
SpConcatenatePaths(TemporaryBuffer, SETUP_LOG_FILENAME);
|
|
*FullLogFileName = SpDupStringW(TemporaryBuffer);
|
|
|
|
DbgStatusMesg((_asrinfo,
|
|
"ER: User picked system to repair. boot-ptn:[%ws] sys-ptn:[%ws] log-file:[%ws]\n",
|
|
Gbl_BootPartitionName,
|
|
Gbl_SystemPartitionName,
|
|
*FullLogFileName
|
|
));
|
|
|
|
//
|
|
// Read and process the setup.log file.
|
|
//
|
|
result = SpLoadRepairLogFile(*FullLogFileName, RepairSifHandle);
|
|
if (!result) {
|
|
//
|
|
// Load setup.log failed. Ask user to insert a ER diskette again.
|
|
//
|
|
DbgErrorMesg((_asrwarn,
|
|
"ER: Attempt to load log file [%ws] FAILED\n",
|
|
*FullLogFileName
|
|
));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Setup file was read. Will return TRUE
|
|
//
|
|
Gbl_RepairFromErDisk = FALSE;
|
|
}
|
|
else {
|
|
//
|
|
// User did not select a system to repair
|
|
//
|
|
|
|
if (foundRepairableSystem) {
|
|
//
|
|
// Setup found a WINNT installation, but no installation was
|
|
// chosen by the user. We will go back to ask for the ER
|
|
// diskette again.
|
|
//
|
|
DbgErrorMesg((_asrwarn, "ER: Repairable systems were found, but user did not select any\n"));
|
|
return FALSE;
|
|
}
|
|
else {
|
|
//
|
|
// Couldn't find any NT to repair
|
|
//
|
|
ULONG validKeys[] = {KEY_F3, ASCI_CR, 0};
|
|
ULONG mnemonicKeys[] = {MnemonicCustom, 0};
|
|
|
|
DbgErrorMesg((_asrwarn, "ER: No repairable systems were found\n"));
|
|
|
|
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
|
|
);
|
|
|
|
SpInputDrain();
|
|
|
|
switch (SpWaitValidKey(validKeys,NULL,NULL)) {
|
|
case KEY_F3:
|
|
//
|
|
// User wants to exit Setup
|
|
//
|
|
SpDone(0,TRUE,TRUE);
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
SpAsrGetErDiskette(IN PVOID SifHandle)
|
|
/*++
|
|
|
|
-pending code description
|
|
|
|
--*/
|
|
{
|
|
PWSTR fullLogFileName = NULL;
|
|
BOOLEAN done = FALSE,
|
|
hasErDisk = FALSE;
|
|
|
|
while (!done) {
|
|
//
|
|
// display message to let user know he can either provide his
|
|
// own ER disk or let setup search for him.
|
|
//
|
|
if (!SpErDiskScreen(&hasErDisk)) {
|
|
return FALSE;
|
|
}
|
|
|
|
Gbl_HandleToSetupLog = NULL;
|
|
fullLogFileName = NULL;
|
|
|
|
if (hasErDisk) {
|
|
//
|
|
// Ask for emergency repair diskette until either we get it or
|
|
// user cancels the request.
|
|
//
|
|
done = SpAsrLoadErDiskette();
|
|
if (done) {
|
|
Gbl_SourceSetupLogFileName = ASR_DEFAULT_SETUP_LOG_PATH;
|
|
done = SpAsrProcessSetupLogFile(Gbl_SourceSetupLogFileName, TRUE);
|
|
}
|
|
}
|
|
else {
|
|
done = SpAsrGetErFromHardDrive(SifHandle, &Gbl_HandleToSetupLog, &fullLogFileName);
|
|
|
|
if (fullLogFileName) {
|
|
Gbl_SourceSetupLogFileName = SpDupStringW(fullLogFileName);
|
|
SpMemFree(fullLogFileName);
|
|
}
|
|
}
|
|
}
|
|
|
|
DbgStatusMesg((_asrinfo, "SpAsrGetErDiskette. ER: %s Floppy. Using setup log file [%ws]\n",
|
|
hasErDisk?"Using":"NO", (Gbl_SourceSetupLogFileName ? Gbl_SourceSetupLogFileName : L"")));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
PSIF_PARTITION_RECORD
|
|
SpAsrGetBootPartitionRecord(VOID)
|
|
{
|
|
ULONG diskIndex = 0;
|
|
PSIF_PARTITION_RECORD pRecord = NULL;
|
|
|
|
if (Gbl_BootPartitionRecord) {
|
|
return Gbl_BootPartitionRecord;
|
|
}
|
|
|
|
for (diskIndex = 0; diskIndex < HardDiskCount; diskIndex++) {
|
|
//
|
|
// Find NT partition record from the partition set table.
|
|
//
|
|
if (Gbl_PartitionSetTable2[diskIndex] == NULL ||
|
|
Gbl_PartitionSetTable2[diskIndex]->pDiskRecord == NULL ||
|
|
Gbl_PartitionSetTable2[diskIndex]->pDiskRecord->PartitionList == NULL) {
|
|
continue;
|
|
}
|
|
|
|
DbgStatusMesg((_asrinfo, "Disk %lu ptn records: ", diskIndex));
|
|
pRecord = Gbl_PartitionSetTable2[diskIndex]->pDiskRecord->PartitionList->First;
|
|
|
|
while (pRecord) {
|
|
|
|
DbgMesg((_asrinfo, "[%ws]", pRecord->CurrPartKey));
|
|
|
|
if (SpAsrIsBootPartitionRecord(pRecord->PartitionFlag)) {
|
|
ASSERT((pRecord->NtDirectoryName) && L"Boot partition is missing NT directory name.");
|
|
return pRecord;
|
|
}
|
|
|
|
pRecord = pRecord->Next;
|
|
}
|
|
|
|
DbgMesg((_asrinfo, "\n"));
|
|
}
|
|
|
|
DbgFatalMesg((_asrerr, "SpAsrGetBootPartitionRecord. No boot partition record was found.\n"));
|
|
SpAsrRaiseFatalErrorWs(
|
|
SP_SCRN_DR_SIF_BAD_RECORD,
|
|
L"No boot partition found in asr.sif",
|
|
SIF_ASR_PARTITIONS_SECTION
|
|
);
|
|
//
|
|
// Never gets here
|
|
//
|
|
return NULL;
|
|
}
|
|
|
|
|
|
PWSTR
|
|
SpDrGetNtDirectory(VOID)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Returns the target path according to the value found in the asr.sif
|
|
file, but without the leading drive letter and colon.
|
|
|
|
Arguments:
|
|
None
|
|
|
|
Return Value:
|
|
A pointer to a string containing the NT directory path. This will be of
|
|
the form:
|
|
\WINDOWS
|
|
and not:
|
|
C:\WINDOWS
|
|
--*/
|
|
{
|
|
PSIF_PARTITION_RECORD pRecord = SpAsrGetBootPartitionRecord();
|
|
return (pRecord ? pRecord->NtDirectoryName : NULL);
|
|
}
|
|
|
|
|
|
ASRMODE
|
|
SpAsrGetAsrMode(VOID)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Returns whether ASR is in progress
|
|
|
|
Return Value:
|
|
The Asr type currently in progress.
|
|
|
|
--*/
|
|
{
|
|
return Gbl_AsrMode;
|
|
}
|
|
|
|
|
|
ASRMODE
|
|
SpAsrSetAsrMode(
|
|
IN CONST ASRMODE NewAsrMode
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Sets the Gbl_AsrMode state variable to the value of NewAsrMode.
|
|
|
|
Arguments:
|
|
NewAsrMode - new Asr mode
|
|
|
|
Return Value:
|
|
Returns the previous Asr mode
|
|
|
|
--*/
|
|
{
|
|
ASRMODE oldMode = Gbl_AsrMode;
|
|
Gbl_AsrMode = NewAsrMode;
|
|
return oldMode;
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
SpDrEnabled(VOID) {
|
|
|
|
//
|
|
// Asr is enabled if Gbl_AsrMode is set to anything other than
|
|
// ASRMODE_NONE
|
|
//
|
|
return (ASRMODE_NONE != Gbl_AsrMode);
|
|
}
|
|
|
|
BOOLEAN
|
|
SpAsrIsQuickTest(VOID) {
|
|
return (
|
|
(ASRMODE_QUICKTEST_TEXT == Gbl_AsrMode) ||
|
|
(ASRMODE_QUICKTEST_FULL == Gbl_AsrMode)
|
|
);
|
|
}
|
|
|
|
BOOLEAN
|
|
SpDrIsRepairFast(VOID)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Tests whether the "Fast" Emergency Repair flag is set.
|
|
|
|
Return Value:
|
|
TRUE if "Fast" ER flag is set
|
|
FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
return Gbl_RepairWinntFast;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
SpDrSetRepairFast(BOOLEAN NewValue)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Sets the "Fast" Emergency Repair flag.
|
|
|
|
Arguments:
|
|
Value New Value (TRUE or FALSE) to which to set the
|
|
Gbl_RepairWinntFast flag
|
|
|
|
Return Value:
|
|
Previous value of Gbl_RepairWinntFast;
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN oldValue = Gbl_RepairWinntFast;
|
|
|
|
Gbl_RepairWinntFast = NewValue;
|
|
return oldValue;
|
|
}
|
|
|
|
|
|
extern VOID
|
|
SpAsrDbgDumpSystemMountPoints(VOID);
|
|
|
|
VOID
|
|
SpDrCleanup(VOID)
|
|
/*++
|
|
|
|
-pending code description
|
|
|
|
--*/
|
|
{
|
|
ULONG diskIndex = 0;
|
|
|
|
//
|
|
// Remove all the mountpoints in the system, we shall recreate them.
|
|
//
|
|
SpAsrRemoveMountPoints();
|
|
|
|
DbgStatusMesg((_asrinfo, "Restoring volume mount points.\n"));
|
|
|
|
for (diskIndex = 0; diskIndex < HardDiskCount; diskIndex++) {
|
|
|
|
if (!(DISK_IS_REMOVABLE(diskIndex))) {
|
|
SpAsrRestoreDiskMountPoints(diskIndex);
|
|
SpAsrDbgDumpDisk(diskIndex);
|
|
}
|
|
}
|
|
|
|
// DbgStatusMesg((_asrinfo, "Dumping mount points AFTER text-mode ASR:\n"));
|
|
// SpAsrDbgDumpSystemMountPoints();
|
|
}
|
|
|
|
|
|
VOID
|
|
SpAsrCopyStateFile(VOID)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
PWSTR diskName = NULL,
|
|
targetFilePath = NULL,
|
|
sourceFilePath = NULL,
|
|
bootPartition = NULL,
|
|
diskDeviceName = NULL;
|
|
|
|
SpdInitialize();
|
|
|
|
SpFormatMessage(
|
|
TemporaryBuffer,
|
|
sizeof(TemporaryBuffer),
|
|
SP_TEXT_DR_DISK_NAME
|
|
);
|
|
|
|
diskName = SpDupStringW(TemporaryBuffer);
|
|
|
|
if (RemoteBootAsrSifName == NULL) {
|
|
|
|
if (Gbl_AsrSifOnInstallationMedia) {
|
|
wcscpy(TemporaryBuffer,NtBootDevicePath);
|
|
SpConcatenatePaths(TemporaryBuffer,ASR_SIF_NAME);
|
|
sourceFilePath = SpDupStringW(TemporaryBuffer);
|
|
}
|
|
else {
|
|
//
|
|
// Prompt the user to insert the ASR disk, if it isn't
|
|
// already in the drive
|
|
//
|
|
diskDeviceName = SpDupStringW(ASR_FLOPPY0_DEVICE_PATH);
|
|
sourceFilePath = SpDupStringW(ASR_SIF_PATH);
|
|
|
|
SpPromptForDisk(
|
|
diskName,
|
|
diskDeviceName,
|
|
ASR_SIF_NAME,
|
|
FALSE, // no ignore disk in drive
|
|
FALSE, // no allow escape
|
|
TRUE, // warn multiple prompts
|
|
NULL // don't care about redraw flag
|
|
);
|
|
|
|
SpMemFree(diskDeviceName);
|
|
}
|
|
} else {
|
|
sourceFilePath = SpDupStringW(RemoteBootAsrSifName);
|
|
}
|
|
|
|
//
|
|
// Build the full path to the directory into which the file will be
|
|
// written.
|
|
//
|
|
bootPartition = SpAsrGetRegionName(Gbl_BootPartitionRegion);
|
|
if (!Gbl_BootPartitionDirectory) {
|
|
Gbl_BootPartitionDirectory = SpDrGetNtDirectory();
|
|
}
|
|
wcscpy(TemporaryBuffer, bootPartition);
|
|
SpConcatenatePaths(TemporaryBuffer, Gbl_BootPartitionDirectory);
|
|
SpConcatenatePaths(TemporaryBuffer, ASR_SIF_TARGET_PATH);
|
|
targetFilePath = SpDupStringW(TemporaryBuffer);
|
|
SpMemFree(bootPartition);
|
|
|
|
//
|
|
// Copy the file. In case of errors, user will have the option
|
|
// to retry, or quit Setup. We cannot skip this file.
|
|
//
|
|
do {
|
|
|
|
if (SpFileExists(targetFilePath, FALSE)) {
|
|
SpDeleteFile(targetFilePath, NULL, NULL);
|
|
}
|
|
|
|
status = SpCopyFileUsingNames(
|
|
sourceFilePath,
|
|
targetFilePath,
|
|
0,
|
|
0
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
DbgErrorMesg((_asrwarn, "SpAsrCopyFiles. Could not copy asr.sif. src:[%ws] dest:[%ws]. (0x%x)\n",
|
|
ASR_SIF_PATH,
|
|
targetFilePath,
|
|
status
|
|
));
|
|
|
|
SpAsrFileErrorRetrySkipAbort(
|
|
SP_SCRN_DR_SIF_NOT_FOUND,
|
|
ASR_SIF_PATH,
|
|
diskName,
|
|
NULL,
|
|
FALSE // no allow skip
|
|
);
|
|
}
|
|
} while (!NT_SUCCESS(status));
|
|
|
|
|
|
SpdTerminate();
|
|
SpMemFree(diskName);
|
|
SpMemFree(targetFilePath);
|
|
SpMemFree(sourceFilePath);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SpAsrCopy3rdPartyFiles(
|
|
VOID
|
|
)
|
|
{
|
|
PWSTR bootPartition = NULL,
|
|
fullTargetPath = NULL,
|
|
fullSourcePath = NULL,
|
|
windirPathPrefix = NULL,
|
|
tempPathPrefix = NULL;
|
|
|
|
BOOL moveToNext = FALSE,
|
|
diskLoaded = FALSE;
|
|
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PSIF_INSTALLFILE_RECORD pRec = NULL;
|
|
|
|
if (!Gbl_3rdPartyFileList) {
|
|
//
|
|
// No files to copy, we're done
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Build the expansion strings for
|
|
// %TEMP%, %TMP%, and %SYSTEMROOT%
|
|
//
|
|
bootPartition = SpAsrGetRegionName(Gbl_BootPartitionRegion);
|
|
if (!Gbl_BootPartitionDirectory) {
|
|
Gbl_BootPartitionDirectory = SpDrGetNtDirectory();
|
|
}
|
|
|
|
wcscpy(TemporaryBuffer, bootPartition);
|
|
SpConcatenatePaths(TemporaryBuffer, Gbl_BootPartitionDirectory);
|
|
windirPathPrefix = SpDupStringW(TemporaryBuffer);
|
|
|
|
wcscpy(TemporaryBuffer, bootPartition);
|
|
SpConcatenatePaths(TemporaryBuffer, ASR_TEMP_DIRECTORY_PATH);
|
|
tempPathPrefix = SpDupStringW(TemporaryBuffer);
|
|
|
|
//
|
|
// Create the TEMP directory
|
|
//
|
|
SpCreateDirectory(
|
|
bootPartition,
|
|
NULL,
|
|
ASR_TEMP_DIRECTORY_PATH,
|
|
0,
|
|
0
|
|
);
|
|
|
|
SpMemFree(bootPartition);
|
|
|
|
//
|
|
// Initialize the compression engine. We may have to uncompress files
|
|
//
|
|
SpdInitialize();
|
|
|
|
//
|
|
// Begin copying the files over
|
|
//
|
|
|
|
//! display status setup is copying ...
|
|
while (pRec = SpAsrRemoveInstallFileRecord(Gbl_3rdPartyFileList)) {
|
|
|
|
if ((!pRec->DestinationFilePath) ||
|
|
(!pRec->SourceFilePath) ||
|
|
(!pRec->DiskDeviceName) ||
|
|
(!pRec->SourceMediaExternalLabel)
|
|
) {
|
|
ASSERT(0 && L"InstallFiles: Invalid record, one or more attributes are NULL");
|
|
continue;
|
|
}
|
|
|
|
diskLoaded = TRUE;
|
|
|
|
//
|
|
// Prompt the user for the media if needed
|
|
//
|
|
if ((pRec->Flags & ASR_ALWAYS_PROMPT_FOR_MEDIA) ||
|
|
(pRec->Flags & ASR_PROMPT_USER_ON_MEDIA_ERROR)
|
|
) {
|
|
|
|
do {
|
|
moveToNext = TRUE;
|
|
|
|
//
|
|
// Prompt the user to insert the appropriate disk
|
|
//
|
|
diskLoaded = SpPromptForDisk(
|
|
pRec->SourceMediaExternalLabel,
|
|
pRec->DiskDeviceName, // if this isn't CD or floppy, SpPromptForDisk will always return true
|
|
pRec->SourceFilePath,
|
|
(BOOLEAN)(pRec->Flags & ASR_ALWAYS_PROMPT_FOR_MEDIA), // IgnoreDiskInDrive if PromptAlways
|
|
! (BOOLEAN)(pRec->Flags & ASR_FILE_IS_REQUIRED), // AllowEscape if the File is not Required
|
|
TRUE, // WarnMultiplePrompts
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// If the user hit <ESC> to cancel, we put up a prompt allowing
|
|
// him to retry, skip this file and continue, or exit from Setup.
|
|
//
|
|
if (!diskLoaded) {
|
|
|
|
moveToNext = SpAsrFileErrorRetrySkipAbort(
|
|
SP_SCRN_DR_SIF_INSTALL_FILE_NOT_FOUND,
|
|
pRec->SourceFilePath,
|
|
pRec->SourceMediaExternalLabel,
|
|
pRec->VendorString,
|
|
!(pRec->Flags & ASR_FILE_IS_REQUIRED) // allow skip
|
|
);
|
|
|
|
}
|
|
|
|
} while (!moveToNext);
|
|
}
|
|
|
|
|
|
if (!diskLoaded) {
|
|
//
|
|
// Disk was not loaded and the user wants to skip this file
|
|
//
|
|
DbgErrorMesg((_asrwarn,
|
|
"SpDrCopy3rdPartyFiles: User skipped file (disk not loaded), src:[%ws] dest[%ws]\n",
|
|
pRec->SourceFilePath,
|
|
pRec->DestinationFilePath
|
|
));
|
|
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// The correct disk was loaded. Build the full target path. pRec->CopyToDirectory
|
|
// indicates which prefix we should use.
|
|
//
|
|
switch (pRec->CopyToDirectory) {
|
|
case _SystemRoot:
|
|
wcscpy(TemporaryBuffer, windirPathPrefix);
|
|
break;
|
|
|
|
case _Temp:
|
|
case _Tmp:
|
|
case _Default:
|
|
default:
|
|
wcscpy(TemporaryBuffer, tempPathPrefix);
|
|
break;
|
|
}
|
|
|
|
SpConcatenatePaths(TemporaryBuffer, pRec->DestinationFilePath);
|
|
fullTargetPath = SpDupStringW(TemporaryBuffer);
|
|
|
|
//
|
|
// If the file already exists, prompt the user if needed. We allow him
|
|
// to over-write (delete the existing file), preserve existing
|
|
// (skip copying this file), or exit from Setup.
|
|
//
|
|
if (SpFileExists(fullTargetPath, FALSE)) {
|
|
BOOL deleteFile = FALSE;
|
|
|
|
if (pRec->Flags & ASR_PROMPT_USER_ON_COLLISION) {
|
|
if (SpAsrFileErrorDeleteSkipAbort(SP_SCRN_DR_OVERWRITE_EXISTING_FILE, fullTargetPath)) {
|
|
deleteFile = TRUE;
|
|
}
|
|
}
|
|
else if (pRec->Flags & ASR_OVERWRITE_ON_COLLISION) {
|
|
deleteFile = TRUE;
|
|
}
|
|
|
|
if (deleteFile) {
|
|
//
|
|
// User chose to overwrite (or OVERWRITE_ON_COLLISION flag was set)
|
|
//
|
|
SpDeleteFile(fullTargetPath, NULL, NULL);
|
|
|
|
DbgErrorMesg((_asrwarn,
|
|
"SpDrCopy3rdPartyFiles: Over-writing file, src:[%ws] dest[%ws]\n",
|
|
pRec->SourceFilePath,
|
|
fullTargetPath
|
|
));
|
|
}
|
|
else {
|
|
//
|
|
// User chose to preserve existing file
|
|
//
|
|
DbgErrorMesg((_asrwarn,
|
|
"SpDrCopy3rdPartyFiles: File exists, existing file was preserved. src:[%ws] dest[%ws]\n",
|
|
pRec->SourceFilePath,
|
|
fullTargetPath
|
|
));
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Combine the devicepath ("\device\cdrom0") and the sourcefilepath
|
|
// ("i386\driver.sys") to get the full path ("\device\cdrom0\i386\driver.sys")
|
|
// SpConcatenatePaths takes care of adding in the \ between the two if needed
|
|
//
|
|
wcscpy(TemporaryBuffer, pRec->DiskDeviceName);
|
|
SpConcatenatePaths(TemporaryBuffer, pRec->SourceFilePath);
|
|
fullSourcePath = SpDupStringW(TemporaryBuffer);
|
|
|
|
moveToNext = FALSE;
|
|
while (!moveToNext) {
|
|
|
|
moveToNext = TRUE;
|
|
status = SpCopyFileUsingNames(
|
|
fullSourcePath,
|
|
fullTargetPath,
|
|
0, // no attributes
|
|
0 // no flags
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
DbgErrorMesg((_asrwarn, "SpDrCopy3rdPartyFiles. SpCopyFileUsingNames failed. src:[%ws] dest:[%ws]. (0x%x)\n",
|
|
pRec->SourceFilePath,
|
|
fullTargetPath,
|
|
status
|
|
));
|
|
|
|
//
|
|
// File copy was unsuccessful, we put up a prompt allowing
|
|
// the user to retry, skip this file and continue, or exit
|
|
// from Setup.
|
|
//
|
|
if ((pRec->Flags & ASR_ALWAYS_PROMPT_FOR_MEDIA) ||
|
|
(pRec->Flags & ASR_PROMPT_USER_ON_MEDIA_ERROR)) {
|
|
|
|
moveToNext = SpAsrFileErrorRetrySkipAbort(
|
|
SP_SCRN_DR_SIF_INSTALL_FILE_NOT_FOUND,
|
|
pRec->SourceFilePath,
|
|
pRec->SourceMediaExternalLabel,
|
|
pRec->VendorString,
|
|
TRUE // allow skip
|
|
);
|
|
}
|
|
else {
|
|
moveToNext = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
DbgErrorMesg((_asrwarn, "SpDrCopy3rdPartyFiles: Unable to copy file (copy error), src:[%ws] dest[%ws]\n",
|
|
pRec->SourceFilePath,
|
|
fullTargetPath
|
|
));
|
|
}
|
|
else {
|
|
DbgStatusMesg((_asrinfo, "SpDrCopy3rdPartyFiles. Copied [%ws] to [%ws]\n",
|
|
pRec->SourceFilePath,
|
|
fullTargetPath
|
|
));
|
|
}
|
|
|
|
SpMemFree(fullSourcePath);
|
|
SpMemFree(fullTargetPath);
|
|
SpAsrDeleteInstallFileRecord(pRec);
|
|
}
|
|
|
|
//
|
|
// Done. Shut down the compression engine.
|
|
//
|
|
SpdTerminate();
|
|
SpMemFree(Gbl_3rdPartyFileList);
|
|
SpMemFree(tempPathPrefix);
|
|
SpMemFree(windirPathPrefix);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SpDrCopyFiles(VOID)
|
|
{
|
|
SpAsrCopyStateFile();
|
|
return SpAsrCopy3rdPartyFiles();
|
|
}
|
|
|
|
|
|
|
|
#define STRING_VALUE(s) REG_SZ,(s),(wcslen((s))+1)*sizeof(WCHAR)
|
|
|
|
NTSTATUS
|
|
SpDrSetEnvironmentVariables(HANDLE *HiveRootKeys)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
status = SpOpenSetValueAndClose(
|
|
HiveRootKeys[SetupHiveSystem],
|
|
ASR_CONTEXT_KEY,
|
|
ASR_CONTEXT_VALUE,
|
|
STRING_VALUE(ASR_CONTEXT_DATA));
|
|
|
|
DbgStatusMesg((_asrinfo, "Set [%ws]\\[%ws] to [%ws] (0x%x)\n",
|
|
ASR_CONTEXT_KEY,
|
|
ASR_CONTEXT_VALUE,
|
|
ASR_CONTEXT_DATA,
|
|
status));
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
Gbl_SystemPartitionName = SpAsrGetRegionName(Gbl_SystemPartitionRegion);
|
|
status = SpOpenSetValueAndClose(
|
|
HiveRootKeys[SetupHiveSystem],
|
|
ASR_CONTEXT_KEY,
|
|
ASR_SYSTEM_PARTITION_VALUE,
|
|
STRING_VALUE(Gbl_SystemPartitionName));
|
|
|
|
DbgStatusMesg((_asrinfo, "Set [%ws]\\[%ws] to [%ws] (0x%x)\n",
|
|
ASR_CONTEXT_KEY,
|
|
ASR_SYSTEM_PARTITION_VALUE,
|
|
Gbl_SystemPartitionName,
|
|
status));
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
Gbl_BootPartitionName = SpAsrGetRegionName(Gbl_BootPartitionRegion);
|
|
status = SpOpenSetValueAndClose(
|
|
HiveRootKeys[SetupHiveSystem],
|
|
ASR_CONTEXT_KEY,
|
|
ASR_BOOT_PARTITION_VALUE,
|
|
STRING_VALUE(Gbl_BootPartitionName));
|
|
|
|
DbgStatusMesg((_asrinfo, "Set [%ws]\\[%ws] to [%ws] (0x%x)\n",
|
|
ASR_CONTEXT_KEY,
|
|
ASR_BOOT_PARTITION_VALUE,
|
|
Gbl_BootPartitionName,
|
|
status));
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
PDISK_REGION
|
|
SpAsrPrepareBootRegion(
|
|
IN PVOID SifHandle,
|
|
IN PWSTR Local_SetupSourceDevicePath,
|
|
IN PWSTR Local_DirectoryOnSetupSource
|
|
)
|
|
/*++
|
|
|
|
-pending code description
|
|
|
|
--*/
|
|
{
|
|
PWSTR systemKey = ASR_SIF_SYSTEM_KEY;
|
|
PWSTR ntDir = NULL;
|
|
ULONG diskIndex = 0;
|
|
PSIF_PARTITION_RECORD ppartitionRecord = NULL;
|
|
FilesystemType regionFsType = FilesystemUnknown;
|
|
BOOLEAN isBoot = FALSE;
|
|
|
|
//
|
|
// Initialize Gbl_BootPartitionDriveLetter.
|
|
//
|
|
ntDir = SpAsrGetNtDirectoryPathBySystemKey(systemKey);
|
|
|
|
if (!SpAsrIsValidBootDrive(ntDir)) {
|
|
SpAsrRaiseFatalErrorWs(
|
|
SP_SCRN_DR_SIF_BAD_RECORD,
|
|
L"Windows directory specified in asr.sif is invalid",
|
|
SIF_ASR_SYSTEMS_SECTION
|
|
);
|
|
// Does not return
|
|
}
|
|
|
|
Gbl_BootPartitionDriveLetter = ntDir[0];
|
|
|
|
//
|
|
// Find boot partition region from the partition set table.
|
|
// from the records in the global partition set.
|
|
//
|
|
Gbl_BootPartitionRegion = NULL;
|
|
for (diskIndex = 0; (diskIndex < HardDiskCount); diskIndex++) {
|
|
|
|
if (!(Gbl_PartitionSetTable2[diskIndex] &&
|
|
Gbl_PartitionSetTable2[diskIndex]->pDiskRecord &&
|
|
Gbl_PartitionSetTable2[diskIndex]->pDiskRecord->PartitionList)) {
|
|
continue;
|
|
}
|
|
|
|
ppartitionRecord = Gbl_PartitionSetTable2[diskIndex]->pDiskRecord->PartitionList->First;
|
|
|
|
while (ppartitionRecord) {
|
|
isBoot = SpAsrIsBootPartitionRecord(ppartitionRecord->PartitionFlag);
|
|
if (isBoot) {
|
|
|
|
Gbl_BootPartitionRegion = SpAsrDiskPartitionExists(diskIndex, ppartitionRecord);
|
|
|
|
if (!Gbl_BootPartitionRegion) {
|
|
DbgFatalMesg((_asrerr,
|
|
"Partition record with boot region found, but boot (winnt) region is NULL\n"
|
|
));
|
|
|
|
SpAsrRaiseFatalError(SP_SCRN_DR_CREATE_ERROR_DISK_PARTITION,
|
|
L"Boot pRegion is NULL"
|
|
);
|
|
}
|
|
|
|
Gbl_BootPartitionRecord = SpAsrCopyPartitionRecord(ppartitionRecord);
|
|
break;
|
|
}
|
|
|
|
ppartitionRecord = ppartitionRecord->Next;
|
|
}
|
|
|
|
}
|
|
|
|
if (!Gbl_BootPartitionRegion) {
|
|
|
|
DbgFatalMesg((_asrerr, "No partition record with boot region found, boot (winnt) region is NULL\n"));
|
|
|
|
SpAsrRaiseFatalErrorWs(
|
|
SP_SCRN_DR_SIF_BAD_RECORD,
|
|
L"No boot partition found in asr.sif",
|
|
SIF_ASR_PARTITIONS_SECTION
|
|
);
|
|
}
|
|
|
|
SpAsrReformatPartition(Gbl_BootPartitionRegion,
|
|
Gbl_BootPartitionRecord->FileSystemType,
|
|
SifHandle,
|
|
Gbl_BootPartitionRecord->ClusterSize,
|
|
Local_SetupSourceDevicePath,
|
|
Local_DirectoryOnSetupSource,
|
|
TRUE
|
|
);
|
|
|
|
return Gbl_BootPartitionRegion;
|
|
}
|
|
|
|
|
|
PDISK_REGION
|
|
SpAsrPrepareSystemRegion(
|
|
IN PVOID SifHandle,
|
|
IN PWSTR Local_SetupSourceDevicePath,
|
|
IN PWSTR Local_DirectoryOnSetupSource
|
|
)
|
|
/*++
|
|
|
|
-pending code description
|
|
|
|
--*/
|
|
{
|
|
ULONG diskIndex = 0;
|
|
BOOLEAN found = FALSE;
|
|
|
|
BOOLEAN diskChanged = FALSE;
|
|
|
|
PWSTR partitionDeviceName = NULL;
|
|
PDISK_REGION pRegion = NULL;
|
|
PSIF_PARTITION_RECORD ppartitionRecord = NULL;
|
|
|
|
ULONGLONG startSector = 0;
|
|
DWORD diskNumber = 0;
|
|
|
|
|
|
if (IsNEC_98) {
|
|
// This is a NEC x86 machine
|
|
|
|
pRegion = Gbl_BootPartitionRegion;
|
|
ASSERT(pRegion);
|
|
|
|
} else {
|
|
// This is not a NEC x86 machine
|
|
|
|
#ifdef _IA64_
|
|
|
|
WCHAR RegionName[MAX_PATH];
|
|
|
|
if (!(pRegion = SpPtnLocateESP())) {
|
|
SpAsrRaiseFatalError(SP_SCRN_DR_CREATE_ERROR_DISK_PARTITION,
|
|
L"System Region is NULL"
|
|
);
|
|
}
|
|
|
|
SPPT_MARK_REGION_AS_SYSTEMPARTITION(pRegion, TRUE);
|
|
SPPT_SET_REGION_DIRTY(pRegion, TRUE);
|
|
ValidArcSystemPartition = TRUE;
|
|
//
|
|
// Remove the drive letter also
|
|
//
|
|
swprintf(RegionName,
|
|
L"\\Device\\Harddisk%u\\Partition%u",
|
|
pRegion->DiskNumber,
|
|
pRegion->PartitionNumber);
|
|
|
|
SpDeleteDriveLetter(RegionName);
|
|
pRegion->DriveLetter = 0;
|
|
|
|
#else
|
|
|
|
if (!(pRegion = SpPtValidSystemPartition())) {
|
|
SpAsrRaiseFatalError(SP_SCRN_DR_CREATE_ERROR_DISK_PARTITION,
|
|
L"System Region is NULL"
|
|
);
|
|
}
|
|
|
|
#endif
|
|
}
|
|
|
|
partitionDeviceName = SpAsrGetRegionName(pRegion);
|
|
DbgStatusMesg((_asrinfo, "PrepareSystemRegion. sys-ptn:[%ws]. Making Active\n",
|
|
partitionDeviceName));
|
|
|
|
startSector = pRegion->StartSector;
|
|
diskNumber = pRegion->DiskNumber;
|
|
|
|
#ifndef _IA64_
|
|
|
|
SpPtnMakeRegionActive(pRegion);
|
|
|
|
#endif
|
|
|
|
SpPtnCommitChanges(pRegion->DiskNumber, &diskChanged);
|
|
DbgStatusMesg((
|
|
_asrinfo,
|
|
"PrepareSystemRegion. sys-region made active. Disk %lu. %s.\n",
|
|
pRegion->DiskNumber,
|
|
diskChanged ? "Disk not changed.":"Disk changed"
|
|
));
|
|
|
|
|
|
pRegion = SpPtLookupRegionByStart(SPPT_GET_PARTITIONED_DISK(diskNumber), FALSE, startSector);
|
|
|
|
//
|
|
// Consistency checks. These can eventually be removed
|
|
//
|
|
ASSERT(pRegion);
|
|
|
|
diskIndex = pRegion->DiskNumber;
|
|
ASSERT(Gbl_PartitionSetTable2[diskIndex]);
|
|
ASSERT(Gbl_PartitionSetTable2[diskIndex]->pDiskRecord);
|
|
ASSERT(Gbl_PartitionSetTable2[diskIndex]->pDiskRecord->PartitionList);
|
|
|
|
//
|
|
// Ensure that the partition is correctly formatted. To accomplish this,
|
|
// we need to find the record corresponding to this pRegion. We use the
|
|
// record to check for the correct file format.
|
|
//
|
|
ppartitionRecord = Gbl_PartitionSetTable2[diskIndex]->pDiskRecord->PartitionList->First;
|
|
while (ppartitionRecord) {
|
|
if ((ULONGLONG)ppartitionRecord->StartSector == pRegion->StartSector) {
|
|
found = TRUE;
|
|
break;
|
|
}
|
|
|
|
ppartitionRecord = ppartitionRecord->Next;
|
|
}
|
|
|
|
if (!found) {
|
|
DbgFatalMesg((_asrerr,
|
|
"Did not find system partition, start sector: %I64u\n",
|
|
pRegion->StartSector
|
|
));
|
|
|
|
SpAsrRaiseFatalErrorWs(
|
|
SP_SCRN_DR_SIF_BAD_RECORD,
|
|
L"No system partition found in asr.sif",
|
|
SIF_ASR_PARTITIONS_SECTION
|
|
);
|
|
}
|
|
|
|
//
|
|
// Format the system partition if needed. We don't re-format the system
|
|
// partition if it's intact.
|
|
//
|
|
if (SpAsrPartitionNeedsFormatting(pRegion, ppartitionRecord->FileSystemType)) {
|
|
|
|
SpAsrReformatPartition(
|
|
pRegion,
|
|
ppartitionRecord->FileSystemType,
|
|
SifHandle,
|
|
ppartitionRecord->ClusterSize,
|
|
Local_SetupSourceDevicePath,
|
|
Local_DirectoryOnSetupSource,
|
|
FALSE
|
|
);
|
|
}
|
|
|
|
SpMemFree(partitionDeviceName);
|
|
|
|
Gbl_SystemPartitionRegion = pRegion;
|
|
return Gbl_SystemPartitionRegion;
|
|
}
|
|
|
|
|
|
#if 0
|
|
//
|
|
// We don't convert the partition types any more--it is okay to leave
|
|
// them as type 0x42 if the partitions are intact.
|
|
//
|
|
BOOLEAN
|
|
SpAsrChangeLdmPartitionTypes(VOID)
|
|
/*++
|
|
|
|
Routine Description
|
|
Changes disk types from 0x42 to 0x7 if needed
|
|
(If the disk is intact, it would not have been re-created
|
|
and hence re-typed above)
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG setIndex;
|
|
ULONG ptnIndex;
|
|
PDISK_PARTITION_SET ppartitionSet;
|
|
PSIF_DISK_RECORD pdiskRecord;
|
|
PSIF_PARTITION_RECORD ppartitionRecord;
|
|
BOOLEAN madeAChange = FALSE;
|
|
|
|
// Look for any disks which were marked to change from type 0x42 to
|
|
// type 0x7.
|
|
|
|
for (setIndex = 0; setIndex < HardDiskCount; setIndex++) {
|
|
|
|
ppartitionSet = Gbl_PartitionSetTable2[setIndex];
|
|
|
|
if (ppartitionSet && ppartitionSet->pDiskRecord) {
|
|
pdiskRecord = ppartitionSet->pDiskRecord;
|
|
|
|
if (pdiskRecord->ContainsNtPartition ||
|
|
pdiskRecord->ContainsSystemPartition) {
|
|
|
|
ppartitionRecord = pdiskRecord->PartitionList->First;
|
|
|
|
while (ppartitionRecord) {
|
|
|
|
if (ppartitionRecord->NeedsLdmRetype) {
|
|
|
|
// Disk type needs to be changed
|
|
|
|
PPARTITIONED_DISK pDisk;
|
|
PDISK_REGION pRegion = NULL;
|
|
|
|
pDisk = &PartitionedDisks[setIndex];
|
|
|
|
// try finding the disk region in the main list
|
|
pRegion = SpPtLookupRegionByStart(pDisk, FALSE, ppartitionRecord->StartSector);
|
|
|
|
if (!pRegion) {
|
|
// that failed, try finding disk region using the
|
|
// extended partitions list
|
|
pRegion = SpPtLookupRegionByStart(pDisk, TRUE, ppartitionRecord->StartSector);
|
|
}
|
|
|
|
if (!pRegion) {
|
|
// the disk region couldn't be found
|
|
DbgErrorMesg((_asrwarn, "SpAsrChangeLdmPartitionTypes. Unable to reset LDM partition record %ws at SS %I64u\n",
|
|
ppartitionRecord->CurrPartKey,
|
|
ppartitionRecord->StartSector));
|
|
|
|
ppartitionRecord = ppartitionRecord->Next;
|
|
continue;
|
|
}
|
|
|
|
// The disk region was found, now change the disk type
|
|
if (!IsRecognizedPartition(ppartitionRecord->FileSystemType)) {
|
|
//
|
|
// This is an 0x42 partition on the boot/sys disk, but it is
|
|
// not the boot or system partition. The FileSystemType is not
|
|
// recognised since it is set to be 0x42 as well. (The
|
|
// FileSystemType is only valid for the boot and system
|
|
// partitions--for all other partitions,
|
|
// it is set to be the same as the PartitionType)
|
|
//
|
|
// We set it to 0x7 for the time being. The actual file-system type
|
|
// will be set later in GUI-Setup by asr_ldm and asr_fmt.
|
|
//
|
|
DbgStatusMesg((_asrinfo,
|
|
"MBR ptn-rec %ws re-typed (0x%x->0x7) \n",
|
|
ppartitionRecord->CurrPartKey,
|
|
ppartitionRecord->FileSystemType
|
|
));
|
|
ppartitionRecord->FileSystemType = PARTITION_IFS;
|
|
ppartitionRecord->PartitionType = PARTITION_IFS;
|
|
|
|
}
|
|
else {
|
|
|
|
DbgStatusMesg((_asrinfo,
|
|
"MBR ptn-rec %ws re-typed (0x%x->0x%x).\n",
|
|
ppartitionRecord->CurrPartKey,
|
|
ppartitionRecord->PartitionType,
|
|
ppartitionRecord->FileSystemType
|
|
));
|
|
ppartitionRecord->PartitionType = ppartitionRecord->FileSystemType;
|
|
|
|
}
|
|
|
|
ppartitionRecord->NeedsLdmRetype = FALSE;
|
|
|
|
SPPT_SET_PARTITION_TYPE(pRegion, ppartitionRecord->FileSystemType);
|
|
SPPT_SET_REGION_DIRTY(pRegion, TRUE);
|
|
|
|
pRegion->DynamicVolume = TRUE;
|
|
pRegion->DynamicVolumeSuitableForOS = TRUE;
|
|
madeAChange = TRUE;
|
|
|
|
DbgStatusMesg((_asrinfo, "SpAsrChangeLdmPartitionTypes. Changed disk [%ws] ptn [%ws] type to 0x%x\n",
|
|
pdiskRecord->CurrDiskKey, ppartitionRecord->CurrPartKey, ppartitionRecord->PartitionType));
|
|
}
|
|
|
|
ppartitionRecord = ppartitionRecord->Next;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return madeAChange;
|
|
}
|
|
#endif // 0
|
|
|
|
extern VOID
|
|
SpAsrDbgDumpInstallFileList(IN PSIF_INSTALLFILE_LIST pList);
|
|
|
|
VOID
|
|
SpAsrSetNewDiskID(
|
|
IN ULONG DiskNumber,
|
|
IN GUID *NewGuid, // valid only for GPT disks
|
|
IN ULONG NewSignature // valid only for MBR disks
|
|
)
|
|
{
|
|
PPARTITIONED_DISK pDisk = &PartitionedDisks[DiskNumber];
|
|
PDISK_REGION pFirstRegion = NULL;
|
|
BOOLEAN Changes = FALSE;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
if (PARTITION_STYLE_GPT == (PARTITION_STYLE) (pDisk->HardDisk->DriveLayout.PartitionStyle)) {
|
|
//
|
|
// Set the new disk GUID
|
|
//
|
|
CopyMemory(&(pDisk->HardDisk->DriveLayout.Gpt.DiskId), NewGuid, sizeof(GUID));
|
|
}
|
|
else if (PARTITION_STYLE_MBR == (PARTITION_STYLE) (pDisk->HardDisk->DriveLayout.PartitionStyle)) {
|
|
//
|
|
// Set the new disk signature
|
|
//
|
|
pDisk->HardDisk->DriveLayout.Mbr.Signature = NewSignature;
|
|
}
|
|
else {
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// For Commit to pick up the new Guid, at least one region on the
|
|
// disk must be marked dirty.
|
|
//
|
|
pFirstRegion = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
|
|
SPPT_SET_REGION_DIRTY(pFirstRegion, TRUE);
|
|
|
|
Status = SpPtnCommitChanges(DiskNumber, &Changes);
|
|
|
|
//
|
|
// Reset the dirty flag on the first region
|
|
//
|
|
pFirstRegion = SPPT_GET_PRIMARY_DISK_REGION(DiskNumber);
|
|
SPPT_SET_REGION_DIRTY(pFirstRegion, FALSE);
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SpDrPtPrepareDisks(
|
|
IN PVOID SifHandle,
|
|
OUT PDISK_REGION *BootPartitionRegion,
|
|
OUT PDISK_REGION *SystemPartitionRegion,
|
|
IN PWSTR SetupSourceDevicePath,
|
|
IN PWSTR DirectoryOnSetupSource,
|
|
OUT BOOLEAN *RepairedNt
|
|
)
|
|
/*++
|
|
|
|
Description:
|
|
If necessary, SpDrPtPrepareDisks() restores (recreates and formats) the
|
|
system and boot partitions based on information obtained from the
|
|
asr.sif file.
|
|
|
|
Arguments:
|
|
SifHandle - Handle to txtsetup.sif
|
|
|
|
BootPartitionRegion - Receives a pointer to the partition into
|
|
which NT will be installed (e.g., \WINNT).
|
|
|
|
SystemPartitionRegion - Receives a pointer to the partition into
|
|
which the boot loader will be installed.
|
|
|
|
SetupSourceDevicePath - Path to the CDROM
|
|
|
|
DirectoryOnSetupSource - The directory on the installation CDROM.
|
|
(usually "\I386" for x86 installations)
|
|
|
|
RepairedNt - Receives a pointer to a boolean value that is set to:
|
|
TRUE: Indicates the partition structure on the loader
|
|
disk and he partition structure on the NT disk were
|
|
intact and that ASR attempted to perform a repair
|
|
operation.
|
|
FALSE: Indicates the partition structure on either the
|
|
loader disk or the NT disk (or both) were removed
|
|
and recreated. When SpStartSetup() sees this value,
|
|
it will proceed with a normal installation.
|
|
|
|
Return Value:
|
|
STATUS_SUCCESS, always! (as of now, anyway)
|
|
|
|
--*/
|
|
{
|
|
BOOL done = TRUE,
|
|
next = TRUE,
|
|
warningScreenDone = FALSE;
|
|
|
|
NTSTATUS status;
|
|
|
|
ULONG diskIndex = 0;
|
|
|
|
PWSTR setupSourceDevicePath = NULL,
|
|
directoryOnSetupSource = NULL;
|
|
|
|
DbgStatusMesg((_asrinfo, "Entering SpDrPtPrepareDisks. Beginning ASR/ER/RC Processing\n"));
|
|
DbgStatusMesg((_asrinfo, "SetupSourceDevicePath:[%ws], DirectoryOnSetupSource:[%ws]\n",
|
|
SetupSourceDevicePath, DirectoryOnSetupSource));
|
|
|
|
*RepairedNt = FALSE;
|
|
|
|
//
|
|
// find out if the user wants Recovery Console, traditional Emergency
|
|
// Repair (ER), or full scale Automated System Recovery (ASR)
|
|
//
|
|
Gbl_SifHandle = SifHandle;
|
|
setupSourceDevicePath = SpDupStringW(SetupSourceDevicePath);
|
|
directoryOnSetupSource = SpDupStringW(DirectoryOnSetupSource);
|
|
|
|
do {
|
|
|
|
if (!done) {
|
|
DbgStatusMesg((_asrinfo, "User hit <ESC> to cancel. Prompting for ASR/ER/RC again\n"));
|
|
}
|
|
|
|
if (!SpDrEnabled() || RepairWinnt) {
|
|
SpAsrQueryRepairOrDr();
|
|
}
|
|
|
|
if(ForceConsole) { // Recovery Console
|
|
DbgStatusMesg((_asrinfo, "User chose Recovery Console. Exiting SpDrPtPrepareDisks.\n"));
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
DbgStatusMesg((_asrinfo, "User chose %s, sys-drive:[%wc], nt/boot-drive:[%wc]\n",
|
|
RepairWinnt ? Gbl_RepairWinntFast ? "Fast ER" : "Manual ER" : "ASR",
|
|
(Gbl_SystemPartitionRegion ? Gbl_SystemPartitionRegion->DriveLetter : L'\\'),
|
|
(Gbl_BootPartitionRegion ? Gbl_BootPartitionRegion->DriveLetter : L'\\') ));
|
|
|
|
//
|
|
// Prompt for ER/ASR floppy
|
|
//
|
|
if (RepairWinnt) { // ER
|
|
done = SpAsrGetErDiskette(SifHandle);
|
|
}
|
|
else { // ASR
|
|
if (ASRMODE_NORMAL == SpAsrGetAsrMode()) {
|
|
SpInitializePidString(SifHandle, SetupSourceDevicePath, DirectoryOnSetupSource);
|
|
}
|
|
done = SpAsrLoadAsrDiskette();
|
|
}
|
|
} while (!done);
|
|
|
|
|
|
//
|
|
// At this point, if RepairWinnt is TRUE, user wants ER, else user
|
|
// wants ASR. (If he wanted Recovery Console we would've returned
|
|
// STATUS_SUCCESS above.) In either case, the appropriate disk is
|
|
// already in the drive
|
|
//
|
|
if (RepairWinnt) { // ER
|
|
|
|
//
|
|
// if the boot partition was not repaired (deleted, recreated, and
|
|
// reformatted), then attempt an emergency repair of the system.
|
|
//
|
|
if (Gbl_NtPartitionIntact == TRUE) {
|
|
|
|
*RepairedNt = SpAsrAttemptRepair(
|
|
SifHandle,
|
|
SetupSourceDevicePath,
|
|
DirectoryOnSetupSource,
|
|
SetupSourceDevicePath,
|
|
DirectoryOnSetupSource
|
|
);
|
|
|
|
if (*RepairedNt) {
|
|
WinntSetup = FALSE;
|
|
}
|
|
|
|
*SystemPartitionRegion = Gbl_SystemPartitionRegion;
|
|
*BootPartitionRegion = Gbl_BootPartitionRegion;
|
|
}
|
|
else {
|
|
//
|
|
// If the NT partition is not intact, we cannot do an ER.
|
|
//
|
|
SpAsrCannotDoER();
|
|
SpDone(0, FALSE, TRUE);
|
|
}
|
|
}
|
|
else { // ASR
|
|
SpAsrInitIoDeviceCount();
|
|
SpAsrCheckAsrStateFileVersion();
|
|
SpAsrCreatePartitionSets(setupSourceDevicePath, directoryOnSetupSource);
|
|
Gbl_3rdPartyFileList = SpAsrInit3rdPartyFileList(SetupSourceDevicePath);
|
|
SpAsrDbgDumpPartitionSets();
|
|
SpAsrDeleteMountedDevicesKey();
|
|
SpAsrRemoveMountPoints(); // restored by asr_fmt.exe etc
|
|
|
|
//
|
|
// Check hard disks and repartition as needed
|
|
//
|
|
next = TRUE;
|
|
for (diskIndex = 0; diskIndex < HardDiskCount; (diskIndex += (next ? 1 : 0))) {
|
|
|
|
BOOLEAN skip = FALSE;
|
|
|
|
next = TRUE;
|
|
SpAsrDbgDumpDisk(diskIndex);
|
|
|
|
if (!warningScreenDone) {
|
|
skip = SpAsrpSkipDiskRepartition(diskIndex, FALSE);
|
|
if (!skip) {
|
|
//
|
|
// If we are going to repartition a disk, put up the
|
|
// warning screen to make sure the user knows all
|
|
// partitions on the disk are going to get clobbered,
|
|
// but only once - after the first disk with a problem,
|
|
// don't display the screen again.
|
|
//
|
|
SpAsrClobberDiskWarning();
|
|
warningScreenDone = TRUE;
|
|
}
|
|
}
|
|
|
|
skip = SpAsrpSkipDiskRepartition(diskIndex, TRUE);
|
|
if (!skip) {
|
|
CREATE_DISK CreateDisk;
|
|
PSIF_DISK_RECORD pCurrentDisk = Gbl_PartitionSetTable1[diskIndex]->pDiskRecord;
|
|
PHARD_DISK HardDisk = SPPT_GET_HARDDISK(diskIndex);
|
|
BOOLEAN IsBlank = TRUE;
|
|
BOOLEAN preservePartitions = FALSE;
|
|
UCHAR MbrPartitionType = PARTITION_ENTRY_UNUSED;
|
|
|
|
//
|
|
// We're here because the partition structure of the disk does not
|
|
// match with that specified by the SIF file. As a consequence
|
|
// all of the partitions on this disk will be removed and recreated.
|
|
//
|
|
if (SpPtnGetPartitionCountDisk(diskIndex) ||
|
|
SpPtnGetContainerPartitionCount(diskIndex)) {
|
|
//
|
|
// The physical disk has partitions, clear them
|
|
//
|
|
// On GPT disks, we erase all the partitions with the
|
|
// exception of the EFI System Partition. Note that we
|
|
// delete all foreign/unrecognised partitions as
|
|
// well.
|
|
//
|
|
// For MBR disks, we erase all the partitions with the
|
|
// exception of any OEM partitions. Note that as in the
|
|
// case of GPT disks, we delete unrecognised/foriegn
|
|
// partitions.
|
|
//
|
|
|
|
//
|
|
// Get the partition type of the first partition on the
|
|
// sifDisk. If this is an OEM partition, and the
|
|
// current disk has a partition with the same exact
|
|
// partition type, we should preserve it.
|
|
//
|
|
if (PARTITION_STYLE_MBR == pCurrentDisk->PartitionStyle) {
|
|
|
|
if (((pCurrentDisk->ContainsNtPartition)
|
|
|| (pCurrentDisk->ContainsSystemPartition)) &&
|
|
(pCurrentDisk->PartitionList) &&
|
|
(pCurrentDisk->PartitionList->First)) {
|
|
|
|
MbrPartitionType = pCurrentDisk->PartitionList->First->PartitionType;
|
|
}
|
|
|
|
if (IsOEMPartition(MbrPartitionType)) {
|
|
preservePartitions = TRUE;
|
|
}
|
|
|
|
}
|
|
else if (PARTITION_STYLE_GPT == pCurrentDisk->PartitionStyle) {
|
|
|
|
preservePartitions = TRUE;
|
|
}
|
|
|
|
|
|
SpAsrDeletePartitions(diskIndex, preservePartitions, MbrPartitionType, &IsBlank);
|
|
}
|
|
|
|
if (IsBlank) {
|
|
//
|
|
// The disk is blank, set the appropriate signature/ID
|
|
//
|
|
ZeroMemory(&CreateDisk, sizeof(CREATE_DISK));
|
|
CreateDisk.PartitionStyle = pCurrentDisk->PartitionStyle;
|
|
|
|
if (PARTITION_STYLE_MBR == pCurrentDisk->PartitionStyle) {
|
|
CreateDisk.Mbr.Signature = pCurrentDisk->SifDiskMbrSignature;
|
|
}
|
|
else if (PARTITION_STYLE_GPT == pCurrentDisk->PartitionStyle) {
|
|
|
|
CopyMemory(&(CreateDisk.Gpt.DiskId),
|
|
&(pCurrentDisk->SifDiskGptId),
|
|
sizeof(GUID));
|
|
|
|
CreateDisk.Gpt.MaxPartitionCount = pCurrentDisk->MaxGptPartitionCount;
|
|
}
|
|
else {
|
|
ASSERT(0 && L"Unrecognised partition style");
|
|
continue;
|
|
}
|
|
|
|
SPPT_SET_DISK_BLANK(diskIndex, TRUE);
|
|
|
|
//
|
|
// Intialise the disk to the appropriate style
|
|
//
|
|
status = SpPtnInitializeDiskStyle(diskIndex, pCurrentDisk->PartitionStyle, &CreateDisk);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
status = SpPtnInitializeDiskDrive(diskIndex);
|
|
}
|
|
}
|
|
else {
|
|
//
|
|
// Special case: the EFI system partition, or some OEM
|
|
// partition, was preserved. We should just update
|
|
// the disk GUID or signature.
|
|
//
|
|
SpAsrSetNewDiskID(diskIndex, &(pCurrentDisk->SifDiskGptId), pCurrentDisk->SifDiskMbrSignature);
|
|
}
|
|
|
|
//
|
|
// Create the new paritions
|
|
//
|
|
SpAsrRecreateDiskPartitions(diskIndex, (preservePartitions && (!IsBlank)), MbrPartitionType);
|
|
}
|
|
}
|
|
|
|
SpAsrDbgDumpPartitionLists(2, L"After partition recreation.");
|
|
|
|
//
|
|
// Format the Boot partition. (Always, EXCEPT in automated tests)
|
|
// This won't return if the boot partition region doesn't exist
|
|
//
|
|
*BootPartitionRegion = SpAsrPrepareBootRegion(
|
|
SifHandle,
|
|
setupSourceDevicePath,
|
|
directoryOnSetupSource
|
|
);
|
|
|
|
//
|
|
// Format the system partition only if necessary.
|
|
// This won't return if the system partition region doesn't exist
|
|
//
|
|
*SystemPartitionRegion = SpAsrPrepareSystemRegion(
|
|
SifHandle,
|
|
setupSourceDevicePath,
|
|
directoryOnSetupSource
|
|
);
|
|
|
|
} // RepairWinnt
|
|
|
|
SpMemFree(setupSourceDevicePath);
|
|
SpMemFree(directoryOnSetupSource);
|
|
|
|
DbgStatusMesg((_asrinfo, "Exiting SpDrPtPrepareDisks\n"));
|
|
return STATUS_SUCCESS;
|
|
}
|