[USETUP] Deduplicate code in SelectPartitionPage()
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sun, 10 Nov 2024 16:43:31 +0000 (17:43 +0100)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sun, 10 Nov 2024 17:45:58 +0000 (18:45 +0100)
base/setup/usetup/usetup.c

index ee02faa..d5d569e 100644 (file)
@@ -1493,23 +1493,20 @@ LayoutSettingsPage(PINPUT_RECORD Ir)
 
 
 static BOOLEAN
-IsPartitionLargeEnough(
-    _In_ PPARTENTRY PartEntry)
+IsMediumLargeEnough(
+    _In_ ULONGLONG SizeInBytes)
 {
     /* Retrieve the maximum size in MB (rounded up) */
-    ULONGLONG PartSize = RoundingDivide(GetPartEntrySizeInBytes(PartEntry), MB);
+    ULONGLONG SizeInMB = RoundingDivide(SizeInBytes, MB);
 
-    if (PartSize < USetupData.RequiredPartitionDiskSpace)
+    /* Check the medium size */
+    if (SizeInMB < USetupData.RequiredPartitionDiskSpace)
     {
-        /* Partition is too small so ask for another one */
-        DPRINT1("Partition is too small (size: %I64u MB), required disk space is %lu MB\n",
-                PartSize, USetupData.RequiredPartitionDiskSpace);
+        DPRINT1("Partition/Volume is too small (size: %I64u MB), required space is %lu MB\n",
+                SizeInMB, USetupData.RequiredPartitionDiskSpace);
         return FALSE;
     }
-    else
-    {
-        return TRUE;
-    }
+    return TRUE;
 }
 
 
@@ -1535,6 +1532,7 @@ SelectPartitionPage(PINPUT_RECORD Ir)
 {
     PARTLIST_UI ListUi;
     ULONG Error;
+    ULONGLONG MaxTargetSize;
 
     if (PartitionList == NULL)
     {
@@ -1555,7 +1553,9 @@ SelectPartitionPage(PINPUT_RECORD Ir)
     {
         ASSERT(CurrentInstallation);
 
-        /* Determine the selected installation disk & partition */
+        /* Determine the selected installation disk & partition.
+         * It must exist and be valid, since this is the partition
+         * where the existing installation already resides. */
         InstallPartition = SelectPartition(PartitionList,
                                            CurrentInstallation->DiskNumber,
                                            CurrentInstallation->PartitionNumber);
@@ -1564,6 +1564,8 @@ SelectPartitionPage(PINPUT_RECORD Ir)
             DPRINT1("RepairUpdateFlag == TRUE, SelectPartition() returned FALSE, assert!\n");
             ASSERT(FALSE);
         }
+        ASSERT(InstallPartition->IsPartitioned);
+        ASSERT(InstallPartition->Volume);
 
         return START_PARTITION_OPERATIONS_PAGE;
     }
@@ -1577,59 +1579,46 @@ SelectPartitionPage(PINPUT_RECORD Ir)
                         yScreen - 3);
     DrawPartitionList(&ListUi);
 
