/*++ 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 // // BUGBUG - jaimes: move to a header file // NTSTATUS SpDoubleSpaceFormat( PDISK_REGION ); ULONG SpFormattingOptions( IN BOOLEAN AllowFatFormat, IN BOOLEAN AllowNtfsFormat, IN BOOLEAN AllowConvertNtfs, IN BOOLEAN AllowDoubleSpaace, IN BOOLEAN AllowDoNothing ); BOOLEAN SpPtRegionDescription( IN PPARTITIONED_DISK pDisk, IN PDISK_REGION pRegion, OUT PWCHAR Buffer, IN ULONG BufferSize ); NTSTATUS SpDoFormat( IN PWSTR RegionDescr, IN PDISK_REGION Region, IN ULONG FilesystemType, IN BOOLEAN SetConversionFlagIfNtfs, IN BOOLEAN IsFailureFatal, IN BOOLEAN CheckFatSize, IN PVOID SifHandle, IN PWSTR SetupSourceDevicePath, IN PWSTR DirectoryOnSetupSource ); typedef enum { FormatOptionCancel = 0, FormatOptionFat, FormatOptionNtfs, FormatOptionConvertToNtfs, FormatOptionDoubleSpace, FormatOptionDoNothing } FormatOptions; #define SP_STATUS_PART_TOO_BIG ((NTSTATUS)0xA0000000L) BOOLEAN SpPtDoPartitionSelection( IN OUT PDISK_REGION *Region, IN PWSTR RegionDescription, IN PVOID SifHandle, IN BOOLEAN Unattended, IN PWSTR SetupSourceDevicePath, IN PWSTR DirectoryOnSetupSource ) { ULONG RequiredKB; 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; #ifdef _X86_ PDISK_REGION systemPartitionRegion; #endif BOOLEAN AllowNtfsOptions; ULONG selection; NTSTATUS Status; ULONG Count; PWSTR p; PWSTR RegionDescr; PDISK_REGION region = *Region; LARGE_INTEGER temp; // // Assume that if we need to format the drive, that // the user needs to confirm. // PreconfirmFormatId = 0; NewlyCreated = FALSE; AllowNtfsOptions = 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); } // // 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)) { #ifdef _X86_ // // On 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 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); } SpFetchDiskSpaceRequirements(SifHandle,&RequiredKB,NULL); // // 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 ); SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_ENTER_EQUALS_CONTINUE,0); SpWaitValidKey(ValidKeys1,NULL,NULL); return(FALSE); } if(region->PartitionedSpace) { // // If the region is a partition but not a native // type, then tell the user that he must explicitly delete it // and recreate it first. // SystemId = region->MbrInfo->OnDiskMbr.PartitionTable[region->TablePosition].SystemId; ASSERT(SystemId != PARTITION_ENTRY_UNUSED); ASSERT(!IsContainerPartition(SystemId)); if(PartitionNameIds[SystemId] != (UCHAR)(-1)) { 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); } // // 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. // // Before deciding that this partition is not usable, // see if there any existing NT trees to remove. // if(SpIsNtOnPartition(region)) { WCHAR DriveSpec[3]; BOOLEAN b; ULONG SpaceFreed; if(region->DriveLetter) { DriveSpec[0] = region->DriveLetter; DriveSpec[1] = L':'; DriveSpec[2] = 0; } else { DriveSpec[0] = 0; } // // Allow the user to delete an installation -- // there is at least one there. // b = SpAllowRemoveNt( region, DriveSpec, TRUE, SP_SCRN_REMOVE_NT_FILES, &SpaceFreed ); if(b) { region->FreeSpaceKB += SpaceFreed/1024; region->AdjustedFreeSpaceKB += SpaceFreed/1024; // // Round up if necessary. // if((SpaceFreed % 1024) >= 512) { region->FreeSpaceKB++; region->AdjustedFreeSpaceKB++; } return(FALSE); } else { // // User chose not to remove any NTs. // Only choice if the user still wants to // install here is to reformat. // // Just fall through. // } } #ifdef _X86_ // We check here to see if this partition is the partition we // booted from (in floppyless case on x86). If so, then the // user can't format, and we give a generic 'disk too full' // error. // if( IsFloppylessBoot && (region == (SpRegionFromArcName(ArcBootDevicePath, PartitionOrdinalOriginal, NULL)))) { SpStartScreen( SP_SCRN_INSUFFICIENT_FREESPACE_NO_FMT, 3, HEADER_HEIGHT+1, FALSE, FALSE, DEFAULT_ATTRIBUTE, RequiredKB / 1024 ); SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_ENTER_EQUALS_CONTINUE, 0 ); SpWaitValidKey(ValidKeys1,NULL,NULL); return FALSE; } #endif // // 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 ); 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)) { 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, (PWSTR)TemporaryBuffer, sizeof(TemporaryBuffer) ); RegionDescr = SpDupStringW((PWSTR)TemporaryBuffer); } else { RegionDescr = SpDupStringW(RegionDescription); } #ifdef _X86_ { // // On an x86 machine, make sure that we have a valid primary partition // on drive 0 (C:), for booting. // 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); } #endif // // Attempt to grow the partition the system will be on // if necessary. // if(PreInstall && Unattended && (p = SpGetSectionKeyIndex(UnattendedSifHandle,SIF_UNATTENDED,L"ExtendOemPartition",0)) && SpStringToLong(p,NULL,10)) { ExtendingOemPartition = SpPtExtend(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(); #ifdef _X86_ // // On an 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, (PWSTR)TemporaryBuffer, sizeof(TemporaryBuffer) ); SysPartRegionDescr = SpDupStringW((PWSTR)TemporaryBuffer); bValidCColon = SpPtValidateCColonFormat(SifHandle, SysPartRegionDescr, systemPartitionRegion, FALSE, SetupSourceDevicePath, DirectoryOnSetupSource); SpMemFree(SysPartRegionDescr); if(!bValidCColon) { SpMemFree(RegionDescr); return(FALSE); } } #else // // 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; } #endif // // 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)) { 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 ); } if( region->Filesystem != FilesystemDoubleSpace ) { selection = SpFormattingOptions( TRUE, AllowNtfsOptions, FALSE, FALSE, FALSE ); } else { selection = SpFormattingOptions(FALSE,FALSE,FALSE,TRUE,FALSE); } switch(selection) { case FormatOptionCancel: SpMemFree(RegionDescr); return(FALSE); default: // // Format the partition right here and now. // #ifndef FULL_DOUBLE_SPACE_SUPPORT Status = SpDoFormat( RegionDescr, region, (selection == FormatOptionNtfs) ? FilesystemNtfs : FilesystemFat, TRUE, FALSE, TRUE, SifHandle, SetupSourceDevicePath, DirectoryOnSetupSource ); #else // FULL_DOUBLE_SPACE_SUPPORT if( region->Filesystem != FilesystemDoubleSpace ) { Status = SpDoFormat( RegionDescr, region, (selection == FormatOptionNtfs) ? FilesystemNtfs : FilesystemFat, TRUE, FALSE, TRUE SifHandle, SetupSourceDevicePath, DirectoryOnSetupSource ); } else { Status = SpDoFormat( RegionDescr, region, FilesystemDoubleSpace, TRUE, FALSE, TRUE SifHandle, SetupSourceDevicePath, DirectoryOnSetupSource ); } #endif // FULL_DOUBLE_SPACE_SUPPORT 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. // if(!Unattended) { SpStartScreen( SP_SCRN_FS_OPTIONS, 3, HEADER_HEIGHT+1, FALSE, FALSE, DEFAULT_ATTRIBUTE, RegionDescr, HardDisks[region->DiskNumber].Description ); } if( region->Filesystem != FilesystemDoubleSpace ) { BOOLEAN AllowFormatting; // // 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 x86 floppyless boot case). // AllowFormatting = !region->IsLocalSource; #ifdef _X86_ if(AllowFormatting) { AllowFormatting = !(IsFloppylessBoot && (region == (SpRegionFromArcName(ArcBootDevicePath, PartitionOrdinalOriginal, NULL)))); } #endif selection = SpFormattingOptions( AllowFormatting, (BOOLEAN)(AllowFormatting ? AllowNtfsOptions : FALSE), (BOOLEAN)(AllowNtfsOptions && (BOOLEAN)(region->Filesystem != FilesystemNtfs)), FALSE, TRUE ); } else { selection = SpFormattingOptions(FALSE,FALSE,FALSE,TRUE,TRUE); } switch(selection) { case FormatOptionDoNothing: SpMemFree(RegionDescr); return(TRUE); case FormatOptionFat: case FormatOptionNtfs: case FormatOptionDoubleSpace: // // 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); } // // Format the partition right here and now. // #ifndef FULL_DOUBLE_SPACE_SUPPORT Status = SpDoFormat( RegionDescr, region, (selection == FormatOptionNtfs) ? FilesystemNtfs : FilesystemFat, TRUE, FALSE, TRUE, SifHandle, SetupSourceDevicePath, DirectoryOnSetupSource ); #else // FULL_DOUBLE_SPACE_SUPPORT // // BUGBUG - Cairo - Remove CairoSetup flag in the future // if( region->Filesystem != FilesystemDoubleSpace ) { Status = SpDoFormat( RegionDescr, region, (selection == FormatOptionNtfs) ? FilesystemNtfs : FilesystemFat, TRUE, FALSE, TRUE SifHandle, SetupSourceDevicePath, DirectoryOnSetupSource ); } else { Status = SpDoFormat( RegionDescr, region, FilesystemDoubleSpace, TRUE, FALSE, TRUE SifHandle, SetupSourceDevicePath, DirectoryOnSetupSource ); } #endif // FULL_DOUBLE_SPACE_SUPPORT 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 AllowDoubleSpaceFormat, IN BOOLEAN AllowDoNothing ) /*++ 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. 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. 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 DoubleSpaceFormatOption = (ULONG)(-1); ULONG FatFormatOption = (ULONG)(-1); ULONG NtfsFormatOption = (ULONG)(-1); ULONG ConvertNtfsOption = (ULONG)(-1); ULONG DoNothingOption = (ULONG)(-1); ULONG OptionCount = 0; PVOID Menu; WCHAR DoubleSpaceFormatText[128]; WCHAR FatFormatText[128]; WCHAR NtfsFormatText[128]; WCHAR ConvertNtfsText[128]; WCHAR DoNothingText[128]; ULONG l,MaxLength; ULONG Key,Selection; ULONG ValidKeys[4] = { ASCI_CR, ASCI_ESC, KEY_F3, 0 }; BOOLEAN Chosen; // // For unattended operation check the value in the unattended file. // If the value is unspecified or invalid ignore it and // drop into attended selection. // if(UnattendedOperation) { if(Menu = SpGetSectionKeyIndex(UnattendedSifHandle,SIF_UNATTENDED,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"LeaveAlone") && AllowDoNothing) { return(FormatOptionDoNothing); } } else { if(AllowDoNothing) { return(FormatOptionDoNothing); } } } ASSERT(AllowFatFormat || AllowNtfsFormat || AllowConvertNtfs || AllowDoNothing); SpFormatMessage(DoubleSpaceFormatText ,sizeof(DoubleSpaceFormatText),SP_TEXT_DBLSPACE_FORMAT); 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); // // Determine maximum length of the option strings. // MaxLength=wcslen(FatFormatText); if((l = wcslen(DoubleSpaceFormatText)) > MaxLength) { MaxLength = l; } if((l = wcslen(NtfsFormatText)) > MaxLength) { MaxLength = l; } if((l = wcslen(ConvertNtfsText)) > MaxLength) { MaxLength = l; } if((l = wcslen(DoNothingText)) > MaxLength) { MaxLength = l; } // // BUGBUG - Cairo - Remove CairoSetup flag in the future // Menu = SpMnCreate(5,NextMessageTopLine+1,VideoVars.ScreenWidth-5,CairoSetup? 6 : 4); if(AllowDoubleSpaceFormat) { DoubleSpaceFormatOption = OptionCount++; SpMnAddItem(Menu,DoubleSpaceFormatText,5,MaxLength,TRUE,DoubleSpaceFormatOption); } if(AllowFatFormat) { FatFormatOption = OptionCount++; SpMnAddItem(Menu,FatFormatText,5,MaxLength,TRUE,FatFormatOption); } if(AllowNtfsFormat) { NtfsFormatOption = OptionCount++; SpMnAddItem(Menu,NtfsFormatText,5,MaxLength,TRUE,NtfsFormatOption); } 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(AllowFatFormat) { Selection = FatFormatOption; } else { Selection = 0; } } // // Display the menu. // Chosen = FALSE; do { SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_ENTER_EQUALS_CONTINUE, SP_STAT_ESC_EQUALS_CANCEL, 0 ); SpMnDisplay(Menu,Selection,FALSE,ValidKeys,NULL,NULL,&Key,&Selection); switch(Key) { case ASCI_CR: Chosen = TRUE; break; case ASCI_ESC: SpMnDestroy(Menu); return(FormatOptionCancel); } } while(!Chosen); SpMnDestroy(Menu); // // Convert chosen option to a meaningful value. // if(Selection == DoubleSpaceFormatOption) { return(FormatOptionDoubleSpace); } 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; ULONG ValidKeys[3] = { KEY_F1,KEY_F3,0 }; BOOLEAN AnyChanges = FALSE; CLEAR_CLIENT_SCREEN(); // // Update dblspace.ini, if necessary // SpUpdateDoubleSpaceIni(); // // Iterate through the disks. // for(i=0; iDiskNumber]), Region->SectorCount ); SecPerCluster = ComputeSecPerCluster(Region->SectorCount, FALSE); if((RegionSizeMB > 4096) || (SecPerCluster > 128)) { SpStartScreen( SP_SCRN_OSPART_TOO_BIG, 3, HEADER_HEIGHT+1, FALSE, FALSE, DEFAULT_ATTRIBUTE, RegionDescr, HardDisks[Region->DiskNumber].Description ); SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_ENTER_EQUALS_CONTINUE, SP_STAT_F3_EQUALS_EXIT, 0 ); switch(SpWaitValidKey(ValidKeys,NULL,NULL)) { case KEY_F3: SpConfirmExit(); case ASCI_CR: return SP_STATUS_PART_TOO_BIG; } } // // If the format is for a FAT partition, check to see if the partition is > 2GB. // If so, then give the user a warning that the FAT volume may not be compatible // with MS-DOS. // // At this point, the user can opt to select another partition on which to install, // or plow ahead and use the big partition. // if(CheckFatSize && (FilesystemType == FilesystemFat) && (RegionSizeMB > 2048)) { SpStartScreen( SP_SCRN_OSPART_LARGE, 3, HEADER_HEIGHT+1, FALSE, FALSE, DEFAULT_ATTRIBUTE, RegionDescr, HardDisks[Region->DiskNumber].Description ); SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_ENTER_EQUALS_CONTINUE, SP_STAT_ESC_EQUALS_CANCEL, SP_STAT_F3_EQUALS_EXIT, 0 ); switch(SpWaitValidKey(ValidKeys2,NULL,NULL)) { case KEY_F3: SpConfirmExit(); case ASCI_ESC: return SP_STATUS_PART_TOO_BIG; case ASCI_CR: break; // continue with format } } // // Put up a screen indicating what we are doing. // SpStartScreen( SP_SCRN_SETUP_IS_FORMATTING, 0, HEADER_HEIGHT + 3, TRUE, FALSE, DEFAULT_ATTRIBUTE, RegionDescr, HardDisks[Region->DiskNumber].Description ); SpvidClearScreenRegion( 0, VideoVars.ScreenHeight-STATUS_HEIGHT, VideoVars.ScreenWidth, STATUS_HEIGHT, DEFAULT_STATUS_BACKGROUND ); #ifndef FULL_DOUBLE_SPACE_SUPPORT Status = SpFatFormat(Region); #else // FULL_DOUBLE_SPACE_SUPPORT if( FilesystemType != FilesystemDoubleSpace ) { Status = SpFatFormat(Region); } else { // KdPrint( ("SETUP: Calling SpDoubleSpaceFormat() \n" ) ); Status = SpDoubleSpaceFormat( Region ); // KdPrint( ("SETUP: returned from SpDoubleSpaceFormat() \n" ) ); } #endif // FULL_DOUBLE_SPACE_SUPPORT if(!NT_SUCCESS(Status)) { KdPrint(("SETUP: unable to format (%lx)\n",Status)); if(IsFailureFatal) { // // Then we can't continue (this means that the system partition // couldn't be formatted). // SpDisplayScreen(SP_SCRN_SYSPART_FORMAT_ERROR,3,HEADER_HEIGHT+1); SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_F3_EQUALS_EXIT,0); SpkbdDrain(); while(SpkbdGetKeypress() != KEY_F3) ; SpDone(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 ); SpkbdDrain(); while(SpkbdGetKeypress() != ASCI_CR) ; return(Status); } } if(SetConversionFlagIfNtfs && (FilesystemType == FilesystemNtfs)) { ConvertNtVolumeToNtfs = TRUE; } return(STATUS_SUCCESS); } #ifdef _X86_ 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); SpkbdDrain(); while(SpkbdGetKeypress() != ASCI_CR) ; WarnedOtherOs = TRUE; } } } } ASSERT(Region->PartitionedSpace); ASSERT(Region->TablePosition < PTABLE_DIMENSION); SpPtMarkActive(Region->TablePosition); } 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 ValidKeys2[3] = { ASCI_CR, KEY_F3, 0 }; ULONG ValidKeys3[2] = { KEY_F3, 0 }; ULONG ValidKeys4[4] = { ASCI_CR, ASCI_ESC, KEY_F3, 0 }; ULONG Mnemonics[2] = { MnemonicFormat,0 }; BOOLEAN Confirm; NTSTATUS Status; ULONG RegionSizeMB; USHORT SecPerCluster; // ASSERT( CheckOnly || (( SetupSourceDevicePath != NULL ) && ( DirectoryOnSetupSource != NULL ))); // // Get the minimum free space required for C:. // SpFetchDiskSpaceRequirements(SifHandle,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 // havven'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); } SpDisplayScreen(SP_SCRN_C_UNKNOWN,3,HEADER_HEIGHT+1); 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 ); SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_F3_EQUALS_EXIT, 0 ); SpWaitValidKey(ValidKeys3,NULL,NULL); SpDone(FALSE,TRUE); } Confirm = TRUE; SpStartScreen( SP_SCRN_C_FULL, 3, HEADER_HEIGHT+1, FALSE, FALSE, DEFAULT_ATTRIBUTE, MinFreeKB ); // // 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; } } // // Check to make sure the C: partition we're about to format is <= 4GB, and that // the sectors per cluster is <= 128. If not, then we give the user a message // saying we can't format. // RegionSizeMB = SpPtSectorCountToMB( &(HardDisks[Region->DiskNumber]), Region->SectorCount ); SecPerCluster = ComputeSecPerCluster(Region->SectorCount, FALSE); if((RegionSizeMB > 4096) || (SecPerCluster > 128)) { SpStartScreen( SP_SCRN_C_TOO_BIG, 3, HEADER_HEIGHT+1, FALSE, FALSE, DEFAULT_ATTRIBUTE, RegionSizeMB ); SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_ENTER_EQUALS_CONTINUE, SP_STAT_F3_EQUALS_EXIT, 0 ); switch(SpWaitValidKey(ValidKeys2, NULL, NULL)) { case KEY_F3: SpConfirmExit(); case ASCI_CR: return(FALSE); } } // // Now check to see if the partition is > 2GB. If so, warn // the user about FAT incompatibilities. // if(RegionSizeMB > 2048) { SpStartScreen( SP_SCRN_C_LARGE, 3, HEADER_HEIGHT+1, FALSE, FALSE, DEFAULT_ATTRIBUTE, RegionSizeMB ); SpDisplayStatusOptions( DEFAULT_STATUS_ATTRIBUTE, SP_STAT_ENTER_EQUALS_CONTINUE, SP_STAT_ESC_EQUALS_CANCEL, SP_STAT_F3_EQUALS_EXIT, 0 ); switch(SpWaitValidKey(ValidKeys4, NULL, NULL)) { case KEY_F3: SpConfirmExit(); case ASCI_ESC: return(FALSE); case ASCI_CR: break; // continue with format } } if(!Confirm) { // // Just put up an information screen so the user doesn't // go bonkers when we just start formatting his newly created C:. // SpDisplayScreen(SP_SCRN_ABOUT_TO_FORMAT_C,3,HEADER_HEIGHT+1); SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,SP_STAT_ENTER_EQUALS_CONTINUE,0); SpkbdDrain(); while(SpkbdGetKeypress() != ASCI_CR) ; } // // Do the format. // Status = SpDoFormat(RegionDescr, Region, FilesystemFat, FALSE, TRUE, FALSE, SifHandle, SetupSourceDevicePath, DirectoryOnSetupSource ); return(NT_SUCCESS(Status)); } 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(); // // 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)) || RepairWinnt && (((TmpSysId & VALID_NTFT) == VALID_NTFT) || ((TmpSysId & PARTITION_NTFT) == PARTITION_NTFT)) ) ) { // // 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); } 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 = SpArcDevicePathToDiskNumber(L"multi(0)disk(0)rdisk(0)"); return((DiskNumber == (ULONG)(-1)) ? 0 : DiskNumber); } #else PDISK_REGION SpPtValidSystemPartition( IN PVOID SifHandle ) /*++ 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; ULONG disk,pass; PPARTITIONED_DISK pDisk; PDISK_REGION pRegion; // // Determine the amount of free space required on a system partition. // SpFetchDiskSpaceRequirements(SifHandle,NULL,&RequiredSpaceKB); // // 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; if ((pRegion->FreeSpaceKB + TotalSizeOfFilesOnOsWinnt) >= RequiredSpaceKB) { return(pRegion); } } } } } // // 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); SpkbdDrain(); while(SpkbdGetKeypress() != KEY_F3) ; SpDone(FALSE,TRUE); } #endif // def _X86_