/*++ Copyright (c) 1993 Microsoft Corporation Module Name: sppart2.c Abstract: Second file for disk preparation UI; supplies routines to handle a user's selection of the partition onto which he wants to install NT. Author: Ted Miller (tedm) 16-Sep-1993 Revision History: --*/ #include "spprecmp.h" #pragma hdrstop #ifdef _X86_ BOOLEAN SpIsWin9xMsdosSys( IN PDISK_REGION Region, OUT PSTR* Win9xPath ); #endif ULONG SpFormattingOptions( IN BOOLEAN AllowFatFormat, IN BOOLEAN AllowNtfsFormat, IN BOOLEAN AllowConvertNtfs, IN BOOLEAN AllowDoNothing, IN BOOLEAN AllowEscape ); BOOLEAN SpPtRegionDescription( IN PPARTITIONED_DISK pDisk, IN PDISK_REGION pRegion, OUT PWCHAR Buffer, IN ULONG BufferSize ); typedef enum { FormatOptionCancel = 0, FormatOptionFat, FormatOptionNtfs, FormatOptionFatQuick, FormatOptionNtfsQuick, FormatOptionConvertToNtfs, FormatOptionDoNothing } FormatOptions; extern PSETUP_COMMUNICATION CommunicationParams; //#ifdef TEST #if defined(_AMD64_) || defined(_X86_) BOOLEAN SpIsExistsOs( IN PDISK_REGION CColonRegion ); extern NTSTATUS pSpBootCodeIo( IN PWSTR FilePath, IN PWSTR AdditionalFilePath, OPTIONAL IN ULONG BytesToRead, IN PUCHAR *Buffer, IN ULONG OpenDisposition, IN BOOLEAN Write, IN ULONGLONG Offset, IN ULONG BytesPerSector ); extern VOID SpDetermineOsTypeFromBootSector( IN PWSTR CColonPath, IN PUCHAR BootSector, OUT PUCHAR *OsDescription, OUT PBOOLEAN IsNtBootcode, OUT PBOOLEAN IsOtherOsInstalled, IN WCHAR DriveLetter ); extern BOOLEAN SpHasMZHeader( IN PWSTR FileName ); #endif // defined(_AMD64_) || defined(_X86_) //#endif //TEST BOOLEAN SpPtIsForeignPartition( IN PDISK_REGION Region ) { BOOLEAN ForeignPartition = TRUE; // for blank disks ? if (Region){ UCHAR SystemId; if (SPPT_IS_MBR_DISK(Region->DiskNumber)) { SystemId = SpPtGetPartitionType(Region); ASSERT(SystemId != PARTITION_ENTRY_UNUSED); ASSERT(!IsContainerPartition(SystemId)); ForeignPartition = ((PartitionNameIds[SystemId] != (UCHAR)(-1)) && (!Region->DynamicVolume || !Region->DynamicVolumeSuitableForOS)); } if (SPPT_IS_GPT_DISK(Region->DiskNumber)) { // // If problem occurs of unattend case trying to install to an OEM partition // Add this condition (||(Region->IsReserved)) to block selection of OEM // partition. // ForeignPartition = (Region->DynamicVolume && !Region->DynamicVolumeSuitableForOS); } } return ForeignPartition; } BOOLEAN SpPtDeterminePartitionGood( IN PDISK_REGION Region, IN ULONGLONG RequiredKB, IN BOOLEAN DisallowOtherInstalls ) { UCHAR SystemId; BOOLEAN NewlyCreated; ULONG PreconfirmFormatId; ULONG ValidKeys1[2] = { ASCI_CR ,0 }; ULONG ValidKeys2[2] = { ASCI_ESC,0 }; ULONG Mnemonics1[2] = { MnemonicContinueSetup, 0 }; ULONG Mnemonics2[2] = { 0,0 }; ULONGLONG RegionSizeKB; ULONG r; #if defined(_AMD64_) || defined(_X86_) PDISK_REGION systemPartitionRegion; #endif // defined(_AMD64_) || defined(_X86_) ULONG selection; NTSTATUS Status; ULONG Count; PWSTR p; PWSTR RegionDescr; LARGE_INTEGER temp; KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpPtDeterminePartitionGood(): Starting partition verification\n" )); // // Make sure we can see the disk from the firmware/bios. // If we can get an arc name for the disk, assume it's ok. // Otherwise, it ain't. // p = SpNtToArc( HardDisks[Region->DiskNumber].DevicePath,PrimaryArcPath ); if (p == NULL) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpPtDeterminePartitionGood(): Failed to create an arc name for this partition\n" )); return FALSE; } KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpPtDeterminePartitionGood(): partition=[%ws]\n", p )); // // Make sure the partition is formatted. // if( Region->PartitionedSpace ) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpPtDeterminePartitionGood(): This partition is formated.\n")); } else { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpPtDeterminePartitionGood(): This partition hasn't been formated.\n")); return FALSE; } // // I think he's formatted, but he better be of a format that I can read. // Make sure. // if( (Region->Filesystem == FilesystemFat) || (Region->Filesystem == FilesystemFirstKnown) || (Region->Filesystem == FilesystemNtfs) || (Region->Filesystem == FilesystemFat32) ) { // // Life is grand. Let's tell the user and keep going. // KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpPtDeterminePartitionGood(): This partition " "is formated with a known filesystem (%d).\n", Region->Filesystem )); } else { // // Darn! We don't know how to read this filesystem. Bail. // KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpPtDeterminePartitionGood(): This partition is " "formated with an unknown (or invalid for holding an installation) " "filesystem (%d).\n", Region->Filesystem )); return FALSE; } #if defined(_AMD64_) || defined(_X86_) // // On amd64/x86 we don't allow disks that have LUN greater than 0 // SpStringToLower( p ); if( wcsstr( p, L"scsi(" ) && wcsstr( p, L")rdisk(" ) ) { if( wcsstr( p, L")rdisk(0)" ) == NULL ) { SpMemFree(p); KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpPtDeterminePartitionGood(): Disks with " "a LUN greater than zero are not allowed\n" )); return FALSE; } } #endif // defined(_AMD64_) || defined(_X86_) SpMemFree(p); // // Disallow installation to PCMCIA disks. // if(HardDisks[Region->DiskNumber].PCCard) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpPtDeterminePartitionGood(): Cannot install to PCMCIA disk\n" )); return FALSE; } // // don't choose a removeable drive // #if 0 // // Allow installs to removable media... // if(HardDisks[Region->DiskNumber].Characteristics & FILE_REMOVABLE_MEDIA) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpPtDeterminePartitionGood(): Cannot install to a removable disk\n" )); return FALSE; } #endif // // Disallow installs to removable media or AT formatted drive, on NEC98. // if(IsNEC_98 && ((HardDisks[Region->DiskNumber].Characteristics & FILE_REMOVABLE_MEDIA) || (HardDisks[Region->DiskNumber].FormatType == DISK_FORMAT_TYPE_PCAT))) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpPtDeterminePartitionGood(): Cannot install " "to a removable disk or AT formatted disk\n" )); return FALSE; } // // Calculate the size of the region in KB. // temp.QuadPart = UInt32x32To64( Region->SectorCount, HardDisks[Region->DiskNumber].Geometry.BytesPerSector ); RegionSizeKB = RtlExtendedLargeIntegerDivide(temp,1024,&r).LowPart; // // If the region is not large enough, bail // if (RegionSizeKB < RequiredKB) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpPtDeterminePartitionGood(): Partition does not " "have enough free space: required=%ld, available=%ld\n", RequiredKB, RegionSizeKB )); return FALSE; } if (!Region->PartitionedSpace) { // // can't use a partition with just free space // KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpPtDeterminePartitionGood(): Partition does not " "have any partitioned space\n" )); return FALSE; } SystemId = SpPtGetPartitionType(Region); if (SystemId == PARTITION_ENTRY_UNUSED || IsContainerPartition(SystemId)) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpPtDeterminePartitionGood(): Invalid partition type(1)\n" )); return FALSE; } if(SpPtIsForeignPartition(Region)) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpPtDeterminePartitionGood(): Invalid partition type(2)\n" )); return FALSE; } // // The region is a partition that we recognize. // See whether it has enough free space on it. // if(Region->AdjustedFreeSpaceKB == (ULONG)(-1)) { // // If the partition was newly created during setup // then it is acceptable (because the check to see // if it is large enough was done above). // if(Region->Filesystem != FilesystemNewlyCreated) { // // Otherwise, we don't know how much space is // on the drive so reformat will be necessary. // KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpPtDeterminePartitionGood(): Format is necessary\n" )); return FALSE; } } else { if(Region->AdjustedFreeSpaceKB < RequiredKB) { // // If we get here, then the partition is large enough, // but there is definitely not enough free space on it. // KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpPtDeterminePartitionGood(): Partition does not have " "enough free space: required=%ld, available=%ld\n", RequiredKB, Region->AdjustedFreeSpaceKB )); return FALSE; } } #if defined(_AMD64_) || defined(_X86_) if(!SpIsArc()) { // // On an amd64/x86 machine, make sure that we have a valid primary partition // on drive 0 (C:), for booting. // if (!IsNEC_98) { // this is a standard PC/AT type machine if((systemPartitionRegion = SpPtValidSystemPartition()) == NULL) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpPtDeterminePartitionGood(): Not a valid primary partition\n" )); return FALSE; } // // Make sure the system partition is active and all others are inactive. // SpPtMakeRegionActive(systemPartitionRegion); } else { // // Check existing system on target partition, // If it exists, don't choose it as target partition. // if (SpIsExistsOs(Region)) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpPtDeterminePartitionGood(): OS already exists\n" )); return(FALSE); } // // All of partition is bootable on NEC98, // so we don't need to check system partition on C:. // systemPartitionRegion = Region; } //NEC98 } #endif // defined(_AMD64_) || defined(_X86_) if (DisallowOtherInstalls) { PUCHAR Win9xPath; #ifdef _X86_ if (SpIsWin9xMsdosSys( Region, &Win9xPath )) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpPtDeterminePartitionGood(): Cannot use a partition with WIN9x installed on it\n" )); return FALSE; } #endif if (SpIsNtOnPartition(Region)) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpPtDeterminePartitionGood(): Cannot use a partition with NT installed on it\n" )); return FALSE; } } KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_INFO_LEVEL, "SETUP: SpPtDeterminePartitionGood(): Parition is GOOD :)\n" )); return TRUE; } #if defined(_AMD64_) || defined(_X86_) BOOLEAN SpIsExistsOs( IN OUT PDISK_REGION CColonRegion ) { PUCHAR NewBootCode; ULONG BootCodeSize; PUCHAR ExistingBootCode; NTSTATUS Status; PUCHAR ExistingBootCodeOs; PWSTR CColonPath; HANDLE PartitionHandle; BOOLEAN IsNtBootcode,OtherOsInstalled; UNICODE_STRING UnicodeString; OBJECT_ATTRIBUTES Obja; IO_STATUS_BLOCK IoStatusBlock; BOOLEAN BootSectorCorrupt = FALSE; ULONG BytesPerSector; ULONG ActualSectorCount, hidden_sectors, super_area_size; BOOLEAN IsExist = TRUE; ULONG MirrorSector; PWSTR *FilesToLookFor; ULONG FileCount; PWSTR NtFiles[1] = { L"NTLDR" }; PWSTR ChicagoFiles[1] = { L"IO.SYS" }; ExistingBootCode = NULL; BytesPerSector = HardDisks[CColonRegion->DiskNumber].Geometry.BytesPerSector; switch(CColonRegion->Filesystem) { case FilesystemNewlyCreated: // // If the filesystem is newly-created, then there is // nothing to do, because there can be no previous // operating system. // IsExist = TRUE; return( IsExist ); case FilesystemNtfs: NewBootCode = PC98NtfsBootCode; BootCodeSize = sizeof(PC98NtfsBootCode); ASSERT(BootCodeSize == 8192); break; case FilesystemFat: NewBootCode = PC98FatBootCode; BootCodeSize = sizeof(PC98FatBootCode); ASSERT(BootCodeSize == 512); break; case FilesystemFat32: // // Special hackage required for Fat32 because its NT boot code // is discontiguous. // ASSERT(sizeof(Fat32BootCode) == 1536); NewBootCode = PC98Fat32BootCode; BootCodeSize = 512; break; default: ASSERT(0); IsExist = TRUE; return( IsExist ); } // // Form the device path to C: and open the partition. // SpNtNameFromRegion(CColonRegion,TemporaryBuffer,sizeof(TemporaryBuffer),PartitionOrdinalCurrent); CColonPath = SpDupStringW(TemporaryBuffer); INIT_OBJA(&Obja,&UnicodeString,CColonPath); Status = ZwCreateFile( &PartitionHandle, FILE_GENERIC_READ | FILE_GENERIC_WRITE, &Obja, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 ); if (!NT_SUCCESS(Status)) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: unable to open the partition!\n")); ASSERT(0); IsExist = TRUE; return( IsExist ); } // // Just use the existing boot code. // Status = pSpBootCodeIo( CColonPath, NULL, BootCodeSize, &ExistingBootCode, FILE_OPEN, FALSE, 0, BytesPerSector ); if(CColonRegion->Filesystem == FilesystemNtfs) { MirrorSector = NtfsMirrorBootSector(PartitionHandle,BytesPerSector,NULL); } switch(CColonRegion->Filesystem) { case FilesystemFat: if(NT_SUCCESS(Status)) { // // Determine the type of operating system the existing boot sector(s) are for // and whether that os is actually installed. // SpDetermineOsTypeFromBootSector( CColonPath, ExistingBootCode, &ExistingBootCodeOs, &IsNtBootcode, &OtherOsInstalled, CColonRegion->DriveLetter ); if (OtherOsInstalled == TRUE) { IsExist = TRUE; } else if (IsNtBootcode == TRUE) { wcscpy(TemporaryBuffer,CColonPath); FilesToLookFor = NtFiles; FileCount = ELEMENT_COUNT(NtFiles); if(SpNFilesExist(TemporaryBuffer,FilesToLookFor,FileCount,FALSE)) { IsExist = TRUE; } else { IsExist = FALSE; } } else { IsExist = FALSE; } } else { IsExist = TRUE; } break; case FilesystemFat32: wcscpy(TemporaryBuffer,CColonPath); FilesToLookFor = NtFiles; FileCount = ELEMENT_COUNT(NtFiles); if(SpNFilesExist(TemporaryBuffer,FilesToLookFor,FileCount,FALSE)) { IsExist = TRUE; } FilesToLookFor = ChicagoFiles; FileCount = ELEMENT_COUNT(ChicagoFiles); if(SpNFilesExist(TemporaryBuffer,FilesToLookFor,FileCount,FALSE)) { wcscpy(TemporaryBuffer, CColonPath); SpConcatenatePaths(TemporaryBuffer, L"IO.SYS"); if(SpHasMZHeader(TemporaryBuffer)) { IsExist = TRUE; } else { IsExist = FALSE; } } else { IsExist = FALSE; } break; case FilesystemNtfs: wcscpy(TemporaryBuffer,CColonPath); FilesToLookFor = NtFiles; FileCount = ELEMENT_COUNT(NtFiles); if(SpNFilesExist(TemporaryBuffer,FilesToLookFor,FileCount,FALSE)) { IsExist = TRUE; } else { IsExist = FALSE; } break; default: ASSERT(0); IsExist = TRUE; } SpMemFree(CColonPath); ZwClose (PartitionHandle); return( IsExist ); } #endif // defined(_AMD64_) || defined(_X86_) BOOLEAN SpPtDoPartitionSelection( IN OUT PDISK_REGION *Region, IN PWSTR RegionDescription, IN PVOID SifHandle, IN BOOLEAN Unattended, IN PWSTR SetupSourceDevicePath, IN PWSTR DirectoryOnSetupSource, IN BOOLEAN RemoteBootRepartition, OUT PBOOLEAN Win9xInstallationPresent ) { ULONG RequiredKB; ULONG TempKB; UCHAR SystemId; BOOLEAN NewlyCreated; ULONG PreconfirmFormatId; ULONG ValidKeys1[2] = { ASCI_CR ,0 }; ULONG ValidKeys2[2] = { ASCI_ESC,0 }; ULONG Mnemonics1[2] = { MnemonicContinueSetup, 0 }; ULONG Mnemonics2[2] = { 0,0 }; ULONG RegionSizeKB; ULONG r; #if defined(_AMD64_) || defined(_X86_) PDISK_REGION systemPartitionRegion; #endif // defined(_AMD64_) || defined(_X86_) BOOLEAN AllowNtfsOptions; BOOLEAN AllowFatOptions; ULONG selection; NTSTATUS Status; ULONG Count; PWSTR p; PWSTR RegionDescr; PDISK_REGION region = *Region; LARGE_INTEGER temp; BOOLEAN AllowFormatting; BOOLEAN QuickFormat = FALSE, OtherOSOnPartition; PSTR Win9xPath = NULL; PWCHAR Win9xPathW = NULL; if (Win9xInstallationPresent) { *Win9xInstallationPresent = FALSE; } #if defined(REMOTE_BOOT) // // If this is a remote boot setup on a diskless machine, skip partition // selection (note that we check the RemoteBootSetup global flag, not // the passed-in RemoteBootRepartition flag). // if (RemoteBootSetup && (HardDiskCount == 0)) { return TRUE; } #endif // defined(REMOTE_BOOT) // // Assume that if we need to format the drive, that // the user needs to confirm. // PreconfirmFormatId = 0; NewlyCreated = FALSE; AllowNtfsOptions = TRUE; AllowFatOptions = TRUE; // // Disallow installation to PCMCIA disks. // if(HardDisks[region->DiskNumber].PCCard) { SpDisplayScreen(SP_SCRN_CANT_INSTALL_ON_PCMCIA,3,HEADER_HEIGHT+1); SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_ENTER_EQUALS_CONTINUE,0); SpWaitValidKey(ValidKeys1,NULL,NULL); return(FALSE); } // // Disallow installation to non-platform disk // on clean installs // // AMD64/X86 - Installs only to MBR disks // IA64 - Installs only to GPT disks // if (SPPT_GET_DISK_TYPE(region->DiskNumber) != SPPT_DEFAULT_DISK_STYLE) { SpDisplayScreen(SP_SCRN_INVALID_INSTALLPART, 3, HEADER_HEIGHT+1); SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_ENTER_EQUALS_CONTINUE,0); SpWaitValidKey(ValidKeys1,NULL,NULL); return FALSE; } // // Make sure we can see the disk from the firmware/bios. // If we can get an arc name for the disk, assume it's ok. // Otherwise, it ain't. // if(p = SpNtToArc(HardDisks[region->DiskNumber].DevicePath,PrimaryArcPath)) { #if defined(_AMD64_) || defined(_X86_) // // On amd64/x86 we don't allow disks that have LUN greater than 0 // SpStringToLower( p ); if( wcsstr( p, L"scsi(" ) && wcsstr( p, L")rdisk(" ) ) { if( wcsstr( p, L")rdisk(0)" ) == NULL ) { // // Tell the user that we can't install to that disk. // SpDisplayScreen(SP_SCRN_DISK_NOT_INSTALLABLE_LUN_NOT_SUPPORTED, 3, HEADER_HEIGHT+1); SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_ENTER_EQUALS_CONTINUE,0); SpWaitValidKey(ValidKeys1,NULL,NULL); SpMemFree(p); return(FALSE); } } #endif // defined(_AMD64_) || defined(_X86_) SpMemFree(p); } else { // // Tell the user that we can't install to that disk. // SpDisplayScreen(SP_SCRN_DISK_NOT_INSTALLABLE,3,HEADER_HEIGHT+1); SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_ENTER_EQUALS_CONTINUE,0); SpWaitValidKey(ValidKeys1,NULL,NULL); return(FALSE); } // // Disallow installation of Personal onto dynamic disks // since dynamic disks feature is not available on Personal // if (SpIsProductSuite(VER_SUITE_PERSONAL) && SpPtnIsDynamicDisk(region->DiskNumber)) { SpDisplayScreen(SP_NO_DYNAMIC_DISK_INSTALL, 3, HEADER_HEIGHT + 1); SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE, SP_STAT_ENTER_EQUALS_CONTINUE, 0); SpWaitValidKey(ValidKeys1, NULL, NULL); return FALSE; } // // Fetch the amount of free space required on the windows nt drive. // SpFetchDiskSpaceRequirements( SifHandle, region->BytesPerCluster, &RequiredKB, NULL); // // For remote install, we have not yet copied ~LS, so add that space // in also. // if (RemoteInstallSetup) { SpFetchTempDiskSpaceRequirements( SifHandle, region->BytesPerCluster, &TempKB, NULL); RequiredKB += TempKB; } // // Calculate the size of the region in KB. // temp.QuadPart = UInt32x32To64( region->SectorCount, HardDisks[region->DiskNumber].Geometry.BytesPerSector ); RegionSizeKB = RtlExtendedLargeIntegerDivide(temp,1024,&r).LowPart; // // If the region is not large enough, tell the user. // if(RegionSizeKB < RequiredKB) { SpStartScreen( SP_SCRN_REGION_TOO_SMALL, 3, HEADER_HEIGHT+1, FALSE, FALSE, DEFAULT_ATTRIBUTE, (RequiredKB / 1024) + 1 ); SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_ENTER_EQUALS_CONTINUE,0); SpWaitValidKey(ValidKeys1,NULL,NULL); return(FALSE); } if(region->PartitionedSpace) { if (SpPtIsForeignPartition(region)) { SpStartScreen( SP_SCRN_FOREIGN_PARTITION, 3, HEADER_HEIGHT+1, FALSE, FALSE, DEFAULT_ATTRIBUTE ); SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE, SP_STAT_ENTER_EQUALS_CONTINUE, 0); SpWaitValidKey(ValidKeys1, NULL, NULL); return FALSE; } if (!RemoteBootRepartition) { // // The region is a partition that we recognize. // See whether it has enough free space on it. // if(region->AdjustedFreeSpaceKB == (ULONG)(-1)) { // // If the partition was newly created during setup // then it acceptable (because the check to see // if it is large enough was done above). // if(region->Filesystem != FilesystemNewlyCreated) { // // Otherwise, we don't know how much space is // on the drive so reformat will be necessary. // PreconfirmFormatId = SP_SCRN_UNKNOWN_FREESPACE; } } else { if(region->AdjustedFreeSpaceKB < RequiredKB) { // // If we get here, then the partition is large enough, // but there is definitely not enough free space on it. // CLEAR_CLIENT_SCREEN(); SpDisplayStatusText(SP_STAT_EXAMINING_DISK_CONFIG,DEFAULT_STATUS_ATTRIBUTE); // // We check here to see if this partition is the partition we // booted from (in floppyless case on amd64/x86). // // Also make sure we aren't trying to format the drive w/ // local source. // // If so, then the // user can't format, and we give a generic 'disk too full' // error. // if( ( region->IsLocalSource ) #if defined(_AMD64_) || defined(_X86_) || ( (IsFloppylessBoot) && (region == (SpRegionFromArcName(ArcBootDevicePath, PartitionOrdinalOriginal, NULL))) ) #endif // defined(_AMD64_) || defined(_X86_) ) { SpStartScreen( SP_SCRN_INSUFFICIENT_FREESPACE_NO_FMT, 3, HEADER_HEIGHT+1, FALSE, FALSE, DEFAULT_ATTRIBUTE, (RequiredKB / 1024) + 1 ); SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_ENTER_EQUALS_CONTINUE, 0 ); SpWaitValidKey(ValidKeys1,NULL,NULL); return FALSE; } // // To use the selected partition, we will have to reformat. // Inform the user of that, and let him decide to bail // right here if this is not acceptable. // PreconfirmFormatId = SP_SCRN_INSUFFICIENT_FREESPACE; } } if(PreconfirmFormatId) { // // Do a 'preconfirmation' that the user really wants // to reformat this drive. We'll confirm again later // before actually reformatting anything. // SpStartScreen( PreconfirmFormatId, 3, HEADER_HEIGHT+1, FALSE, FALSE, DEFAULT_ATTRIBUTE, (RequiredKB / 1024) + 1 ); SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_C_EQUALS_CONTINUE_SETUP, SP_STAT_ESC_EQUALS_CANCEL, 0 ); if(SpWaitValidKey(ValidKeys2,NULL,Mnemonics1) == ASCI_ESC) { // // User decided to select a different partition. // return(FALSE); } // otherwise user decided to use the partition anyway. } } } else { // // The region is a free space. Attempt to create a partition // in the space. The create routine will tell us whether this // was successful. If it was not successful, then the create routine // will have already informed the user of why. // PDISK_REGION p; if(!SpPtDoCreate(region,&p,TRUE,0,0,TRUE)) { return(FALSE); } // // If we just created an extended partition and a logical drive, // we'll need to switch regions -- Region points to the extended partition // region, but we want to point to the logical drive region. // ASSERT(p); region = p; *Region = p; NewlyCreated = TRUE; } if(NewlyCreated) { SpPtRegionDescription( &PartitionedDisks[region->DiskNumber], region, TemporaryBuffer, sizeof(TemporaryBuffer) ); RegionDescr = SpDupStringW(TemporaryBuffer); } else { RegionDescr = SpDupStringW(RegionDescription); } OtherOSOnPartition = FALSE; if( SpIsNtOnPartition( region ) ) OtherOSOnPartition = TRUE; #if defined(_AMD64_) || defined(_X86_) if(!SpIsArc()) { // // On an amd64/x86 machine, make sure that we have a valid primary partition // on drive 0 (C:), for booting. // if (!IsNEC_98) { //NEC98 if((systemPartitionRegion = SpPtValidSystemPartition()) == NULL) { SpStartScreen( SP_SCRN_NO_VALID_C_COLON, 3, HEADER_HEIGHT+1, FALSE, FALSE, DEFAULT_ATTRIBUTE, HardDisks[SpDetermineDisk0()].Description ); SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_ENTER_EQUALS_CONTINUE,0); SpWaitValidKey(ValidKeys1,NULL,NULL); SpMemFree(RegionDescr); return(FALSE); } // // Make sure the system partition is active and all others are inactive. // SpPtMakeRegionActive(systemPartitionRegion); // // Warn user about win9x installations on same partition // #if defined(_X86_) if( !OtherOSOnPartition && SpIsWin9xMsdosSys( systemPartitionRegion, &Win9xPath )){ Win9xPathW = SpToUnicode(Win9xPath); if(SpIsWin4Dir(region, Win9xPathW)) { OtherOSOnPartition = TRUE; if (Win9xInstallationPresent) { *Win9xInstallationPresent = TRUE; } } SpMemFree(Win9xPathW); } if(Win9xPath) { SpMemFree(Win9xPath); } #endif // defined(_X86_) } else { // // All of partition is bootable on NEC98, // so we don't need to check system partition on C:. // systemPartitionRegion = *Region; } //NEC98 } #endif // defined(_AMD64_) || defined(_X86_) // // Display common warning for other OS on partition // if( OtherOSOnPartition && !Unattended ){ SpDisplayScreen(SP_SCRN_OTHEROS_ON_PARTITION,3,HEADER_HEIGHT+1); SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_C_EQUALS_CONTINUE_SETUP, SP_STAT_ESC_EQUALS_CANCEL, 0 ); if(SpWaitValidKey(ValidKeys2,NULL,Mnemonics1) == ASCI_ESC) { return(FALSE); } // // Remove the boot sets which are already present for // this partition in boot.ini, if any. This aids in // disabling the other OSes installed on the same // partition // // // NOTE : We want to really think about enforcing // single installs on a partition, so for the time // being disable it // // SpPtDeleteBootSetsForRegion(region); } // // At this point, everything is fine, so commit any // partition changes the user may have made. // This won't return if an error occurs while updating the disk. // SpPtDoCommitChanges(); // // Attempt to grow the partition the system will be on // if necessary. // if(PreInstall && Unattended && (p = SpGetSectionKeyIndex(UnattendedSifHandle,SIF_UNATTENDED,SIF_EXTENDOEMPART,0)) && (Count = SpStringToLong(p,NULL,10))) { // // 1 means size it maximally, any other non-0 number means // extend by that many MB // ExtendingOemPartition = SpPtExtend(region,(Count == 1) ? 0 : Count); } #if defined(_AMD64_) || defined(_X86_) if(!SpIsArc()) { // // On an amd64/x86 machine, see whether we need to format C: and if so, // go ahead and do it. If the system is going on C:, then don't // bother with this here because it will be covered in the options // for the target NT partition. // if(systemPartitionRegion != region) { PWSTR SysPartRegionDescr; BOOLEAN bValidCColon; SpPtRegionDescription( &PartitionedDisks[systemPartitionRegion->DiskNumber], systemPartitionRegion, TemporaryBuffer, sizeof(TemporaryBuffer) ); SysPartRegionDescr = SpDupStringW(TemporaryBuffer); bValidCColon = SpPtValidateCColonFormat(SifHandle, SysPartRegionDescr, systemPartitionRegion, FALSE, SetupSourceDevicePath, DirectoryOnSetupSource); SpMemFree(SysPartRegionDescr); if(!bValidCColon) { SpMemFree(RegionDescr); return(FALSE); } } }else #endif // defined(_AMD64_) || defined(_X86_) { // // If we are going to install on the system partition, // issue a special warning because it can't be converted to ntfs. // if((region->IsSystemPartition == 2) && !Unattended) { ULONG ValidKeys[3] = { ASCI_CR, ASCI_ESC, 0 }; SpDisplayScreen(SP_SCRN_INSTALL_ON_SYSPART,3,HEADER_HEIGHT+1); SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_ENTER_EQUALS_CONTINUE, SP_STAT_ESC_EQUALS_CANCEL, 0 ); if(SpWaitValidKey(ValidKeys,NULL,NULL) == ASCI_ESC) { SpMemFree(RegionDescr); return(FALSE); } AllowNtfsOptions = FALSE; } } if( SpPtSectorCountToMB( &(HardDisks[region->DiskNumber]), region->SectorCount ) > 32*1024 ) { // // If the partition size is greater than 32 GB, then we don't allow Fat formatting, // because Fat32 does not support partitions that are that big. // AllowFatOptions = FALSE; } // // Present formatting/conversion options to the user. // // // If the partition was newly created, the only option is // to format the partition. Ditto if the partition is // a 'bad' partition -- damaged, can't tell free space, etc. // if(NewlyCreated || (region->Filesystem < FilesystemFirstKnown) || (region->FreeSpaceKB == (ULONG)(-1)) || (region->AdjustedFreeSpaceKB < RequiredKB) || RemoteBootRepartition) { if (RemoteBootRepartition) { // // For remote boot we always quick format as NTFS without // prompting the user. // selection = FormatOptionNtfs; QuickFormat = TRUE; } else { if(NewlyCreated) { SpStartScreen( SP_SCRN_FORMAT_NEW_PART, 3, HEADER_HEIGHT+1, FALSE, FALSE, DEFAULT_ATTRIBUTE, HardDisks[region->DiskNumber].Description ); } else if(region->Filesystem == FilesystemNewlyCreated) { SpDisplayScreen(SP_SCRN_FORMAT_NEW_PART2,3,HEADER_HEIGHT+1); } else { SpStartScreen( SP_SCRN_FORMAT_BAD_PART, 3, HEADER_HEIGHT+1, FALSE, FALSE, DEFAULT_ATTRIBUTE, RegionDescr, HardDisks[region->DiskNumber].Description ); } selection = SpFormattingOptions( AllowFatOptions, AllowNtfsOptions, FALSE, FALSE, TRUE ); } switch(selection) { case FormatOptionCancel: SpMemFree(RegionDescr); return(FALSE); default: // // Format the partition right here and now. // if ((selection == FormatOptionFatQuick) || (selection == FormatOptionNtfsQuick)) QuickFormat = TRUE; Status = SpDoFormat( RegionDescr, region, ((selection == FormatOptionNtfs) || (selection == FormatOptionNtfsQuick)) ? FilesystemNtfs : FilesystemFat, FALSE, TRUE, QuickFormat, SifHandle, 0, // default cluster size SetupSourceDevicePath, DirectoryOnSetupSource ); SpMemFree(RegionDescr); return(NT_SUCCESS(Status)); } } // // The partition is acceptable as-is. // Options are to reformat to fat or ntfs, or to leave as-is. // If it's FAT, converting to ntfs is an option // unless we're installing onto an ARC system partition. // SpStartScreen( SP_SCRN_FS_OPTIONS, 3, HEADER_HEIGHT+1, FALSE, FALSE, DEFAULT_ATTRIBUTE, RegionDescr, HardDisks[region->DiskNumber].Description ); // // If this is a winnt installation, don't want to let the user // reformat the local source partition! // // Also, don't let them reformat if this is the partition we booted // off of (in amd64/x86 floppyless boot case). // AllowFormatting = !region->IsLocalSource; #if defined(_AMD64_) || defined(_X86_) if(AllowFormatting) { AllowFormatting = !(IsFloppylessBoot && (region == (SpRegionFromArcName(ArcBootDevicePath, PartitionOrdinalOriginal, NULL)))); } #endif // defined(_AMD64_) || defined(_X86_) selection = SpFormattingOptions( (BOOLEAN)(AllowFormatting ? AllowFatOptions : FALSE), (BOOLEAN)(AllowFormatting ? AllowNtfsOptions : FALSE), (BOOLEAN)(AllowNtfsOptions && (BOOLEAN)(region->Filesystem != FilesystemNtfs)), TRUE, TRUE ); switch(selection) { case FormatOptionDoNothing: SpMemFree(RegionDescr); return(TRUE); case FormatOptionFat: case FormatOptionFatQuick: case FormatOptionNtfs: case FormatOptionNtfsQuick: // // Confirm the format. // if( ( region->Filesystem != FilesystemFat ) || ( ( region->Filesystem == FilesystemFat ) && ( ( Count = SpGetNumberOfCompressedDrives( region ) ) == 0 ) ) ) { SpStartScreen( SP_SCRN_CONFIRM_FORMAT, 3, HEADER_HEIGHT+1, FALSE, FALSE, DEFAULT_ATTRIBUTE, RegionDescr, HardDisks[region->DiskNumber].Description ); } else { SpStartScreen( SP_SCRN_CONFIRM_FORMAT_COMPRESSED, 3, HEADER_HEIGHT+1, FALSE, FALSE, DEFAULT_ATTRIBUTE, RegionDescr, HardDisks[region->DiskNumber].Description, Count ); } SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_F_EQUALS_FORMAT, SP_STAT_ESC_EQUALS_CANCEL, 0 ); Mnemonics2[0] = MnemonicFormat; if(SpWaitValidKey(ValidKeys2,NULL,Mnemonics2) == ASCI_ESC) { SpMemFree(RegionDescr); return(FALSE); } if ((selection == FormatOptionNtfsQuick) || (selection == FormatOptionFatQuick)) QuickFormat = TRUE; // // Format the partition right here and now. // Status = SpDoFormat( RegionDescr, region, ((selection == FormatOptionNtfs) || (selection == FormatOptionNtfsQuick)) ? FilesystemNtfs : FilesystemFat, FALSE, TRUE, QuickFormat, SifHandle, 0, // default cluster size SetupSourceDevicePath, DirectoryOnSetupSource ); SpMemFree(RegionDescr); return(NT_SUCCESS(Status)); case FormatOptionCancel: SpMemFree(RegionDescr); return(FALSE); case FormatOptionConvertToNtfs: if(!UnattendedOperation) { // // Confirm that the user really wants to do this. // if( ( Count = SpGetNumberOfCompressedDrives( region ) ) == 0 ) { SpStartScreen( SP_SCRN_CONFIRM_CONVERT, 3, HEADER_HEIGHT+1, FALSE, FALSE, DEFAULT_ATTRIBUTE, RegionDescr, HardDisks[region->DiskNumber].Description ); } else { SpStartScreen( SP_SCRN_CONFIRM_CONVERT_COMPRESSED, 3, HEADER_HEIGHT+1, FALSE, FALSE, DEFAULT_ATTRIBUTE, RegionDescr, HardDisks[region->DiskNumber].Description, Count ); } SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_C_EQUALS_CONVERT, SP_STAT_ESC_EQUALS_CANCEL, 0 ); Mnemonics2[0] = MnemonicConvert; if(SpWaitValidKey(ValidKeys2,NULL,Mnemonics2) == ASCI_ESC) { SpMemFree(RegionDescr); return(FALSE); } } // // Remember that we need to convert the NT drive to NTFS. // ConvertNtVolumeToNtfs = TRUE; SpMemFree(RegionDescr); return(TRUE); } // // Should never get here. // SpMemFree(RegionDescr); ASSERT(FALSE); return(FALSE); } ULONG SpFormattingOptions( IN BOOLEAN AllowFatFormat, IN BOOLEAN AllowNtfsFormat, IN BOOLEAN AllowConvertNtfs, IN BOOLEAN AllowDoNothing, IN BOOLEAN AllowEscape ) /*++ Routine Description: Present a menu of formatting options and allow the user to choose among them. The text describing the menu must already be present on-screen. The user may also press escape to indicate that he wants to select a different partition. Arguments: AllowFatFormat - TRUE if the option to format the partition to FAT should be presented in the menu. AllowNtfsFormat - TRUE if the option to format the partition to NTFS should be presented in the menu. AllowConvertNtfs - TRUE if the option to convert the partition to NTFS should be presented in the menu. AllowDoNothing - TRUE if the option to leave the partition as-is should be presented in the menu. Return Value: Value from the FormatOptions enum indicating the outcome of the user's interaction with the menu, which will be FormatOptionCancel if the user pressed escape. --*/ { ULONG FatFormatOption = (ULONG)(-1); ULONG NtfsFormatOption = (ULONG)(-1); ULONG FatQFormatOption = (ULONG)(-1); ULONG NtfsQFormatOption = (ULONG)(-1); ULONG ConvertNtfsOption = (ULONG)(-1); ULONG DoNothingOption = (ULONG)(-1); ULONG OptionCount = 0; PVOID Menu; WCHAR FatQFormatText[128]; WCHAR NtfsQFormatText[128]; WCHAR FatFormatText[128]; WCHAR NtfsFormatText[128]; WCHAR ConvertNtfsText[128]; WCHAR DoNothingText[128]; WCHAR QuickText[128]; ULONG MaxLength; ULONG Key; ULONG_PTR Selection; BOOLEAN Chosen; ULONG ValidKeys[4] = { ASCI_CR, KEY_F3, 0, 0 }; if (AllowEscape) { ValidKeys[2] = ASCI_ESC; } // // If the only thing we're allowed to do is nothing, just return. // if(!AllowFatFormat && !AllowNtfsFormat && !AllowConvertNtfs && AllowDoNothing) { return(FormatOptionDoNothing); } // // The FileSystem entry might be in the unattend section if we're // in unattend mode. if we aren't in unattend mode, it may be in // the data section. // // If we fail to find it in either place, then if we're unattended // we return DoNothing. If we're attended, fall through to the attended // case. // if( ( UnattendedSifHandle && (Menu = SpGetSectionKeyIndex(UnattendedSifHandle,SIF_UNATTENDED,L"Filesystem",0)) ) || ( WinntSifHandle && (Menu = SpGetSectionKeyIndex(WinntSifHandle,SIF_DATA,L"Filesystem",0)) ) ) { if(!_wcsicmp(Menu,L"FormatFat") && AllowFatFormat) { return(FormatOptionFat); } if(!_wcsicmp(Menu,L"FormatNtfs") && AllowNtfsFormat) { return(FormatOptionNtfs); } if(!_wcsicmp(Menu,L"ConvertNtfs") && AllowConvertNtfs) { return(FormatOptionConvertToNtfs); } if( (!_wcsicmp(Menu,L"ConvertNtfs")) && (!AllowConvertNtfs) && (AllowDoNothing) ) { return(FormatOptionDoNothing); } if(!_wcsicmp(Menu,L"LeaveAlone") && AllowDoNothing) { return(FormatOptionDoNothing); } } else { if(UnattendedOperation && AllowDoNothing) { return(FormatOptionDoNothing); } } ASSERT(AllowFatFormat || AllowNtfsFormat || AllowConvertNtfs || AllowDoNothing); SpFormatMessage(FatFormatText ,sizeof(FatFormatText),SP_TEXT_FAT_FORMAT); SpFormatMessage(NtfsFormatText ,sizeof(FatFormatText),SP_TEXT_NTFS_FORMAT); SpFormatMessage(ConvertNtfsText,sizeof(FatFormatText),SP_TEXT_NTFS_CONVERT); SpFormatMessage(DoNothingText ,sizeof(FatFormatText),SP_TEXT_DO_NOTHING); SpFormatMessage(QuickText, sizeof(QuickText), SP_TEXT_FORMAT_QUICK); wcscpy(FatQFormatText, FatFormatText); wcscat(FatQFormatText, QuickText); wcscpy(NtfsQFormatText, NtfsFormatText); wcscat(NtfsQFormatText, QuickText); // // Determine maximum length of the option strings. // MaxLength = wcslen(FatFormatText); MaxLength = max(wcslen(NtfsFormatText), MaxLength); MaxLength = max(wcslen(ConvertNtfsText), MaxLength); MaxLength = max(wcslen(DoNothingText), MaxLength); MaxLength = max(wcslen(FatQFormatText), MaxLength); MaxLength = max(wcslen(NtfsQFormatText), MaxLength); Menu = SpMnCreate(5, NextMessageTopLine + 1, VideoVars.ScreenWidth - 5, 6); // // If we cannot create menu then cancel the formatting // request itself // if (!Menu) { return FormatOptionCancel; } #ifdef NEW_PARTITION_ENGINE if(AllowNtfsFormat) { NtfsQFormatOption = OptionCount++; SpMnAddItem(Menu, NtfsQFormatText, 5, MaxLength, TRUE, NtfsQFormatOption); } if(AllowFatFormat) { FatQFormatOption = OptionCount++; SpMnAddItem(Menu, FatQFormatText, 5, MaxLength, TRUE, FatQFormatOption); } #endif if(AllowNtfsFormat) { NtfsFormatOption = OptionCount++; SpMnAddItem(Menu, NtfsFormatText, 5, MaxLength, TRUE, NtfsFormatOption); } if(AllowFatFormat) { FatFormatOption = OptionCount++; SpMnAddItem(Menu, FatFormatText, 5, MaxLength, TRUE, FatFormatOption); } if(AllowConvertNtfs) { ConvertNtfsOption = OptionCount++; SpMnAddItem(Menu, ConvertNtfsText, 5, MaxLength, TRUE, ConvertNtfsOption); } if(AllowDoNothing) { DoNothingOption = OptionCount++; SpMnAddItem(Menu, DoNothingText, 5, MaxLength, TRUE, DoNothingOption); } // // Determine the default. // If do nothing if an option, then it is the default. // Otherwise, if fat format is allowed, it is the default. // Otherwise, the first item in the menu is the default. // if(AllowDoNothing) { Selection = DoNothingOption; } else { if(AllowNtfsFormat) { Selection = NtfsFormatOption; } else { Selection = 0; } } // // Display the menu. // Chosen = FALSE; do { SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_ENTER_EQUALS_CONTINUE, AllowEscape ? SP_STAT_ESC_EQUALS_CANCEL : 0, 0 ); SpMnDisplay(Menu, Selection, FALSE, ValidKeys, NULL, NULL, NULL, &Key, &Selection); switch(Key) { case ASCI_CR: Chosen = TRUE; break; case ASCI_ESC: if (AllowEscape) { SpMnDestroy(Menu); return(FormatOptionCancel); } } } while(!Chosen); SpMnDestroy(Menu); // // Convert chosen option to a meaningful value. // if(Selection == FatQFormatOption) { return(FormatOptionFatQuick); } if(Selection == NtfsQFormatOption) { return(FormatOptionNtfsQuick); } if(Selection == FatFormatOption) { return(FormatOptionFat); } if(Selection == NtfsFormatOption) { return(FormatOptionNtfs); } if(Selection == ConvertNtfsOption) { return(FormatOptionConvertToNtfs); } if(Selection == DoNothingOption) { return(FormatOptionDoNothing); } ASSERT(FALSE); return(FormatOptionCancel); } VOID SpPtDoCommitChanges( VOID ) { NTSTATUS Status; ULONG i; BOOLEAN Changes; BOOLEAN AnyChanges = FALSE; CLEAR_CLIENT_SCREEN(); // // Update dblspace.ini, if necessary // SpUpdateDoubleSpaceIni(); // // Iterate through the disks. // for(i=0; iDiskNumber]), Region->SectorCount ); if(RegionSizeMB > 2048) { if(CheckFatSize) { do { SpStartScreen( SP_SCRN_OSPART_LARGE, 3, HEADER_HEIGHT+1, FALSE, FALSE, DEFAULT_ATTRIBUTE ); SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_ENTER_EQUALS_CONTINUE, SP_STAT_ESC_EQUALS_CANCEL, SP_STAT_F3_EQUALS_EXIT, 0 ); switch(Key = SpWaitValidKey(ValidKeys2,NULL,NULL)) { case KEY_F3: SpConfirmExit(); break; case ASCI_ESC: return(STATUS_UNSUCCESSFUL); } } while(Key != ASCI_CR); } FilesystemType = FilesystemFat32; } } AutofrmtRunning = TRUE; Status = SpRunAutoFormat( SifHandle, RegionDescr, Region, FilesystemType, QuickFormat, ClusterSize, SetupSourceDevicePath, DirectoryOnSetupSource ); AutofrmtRunning = FALSE; if(!NT_SUCCESS(Status)) { KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: unable to format (%lx)\n",Status)); if(IsFailureFatal) { // // Then we can't continue (this means that the system partition // couldn't be formatted). // WCHAR DriveLetterString[2]; DriveLetterString[0] = Region->DriveLetter; DriveLetterString[1] = L'\0'; SpStringToUpper(DriveLetterString); SpStartScreen(SP_SCRN_SYSPART_FORMAT_ERROR, 3, HEADER_HEIGHT+1, FALSE, FALSE, DEFAULT_ATTRIBUTE, DriveLetterString ); SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_F3_EQUALS_EXIT,0); SpInputDrain(); while(SpInputGetKeypress() != KEY_F3) ; SpDone(0,FALSE,TRUE); } else { // // Put up an error screen. // SpDisplayScreen(SP_SCRN_FORMAT_ERROR,3,HEADER_HEIGHT+1); SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_ENTER_EQUALS_CONTINUE, 0 ); SpInputDrain(); while(SpInputGetKeypress() != ASCI_CR) ; return(Status); } } else { // // Partition was successfuly formatted. // Save the file system type on the region description. // Region->Filesystem = FilesystemType; SpFormatMessage( Region->TypeName, sizeof(Region->TypeName), SP_TEXT_FS_NAME_BASE + Region->Filesystem ); // // Reset the volume label // Region->VolumeLabel[0] = L'\0'; // Clean up boot.ini entries that referred to this partition SpRemoveInstallationFromBootList( NULL, Region, NULL, NULL, NULL, PrimaryArcPath, NULL ); #if defined(_AMD64_) || defined(_X86_) // call again to delete the secondary Arc name SpRemoveInstallationFromBootList( NULL, Region, NULL, NULL, NULL, SecondaryArcPath, NULL ); #endif // defined(_AMD64_) || defined(_X86_) } return(STATUS_SUCCESS); } // // dummy entry points for the cmd console // VOID SpDetermineOsTypeFromBootSectorC( IN PWSTR CColonPath, IN PUCHAR BootSector, OUT PUCHAR *OsDescription, OUT PBOOLEAN IsNtBootcode, OUT PBOOLEAN IsOtherOsInstalled, IN WCHAR DriveLetter ) { #if defined(_AMD64_) || defined(_X86_) SpDetermineOsTypeFromBootSector( CColonPath, BootSector, OsDescription, IsNtBootcode, IsOtherOsInstalled, DriveLetter ); #else *OsDescription = NULL; *IsNtBootcode = FALSE; *IsOtherOsInstalled = FALSE; return; #endif // defined(_AMD64_) || defined(_X86_) } NTSTATUS pSpBootCodeIoC( IN PWSTR FilePath, IN PWSTR AdditionalFilePath, OPTIONAL IN ULONG BytesToRead, IN OUT PUCHAR *Buffer, IN ULONG OpenDisposition, IN BOOLEAN Write, IN ULONGLONG Offset, IN ULONG BytesPerSector ) { #if defined(_AMD64_) || defined(_X86_) return pSpBootCodeIo( FilePath, AdditionalFilePath, BytesToRead, Buffer, OpenDisposition, Write, Offset, BytesPerSector ); #else return STATUS_NOT_IMPLEMENTED; #endif // defined(_AMD64_) || defined(_X86_) } #ifdef OLD_PARTITION_ENGINE VOID SpPtMakeRegionActive( IN PDISK_REGION Region ) /*++ Routine Description: Make a partition active and make sure all other primary partitions are inactive. The partition must be on disk 0. If a region is found active that is not the region we want to be active, tell the user that his other operating system will be disabled. NOTE: Any changes made here are not committed automatically! Arguments: Region - supplies disk region descriptor for the partition to activate. This region must be on disk 0. Return Value: None. --*/ { ULONG i; static BOOLEAN WarnedOtherOs = FALSE; ASSERT(Region->DiskNumber == SpDetermineDisk0()); if(Region->DiskNumber != SpDetermineDisk0()) { return; } // // Make sure the system partition is active and all others are inactive. // If we find Boot Manager, present a warning that we are going to disable it. // If we find some other operating system is active, present a generic warning. // for(i=0; iDiskNumber].MbrInfo.OnDiskMbr.PartitionTable[i]; if(pte->ActiveFlag) { // // If this is not the region we want to be the system partition, // then investigate its type. // if(i != Region->TablePosition) { // // If this is boot manager, give a specific warning. // Otherwise, give a general warning. // if(!WarnedOtherOs && !UnattendedOperation) { SpDisplayScreen( (pte->SystemId == 10) ? SP_SCRN_BOOT_MANAGER : SP_SCRN_OTHER_OS_ACTIVE, 3, HEADER_HEIGHT+1 ); SpDisplayStatusText(SP_STAT_ENTER_EQUALS_CONTINUE,DEFAULT_STATUS_ATTRIBUTE); SpInputDrain(); while(SpInputGetKeypress() != ASCI_CR) ; WarnedOtherOs = TRUE; } } } } ASSERT(Region->PartitionedSpace); ASSERT(Region->TablePosition < PTABLE_DIMENSION); SpPtMarkActive(Region->TablePosition); } #endif BOOLEAN SpPtValidateCColonFormat( IN PVOID SifHandle, IN PWSTR RegionDescr, IN PDISK_REGION Region, IN BOOLEAN CheckOnly, IN PWSTR SetupSourceDevicePath, IN PWSTR DirectoryOnSetupSource ) /*++ Routine Description: Inspect C: to make sure it is formatted with a filesystem we recognize, and has enough free space on it for the boot files. If any of these tests fail, tell the user that we will have to reformat C: to continue, and give the option of returning to the partitioning screen or continuing anyway. If the user opts to continue, then format the partition to FAT before returning. Arguments: SifHandle - supplies handle to txtsetup.sif. This is used to fetch the value indicating how much space is required on C:. Region - supplies disk region descriptor for C:. Return Value: TRUE if, upon returning from this routine, C: is acceptable. FALSE if not, which could mean that the user asked us not to format his C:, or that the format failed. --*/ { ULONG MinFreeKB; ULONG ValidKeys[3] = { ASCI_ESC, KEY_F3, 0 }; ULONG ValidKeys3[2] = { KEY_F3, 0 }; ULONG ValidKeys4[4] = { ASCI_CR, ASCI_ESC, KEY_F3, 0 }; ULONG Mnemonics[2] = { MnemonicFormat,0 }; ULONG Key; BOOLEAN Confirm; BOOLEAN Fat32; NTSTATUS Status; ULONGLONG RegionSizeMB; WCHAR DriveLetterString[2]; BOOLEAN QuickFormat = TRUE; ULONG FileSystem = FilesystemFat; BOOLEAN AllowFat = FALSE; // // Initialize the drive letter string, to be used in the various error messages // DriveLetterString[0] = Region->DriveLetter; DriveLetterString[1] = L'\0'; SpStringToUpper(DriveLetterString); // // Get the minimum free space required for C:. // SpFetchDiskSpaceRequirements( SifHandle, Region->BytesPerCluster, NULL, &MinFreeKB ); d1: // // If the user newly created the C: drive, no confirmation is // necessary. // if(Region->Filesystem == FilesystemNewlyCreated) { // // Shouldn't be newly created if we're checking // to see whether we should do an upgrade, because we // haven't gotten to the partitioning screen yet. // ASSERT(!CheckOnly); Confirm = FALSE; // // If we don't know the filesystem on C: or we can't determine the // free space, then we need to format the drive, and will confirm first. // } else if((Region->Filesystem == FilesystemUnknown) || (Region->FreeSpaceKB == (ULONG)(-1))) { if(CheckOnly) { return(FALSE); } SpStartScreen(SP_SCRN_C_UNKNOWN, 3, HEADER_HEIGHT+1, FALSE, FALSE, DEFAULT_ATTRIBUTE, DriveLetterString ); Confirm = TRUE; // // If C: is too full, then we need to format over it. // Confirm first. // } else if(Region->FreeSpaceKB < MinFreeKB) { if(CheckOnly) { return(FALSE); } // // If this is a floppyless boot, then the user (probably) cannot // format, and has no choice but to exit Setup and free some space. // if( IsFloppylessBoot && (Region == (SpRegionFromArcName(ArcBootDevicePath, PartitionOrdinalOriginal, NULL)))) { SpStartScreen( SP_SCRN_C_FULL_NO_FMT, 3, HEADER_HEIGHT+1, FALSE, FALSE, DEFAULT_ATTRIBUTE, MinFreeKB, DriveLetterString ); SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_F3_EQUALS_EXIT, 0 ); SpWaitValidKey(ValidKeys3,NULL,NULL); SpDone(0,FALSE,TRUE); } Confirm = TRUE; SpStartScreen( SP_SCRN_C_FULL, 3, HEADER_HEIGHT+1, FALSE, FALSE, DEFAULT_ATTRIBUTE, MinFreeKB, DriveLetterString ); // // If all of the above tests fail, then the partition is acceptable as-is. // } else { return(TRUE); } // // If we are supposed to confirm, then do that here, forcing the // user to press F if he really wants to format or esc to bail. // if(Confirm) { SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_ESC_EQUALS_CANCEL, SP_STAT_F_EQUALS_FORMAT, SP_STAT_F3_EQUALS_EXIT, 0 ); switch(SpWaitValidKey(ValidKeys,NULL,Mnemonics)) { case KEY_F3: SpConfirmExit(); goto d1; case ASCI_ESC: // // User bailed. // return(FALSE); default: // // Must be F. // break; } } // // Whistler formats only 32GB Fat32 partitions // AllowFat = (SPPT_REGION_FREESPACE_GB(Region) <= 32); // // Prompt the user for the formatting options // if (!UnattendedOperation) { ULONG Selection; SpDisplayScreen(SP_SCRN_FORMAT_NEW_PART3, 3, HEADER_HEIGHT+1); SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE, SP_STAT_ENTER_EQUALS_SELECT, 0); Selection = SpFormattingOptions( AllowFat, TRUE, FALSE, FALSE, TRUE); if ((Selection != FormatOptionFatQuick) && (Selection != FormatOptionNtfsQuick)) { QuickFormat = FALSE; } if ((Selection == FormatOptionNtfs) || (Selection == FormatOptionNtfsQuick)) { FileSystem = FilesystemNtfs; } if (Selection == FormatOptionCancel) { return FALSE; // user bailed out } } if (!AllowFat && ((FileSystem == FilesystemFat) || (FileSystem == FilesystemFat32))) { FileSystem = FilesystemNtfs; } if (FileSystem == FilesystemFat) { // // If the partition is larger than 2048MB then we want to make it // Fat32. Ask the user first. // Fat32 = FALSE; RegionSizeMB = SpPtSectorCountToMB( &(HardDisks[Region->DiskNumber]), Region->SectorCount ); if(RegionSizeMB > 2048) { do { SpStartScreen( SP_SCRN_C_LARGE, 3, HEADER_HEIGHT+1, FALSE, FALSE, DEFAULT_ATTRIBUTE, DriveLetterString ); SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_ENTER_EQUALS_CONTINUE, SP_STAT_ESC_EQUALS_CANCEL, SP_STAT_F3_EQUALS_EXIT, 0 ); switch(Key = SpWaitValidKey(ValidKeys4,NULL,NULL)) { case KEY_F3: SpConfirmExit(); break; case ASCI_ESC: return(FALSE); } } while(Key != ASCI_CR); Fat32 = TRUE; } FileSystem = Fat32 ? FilesystemFat32 : FilesystemFat; } if(!Confirm) { // // Just put up an information screen so the user doesn't // go bonkers when we just start formatting his newly created C:. // SpStartScreen(SP_SCRN_ABOUT_TO_FORMAT_C, 3, HEADER_HEIGHT+1, FALSE, FALSE, DEFAULT_ATTRIBUTE, DriveLetterString ); SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_ENTER_EQUALS_CONTINUE,0); SpInputDrain(); while(SpInputGetKeypress() != ASCI_CR) ; } // // Do the format. // Status = SpDoFormat( RegionDescr, Region, FileSystem, TRUE, FALSE, QuickFormat, SifHandle, 0, // default cluster size SetupSourceDevicePath, DirectoryOnSetupSource ); if(NT_SUCCESS(Status)) { // // At this point we must initialize the available free space on the partition. Otherwise, // SpPtValidateCColonFormat() will not recognized this partition, if it is called again. // This can happen if the user decides not format the partition (newly created or unformatted), // that he initially selected as the target partition. // SpPtDetermineRegionSpace(Region); } return(NT_SUCCESS(Status)); } #ifndef NEW_PARTITION_ENGINE PDISK_REGION SpPtValidSystemPartition( VOID ) /*++ Routine Description: Determine whether there is a valid disk partition suitable for use as the system partition on an x86 machine (ie, C:). A primary, recognized (1/4/6/7 type) partition on disk 0 is suitable. If there is a partition that meets these criteria that is marked active, then it is the system partition, regardless of whether there are other partitions that also meet the criteria. Arguments: None. Return Value: Pointer to a disk region descriptor for a suitable system partition (C:) for an x86 machine. NULL if no such partition currently exists. --*/ { PON_DISK_PTE pte; PDISK_REGION pRegion,pActiveRegion,pFirstRegion; ULONG DiskNumber; pActiveRegion = NULL; pFirstRegion = NULL; DiskNumber = SpDetermineDisk0(); #if defined(REMOTE_BOOT) // // If this is a diskless remote boot setup, there is no drive 0. // if ( DiskNumber == (ULONG)-1 ) { return NULL; } #endif // defined(REMOTE_BOOT) #ifdef GPT_PARTITION_ENGINE if (SPPT_IS_GPT_DISK(DiskNumber)) { return SpPtnValidSystemPartition(); } #endif // // Look for the active partition on drive 0 // and for the first recognized primary partition on drive 0. // for(pRegion=PartitionedDisks[DiskNumber].PrimaryDiskRegions; pRegion; pRegion=pRegion->Next) { if(pRegion->PartitionedSpace) { UCHAR TmpSysId; ASSERT(pRegion->TablePosition < PTABLE_DIMENSION); pte = &pRegion->MbrInfo->OnDiskMbr.PartitionTable[pRegion->TablePosition]; ASSERT(pte->SystemId != PARTITION_ENTRY_UNUSED); // // Skip if not recognized. // In the repair case, we recognize FT partitions // TmpSysId = pte->SystemId; if( !IsContainerPartition(TmpSysId) && ( (PartitionNameIds[pte->SystemId] == (UCHAR)(-1)) || (pRegion->DynamicVolume && pRegion->DynamicVolumeSuitableForOS) || ((RepairWinnt || WinntSetup || SpDrEnabled() ) && pRegion->FtPartition ) ) ) { // // Remember it if it's active. // if((pte->ActiveFlag) && !pActiveRegion) { pActiveRegion = pRegion; } // // Remember it if it's the first one we've seen. // if(!pFirstRegion) { pFirstRegion = pRegion; } } } } // // If there is an active, recognized region, use it as the // system partition. Otherwise, use the first primary // we encountered as the system partition. If there is // no recognized primary, then there is no valid system partition. // return(pActiveRegion ? pActiveRegion : pFirstRegion); } #endif // ! NEW_PARTITION_ENGINE ULONG SpDetermineDisk0( VOID ) /*++ Routine Description: Determine the real disk 0, which may not be the same as \device\harddisk0. Consider the case where we have 2 scsi adapters and the NT drivers load in an order such that the one with the BIOS gets loaded *second* -- meaning that the system partition is actually on disk 1, not disk 0. Arguments: None. Return Value: NT disk ordinal suitable for use in generating nt device paths of the form \device\harddiskx. --*/ { ULONG DiskNumber = (ULONG)-1; ULONG CurrentDisk = 0; WCHAR ArcDiskName[MAX_PATH]; // // Find the first harddisk (non-removable) media that the // BIOS enumerated to be used for system partition // while (CurrentDisk < HardDiskCount) { swprintf(ArcDiskName, L"multi(0)disk(0)rdisk(%d)", CurrentDisk); DiskNumber = SpArcDevicePathToDiskNumber(ArcDiskName); if (DiskNumber != (ULONG)-1) { if (!SPPT_IS_REMOVABLE_DISK(DiskNumber)) { break; } else { DiskNumber = (ULONG)-1; } } CurrentDisk++; } #if defined(REMOTE_BOOT) // // If this is a diskless remote boot setup, there is no drive 0. // if ( RemoteBootSetup && (DiskNumber == (ULONG)-1) && (HardDiskCount == 0) ) { return DiskNumber; } #endif // defined(REMOTE_BOOT) return (DiskNumber == (ULONG)-1) ? 0 : DiskNumber; } #ifdef OLD_PARTITION_ENGINE BOOL SpPtIsSystemPartitionRecognizable( VOID ) /*++ Routine Description: Determine whether the active partition is suitable for use as the system partition on an x86 machine (ie, C:). A primary, recognized (1/4/6/7 type) partition on disk 0 is suitable. Arguments: None. Return Value: TRUE - We found a suitable partition FALSE - We didn't find a suitable partition --*/ { PON_DISK_PTE pte; PDISK_REGION pRegion; ULONG DiskNumber; // // Any partitions on NEC98 are primary and active. So don't need to check on NEC98. // if( IsNEC_98 ) { return TRUE; } DiskNumber = SpDetermineDisk0(); // // Look for the active partition on drive 0 // and for the first recognized primary partition on drive 0. // for(pRegion=PartitionedDisks[DiskNumber].PrimaryDiskRegions; pRegion; pRegion=pRegion->Next) { pte = &pRegion->MbrInfo->OnDiskMbr.PartitionTable[pRegion->TablePosition]; if( (pRegion->PartitionedSpace) && (pte->ActiveFlag) ) { // // We've hit the active partition. Check its format. // if( (pRegion->Filesystem == FilesystemNtfs) || (pRegion->Filesystem == FilesystemFat) || (pRegion->Filesystem == FilesystemFat32) ) { // // We recognize him. // return TRUE; } } } // // If we get here, we didn't find any active partitions // we recognize. // return FALSE; } PDISK_REGION SpPtValidSystemPartitionArc( IN PVOID SifHandle, IN PWSTR SetupSourceDevicePath, IN PWSTR DirectoryOnSetupSource ) /*++ Routine Description: Determine whether there is a valid disk partition suitable for use as the system partition on an ARC machine. A partition is suitable if it is marked as a system partition in nvram, has the required free space and is formatted with the FAT filesystem. Arguments: SifHandle - supplies handle to loaded setup information file. Return Value: Pointer to a disk region descriptor for a suitable system partition. Does not return if no such partition exists. --*/ { ULONG RequiredSpaceKB = 0; ULONG disk,pass; PPARTITIONED_DISK pDisk; PDISK_REGION pRegion; // // Go through all the regions. The first one that has enough free space // and is of the required filesystem becomes *the* system partition. // for(disk=0; diskExtendedDiskRegions : pDisk->PrimaryDiskRegions; for( ; pRegion; pRegion=pRegion->Next) { if(pRegion->IsSystemPartition && (pRegion->FreeSpaceKB != (ULONG)(-1)) && (pRegion->Filesystem == FilesystemFat)) { ULONG TotalSizeOfFilesOnOsWinnt; // // On non-x86 platformrs, specially alpha machines that in general // have small system partitions (~3 MB), we should compute the size // of the files on \os\winnt (currently, osloader.exe and hall.dll), // and consider this size as available disk space. We can do this // since these files will be overwritten by the new ones. // This fixes the problem that we see on Alpha, when the system // partition is too full. // SpFindSizeOfFilesInOsWinnt( SifHandle, pRegion, &TotalSizeOfFilesOnOsWinnt ); // // Transform the size into KB // TotalSizeOfFilesOnOsWinnt /= 1024; // // Determine the amount of free space required on a system partition. // SpFetchDiskSpaceRequirements( SifHandle, pRegion->BytesPerCluster, NULL, &RequiredSpaceKB ); if ((pRegion->FreeSpaceKB + TotalSizeOfFilesOnOsWinnt) >= RequiredSpaceKB) { return(pRegion); } } } } } // // Make sure we don't look bad. // if( RequiredSpaceKB == 0 ) { SpFetchDiskSpaceRequirements( SifHandle, (32 * 1024), NULL, &RequiredSpaceKB ); } // // No valid system partition. // SpStartScreen( SP_SCRN_NO_SYSPARTS, 3, HEADER_HEIGHT+1, FALSE, FALSE, DEFAULT_ATTRIBUTE, RequiredSpaceKB ); SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_F3_EQUALS_EXIT,0); SpInputDrain(); while(SpInputGetKeypress() != KEY_F3) ; SpDone(0,FALSE,TRUE); // // Should never get here, but it keeps the compiler happy // return NULL; } #endif // OLD_PARTITION_ENGINE