From e3445e18d15ba84db3c25b7f157671953a29c4d7 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Herm=C3=A8s=20B=C3=A9lusca-Ma=C3=AFto?= Date: Tue, 1 Mar 2016 15:00:56 +0000 Subject: [PATCH] [USETUP] - bootsup.c/.h, usetup.c: Save the old MBR sector in the system partition (this makes easier to restore the old one). - fslist.c/.h, usetup.h: Fix header inclusion order. - partlist.c/.h, usetup.c: On BIOS-PC architectures, the system partition can be formatted in any FS as long as it is the active partition (on the contrary, on architectures where such system partition is required, it is formatted in FAT). We currently do not have write support for all FSes out there (apart for FAT until now), so do a "clever" "trick" to work around this problem: on initialized disks, find the active partition and check its FS. If we support write access to this FS then we're OK, otherwise we change the (active) system partition for the one on which we are going to install ReactOS (which is, by construction, formatted with a FS on which we support write access). The MBR (resp. the VBR) of the disk (resp. of the system partition) are always saved into files, making easy for people to boot on them (using FreeLdr) or restoring them. CORE-10898 svn path=/trunk/; revision=70837 --- reactos/base/setup/usetup/bootsup.c | 16 +- reactos/base/setup/usetup/bootsup.h | 9 + reactos/base/setup/usetup/fslist.c | 12 +- reactos/base/setup/usetup/fslist.h | 3 +- reactos/base/setup/usetup/interface/usetup.c | 40 +++- reactos/base/setup/usetup/partlist.c | 227 ++++++++++++++++--- reactos/base/setup/usetup/partlist.h | 12 +- reactos/base/setup/usetup/usetup.h | 2 +- 8 files changed, 267 insertions(+), 54 deletions(-) diff --git a/reactos/base/setup/usetup/bootsup.c b/reactos/base/setup/usetup/bootsup.c index 68b64aa4cf6..1d970a6147a 100644 --- a/reactos/base/setup/usetup/bootsup.c +++ b/reactos/base/setup/usetup/bootsup.c @@ -626,7 +626,6 @@ UpdateFreeLoaderIni( return STATUS_SUCCESS; } -static BOOLEAN IsThereAValidBootSector(PWSTR RootPath) { @@ -695,9 +694,8 @@ IsThereAValidBootSector(PWSTR RootPath) return (Instruction != 0x00000000); } -static NTSTATUS -SaveCurrentBootSector( +SaveBootSector( PWSTR RootPath, PWSTR DstPath, ULONG Length) @@ -1210,7 +1208,7 @@ InstallMbrBootCodeToDisk( NULL, &IoStatusBlock, OrigBootSector, - SECTORSIZE, + sizeof(PARTITION_SECTOR), &FileOffset, NULL); NtClose(FileHandle); @@ -1306,7 +1304,7 @@ InstallMbrBootCodeToDisk( NULL, &IoStatusBlock, NewBootSector, - SECTORSIZE, + sizeof(PARTITION_SECTOR), &FileOffset, NULL); NtClose(FileHandle); @@ -2447,10 +2445,10 @@ InstallFatBootcodeToPartition( wcscat(DstPath, BootSectorFileName); DPRINT1("Save bootsector: %S ==> %S\n", SystemRootPath->Buffer, DstPath); - Status = SaveCurrentBootSector(SystemRootPath->Buffer, DstPath, SECTORSIZE); + Status = SaveBootSector(SystemRootPath->Buffer, DstPath, SECTORSIZE); if (!NT_SUCCESS(Status)) { - DPRINT1("SaveCurrentBootSector() failed (Status %lx)\n", Status); + DPRINT1("SaveBootSector() failed (Status %lx)\n", Status); return Status; } } @@ -2582,10 +2580,10 @@ InstallExt2BootcodeToPartition( wcscat(DstPath, L"\\bootsect.old"); DPRINT1("Save bootsector: %S ==> %S\n", SystemRootPath->Buffer, DstPath); - Status = SaveCurrentBootSector(SystemRootPath->Buffer, DstPath, sizeof(EXT2_BOOTSECTOR)); + Status = SaveBootSector(SystemRootPath->Buffer, DstPath, sizeof(EXT2_BOOTSECTOR)); if (!NT_SUCCESS(Status)) { - DPRINT1("SaveCurrentBootSector() failed (Status %lx)\n", Status); + DPRINT1("SaveBootSector() failed (Status %lx)\n", Status); return Status; } } diff --git a/reactos/base/setup/usetup/bootsup.h b/reactos/base/setup/usetup/bootsup.h index 9f0dc5c1ecb..0bdeb37bdd7 100644 --- a/reactos/base/setup/usetup/bootsup.h +++ b/reactos/base/setup/usetup/bootsup.h @@ -26,6 +26,15 @@ #pragma once +BOOLEAN +IsThereAValidBootSector(PWSTR RootPath); + +NTSTATUS +SaveBootSector( + PWSTR RootPath, + PWSTR DstPath, + ULONG Length); + NTSTATUS InstallMbrBootCodeToDisk( PWSTR SrcPath, diff --git a/reactos/base/setup/usetup/fslist.c b/reactos/base/setup/usetup/fslist.c index ee3c2a82158..99fe2f8460c 100644 --- a/reactos/base/setup/usetup/fslist.c +++ b/reactos/base/setup/usetup/fslist.c @@ -91,7 +91,7 @@ GetFileSystemByName( PFILE_SYSTEM_ITEM GetFileSystem( IN PFILE_SYSTEM_LIST FileSystemList, - IN PPARTENTRY PartEntry) + IN struct _PARTENTRY* PartEntry) { PFILE_SYSTEM_ITEM CurrentFileSystem; LPWSTR FileSystemName = NULL; @@ -102,6 +102,8 @@ GetFileSystem( if (CurrentFileSystem != NULL && CurrentFileSystem->FileSystemName != NULL) return CurrentFileSystem; + DPRINT1("File system not found, try to guess one...\n"); + CurrentFileSystem = NULL; /* @@ -121,9 +123,9 @@ GetFileSystem( */ if ((PartEntry->PartitionType == PARTITION_FAT_12) || (PartEntry->PartitionType == PARTITION_FAT_16) || - (PartEntry->PartitionType == PARTITION_HUGE) || + (PartEntry->PartitionType == PARTITION_HUGE ) || (PartEntry->PartitionType == PARTITION_XINT13) || - (PartEntry->PartitionType == PARTITION_FAT32) || + (PartEntry->PartitionType == PARTITION_FAT32 ) || (PartEntry->PartitionType == PARTITION_FAT32_XINT13)) { FileSystemName = L"FAT"; @@ -139,9 +141,9 @@ GetFileSystem( FileSystemName = L"NTFS"; /* FIXME: Not quite correct! */ } - // WARNING: We cannot write on this FS yet! + // HACK: WARNING: We cannot write on this FS yet! if (PartEntry->PartitionType == PARTITION_EXT2 || PartEntry->PartitionType == PARTITION_IFS) - DPRINT1("Recognized FileSystem %S that doesn't support write support yet!\n", FileSystemName); + DPRINT1("Recognized file system %S that doesn't support write support yet!\n", FileSystemName); DPRINT1("GetFileSystem -- PartitionType: 0x%02X ; FileSystemName (guessed): %S\n", PartEntry->PartitionType, FileSystemName); diff --git a/reactos/base/setup/usetup/fslist.h b/reactos/base/setup/usetup/fslist.h index 4e8f06725d8..685a2cfe2e8 100644 --- a/reactos/base/setup/usetup/fslist.h +++ b/reactos/base/setup/usetup/fslist.h @@ -57,10 +57,11 @@ GetFileSystemByName( IN PFILE_SYSTEM_LIST List, IN LPWSTR FileSystemName); +struct _PARTENTRY; // Defined in partlist.h PFILE_SYSTEM_ITEM GetFileSystem( IN PFILE_SYSTEM_LIST FileSystemList, - IN PPARTENTRY PartEntry); + IN struct _PARTENTRY* PartEntry); PFILE_SYSTEM_LIST CreateFileSystemList( diff --git a/reactos/base/setup/usetup/interface/usetup.c b/reactos/base/setup/usetup/interface/usetup.c index e95bb96f30f..b12bdf2833e 100644 --- a/reactos/base/setup/usetup/interface/usetup.c +++ b/reactos/base/setup/usetup/interface/usetup.c @@ -1731,8 +1731,11 @@ SelectPartitionPage(PINPUT_RECORD Ir) return SELECT_PARTITION_PAGE; } - if (PartitionList->CurrentPartition->BootIndicator) + if (PartitionList->CurrentPartition->BootIndicator || + PartitionList->CurrentPartition == PartitionList->SystemPartition) + { return CONFIRM_DELETE_SYSTEM_PARTITION_PAGE; + } return DELETE_PARTITION_PAGE; } @@ -2553,8 +2556,21 @@ SelectFileSystemPage(PINPUT_RECORD Ir) return QUIT_PAGE; } + /*** HACK! ***/ + if (FileSystemList == NULL) + { + FileSystemList = CreateFileSystemList(6, 26, PartitionList->CurrentPartition->New, L"FAT"); + if (FileSystemList == NULL) + { + /* FIXME: show an error dialog */ + return QUIT_PAGE; + } + + /* FIXME: Add file systems to list */ + } + /* Find or set the active system partition */ - CheckActiveSystemPartition(PartitionList); + CheckActiveSystemPartition(PartitionList, FileSystemList); if (PartitionList->SystemDisk == NULL || PartitionList->SystemPartition == NULL) @@ -4130,7 +4146,7 @@ BootLoaderPage(PINPUT_RECORD Ir) PartitionList->SystemDisk->DiskNumber, PartitionList->SystemPartition->PartitionNumber); RtlCreateUnicodeString(&SystemRootPath, PathBuffer); - DPRINT("SystemRootPath: %wZ\n", &SystemRootPath); + DPRINT1("SystemRootPath: %wZ\n", &SystemRootPath); PartitionType = PartitionList->SystemPartition->PartitionType; @@ -4382,6 +4398,7 @@ BootLoaderHarddiskMbrPage(PINPUT_RECORD Ir) NTSTATUS Status; WCHAR DestinationDevicePathBuffer[MAX_PATH]; WCHAR SourceMbrPathBuffer[MAX_PATH]; + WCHAR DstPath[MAX_PATH]; /* Step 1: Write the VBR */ PartitionType = PartitionList->SystemPartition->PartitionType; @@ -4404,9 +4421,24 @@ BootLoaderHarddiskMbrPage(PINPUT_RECORD Ir) wcscpy(SourceMbrPathBuffer, SourceRootPath.Buffer); wcscat(SourceMbrPathBuffer, L"\\loader\\dosmbr.bin"); - DPRINT("Install MBR bootcode: %S ==> %S\n", + DPRINT1("Install MBR bootcode: %S ==> %S\n", SourceMbrPathBuffer, DestinationDevicePathBuffer); + if (IsThereAValidBootSector(DestinationDevicePathBuffer)) + { + /* Save current MBR */ + wcscpy(DstPath, SystemRootPath.Buffer); + wcscat(DstPath, L"\\mbr.old"); + + DPRINT1("Save MBR: %S ==> %S\n", DestinationDevicePathBuffer, DstPath); + Status = SaveBootSector(DestinationDevicePathBuffer, DstPath, sizeof(PARTITION_SECTOR)); + if (!NT_SUCCESS(Status)) + { + DPRINT1("SaveBootSector() failed (Status %lx)\n", Status); + // Don't care if we succeeded or not saving the old MBR, just go ahead. + } + } + Status = InstallMbrBootCodeToDisk(SourceMbrPathBuffer, DestinationDevicePathBuffer); if (!NT_SUCCESS(Status)) diff --git a/reactos/base/setup/usetup/partlist.c b/reactos/base/setup/usetup/partlist.c index 54e2d280aa2..0d3aa027b80 100644 --- a/reactos/base/setup/usetup/partlist.c +++ b/reactos/base/setup/usetup/partlist.c @@ -1430,6 +1430,8 @@ CreatePartitionList( List->SystemDisk = NULL; List->SystemPartition = NULL; + List->OriginalSystemDisk = NULL; + List->OriginalSystemPartition = NULL; List->TempDisk = NULL; List->TempPartition = NULL; @@ -3111,29 +3113,26 @@ DeleteCurrentPartition( VOID CheckActiveSystemPartition( - PPARTLIST List) + IN PPARTLIST List, + IN PFILE_SYSTEM_LIST FileSystemList /* Needed for checking the FS of the candidate system partition */ + ) { PDISKENTRY DiskEntry; PPARTENTRY PartEntry; PLIST_ENTRY ListEntry; + PFILE_SYSTEM_ITEM FileSystem; + /* Check for empty disk list */ if (IsListEmpty(&List->DiskListHead)) { List->SystemDisk = NULL; List->SystemPartition = NULL; + List->OriginalSystemDisk = NULL; + List->OriginalSystemPartition = NULL; return; } -#if 0 - if (List->SystemDisk != NULL && - List->SystemPartition != NULL) - { - /* We already have an active system partition */ - return; - } -#endif - /* Choose the currently selected disk */ DiskEntry = List->CurrentDisk; @@ -3142,64 +3141,226 @@ CheckActiveSystemPartition( { List->SystemDisk = NULL; List->SystemPartition = NULL; + List->OriginalSystemDisk = NULL; + List->OriginalSystemPartition = NULL; return; } - /* - * Check the first partition of the disk in case it is fresh new, - * and if so, use it as the system partition. - */ + if (List->SystemDisk != NULL && List->SystemPartition != NULL) + { + /* We already have an active system partition */ + DPRINT1("Use the current system partition %lu in disk %lu, drive letter %c\n", + List->SystemPartition->PartitionNumber, + List->SystemDisk->DiskNumber, + (List->SystemPartition->DriveLetter == 0) ? '-' : List->SystemPartition->DriveLetter); + return; + } + + DPRINT1("We are here (1)!\n"); + + List->SystemDisk = NULL; + List->SystemPartition = NULL; + List->OriginalSystemDisk = NULL; + List->OriginalSystemPartition = NULL; + /* Retrieve the first partition of the disk */ PartEntry = CONTAINING_RECORD(DiskEntry->PrimaryPartListHead.Flink, PARTENTRY, ListEntry); + List->SystemDisk = DiskEntry; + List->SystemPartition = PartEntry; + + // + // See: https://svn.reactos.org/svn/reactos/trunk/reactos/base/setup/usetup/partlist.c?r1=63355&r2=63354&pathrev=63355#l2318 + // - /* Set active system partition */ - if ((DiskEntry->NewDisk == TRUE) || - (PartEntry->BootIndicator == FALSE)) + /* Check if the disk is new and if so, use its first partition as the active system partition */ + if (DiskEntry->NewDisk) { - PartEntry->BootIndicator = TRUE; - DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].BootIndicator = TRUE; - DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE; - DiskEntry->Dirty = TRUE; + if (PartEntry->PartitionType == PARTITION_ENTRY_UNUSED || PartEntry->BootIndicator == FALSE) + { + /* FIXME: Might be incorrect if partitions were created by Linux FDISK */ + List->SystemDisk = DiskEntry; + List->SystemPartition = PartEntry; + + List->OriginalSystemDisk = List->SystemDisk; + List->OriginalSystemPartition = List->SystemPartition; + + DPRINT1("Use new first active system partition %lu in disk %lu, drive letter %c\n", + List->SystemPartition->PartitionNumber, + List->SystemDisk->DiskNumber, + (List->SystemPartition->DriveLetter == 0) ? '-' : List->SystemPartition->DriveLetter); + + goto SetSystemPartition; + } + + // FIXME: What to do?? + DPRINT1("NewDisk TRUE but first partition is used?\n"); + } + + DPRINT1("We are here (2)!\n"); + + /* + * The disk is not new, check if any partition is initialized; + * if not, the first one becomes the system partition. + */ + ListEntry = DiskEntry->PrimaryPartListHead.Flink; + while (ListEntry != &DiskEntry->PrimaryPartListHead) + { + /* Retrieve the partition and go to the next one */ + PartEntry = CONTAINING_RECORD(ListEntry, + PARTENTRY, + ListEntry); + + /* Check if the partition is partitioned and is used */ + if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED || PartEntry->BootIndicator != FALSE) + { + break; + } + + /* Go to the next one */ + ListEntry = ListEntry->Flink; + } + if (ListEntry == &DiskEntry->PrimaryPartListHead) + { + /* + * OK we haven't encountered any used and active partition, + * so use the first one as the system partition. + */ /* FIXME: Might be incorrect if partitions were created by Linux FDISK */ - List->SystemDisk = DiskEntry; - List->SystemPartition = PartEntry; + List->OriginalSystemDisk = List->SystemDisk; // DiskEntry + List->OriginalSystemPartition = List->SystemPartition; // First PartEntry - return; + DPRINT1("Use first active system partition %lu in disk %lu, drive letter %c\n", + List->SystemPartition->PartitionNumber, + List->SystemDisk->DiskNumber, + (List->SystemPartition->DriveLetter == 0) ? '-' : List->SystemPartition->DriveLetter); + + goto SetSystemPartition; } - /* Disk is not new, scan all partitions to find a bootable one */ List->SystemDisk = NULL; List->SystemPartition = NULL; + List->OriginalSystemDisk = NULL; + List->OriginalSystemPartition = NULL; + DPRINT1("We are here (3)!\n"); + + /* The disk is not new, scan all partitions to find the (active) system partition */ ListEntry = DiskEntry->PrimaryPartListHead.Flink; while (ListEntry != &DiskEntry->PrimaryPartListHead) { + /* Retrieve the partition and go to the next one */ PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry); + ListEntry = ListEntry->Flink; - /* Check if it is partitioned */ - if (PartEntry->IsPartitioned) + /* Check if the partition is partitioned and used */ + if (PartEntry->IsPartitioned && + PartEntry->PartitionType != PARTITION_ENTRY_UNUSED) { - if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED && - PartEntry->BootIndicator) + /* Check if the partition is active */ + if (PartEntry->BootIndicator) { /* Yes, we found it */ List->SystemDisk = DiskEntry; List->SystemPartition = PartEntry; - DPRINT("Found bootable partition disk %d, drive letter %c\n", - DiskEntry->DiskNumber, PartEntry->DriveLetter); + DPRINT1("Found active system partition %lu in disk %lu, drive letter %c\n", + PartEntry->PartitionNumber, + DiskEntry->DiskNumber, + (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter); break; } } + } - /* Go to the next one */ - ListEntry = ListEntry->Flink; + /* Check if we have found the system partition */ + if (List->SystemDisk == NULL || List->SystemPartition == NULL) + { + /* Nothing, use the alternative system partition */ + DPRINT1("No system partition found, use the alternative partition!\n"); + goto UseAlternativeSystemPartition; + } + + /* Save them */ + List->OriginalSystemDisk = List->SystemDisk; + List->OriginalSystemPartition = List->SystemPartition; + + /* + * ADDITIONAL CHECKS / BIG HACK: + * + * Retrieve its file system and check whether we have + * write support for it. If that is the case we are fine + * and we can use it directly. However if we don't have + * write support we will need to change the active system + * partition. + * + * NOTE that this is completely useless on architectures + * where a real system partition is required, as on these + * architectures the partition uses the FAT FS, for which + * we do have write support. + * NOTE also that for those architectures looking for a + * partition boot indicator is insufficient. + */ + FileSystem = GetFileSystem(FileSystemList, List->OriginalSystemPartition); + if (FileSystem == NULL) + { + DPRINT1("System partition %lu in disk %lu with no FS?!\n", + List->OriginalSystemPartition->PartitionNumber, + List->OriginalSystemDisk->DiskNumber); + goto FindAndUseAlternativeSystemPartition; } + // HACK: WARNING: We cannot write on this FS yet! + // See fslist.c:GetFileSystem() + if (List->OriginalSystemPartition->PartitionType == PARTITION_EXT2 || + List->OriginalSystemPartition->PartitionType == PARTITION_IFS) + { + DPRINT1("Recognized file system %S that doesn't support write support yet!\n", + FileSystem->FileSystemName); + goto FindAndUseAlternativeSystemPartition; + } + + DPRINT1("Use existing active system partition %lu in disk %lu, drive letter %c\n", + List->SystemPartition->PartitionNumber, + List->SystemDisk->DiskNumber, + (List->SystemPartition->DriveLetter == 0) ? '-' : List->SystemPartition->DriveLetter); + + return; + +FindAndUseAlternativeSystemPartition: + /* + * We are here because we have not found any (active) candidate + * system partition that we know how to support. What we are going + * to do is to change the existing system partition and use the + * partition on which we install ReactOS as the new system partition, + * and then we will need to add in FreeLdr's entry a boot entry to boot + * from the original system partition. + */ + + /* Unset the old system partition */ + List->SystemPartition->BootIndicator = FALSE; + List->SystemDisk->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].BootIndicator = FALSE; + List->SystemDisk->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].RewritePartition = TRUE; + List->SystemDisk->Dirty = TRUE; + +UseAlternativeSystemPartition: + List->SystemDisk = List->CurrentDisk; + List->SystemPartition = List->CurrentPartition; + + DPRINT1("Use alternative active system partition %lu in disk %lu, drive letter %c\n", + List->SystemPartition->PartitionNumber, + List->SystemDisk->DiskNumber, + (List->SystemPartition->DriveLetter == 0) ? '-' : List->SystemPartition->DriveLetter); + +SetSystemPartition: + /* Set the new active system partition */ + List->SystemPartition->BootIndicator = TRUE; + List->SystemDisk->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].BootIndicator = TRUE; + List->SystemDisk->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].RewritePartition = TRUE; + List->SystemDisk->Dirty = TRUE; } diff --git a/reactos/base/setup/usetup/partlist.h b/reactos/base/setup/usetup/partlist.h index 748da07527e..0a7761dbd14 100644 --- a/reactos/base/setup/usetup/partlist.h +++ b/reactos/base/setup/usetup/partlist.h @@ -155,6 +155,15 @@ typedef struct _PARTLIST /* The system disk and partition where the boot manager resides */ PDISKENTRY SystemDisk; PPARTENTRY SystemPartition; + /* + * The original system disk and partition in case we are redefining them + * because we do not have write support on them. + * Please not that this is partly a HACK and MUST NEVER happen on + * architectures where real system partitions are mandatory (because then + * they are formatted in FAT FS and we support write operation on them). + */ + PDISKENTRY OriginalSystemDisk; + PPARTENTRY OriginalSystemPartition; PDISKENTRY TempDisk; PPARTENTRY TempPartition; @@ -258,7 +267,8 @@ DeleteCurrentPartition( VOID CheckActiveSystemPartition( - PPARTLIST List); + IN PPARTLIST List, + IN PFILE_SYSTEM_LIST FileSystemList); BOOLEAN WritePartitionsToDisk( diff --git a/reactos/base/setup/usetup/usetup.h b/reactos/base/setup/usetup/usetup.h index 7218bc79776..a640728b056 100644 --- a/reactos/base/setup/usetup/usetup.h +++ b/reactos/base/setup/usetup/usetup.h @@ -60,7 +60,6 @@ /* Internal Headers */ #include "interface/consup.h" -#include "partlist.h" #include "inffile.h" #include "inicache.h" #include "progress.h" @@ -70,6 +69,7 @@ #endif #include "registry.h" #include "fslist.h" +#include "partlist.h" #include "cabinet.h" #include "filesup.h" #include "genlist.h" -- 2.17.1