https://git.reactos.org/?p=reactos.git;a=commitdiff;h=0d9ebb67ce6a762f8f3f2…
commit 0d9ebb67ce6a762f8f3f29db9ec39c2aaee3dc3a
Author: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
AuthorDate: Mon Feb 25 23:43:20 2019 +0100
Commit: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
CommitDate: Mon Mar 11 00:05:36 2019 +0100
[SETUPLIB] Improve the discovery of the active system partition.
CORE-7749, CORE-6305, CORE-13205
---
base/setup/lib/utils/partlist.c | 354 +++++++++++++++++++++++++++++++---------
1 file changed, 274 insertions(+), 80 deletions(-)
diff --git a/base/setup/lib/utils/partlist.c b/base/setup/lib/utils/partlist.c
index 269bb99b2f..32adeda7c0 100644
--- a/base/setup/lib/utils/partlist.c
+++ b/base/setup/lib/utils/partlist.c
@@ -3037,6 +3037,74 @@ DeleteCurrentPartition(
DeletePartition(List, List->CurrentPartition);
}
+/*
+ * Retrieve the actual "active" partition of the given disk.
+ * On MBR disks, partition with the Active/Boot flag set;
+ * on GPT disks, partition with the correct GUID.
+ */
+static
+PPARTENTRY
+GetActiveDiskPartition(
+ IN PDISKENTRY DiskEntry)
+{
+ PLIST_ENTRY ListEntry;
+ PPARTENTRY PartEntry;
+ PPARTENTRY ActivePartition = NULL;
+
+ /* Check for empty disk list */
+ // ASSERT(DiskEntry);
+ if (!DiskEntry)
+ return NULL;
+
+ /* Check for empty partition list */
+ if (IsListEmpty(&DiskEntry->PrimaryPartListHead))
+ return NULL;
+
+ if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
+ {
+ DPRINT1("GPT-partitioned disk detected, not currently supported by
SETUP!\n");
+ return NULL;
+ }
+
+ /* Scan all (primary) partitions to find the active disk partition */
+ for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
+ ListEntry != &DiskEntry->PrimaryPartListHead;
+ ListEntry = ListEntry->Flink)
+ {
+ /* Retrieve the partition */
+ PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
+
+ // TODO: Support for GPT disks!
+
+ /* Check if the partition is partitioned, used and active */
+ if (PartEntry->IsPartitioned &&
+ // !IsContainerPartition(PartEntry->PartitionType) &&
+ PartEntry->BootIndicator)
+ {
+ /* Yes, we found it */
+ ASSERT(DiskEntry == PartEntry->DiskEntry);
+ ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED);
+
+ ActivePartition = PartEntry;
+
+ DPRINT1("Found active system partition %lu in disk %lu, drive letter
%C\n",
+ PartEntry->PartitionNumber, DiskEntry->DiskNumber,
+ (PartEntry->DriveLetter == 0) ? L'-' :
PartEntry->DriveLetter);
+ break;
+ }
+ }
+
+ /* Check if the disk is new and if so, use its first partition as the active system
partition */
+ if (DiskEntry->NewDisk && ActivePartition != NULL)
+ {
+ // FIXME: What to do??
+ DPRINT1("NewDisk TRUE but already existing active partition?\n");
+ }
+
+ /* Return the active partition found (or none) */
+ return ActivePartition;
+}
+
static
BOOLEAN
IsSupportedActivePartition(
@@ -3119,24 +3187,16 @@ VOID
CheckActiveSystemPartition(
IN PPARTLIST List)
{
+ PLIST_ENTRY ListEntry;
PDISKENTRY DiskEntry;
PPARTENTRY PartEntry;
- PLIST_ENTRY ListEntry;
+ PPARTENTRY ActivePartition;
+ PPARTENTRY CandidatePartition = NULL;
/* Check for empty disk list */
if (IsListEmpty(&List->DiskListHead))
{
- List->SystemPartition = NULL;
- List->OriginalSystemPartition = NULL;
- return;
- }
-
- /* Choose the currently selected disk */
- DiskEntry = List->CurrentDisk;
-
- /* Check for empty partition list */
- if (IsListEmpty(&DiskEntry->PrimaryPartListHead))
- {
+ /* No system partition! */
List->SystemPartition = NULL;
List->OriginalSystemPartition = NULL;
return;
@@ -3152,17 +3212,182 @@ CheckActiveSystemPartition(
return;
}
- DPRINT("We are here (1)!\n");
-
+ /* Start fresh */
List->SystemPartition = NULL;
List->OriginalSystemPartition = NULL;
+
+//
+// Pass == 1 : Checking the first disk.
+//
+ DPRINT("We are here (1)!\n");
+
+ /*
+ * First, check whether the first disk (the one that will be booted
+ * by default by the hardware) contains an active partition. If so
+ * this should be our system partition.
+ */
+ DiskEntry = CONTAINING_RECORD(List->DiskListHead.Flink,
+ DISKENTRY, ListEntry);
+
+ // if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
+ // {
+ // DPRINT1("GPT-partitioned disk detected, not currently supported by
SETUP!\n");
+ // continue;
+ // }
+
+ DPRINT("We are here (1a)!\n");
+
+ ActivePartition = GetActiveDiskPartition(DiskEntry);
+ if (ActivePartition)
+ {
+ /* Save the actual system partition */
+ List->OriginalSystemPartition = ActivePartition;
+
+ /* If we get a candidate active partition in the first disk, validate it */
+ if (IsSupportedActivePartition(ActivePartition))
+ {
+ CandidatePartition = ActivePartition;
+ goto SystemPartitionFound;
+ }
+ }
+
+ DPRINT("We are here (1b)!\n");
+
+ /* If this first disk is not the current installation disk, do the minimal checks */
+ if (DiskEntry != List->CurrentDisk)
+ {
+ /*
+ * We don't. Enumerate all the (primary) partitions in the first disk,
+ * excluding the current active partition, to find a candidate new one.
+ */
+ for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
+ ListEntry != &DiskEntry->PrimaryPartListHead;
+ ListEntry = ListEntry->Flink)
+ {
+ /* Retrieve the partition */
+ PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
+
+ /* Skip the current active partition */
+ if (/* ActivePartition != NULL && */ PartEntry == ActivePartition)
+ continue;
+
+ /* Check if the partition is partitioned and used */
+ if (PartEntry->IsPartitioned &&
+ !IsContainerPartition(PartEntry->PartitionType))
+ {
+ ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED);
+
+ /* If we get a candidate active partition in the first disk, validate it
*/
+ if (IsSupportedActivePartition(PartEntry))
+ {
+ CandidatePartition = PartEntry;
+ goto FindAndUseAlternativeSystemPartition;
+ }
+ }
+
+#if 0
+ /* Check if the partition is partitioned and used */
+ if (!PartEntry->IsPartitioned)
+ {
+ ASSERT(PartEntry->PartitionType == PARTITION_ENTRY_UNUSED);
+
+ // TODO: Check for minimal size!!
+ CandidatePartition = PartEntry;
+ goto FindAndUseAlternativeSystemPartition;
+ }
+#endif
+ }
+
+ /*
+ * Still nothing, look whether there is some free space that we can use
+ * for the new system partition. We must be sure that the total number
+ * of partition is less than the maximum allowed, and that the minimal
+ * size is fine.
+ */
+//
+// TODO: Fix the handling of system partition being created in unpartitioned space!!
+// --> When to partition it? etc...
+//
+ if (GetPrimaryPartitionCount(DiskEntry) < 4)
+ {
+ for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
+ ListEntry != &DiskEntry->PrimaryPartListHead;
+ ListEntry = ListEntry->Flink)
+ {
+ /* Retrieve the partition */
+ PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
+
+ /* Skip the current active partition */
+ if (/* ActivePartition != NULL && */ PartEntry ==
ActivePartition)
+ continue;
+
+ /* Check for unpartitioned space */
+ if (!PartEntry->IsPartitioned)
+ {
+ ASSERT(PartEntry->PartitionType == PARTITION_ENTRY_UNUSED);
+
+ // TODO: Check for minimal size!!
+ CandidatePartition = PartEntry;
+ goto FindAndUseAlternativeSystemPartition;
+ }
+ }
+ }
+ }
+
+
+ /**** Case where we don't have an active partition on the first disk ****/
+
+//
+// Pass == 2 : Checking the CurrentDisk on which we install.
+//
+ DPRINT("We are here (2)!\n");
+
+ if (DiskEntry != List->CurrentDisk)
+ {
+ /* Choose the currently selected disk */
+ DiskEntry = List->CurrentDisk;
+
+ if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
+ {
+ DPRINT1("Current disk?! -- GPT-partitioned disk detected, not currently
supported by SETUP!\n");
+ DPRINT1("No supported active partition found on this system!\n");
+ return;
+ }
+
+ DPRINT("We are here (2x)!\n");
+
+ ActivePartition = GetActiveDiskPartition(DiskEntry);
+ if (ActivePartition)
+ {
+ /* If we get a candidate active partition, validate it */
+ if (IsSupportedActivePartition(ActivePartition))
+ {
+ CandidatePartition = ActivePartition;
+ goto FindAndUseAlternativeSystemPartition;
+ }
+ }
+ }
+
+
+ /**** Here, we either don't have an active partition, or we have one BUT it is
not supported ****/
+
+/***
+ *** TODO: Improve the selection:
+ *** - If we want a really separate system partition from the partition where
+ *** we install, do something similar to what's done below in the code.
+ *** - Otherwise if we allow for the system partition to be also the partition
+ *** where we install, just directly fall down to List->CurrentPartition.
+ ***/
+
+ DPRINT("We are here (2a)!\n");
+
/* Retrieve the first partition of the disk */
PartEntry = CONTAINING_RECORD(DiskEntry->PrimaryPartListHead.Flink,
- PARTENTRY,
- ListEntry);
+ PARTENTRY, ListEntry);
ASSERT(DiskEntry == PartEntry->DiskEntry);
- List->SystemPartition = PartEntry;
+
+ CandidatePartition = PartEntry;
//
// See:
https://svn.reactos.org/svn/reactos/trunk/reactos/base/setup/usetup/partlis…
@@ -3171,11 +3396,12 @@ CheckActiveSystemPartition(
/* Check if the disk is new and if so, use its first partition as the active system
partition */
if (DiskEntry->NewDisk)
{
- if (PartEntry->PartitionType == PARTITION_ENTRY_UNUSED ||
PartEntry->BootIndicator == FALSE)
+ // !IsContainerPartition(PartEntry->PartitionType);
+ if (!CandidatePartition->IsPartitioned ||
!CandidatePartition->BootIndicator) /* CandidatePartition != ActivePartition */
{
- ASSERT(DiskEntry == PartEntry->DiskEntry);
- List->SystemPartition = PartEntry;
+ ASSERT(DiskEntry == CandidatePartition->DiskEntry);
+ List->SystemPartition = CandidatePartition;
List->OriginalSystemPartition = List->SystemPartition;
DPRINT1("Use new first active system partition %lu in disk %lu, drive
letter %C\n",
@@ -3190,7 +3416,7 @@ CheckActiveSystemPartition(
DPRINT1("NewDisk TRUE but first partition is used?\n");
}
- DPRINT("We are here (2)!\n");
+ DPRINT("We are here (3)!\n");
/*
* The disk is not new, check if any partition is initialized;
@@ -3201,12 +3427,12 @@ CheckActiveSystemPartition(
ListEntry = ListEntry->Flink)
{
/* Retrieve the partition */
- PartEntry = CONTAINING_RECORD(ListEntry,
- PARTENTRY,
- ListEntry);
+ PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
/* Check if the partition is partitioned and is used */
- if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED ||
PartEntry->BootIndicator != FALSE)
+ // !IsContainerPartition(PartEntry->PartitionType);
+ if (/* PartEntry->IsPartitioned && */
+ PartEntry->PartitionType != PARTITION_ENTRY_UNUSED ||
PartEntry->BootIndicator)
{
break;
}
@@ -3217,8 +3443,9 @@ CheckActiveSystemPartition(
* OK we haven't encountered any used and active partition,
* so use the first one as the system partition.
*/
- ASSERT(DiskEntry == List->SystemPartition->DiskEntry);
- List->OriginalSystemPartition = List->SystemPartition; // First PartEntry
+ ASSERT(DiskEntry == CandidatePartition->DiskEntry);
+ List->SystemPartition = CandidatePartition; // The first PartEntry
+ List->OriginalSystemPartition = List->SystemPartition;
DPRINT1("Use first active system partition %lu in disk %lu, drive letter
%C\n",
List->SystemPartition->PartitionNumber,
@@ -3228,57 +3455,21 @@ CheckActiveSystemPartition(
goto SetSystemPartition;
}
- List->SystemPartition = NULL;
- List->OriginalSystemPartition = NULL;
-
- DPRINT("We are here (3)!\n");
-
- /* The disk is not new, scan all partitions to find the (active) system partition */
- for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
- ListEntry != &DiskEntry->PrimaryPartListHead;
- ListEntry = ListEntry->Flink)
- {
- /* Retrieve the partition */
- PartEntry = CONTAINING_RECORD(ListEntry,
- PARTENTRY,
- ListEntry);
-
- /* Check if the partition is partitioned and used */
- if (PartEntry->IsPartitioned &&
- PartEntry->PartitionType != PARTITION_ENTRY_UNUSED)
- {
- /* Check if the partition is active */
- if (PartEntry->BootIndicator)
- {
- /* Yes, we found it */
- ASSERT(DiskEntry == PartEntry->DiskEntry);
- List->SystemPartition = PartEntry;
-
- DPRINT1("Found active system partition %lu in disk %lu, drive letter
%C\n",
- PartEntry->PartitionNumber,
- DiskEntry->DiskNumber,
- (PartEntry->DriveLetter == 0) ? L'-' :
PartEntry->DriveLetter);
- break;
- }
- }
- }
+ DPRINT("We are here (4)!\n");
- /* Check if we have found the system partition */
- if (List->SystemPartition == NULL)
- {
- /* Nothing, use the alternative system partition */
- DPRINT1("No system partition found, use the alternative
partition!\n");
- goto UseAlternativeSystemPartition;
- }
+ /*
+ * The disk is not new, we did not find any actual active partition,
+ * or the one we found was not supported, or any possible other canditate
+ * is not supported. We then use the current (installation) partition.
+ */
+ /* Nothing, use the alternative system partition */
+ DPRINT1("No system partition found, use the alternative partition!\n");
+ CandidatePartition = List->CurrentPartition;
+ goto UseAlternativeSystemPartition;
- /* Save it */
- List->OriginalSystemPartition = List->SystemPartition;
- /* If we get a candidate active partition, validate it */
- if (!IsSupportedActivePartition(List->OriginalSystemPartition))
- {
- goto FindAndUseAlternativeSystemPartition;
- }
+SystemPartitionFound:
+ List->SystemPartition = CandidatePartition;
DPRINT1("Use existing active system partition %lu in disk %lu, drive letter
%C\n",
List->SystemPartition->PartitionNumber,
@@ -3298,13 +3489,16 @@ FindAndUseAlternativeSystemPartition:
*/
/* Unset the old system partition */
- List->SystemPartition->BootIndicator = FALSE;
-
List->SystemPartition->DiskEntry->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].BootIndicator
= FALSE;
-
List->SystemPartition->DiskEntry->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].RewritePartition
= TRUE;
- List->SystemPartition->DiskEntry->Dirty = TRUE;
+ if (List->OriginalSystemPartition)
+ {
+ List->OriginalSystemPartition->BootIndicator = FALSE;
+
List->OriginalSystemPartition->DiskEntry->LayoutBuffer->PartitionEntry[List->OriginalSystemPartition->PartitionIndex].BootIndicator
= FALSE;
+
List->OriginalSystemPartition->DiskEntry->LayoutBuffer->PartitionEntry[List->OriginalSystemPartition->PartitionIndex].RewritePartition
= TRUE;
+ List->OriginalSystemPartition->DiskEntry->Dirty = TRUE;
+ }
UseAlternativeSystemPartition:
- List->SystemPartition = List->CurrentPartition;
+ List->SystemPartition = CandidatePartition;
DPRINT1("Use alternative active system partition %lu in disk %lu, drive letter
%C\n",
List->SystemPartition->PartitionNumber,