-    if (IsUnattendedSetup)
+    if (IsUnattendedSetup) do
     {
+        /* If DestinationDiskNumber or DestinationPartitionNumber are invalid
+         * (see below), don't select the partition and show the list instead */
+        if (USetupData.DestinationDiskNumber == -1 ||
+            USetupData.DestinationPartitionNumber == -1)
+        {
+            break;
+        }
+
         /* Determine the selected installation disk & partition */
-        InstallPartition = SelectPartition(PartitionList,
+        CurrentPartition = SelectPartition(PartitionList,
                                            USetupData.DestinationDiskNumber,
                                            USetupData.DestinationPartitionNumber);
-        if (!InstallPartition)
-        {
-            CurrentPartition = ListUi.CurrentPartition;
-
-            if (USetupData.AutoPartition)
-            {
-                ASSERT(CurrentPartition != NULL);
-                ASSERT(!IsContainerPartition(CurrentPartition->PartitionType));
-
-                /* Automatically create the partition on the whole empty space;
-                 * it will be formatted later with default parameters */
-                CreatePartition(PartitionList,
-                                CurrentPartition,
-                                0ULL,
-                                0);
-                if (CurrentPartition->Volume)
-                    CurrentPartition->Volume->New |= VOLUME_NEW_AUTOCREATE;
-
-// FIXME?? Aren't we going to enter an infinite loop, if this test fails??
-                if (!IsPartitionLargeEnough(CurrentPartition))
-                {
-                    MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
-                                    USetupData.RequiredPartitionDiskSpace);
-                    return SELECT_PARTITION_PAGE; /* let the user select another partition */
-                }
 
-                InstallPartition = CurrentPartition;
-                return START_PARTITION_OPERATIONS_PAGE;
-            }
-        }
-        else
+        /* Now reset DestinationDiskNumber and DestinationPartitionNumber
+         * to *invalid* values, so that if the corresponding partition is
+         * determined to be invalid by the code below or in CreateInstallPartition,
+         * we don't reselect it when SelectPartitionPage() is called again */
+        USetupData.DestinationDiskNumber = -1;
+        USetupData.DestinationPartitionNumber = -1;
+
+        // FIXME: Here and in the AutoPartition case below, the CurrentPartition
+        // may actually be unsuitable (MBR-extended, non-simple volume...).
+        // More checks need to be made here!
+        //
+        // NOTE: We don't check for CurrentPartition->Volume in case
+        // the partition doesn't contain a recognized volume/none exists.
+        // We also don't check whether IsPartitioned is TRUE, because if
+        // the partition is still empty space, we'll try to partition it.
+        if (CurrentPartition && !IsContainerPartition(CurrentPartition->PartitionType))
+            goto CreateInstallPartition;
+
+        if (USetupData.AutoPartition)
         {
-            ASSERT(!IsContainerPartition(InstallPartition->PartitionType));
-
-            DrawPartitionList(&ListUi); // FIXME: Doesn't make much sense...
-
-// FIXME?? Aren't we going to enter an infinite loop, if this test fails??
-            if (!IsPartitionLargeEnough(InstallPartition))
-            {
-                MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
-                                USetupData.RequiredPartitionDiskSpace);
-                return SELECT_PARTITION_PAGE; /* let the user select another partition */
-            }
-
-            return START_PARTITION_OPERATIONS_PAGE;
+            CurrentPartition = ListUi.CurrentPartition;
+            // TODO: Do more checks, and loop until we find a valid partition.
+            goto CreateInstallPartition;
         }
-    }
+    } while (0);
 
     while (TRUE)
     {
@@ -1638,7 +1627,7 @@ SelectPartitionPage(PINPUT_RECORD Ir)
         CurrentPartition = ListUi.CurrentPartition;
 
         /* Update status text */
-        if (CurrentPartition == NULL)
+        if (!CurrentPartition)
         {
             // FIXME: If we get a NULL current partition, this means that
             // the current disk is of unrecognized type. So we should display
@@ -1679,7 +1668,7 @@ SelectPartitionPage(PINPUT_RECORD Ir)
                 PartitionList = NULL;
                 return QUIT_PAGE;
             }
-            break;
+            return SELECT_PARTITION_PAGE;
         }
         else if ((Ir->Event.KeyEvent.uChar.AsciiChar == 0x00) &&
                  (Ir->Event.KeyEvent.wVirtualKeyCode == VK_DOWN))  /* DOWN */
