[USETUP]
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Tue, 1 Mar 2016 15:00:56 +0000 (15:00 +0000)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Tue, 1 Mar 2016 15:00:56 +0000 (15:00 +0000)
- 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
reactos/base/setup/usetup/bootsup.h
reactos/base/setup/usetup/fslist.c
reactos/base/setup/usetup/fslist.h
reactos/base/setup/usetup/interface/usetup.c
reactos/base/setup/usetup/partlist.c
reactos/base/setup/usetup/partlist.h
reactos/base/setup/usetup/usetup.h

index 68b64aa..1d970a6 100644 (file)
@@ -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;
             }
         }
index 9f0dc5c..0bdeb37 100644 (file)
 
 #pragma once
 
+BOOLEAN
+IsThereAValidBootSector(PWSTR RootPath);
+
+NTSTATUS
+SaveBootSector(
+    PWSTR RootPath,
+    PWSTR DstPath,
+    ULONG Length);
+
 NTSTATUS
 InstallMbrBootCodeToDisk(
     PWSTR SrcPath,
index ee3c2a8..99fe2f8 100644 (file)
@@ -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);
index 4e8f067..685a2cf 100644 (file)
@@ -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(
index e95bb96..b12bdf2 100644 (file)
@@ -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))
index 54e2d28..0d3aa02 100644 (file)
@@ -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;
 }
 
 
index 748da07..0a7761d 100644 (file)
@@ -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(
index 7218bc7..a640728 100644 (file)
@@ -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"