@@ -1693,10 +1682,11 @@ SelectPartitionPage(PINPUT_RECORD Ir)
         }
         else if (Ir->Event.KeyEvent.wVirtualKeyCode == VK_RETURN)  /* ENTER */
         {
-            ASSERT(CurrentPartition != NULL);
+            ASSERT(CurrentPartition);
 
+            /* Don't select an extended partition for OS installation */
             if (IsContainerPartition(CurrentPartition->PartitionType))
-                continue; // return SELECT_PARTITION_PAGE;
+                continue;
 
             /*
              * Check whether the user wants to install ReactOS on a disk that
@@ -1715,38 +1705,11 @@ SelectPartitionPage(PINPUT_RECORD Ir)
                 // return SELECT_PARTITION_PAGE;
             }
 
-            if (!CurrentPartition->IsPartitioned)
-            {
-                Error = PartitionCreationChecks(CurrentPartition);
-                if (Error != NOT_AN_ERROR)
-                {
-                    MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
-                    return SELECT_PARTITION_PAGE;
-                }
-
-                /* Automatically create the partition on the whole empty space;
-                 * it will be formatted later with default parameters */
-                CreatePartition(PartitionList,
-                                CurrentPartition,
-                                0ULL,
-                                0);
-                if (CurrentPartition->Volume)
-                    CurrentPartition->Volume->New |= VOLUME_NEW_AUTOCREATE;
-            }
-
-            if (!IsPartitionLargeEnough(CurrentPartition))
-            {
-                MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
-                                USetupData.RequiredPartitionDiskSpace);
-                return SELECT_PARTITION_PAGE; /* let the user select another partition */
-            }
-
-            InstallPartition = CurrentPartition;
-            return START_PARTITION_OPERATIONS_PAGE;
+            goto CreateInstallPartition;
         }
         else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'C')  /* C */
         {
-            ASSERT(CurrentPartition != NULL);
+            ASSERT(CurrentPartition);
 
             Error = PartitionCreationChecks(CurrentPartition);
             if (Error != NOT_AN_ERROR)
@@ -1760,24 +1723,25 @@ SelectPartitionPage(PINPUT_RECORD Ir)
         }
         else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'E')  /* E */
         {
-            ASSERT(CurrentPartition != NULL);
+            ASSERT(CurrentPartition);
 
-            if (CurrentPartition->LogicalPartition == FALSE)
-            {
-                Error = ExtendedPartitionCreationChecks(CurrentPartition);
-                if (Error != NOT_AN_ERROR)
-                {
-                    MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
-                    return SELECT_PARTITION_PAGE;
-                }
+            /* Don't create an extended partition within a logical partition */
+            if (CurrentPartition->LogicalPartition)
+                continue;
 
-                PartCreateType = PartTypeExtended;
-                return CREATE_PARTITION_PAGE;
+            Error = ExtendedPartitionCreationChecks(CurrentPartition);
+            if (Error != NOT_AN_ERROR)
+            {
+                MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
+                return SELECT_PARTITION_PAGE;
             }
+
+            PartCreateType = PartTypeExtended;
+            return CREATE_PARTITION_PAGE;
         }
         else if (Ir->Event.KeyEvent.wVirtualKeyCode == 'D')  /* D */
         {
-            ASSERT(CurrentPartition != NULL);
+            ASSERT(CurrentPartition);
 
             /* Ignore deletion in case this is not a partitioned entry */
             if (!CurrentPartition->IsPartitioned)
@@ -1818,7 +1782,42 @@ SelectPartitionPage(PINPUT_RECORD Ir)
         }
     }
 
-    return SELECT_PARTITION_PAGE;
+CreateInstallPartition:
+    ASSERT(CurrentPartition);
+    ASSERT(!IsContainerPartition(CurrentPartition->PartitionType));
+
+    /* Create the partition if the selected region is empty */
+    if (!CurrentPartition->IsPartitioned)
+    {
+        Error = PartitionCreationChecks(CurrentPartition);
+        if (Error != NOT_AN_ERROR)
+        {
+            MUIDisplayError(Error, Ir, POPUP_WAIT_ANY_KEY);
+            return SELECT_PARTITION_PAGE;
+        }
+
+        /* Automatically create the partition on the whole empty space;
+         * it will be formatted later with default parameters */
+        CreatePartition(PartitionList,
+                        CurrentPartition,
+                        0ULL,
+                        0);
+        ASSERT(CurrentPartition->IsPartitioned);
+        if (CurrentPartition->Volume)
+            CurrentPartition->Volume->New |= VOLUME_NEW_AUTOCREATE;
+    }
+
+    /* Verify the target medium size */
+    MaxTargetSize = GetPartEntrySizeInBytes(CurrentPartition);
+    if (!IsMediumLargeEnough(MaxTargetSize))
+    {
+        MUIDisplayError(ERROR_INSUFFICIENT_PARTITION_SIZE, Ir, POPUP_WAIT_ANY_KEY,
+                        USetupData.RequiredPartitionDiskSpace);
+        return SELECT_PARTITION_PAGE; /* Let the user select another partition */
+    }
+
+    InstallPartition = CurrentPartition;
+    return START_PARTITION_OPERATIONS_PAGE;
 }