[SETUPLIB][USETUP] Remove CurrentDisk/Partition from the partlist lib code, and move...
[reactos.git] / base / setup / lib / utils / partlist.c
index 7145b2f..90dfe7c 100644 (file)
@@ -2,7 +2,8 @@
  * PROJECT:     ReactOS Setup Library
  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
  * PURPOSE:     Partition list functions
- * COPYRIGHT:   Copyright 2003-2018 Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * COPYRIGHT:   Copyright 2003-2019 Casper S. Hornstrup (chorns@users.sourceforge.net)
+ *              Copyright 2018-2019 Hermes Belusca-Maito
  */
 
 #include "precomp.h"
@@ -324,13 +325,15 @@ AssignDriveLetters(
     Letter = L'C';
 
     /* Assign drive letters to primary partitions */
-    Entry1 = List->DiskListHead.Flink;
-    while (Entry1 != &List->DiskListHead)
+    for (Entry1 = List->DiskListHead.Flink;
+         Entry1 != &List->DiskListHead;
+         Entry1 = Entry1->Flink)
     {
         DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
 
-        Entry2 = DiskEntry->PrimaryPartListHead.Flink;
-        while (Entry2 != &DiskEntry->PrimaryPartListHead)
+        for (Entry2 = DiskEntry->PrimaryPartListHead.Flink;
+             Entry2 != &DiskEntry->PrimaryPartListHead;
+             Entry2 = Entry2->Flink)
         {
             PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
 
@@ -339,9 +342,10 @@ AssignDriveLetters(
             if (PartEntry->IsPartitioned &&
                 !IsContainerPartition(PartEntry->PartitionType))
             {
+                ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED);
+
                 if (IsRecognizedPartition(PartEntry->PartitionType) ||
-                    (PartEntry->PartitionType == PARTITION_ENTRY_UNUSED &&
-                     PartEntry->SectorCount.QuadPart != 0LL))
+                    PartEntry->SectorCount.QuadPart != 0LL)
                 {
                     if (Letter <= L'Z')
                     {
@@ -350,21 +354,19 @@ AssignDriveLetters(
                     }
                 }
             }
-
-            Entry2 = Entry2->Flink;
         }
-
-        Entry1 = Entry1->Flink;
     }
 
     /* Assign drive letters to logical drives */
-    Entry1 = List->DiskListHead.Flink;
-    while (Entry1 != &List->DiskListHead)
+    for (Entry1 = List->DiskListHead.Flink;
+         Entry1 != &List->DiskListHead;
+         Entry1 = Entry1->Flink)
     {
         DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
 
-        Entry2 = DiskEntry->LogicalPartListHead.Flink;
-        while (Entry2 != &DiskEntry->LogicalPartListHead)
+        for (Entry2 = DiskEntry->LogicalPartListHead.Flink;
+             Entry2 != &DiskEntry->LogicalPartListHead;
+             Entry2 = Entry2->Flink)
         {
             PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
 
@@ -372,9 +374,10 @@ AssignDriveLetters(
 
             if (PartEntry->IsPartitioned)
             {
+                ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED);
+
                 if (IsRecognizedPartition(PartEntry->PartitionType) ||
-                    (PartEntry->PartitionType == PARTITION_ENTRY_UNUSED &&
-                     PartEntry->SectorCount.QuadPart != 0LL))
+                    PartEntry->SectorCount.QuadPart != 0LL)
                 {
                     if (Letter <= L'Z')
                     {
@@ -383,11 +386,7 @@ AssignDriveLetters(
                     }
                 }
             }
-
-            Entry2 = Entry2->Flink;
         }
-
-        Entry1 = Entry1->Flink;
     }
 }
 
@@ -664,6 +663,183 @@ EnumerateBiosDiskEntries(
 #undef ROOT_NAME
 }
 
+
+
+/*
+ * Inserts the disk region represented by PartEntry into either the primary
+ * or the logical partition list of the given disk.
+ * The lists are kept sorted by increasing order of start sectors.
+ * Of course no disk region should overlap at all with one another.
+ */
+static
+VOID
+InsertDiskRegion(
+    IN PDISKENTRY DiskEntry,
+    IN PPARTENTRY PartEntry,
+    IN BOOLEAN LogicalPartition)
+{
+    PLIST_ENTRY List;
+    PLIST_ENTRY Entry;
+    PPARTENTRY PartEntry2;
+
+    /* Use the correct partition list */
+    if (LogicalPartition)
+        List = &DiskEntry->LogicalPartListHead;
+    else
+        List = &DiskEntry->PrimaryPartListHead;
+
+    /* Find the first disk region before which we need to insert the new one */
+    for (Entry = List->Flink; Entry != List; Entry = Entry->Flink)
+    {
+        PartEntry2 = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
+
+        /* Ignore any unused empty region */
+        if ((PartEntry2->PartitionType == PARTITION_ENTRY_UNUSED &&
+             PartEntry2->StartSector.QuadPart == 0) || PartEntry2->SectorCount.QuadPart == 0)
+        {
+            continue;
+        }
+
+        /* If the current region ends before the one to be inserted, try again */
+        if (PartEntry2->StartSector.QuadPart + PartEntry2->SectorCount.QuadPart - 1 < PartEntry->StartSector.QuadPart)
+            continue;
+
+        /*
+         * One of the disk region boundaries crosses the desired region
+         * (it starts after the desired region, or ends before the end
+         * of the desired region): this is an impossible situation because
+         * disk regions (partitions) cannot overlap!
+         * Throw an error and bail out.
+         */
+        if (max(PartEntry->StartSector.QuadPart, PartEntry2->StartSector.QuadPart)
+            <=
+            min( PartEntry->StartSector.QuadPart +  PartEntry->SectorCount.QuadPart - 1,
+                PartEntry2->StartSector.QuadPart + PartEntry2->SectorCount.QuadPart - 1))
+        {
+            DPRINT1("Disk region overlap problem, stopping there!\n"
+                    "Partition to be inserted:\n"
+                    "    StartSector = %I64u ; EndSector = %I64u\n"
+                    "Existing disk region:\n"
+                    "    StartSector = %I64u ; EndSector = %I64u\n",
+                     PartEntry->StartSector.QuadPart,
+                     PartEntry->StartSector.QuadPart +  PartEntry->SectorCount.QuadPart - 1,
+                    PartEntry2->StartSector.QuadPart,
+                    PartEntry2->StartSector.QuadPart + PartEntry2->SectorCount.QuadPart - 1);
+            return;
+        }
+
+        /* We have found the first region before which the new one has to be inserted */
+        break;
+    }
+
+    /* Insert the disk region */
+    InsertTailList(Entry, &PartEntry->ListEntry);
+}
+
+static
+PPARTENTRY
+CreateInsertBlankRegion(
+    IN PDISKENTRY DiskEntry,
+    IN OUT PLIST_ENTRY ListHead,
+    IN ULONGLONG StartSector,
+    IN ULONGLONG SectorCount,
+    IN BOOLEAN LogicalSpace)
+{
+    PPARTENTRY NewPartEntry;
+
+    NewPartEntry = RtlAllocateHeap(ProcessHeap,
+                                   HEAP_ZERO_MEMORY,
+                                   sizeof(PARTENTRY));
+    if (NewPartEntry == NULL)
+        return NULL;
+
+    NewPartEntry->DiskEntry = DiskEntry;
+
+    NewPartEntry->StartSector.QuadPart = StartSector;
+    NewPartEntry->SectorCount.QuadPart = SectorCount;
+
+    NewPartEntry->IsPartitioned = FALSE;
+    NewPartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
+    NewPartEntry->FormatState = Unformatted;
+    NewPartEntry->FileSystem[0] = L'\0';
+
+    DPRINT1("First Sector : %I64u\n", NewPartEntry->StartSector.QuadPart);
+    DPRINT1("Last Sector  : %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
+    DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
+
+    /* Insert the new entry into the list */
+    InsertTailList(ListHead, &NewPartEntry->ListEntry);
+
+    return NewPartEntry;
+}
+
+static
+// BOOLEAN
+PPARTENTRY
+InitializePartitionEntry(
+    IN PDISKENTRY DiskEntry,
+    IN PPARTENTRY PartEntry,
+    IN ULONGLONG SectorCount,
+    IN BOOLEAN AutoCreate)
+{
+    PPARTENTRY NewPartEntry;
+
+    DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
+
+    if ((AutoCreate != FALSE) ||
+        (AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
+                   PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart))
+    {
+        DPRINT1("Convert existing partition entry\n");
+
+        NewPartEntry = PartEntry;
+        NewPartEntry->AutoCreate = AutoCreate;
+    }
+    else
+    {
+        DPRINT1("Add new partition entry\n");
+
+        /* Insert and initialize a new partition entry */
+        NewPartEntry = RtlAllocateHeap(ProcessHeap,
+                                       HEAP_ZERO_MEMORY,
+                                       sizeof(PARTENTRY));
+        if (NewPartEntry == NULL)
+            return NULL;
+
+        NewPartEntry->DiskEntry = DiskEntry;
+
+        NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
+        NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
+                                             NewPartEntry->StartSector.QuadPart;
+
+        PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
+        PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
+
+        /* Insert the new entry into the list */
+        InsertTailList(&PartEntry->ListEntry, &NewPartEntry->ListEntry);
+    }
+
+    /* Create entry as 'New (Unformatted)' */
+    NewPartEntry->New = TRUE;
+    NewPartEntry->IsPartitioned = TRUE;
+
+    NewPartEntry->PartitionType = FileSystemToPartitionType(L"RAW", &NewPartEntry->StartSector, &NewPartEntry->SectorCount);
+    ASSERT(NewPartEntry->PartitionType != PARTITION_ENTRY_UNUSED);
+
+    NewPartEntry->FormatState = Unformatted;
+    NewPartEntry->FileSystem[0] = L'\0';
+    // NewPartEntry->AutoCreate = AutoCreate;
+    NewPartEntry->BootIndicator = FALSE;
+    NewPartEntry->LogicalPartition = FALSE;
+
+    DPRINT1("First Sector : %I64u\n", NewPartEntry->StartSector.QuadPart);
+    DPRINT1("Last Sector  : %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
+    DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
+
+    return NewPartEntry;
+}
+
+
 static
 VOID
 AddPartitionToDisk(
@@ -675,10 +851,10 @@ AddPartitionToDisk(
     NTSTATUS Status;
     PPARTITION_INFORMATION PartitionInfo;
     PPARTENTRY PartEntry;
-    HANDLE FileHandle;
+    HANDLE PartitionHandle;
     OBJECT_ATTRIBUTES ObjectAttributes;
     IO_STATUS_BLOCK IoStatusBlock;
-    WCHAR Buffer[MAX_PATH];
+    WCHAR PathBuffer[MAX_PATH];
     UNICODE_STRING Name;
     UCHAR LabelBuffer[sizeof(FILE_FS_VOLUME_INFORMATION) + 256 * sizeof(WCHAR)];
     PFILE_FS_VOLUME_INFORMATION LabelInfo = (PFILE_FS_VOLUME_INFORMATION)LabelBuffer;
@@ -708,87 +884,107 @@ AddPartitionToDisk(
 
     PartEntry->LogicalPartition = LogicalPartition;
     PartEntry->IsPartitioned = TRUE;
+    PartEntry->OnDiskPartitionNumber = PartitionInfo->PartitionNumber;
     PartEntry->PartitionNumber = PartitionInfo->PartitionNumber;
     PartEntry->PartitionIndex = PartitionIndex;
 
+    /* Specify the partition as initially unformatted */
+    PartEntry->FormatState = Unformatted;
+    PartEntry->FileSystem[0] = L'\0';
+
+    /* Initialize the partition volume label */
+    RtlZeroMemory(PartEntry->VolumeLabel, sizeof(PartEntry->VolumeLabel));
+
     if (IsContainerPartition(PartEntry->PartitionType))
     {
         PartEntry->FormatState = Unformatted;
-        PartEntry->FileSystem  = NULL;
 
         if (LogicalPartition == FALSE && DiskEntry->ExtendedPartition == NULL)
             DiskEntry->ExtendedPartition = PartEntry;
     }
     else if (IsRecognizedPartition(PartEntry->PartitionType))
     {
-        PartEntry->FileSystem = GetFileSystem(PartEntry);
-        if (PartEntry->FileSystem)
-            PartEntry->FormatState = Preformatted;
-        else
-            PartEntry->FormatState = Unformatted;
-        // PartEntry->FormatState = UnknownFormat;
-    }
-    else
-    {
-        /* Unknown partition, hence unknown partition format (may or may not be actually formatted) */
-        PartEntry->FormatState = UnknownFormat;
-    }
+        ASSERT(PartitionInfo->RecognizedPartition);
+        ASSERT(PartEntry->IsPartitioned && PartEntry->PartitionNumber != 0);
 
-    /* Initialize the partition volume label */
-    RtlZeroMemory(PartEntry->VolumeLabel, sizeof(PartEntry->VolumeLabel));
+        /* Open the volume, ignore any errors */
+        RtlStringCchPrintfW(PathBuffer, ARRAYSIZE(PathBuffer),
+                            L"\\Device\\Harddisk%lu\\Partition%lu",
+                            DiskEntry->DiskNumber,
+                            PartEntry->PartitionNumber);
+        RtlInitUnicodeString(&Name, PathBuffer);
 
-    /* Open the volume, ignore any errors */
-    RtlStringCchPrintfW(Buffer, ARRAYSIZE(Buffer),
-                        L"\\Device\\Harddisk%lu\\Partition%lu",
-                        DiskEntry->DiskNumber, PartEntry->PartitionNumber);
-    RtlInitUnicodeString(&Name, Buffer);
+        InitializeObjectAttributes(&ObjectAttributes,
+                                   &Name,
+                                   OBJ_CASE_INSENSITIVE,
+                                   NULL,
+                                   NULL);
 
-    InitializeObjectAttributes(&ObjectAttributes,
-                               &Name,
-                               OBJ_CASE_INSENSITIVE,
-                               NULL,
-                               NULL);
+        PartitionHandle = NULL;
+        Status = NtOpenFile(&PartitionHandle,
+                            FILE_READ_DATA | SYNCHRONIZE,
+                            &ObjectAttributes,
+                            &IoStatusBlock,
+                            FILE_SHARE_READ | FILE_SHARE_WRITE,
+                            FILE_SYNCHRONOUS_IO_NONALERT);
+        if (!NT_SUCCESS(Status))
+        {
+            DPRINT1("NtOpenFile() failed, Status 0x%08lx\n", Status);
+        }
 
-    Status = NtOpenFile(&FileHandle,
-                        FILE_READ_DATA | SYNCHRONIZE,
-                        &ObjectAttributes,
-                        &IoStatusBlock,
-                        FILE_SHARE_READ | FILE_SHARE_WRITE,
-                        FILE_SYNCHRONOUS_IO_NONALERT);
-    if (NT_SUCCESS(Status))
-    {
-        /* Retrieve the partition volume label */
-        Status = NtQueryVolumeInformationFile(FileHandle,
-                                              &IoStatusBlock,
-                                              &LabelBuffer,
-                                              sizeof(LabelBuffer),
-                                              FileFsVolumeInformation);
-        /* Close the handle */
-        NtClose(FileHandle);
-
-        /* Check for success */
-        if (NT_SUCCESS(Status))
+        if (/* NT_SUCCESS(Status) && */ PartitionHandle)
         {
-            /* Copy the (possibly truncated) volume label and NULL-terminate it */
-            RtlStringCbCopyNW(PartEntry->VolumeLabel, sizeof(PartEntry->VolumeLabel),
-                              LabelInfo->VolumeLabel, LabelInfo->VolumeLabelLength);
+            /* We don't have a FS, try to guess one */
+            Status = InferFileSystemByHandle(PartitionHandle,
+                                             PartEntry->PartitionType,
+                                             PartEntry->FileSystem,
+                                             sizeof(PartEntry->FileSystem));
+            if (!NT_SUCCESS(Status))
+                DPRINT1("InferFileSystemByHandle() failed, Status 0x%08lx\n", Status);
+        }
+        if (*PartEntry->FileSystem)
+        {
+            if (wcsicmp(PartEntry->FileSystem, L"RAW") == 0)
+                PartEntry->FormatState = Unformatted;
+            else
+                PartEntry->FormatState = Preformatted;
         }
         else
         {
-            DPRINT1("NtQueryVolumeInformationFile() failed, Status 0x%08lx\n", Status);
+            PartEntry->FormatState = UnknownFormat;
+        }
+
+        /* Retrieve the partition volume label */
+        if (PartitionHandle)
+        {
+            Status = NtQueryVolumeInformationFile(PartitionHandle,
+                                                  &IoStatusBlock,
+                                                  &LabelBuffer,
+                                                  sizeof(LabelBuffer),
+                                                  FileFsVolumeInformation);
+            if (NT_SUCCESS(Status))
+            {
+                /* Copy the (possibly truncated) volume label and NULL-terminate it */
+                RtlStringCbCopyNW(PartEntry->VolumeLabel, sizeof(PartEntry->VolumeLabel),
+                                  LabelInfo->VolumeLabel, LabelInfo->VolumeLabelLength);
+            }
+            else
+            {
+                DPRINT1("NtQueryVolumeInformationFile() failed, Status 0x%08lx\n", Status);
+            }
         }
+
+        /* Close the partition */
+        if (PartitionHandle)
+            NtClose(PartitionHandle);
     }
     else
     {
-        DPRINT1("NtOpenFile() failed, Status 0x%08lx\n", Status);
+        /* Unknown partition, hence unknown partition format (may or may not be actually formatted) */
+        PartEntry->FormatState = UnknownFormat;
     }
 
-    if (LogicalPartition)
-        InsertTailList(&DiskEntry->LogicalPartListHead,
-                       &PartEntry->ListEntry);
-    else
-        InsertTailList(&DiskEntry->PrimaryPartListHead,
-                       &PartEntry->ListEntry);
+    InsertDiskRegion(DiskEntry, PartEntry, LogicalPartition);
 }
 
 static
@@ -796,6 +992,8 @@ VOID
 ScanForUnpartitionedDiskSpace(
     IN PDISKENTRY DiskEntry)
 {
+    ULONGLONG StartSector;
+    ULONGLONG SectorCount;
     ULONGLONG LastStartSector;
     ULONGLONG LastSectorCount;
     ULONGLONG LastUnusedSectorCount;
@@ -810,39 +1008,35 @@ ScanForUnpartitionedDiskSpace(
         DPRINT1("No primary partition!\n");
 
         /* Create a partition entry that represents the empty disk */
-        NewPartEntry = RtlAllocateHeap(ProcessHeap,
-                                       HEAP_ZERO_MEMORY,
-                                       sizeof(PARTENTRY));
-        if (NewPartEntry == NULL)
-            return;
-
-        NewPartEntry->DiskEntry = DiskEntry;
 
-        NewPartEntry->IsPartitioned = FALSE;
-        NewPartEntry->StartSector.QuadPart = (ULONGLONG)DiskEntry->SectorAlignment;
-        NewPartEntry->SectorCount.QuadPart = AlignDown(DiskEntry->SectorCount.QuadPart, DiskEntry->SectorAlignment) -
-                                             NewPartEntry->StartSector.QuadPart;
-
-        DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
-        DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
-        DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
-
-        NewPartEntry->FormatState = Unformatted;
-        NewPartEntry->FileSystem  = NULL;
-
-        InsertTailList(&DiskEntry->PrimaryPartListHead,
-                       &NewPartEntry->ListEntry);
+        if (DiskEntry->SectorAlignment < 2048)
+            StartSector = 2048ULL;
+        else
+            StartSector = (ULONGLONG)DiskEntry->SectorAlignment;
+        SectorCount = AlignDown(DiskEntry->SectorCount.QuadPart, DiskEntry->SectorAlignment) - StartSector;
+
+        NewPartEntry = CreateInsertBlankRegion(DiskEntry,
+                                               &DiskEntry->PrimaryPartListHead,
+                                               StartSector,
+                                               SectorCount,
+                                               FALSE);
+        if (NewPartEntry == NULL)
+            DPRINT1("Failed to create a new empty region for full disk space!\n");
 
         return;
     }
 
     /* Start partition at head 1, cylinder 0 */
-    LastStartSector = DiskEntry->SectorAlignment;
+    if (DiskEntry->SectorAlignment < 2048)
+        LastStartSector = 2048ULL;
+    else
+        LastStartSector = (ULONGLONG)DiskEntry->SectorAlignment;
     LastSectorCount = 0ULL;
     LastUnusedSectorCount = 0ULL;
 
-    Entry = DiskEntry->PrimaryPartListHead.Flink;
-    while (Entry != &DiskEntry->PrimaryPartListHead)
+    for (Entry = DiskEntry->PrimaryPartListHead.Flink;
+         Entry != &DiskEntry->PrimaryPartListHead;
+         Entry = Entry->Flink)
     {
         PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
 
@@ -857,36 +1051,25 @@ ScanForUnpartitionedDiskSpace(
             {
                 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount);
 
-                NewPartEntry = RtlAllocateHeap(ProcessHeap,
-                                               HEAP_ZERO_MEMORY,
-                                               sizeof(PARTENTRY));
-                if (NewPartEntry == NULL)
-                    return;
-
-                NewPartEntry->DiskEntry = DiskEntry;
-
-                NewPartEntry->IsPartitioned = FALSE;
-                NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
-                NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
-                                                     NewPartEntry->StartSector.QuadPart;
-
-                DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
-                DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
-                DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
-
-                NewPartEntry->FormatState = Unformatted;
-                NewPartEntry->FileSystem  = NULL;
+                StartSector = LastStartSector + LastSectorCount;
+                SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector;
 
                 /* Insert the table into the list */
-                InsertTailList(&PartEntry->ListEntry,
-                               &NewPartEntry->ListEntry);
+                NewPartEntry = CreateInsertBlankRegion(DiskEntry,
+                                                       &PartEntry->ListEntry,
+                                                       StartSector,
+                                                       SectorCount,
+                                                       FALSE);
+                if (NewPartEntry == NULL)
+                {
+                    DPRINT1("Failed to create a new empty region for disk space!\n");
+                    return;
+                }
             }
 
             LastStartSector = PartEntry->StartSector.QuadPart;
             LastSectorCount = PartEntry->SectorCount.QuadPart;
         }
-
-        Entry = Entry->Flink;
     }
 
     /* Check for trailing unpartitioned disk space */
@@ -898,29 +1081,20 @@ ScanForUnpartitionedDiskSpace(
         {
             DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount);
 
-            NewPartEntry = RtlAllocateHeap(ProcessHeap,
-                                           HEAP_ZERO_MEMORY,
-                                           sizeof(PARTENTRY));
-            if (NewPartEntry == NULL)
-                return;
-
-            NewPartEntry->DiskEntry = DiskEntry;
-
-            NewPartEntry->IsPartitioned = FALSE;
-            NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
-            NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
-                                                 NewPartEntry->StartSector.QuadPart;
-
-            DPRINT("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
-            DPRINT("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
-            DPRINT("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
-
-            NewPartEntry->FormatState = Unformatted;
-            NewPartEntry->FileSystem  = NULL;
+            StartSector = LastStartSector + LastSectorCount;
+            SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector;
 
             /* Append the table to the list */
-            InsertTailList(&DiskEntry->PrimaryPartListHead,
-                           &NewPartEntry->ListEntry);
+            NewPartEntry = CreateInsertBlankRegion(DiskEntry,
+                                                   &DiskEntry->PrimaryPartListHead,
+                                                   StartSector,
+                                                   SectorCount,
+                                                   FALSE);
+            if (NewPartEntry == NULL)
+            {
+                DPRINT1("Failed to create a new empty region for trailing disk space!\n");
+                return;
+            }
         }
     }
 
@@ -931,29 +1105,22 @@ ScanForUnpartitionedDiskSpace(
             DPRINT1("No logical partition!\n");
 
             /* Create a partition entry that represents the empty extended partition */
-            NewPartEntry = RtlAllocateHeap(ProcessHeap,
-                                           HEAP_ZERO_MEMORY,
-                                           sizeof(PARTENTRY));
+
+            StartSector = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
+            SectorCount = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment;
+
+            NewPartEntry = CreateInsertBlankRegion(DiskEntry,
+                                                   &DiskEntry->LogicalPartListHead,
+                                                   StartSector,
+                                                   SectorCount,
+                                                   TRUE);
             if (NewPartEntry == NULL)
+            {
+                DPRINT1("Failed to create a new empty region for full extended partition space!\n");
                 return;
-
-            NewPartEntry->DiskEntry = DiskEntry;
+            }
             NewPartEntry->LogicalPartition = TRUE;
 
-            NewPartEntry->IsPartitioned = FALSE;
-            NewPartEntry->StartSector.QuadPart = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
-            NewPartEntry->SectorCount.QuadPart = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment;
-
-            DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
-            DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
-            DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
-
-            NewPartEntry->FormatState = Unformatted;
-            NewPartEntry->FileSystem  = NULL;
-
-            InsertTailList(&DiskEntry->LogicalPartListHead,
-                           &NewPartEntry->ListEntry);
-
             return;
         }
 
@@ -962,8 +1129,9 @@ ScanForUnpartitionedDiskSpace(
         LastSectorCount = 0ULL;
         LastUnusedSectorCount = 0ULL;
 
-        Entry = DiskEntry->LogicalPartListHead.Flink;
-        while (Entry != &DiskEntry->LogicalPartListHead)
+        for (Entry = DiskEntry->LogicalPartListHead.Flink;
+             Entry != &DiskEntry->LogicalPartListHead;
+             Entry = Entry->Flink)
         {
             PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
 
@@ -978,72 +1146,54 @@ ScanForUnpartitionedDiskSpace(
                 {
                     DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount);
 
-                    NewPartEntry = RtlAllocateHeap(ProcessHeap,
-                                                   HEAP_ZERO_MEMORY,
-                                                   sizeof(PARTENTRY));
+                    StartSector = LastStartSector + LastSectorCount;
+                    SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector;
+
+                    /* Insert the table into the list */
+                    NewPartEntry = CreateInsertBlankRegion(DiskEntry,
+                                                           &PartEntry->ListEntry,
+                                                           StartSector,
+                                                           SectorCount,
+                                                           TRUE);
                     if (NewPartEntry == NULL)
+                    {
+                        DPRINT1("Failed to create a new empty region for extended partition space!\n");
                         return;
-
-                    NewPartEntry->DiskEntry = DiskEntry;
+                    }
                     NewPartEntry->LogicalPartition = TRUE;
-
-                    NewPartEntry->IsPartitioned = FALSE;
-                    NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
-                    NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
-                                                         NewPartEntry->StartSector.QuadPart;
-
-                    DPRINT("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
-                    DPRINT("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
-                    DPRINT("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
-
-                    NewPartEntry->FormatState = Unformatted;
-                    NewPartEntry->FileSystem  = NULL;
-
-                    /* Insert the table into the list */
-                    InsertTailList(&PartEntry->ListEntry,
-                                   &NewPartEntry->ListEntry);
                 }
 
                 LastStartSector = PartEntry->StartSector.QuadPart;
                 LastSectorCount = PartEntry->SectorCount.QuadPart;
             }
-
-            Entry = Entry->Flink;
         }
 
         /* Check for trailing unpartitioned disk space */
         if ((LastStartSector + LastSectorCount) < DiskEntry->ExtendedPartition->StartSector.QuadPart + DiskEntry->ExtendedPartition->SectorCount.QuadPart)
         {
-            LastUnusedSectorCount = AlignDown(DiskEntry->ExtendedPartition->StartSector.QuadPart + DiskEntry->ExtendedPartition->SectorCount.QuadPart - (LastStartSector + LastSectorCount), DiskEntry->SectorAlignment);
+            LastUnusedSectorCount = AlignDown(DiskEntry->ExtendedPartition->StartSector.QuadPart +
+                                              DiskEntry->ExtendedPartition->SectorCount.QuadPart - (LastStartSector + LastSectorCount),
+                                              DiskEntry->SectorAlignment);
 
             if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
             {
                 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount);
 
-                NewPartEntry = RtlAllocateHeap(ProcessHeap,
-                                               HEAP_ZERO_MEMORY,
-                                               sizeof(PARTENTRY));
+                StartSector = LastStartSector + LastSectorCount;
+                SectorCount = AlignDown(StartSector + LastUnusedSectorCount, DiskEntry->SectorAlignment) - StartSector;
+
+                /* Append the table to the list */
+                NewPartEntry = CreateInsertBlankRegion(DiskEntry,
+                                                       &DiskEntry->LogicalPartListHead,
+                                                       StartSector,
+                                                       SectorCount,
+                                                       TRUE);
                 if (NewPartEntry == NULL)
+                {
+                    DPRINT1("Failed to create a new empty region for extended partition space!\n");
                     return;
-
-                NewPartEntry->DiskEntry = DiskEntry;
+                }
                 NewPartEntry->LogicalPartition = TRUE;
-
-                NewPartEntry->IsPartitioned = FALSE;
-                NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
-                NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
-                                                     NewPartEntry->StartSector.QuadPart;
-
-                DPRINT("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
-                DPRINT("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
-                DPRINT("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
-
-                NewPartEntry->FormatState = Unformatted;
-                NewPartEntry->FileSystem  = NULL;
-
-                /* Append the table to the list */
-                InsertTailList(&DiskEntry->LogicalPartListHead,
-                               &NewPartEntry->ListEntry);
             }
         }
     }
@@ -1063,6 +1213,12 @@ SetDiskSignature(
     PDISKENTRY DiskEntry2;
     PUCHAR Buffer;
 
+    if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
+    {
+        DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
+        return;
+    }
+
     Buffer = (PUCHAR)&DiskEntry->LayoutBuffer->Signature;
 
     while (TRUE)
@@ -1085,16 +1241,21 @@ SetDiskSignature(
          *   Check also signatures from disks, which are
          *   not visible (bootable) by the bios.
          */
-        Entry2 = List->DiskListHead.Flink;
-        while (Entry2 != &List->DiskListHead)
+        for (Entry2 = List->DiskListHead.Flink;
+             Entry2 != &List->DiskListHead;
+             Entry2 = Entry2->Flink)
         {
             DiskEntry2 = CONTAINING_RECORD(Entry2, DISKENTRY, ListEntry);
 
+            if (DiskEntry2->DiskStyle == PARTITION_STYLE_GPT)
+            {
+                DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
+                continue;
+            }
+
             if (DiskEntry != DiskEntry2 &&
                 DiskEntry->LayoutBuffer->Signature == DiskEntry2->LayoutBuffer->Signature)
                 break;
-
-            Entry2 = Entry2->Flink;
         }
 
         if (Entry2 == &List->DiskListHead)
@@ -1110,20 +1271,25 @@ UpdateDiskSignatures(
     PLIST_ENTRY Entry;
     PDISKENTRY DiskEntry;
 
-    /* Print partition lines */
-    Entry = List->DiskListHead.Flink;
-    while (Entry != &List->DiskListHead)
+    /* Update each disk */
+    for (Entry = List->DiskListHead.Flink;
+         Entry != &List->DiskListHead;
+         Entry = Entry->Flink)
     {
         DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
 
+        if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
+        {
+            DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
+            continue;
+        }
+
         if (DiskEntry->LayoutBuffer &&
             DiskEntry->LayoutBuffer->Signature == 0)
         {
             SetDiskSignature(List, DiskEntry);
             DiskEntry->LayoutBuffer->PartitionEntry[0].RewritePartition = TRUE;
         }
-
-        Entry = Entry->Flink;
     }
 }
 
@@ -1241,6 +1407,8 @@ AddDiskToList(
         return;
     }
 
+    DiskEntry->PartList = List;
+
 //    DiskEntry->Checksum = Checksum;
 //    DiskEntry->Signature = Signature;
     DiskEntry->BiosFound = FALSE;
@@ -1249,22 +1417,42 @@ AddDiskToList(
      * Check if this disk has a valid MBR: verify its signature,
      * and whether its two first bytes are a valid instruction
      * (related to this, see IsThereAValidBootSector() in partlist.c).
+     *
+     * See also ntoskrnl/fstub/fstubex.c!FstubDetectPartitionStyle().
      */
-    if (Mbr->Magic != 0xaa55 || (*(PUSHORT)Mbr->BootCode) == 0x0000)
-        DiskEntry->NoMbr = TRUE;
-    else
-        DiskEntry->NoMbr = FALSE;
-
-    /* Free the MBR sector buffer */
-    RtlFreeHeap(ProcessHeap, 0, Mbr);
 
+    // DiskEntry->NoMbr = (Mbr->Magic != PARTITION_MAGIC || (*(PUSHORT)Mbr->BootCode) == 0x0000);
 
-    ListEntry = List->BiosDiskListHead.Flink;
-    while (ListEntry != &List->BiosDiskListHead)
+    /* If we have not the 0xAA55 then it's raw partition */
+    if (Mbr->Magic != PARTITION_MAGIC)
     {
-        BiosDiskEntry = CONTAINING_RECORD(ListEntry, BIOSDISKENTRY, ListEntry);
-        /* FIXME:
-         *   Compare the size from bios and the reported size from driver.
+        DiskEntry->DiskStyle = PARTITION_STYLE_RAW;
+    }
+    /* Check partitions types: if first is 0xEE and all the others 0, we have GPT */
+    else if (Mbr->Partition[0].PartitionType == EFI_PMBR_OSTYPE_EFI &&
+             Mbr->Partition[1].PartitionType == 0 &&
+             Mbr->Partition[2].PartitionType == 0 &&
+             Mbr->Partition[3].PartitionType == 0)
+    {
+        DiskEntry->DiskStyle = PARTITION_STYLE_GPT;
+    }
+    /* Otherwise, partition table is in MBR */
+    else
+    {
+        DiskEntry->DiskStyle = PARTITION_STYLE_MBR;
+    }
+
+    /* Free the MBR sector buffer */
+    RtlFreeHeap(ProcessHeap, 0, Mbr);
+
+
+    for (ListEntry = List->BiosDiskListHead.Flink;
+         ListEntry != &List->BiosDiskListHead;
+         ListEntry = ListEntry->Flink)
+    {
+        BiosDiskEntry = CONTAINING_RECORD(ListEntry, BIOSDISKENTRY, ListEntry);
+        /* FIXME:
+         *   Compare the size from bios and the reported size from driver.
          *   If we have more than one disk with a zero or with the same signature
          *   we must create new signatures and reboot. After the reboot,
          *   it is possible to identify the disks.
@@ -1284,7 +1472,6 @@ AddDiskToList(
                 // FIXME: What to do?
             }
         }
-        ListEntry = ListEntry->Flink;
     }
 
     if (!DiskEntry->BiosFound)
@@ -1350,6 +1537,16 @@ AddDiskToList(
      * We now retrieve the disk partition layout
      */
 
+    /*
+     * Stop there now if the disk is GPT-partitioned,
+     * since we currently do not support such disks.
+     */
+    if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
+    {
+        DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
+        return;
+    }
+
     /* Allocate a layout buffer with 4 partition entries first */
     LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
                        ((4 - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION));
@@ -1427,22 +1624,25 @@ AddDiskToList(
         DPRINT1("No valid partition table found! Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector);
     }
 
-
     if (DiskEntry->LayoutBuffer->PartitionCount == 0)
     {
         DiskEntry->NewDisk = TRUE;
         DiskEntry->LayoutBuffer->PartitionCount = 4;
 
         for (i = 0; i < 4; i++)
+        {
             DiskEntry->LayoutBuffer->PartitionEntry[i].RewritePartition = TRUE;
+        }
     }
     else
     {
+        /* Enumerate and add the first four primary partitions */
         for (i = 0; i < 4; i++)
         {
             AddPartitionToDisk(DiskNumber, DiskEntry, i, FALSE);
         }
 
+        /* Enumerate and add the remaining partitions as logical ones */
         for (i = 4; i < DiskEntry->LayoutBuffer->PartitionCount; i += 4)
         {
             AddPartitionToDisk(DiskNumber, DiskEntry, i, TRUE);
@@ -1472,9 +1672,6 @@ CreatePartitionList(VOID)
     if (List == NULL)
         return NULL;
 
-    List->CurrentDisk = NULL;
-    List->CurrentPartition = NULL;
-
     List->SystemPartition = NULL;
     List->OriginalSystemPartition = NULL;
 
@@ -1529,30 +1726,6 @@ CreatePartitionList(VOID)
 
     AssignDriveLetters(List);
 
-    /* Search for first usable disk and partition */
-    if (IsListEmpty(&List->DiskListHead))
-    {
-        List->CurrentDisk = NULL;
-        List->CurrentPartition = NULL;
-    }
-    else
-    {
-        List->CurrentDisk = CONTAINING_RECORD(List->DiskListHead.Flink,
-                                              DISKENTRY,
-                                              ListEntry);
-
-        if (IsListEmpty(&List->CurrentDisk->PrimaryPartListHead))
-        {
-            List->CurrentPartition = NULL;
-        }
-        else
-        {
-            List->CurrentPartition = CONTAINING_RECORD(List->CurrentDisk->PrimaryPartListHead.Flink,
-                                                       PARTENTRY,
-                                                       ListEntry);
-        }
-    }
-
     return List;
 }
 
@@ -1622,11 +1795,11 @@ GetDiskByBiosNumber(
     PLIST_ENTRY Entry;
 
     /* Loop over the disks and find the correct one */
-    Entry = List->DiskListHead.Flink;
-    while (Entry != &List->DiskListHead)
+    for (Entry = List->DiskListHead.Flink;
+         Entry != &List->DiskListHead;
+         Entry = Entry->Flink)
     {
         DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
-        Entry = Entry->Flink;
 
         if (DiskEntry->BiosDiskNumber == BiosDiskNumber)
         {
@@ -1648,11 +1821,11 @@ GetDiskByNumber(
     PLIST_ENTRY Entry;
 
     /* Loop over the disks and find the correct one */
-    Entry = List->DiskListHead.Flink;
-    while (Entry != &List->DiskListHead)
+    for (Entry = List->DiskListHead.Flink;
+         Entry != &List->DiskListHead;
+         Entry = Entry->Flink)
     {
         DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
-        Entry = Entry->Flink;
 
         if (DiskEntry->DiskNumber == DiskNumber)
         {
@@ -1676,11 +1849,11 @@ GetDiskBySCSI(
     PLIST_ENTRY Entry;
 
     /* Loop over the disks and find the correct one */
-    Entry = List->DiskListHead.Flink;
-    while (Entry != &List->DiskListHead)
+    for (Entry = List->DiskListHead.Flink;
+         Entry != &List->DiskListHead;
+         Entry = Entry->Flink)
     {
         DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
-        Entry = Entry->Flink;
 
         if (DiskEntry->Port == Port &&
             DiskEntry->Bus  == Bus  &&
@@ -1704,11 +1877,11 @@ GetDiskBySignature(
     PLIST_ENTRY Entry;
 
     /* Loop over the disks and find the correct one */
-    Entry = List->DiskListHead.Flink;
-    while (Entry != &List->DiskListHead)
+    for (Entry = List->DiskListHead.Flink;
+         Entry != &List->DiskListHead;
+         Entry = Entry->Flink)
     {
         DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
-        Entry = Entry->Flink;
 
         if (DiskEntry->LayoutBuffer->Signature == Signature)
         {
@@ -1730,12 +1903,18 @@ GetPartition(
     PPARTENTRY PartEntry;
     PLIST_ENTRY Entry;
 
+    if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
+    {
+        DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
+        return NULL;
+    }
+
     /* Disk found, loop over the primary partitions first... */
-    Entry = DiskEntry->PrimaryPartListHead.Flink;
-    while (Entry != &DiskEntry->PrimaryPartListHead)
+    for (Entry = DiskEntry->PrimaryPartListHead.Flink;
+         Entry != &DiskEntry->PrimaryPartListHead;
+         Entry = Entry->Flink)
     {
         PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
-        Entry = Entry->Flink;
 
         if (PartEntry->PartitionNumber == PartitionNumber)
         {
@@ -1745,11 +1924,11 @@ GetPartition(
     }
 
     /* ... then over the logical partitions if needed */
-    Entry = DiskEntry->LogicalPartListHead.Flink;
-    while (Entry != &DiskEntry->LogicalPartListHead)
+    for (Entry = DiskEntry->LogicalPartListHead.Flink;
+         Entry != &DiskEntry->LogicalPartListHead;
+         Entry = Entry->Flink)
     {
         PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
-        Entry = Entry->Flink;
 
         if (PartEntry->PartitionNumber == PartitionNumber)
         {
@@ -1781,6 +1960,12 @@ GetDiskOrPartition(
     /* If we have a partition (PartitionNumber != 0), find it */
     if (PartitionNumber != 0)
     {
+        if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
+        {
+            DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
+            return FALSE;
+        }
+
         PartEntry = GetPartition(/*List,*/ DiskEntry, PartitionNumber);
         if (!PartEntry)
             return FALSE;
@@ -1796,7 +1981,7 @@ GetDiskOrPartition(
 //
 // NOTE: Was introduced broken in r6258 by Casper
 //
-BOOLEAN
+PPARTENTRY
 SelectPartition(
     IN PPARTLIST List,
     IN ULONG DiskNumber,
@@ -1807,59 +1992,55 @@ SelectPartition(
 
     DiskEntry = GetDiskByNumber(List, DiskNumber);
     if (!DiskEntry)
-        return FALSE;
+        return NULL;
 
     PartEntry = GetPartition(/*List,*/ DiskEntry, PartitionNumber);
     if (!PartEntry)
-        return FALSE;
+        return NULL;
 
     ASSERT(PartEntry->DiskEntry == DiskEntry);
     ASSERT(DiskEntry->DiskNumber == DiskNumber);
     ASSERT(PartEntry->PartitionNumber == PartitionNumber);
 
-    List->CurrentDisk = DiskEntry;
-    List->CurrentPartition = PartEntry;
-    return TRUE;
+    return PartEntry;
 }
 
 PPARTENTRY
 GetNextPartition(
-    IN PPARTLIST List)
+    IN PPARTLIST List,
+    IN PPARTENTRY CurrentPart OPTIONAL)
 {
     PLIST_ENTRY DiskListEntry;
     PLIST_ENTRY PartListEntry;
-    PDISKENTRY DiskEntry;
-    PPARTENTRY PartEntry;
+    PDISKENTRY CurrentDisk;
 
     /* Fail if no disks are available */
     if (IsListEmpty(&List->DiskListHead))
         return NULL;
 
-    /* Check for next usable entry on current disk */
-    if (List->CurrentPartition != NULL)
+    /* Check for the next usable entry on the current partition's disk */
+    if (CurrentPart != NULL)
     {
-        if (List->CurrentPartition->LogicalPartition)
+        CurrentDisk = CurrentPart->DiskEntry;
+
+        if (CurrentPart->LogicalPartition)
         {
             /* Logical partition */
 
-            PartListEntry = List->CurrentPartition->ListEntry.Flink;
-            if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
+            PartListEntry = CurrentPart->ListEntry.Flink;
+            if (PartListEntry != &CurrentDisk->LogicalPartListHead)
             {
                 /* Next logical partition */
-                PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
-
-                List->CurrentPartition = PartEntry;
-                return List->CurrentPartition;
+                CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
+                return CurrentPart;
             }
             else
             {
-                PartListEntry = List->CurrentDisk->ExtendedPartition->ListEntry.Flink;
-                if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
+                PartListEntry = CurrentDisk->ExtendedPartition->ListEntry.Flink;
+                if (PartListEntry != &CurrentDisk->PrimaryPartListHead)
                 {
-                    PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
-
-                    List->CurrentPartition = PartEntry;
-                    return List->CurrentPartition;
+                    CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
+                    return CurrentPart;
                 }
             }
         }
@@ -1867,51 +2048,50 @@ GetNextPartition(
         {
             /* Primary or extended partition */
 
-            if ((List->CurrentPartition->IsPartitioned != FALSE) &&
-                IsContainerPartition(List->CurrentPartition->PartitionType))
+            if (CurrentPart->IsPartitioned &&
+                IsContainerPartition(CurrentPart->PartitionType))
             {
                 /* First logical partition */
-                PartListEntry = List->CurrentDisk->LogicalPartListHead.Flink;
-                if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
+                PartListEntry = CurrentDisk->LogicalPartListHead.Flink;
+                if (PartListEntry != &CurrentDisk->LogicalPartListHead)
                 {
-                    PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
-
-                    List->CurrentPartition = PartEntry;
-                    return List->CurrentPartition;
+                    CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
+                    return CurrentPart;
                 }
             }
             else
             {
                 /* Next primary partition */
-                PartListEntry = List->CurrentPartition->ListEntry.Flink;
-                if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
+                PartListEntry = CurrentPart->ListEntry.Flink;
+                if (PartListEntry != &CurrentDisk->PrimaryPartListHead)
                 {
-                    PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
-
-                    List->CurrentPartition = PartEntry;
-                    return List->CurrentPartition;
+                    CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
+                    return CurrentPart;
                 }
             }
         }
     }
 
     /* Search for the first partition entry on the next disk */
-    DiskListEntry = List->CurrentDisk->ListEntry.Flink;
-    while (DiskListEntry != &List->DiskListHead)
+    for (DiskListEntry = (CurrentPart ? CurrentDisk->ListEntry.Flink
+                                      : List->DiskListHead.Flink);
+         DiskListEntry != &List->DiskListHead;
+         DiskListEntry = DiskListEntry->Flink)
     {
-        DiskEntry = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
+        CurrentDisk = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
 
-        PartListEntry = DiskEntry->PrimaryPartListHead.Flink;
-        if (PartListEntry != &DiskEntry->PrimaryPartListHead)
+        if (CurrentDisk->DiskStyle == PARTITION_STYLE_GPT)
         {
-            PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
-
-            List->CurrentDisk = DiskEntry;
-            List->CurrentPartition = PartEntry;
-            return List->CurrentPartition;
+            DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
+            continue;
         }
 
-        DiskListEntry = DiskListEntry->Flink;
+        PartListEntry = CurrentDisk->PrimaryPartListHead.Flink;
+        if (PartListEntry != &CurrentDisk->PrimaryPartListHead)
+        {
+            CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
+            return CurrentPart;
+        }
     }
 
     return NULL;
@@ -1919,93 +2099,94 @@ GetNextPartition(
 
 PPARTENTRY
 GetPrevPartition(
-    IN PPARTLIST List)
+    IN PPARTLIST List,
+    IN PPARTENTRY CurrentPart OPTIONAL)
 {
     PLIST_ENTRY DiskListEntry;
     PLIST_ENTRY PartListEntry;
-    PDISKENTRY DiskEntry;
-    PPARTENTRY PartEntry;
+    PDISKENTRY CurrentDisk;
 
     /* Fail if no disks are available */
     if (IsListEmpty(&List->DiskListHead))
         return NULL;
 
-    /* Check for previous usable entry on current disk */
-    if (List->CurrentPartition != NULL)
+    /* Check for the previous usable entry on the current partition's disk */
+    if (CurrentPart != NULL)
     {
-        if (List->CurrentPartition->LogicalPartition)
+        CurrentDisk = CurrentPart->DiskEntry;
+
+        if (CurrentPart->LogicalPartition)
         {
             /* Logical partition */
-            PartListEntry = List->CurrentPartition->ListEntry.Blink;
-            if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
+
+            PartListEntry = CurrentPart->ListEntry.Blink;
+            if (PartListEntry != &CurrentDisk->LogicalPartListHead)
             {
                 /* Previous logical partition */
-                PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
+                CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
             }
             else
             {
                 /* Extended partition */
-                PartEntry = List->CurrentDisk->ExtendedPartition;
+                CurrentPart = CurrentDisk->ExtendedPartition;
             }
-
-            List->CurrentPartition = PartEntry;
-            return List->CurrentPartition;
+            return CurrentPart;
         }
         else
         {
             /* Primary or extended partition */
 
-            PartListEntry = List->CurrentPartition->ListEntry.Blink;
-            if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
+            PartListEntry = CurrentPart->ListEntry.Blink;
+            if (PartListEntry != &CurrentDisk->PrimaryPartListHead)
             {
-                PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
+                CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
 
-                if ((PartEntry->IsPartitioned != FALSE) &&
-                    IsContainerPartition(PartEntry->PartitionType))
+                if (CurrentPart->IsPartitioned &&
+                    IsContainerPartition(CurrentPart->PartitionType))
                 {
-                    PartListEntry = List->CurrentDisk->LogicalPartListHead.Blink;
-                    PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
+                    PartListEntry = CurrentDisk->LogicalPartListHead.Blink;
+                    CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
                 }
 
-                List->CurrentPartition = PartEntry;
-                return List->CurrentPartition;
+                return CurrentPart;
             }
         }
     }
 
     /* Search for the last partition entry on the previous disk */
-    DiskListEntry = List->CurrentDisk->ListEntry.Blink;
-    while (DiskListEntry != &List->DiskListHead)
+    for (DiskListEntry = (CurrentPart ? CurrentDisk->ListEntry.Blink
+                                      : List->DiskListHead.Blink);
+         DiskListEntry != &List->DiskListHead;
+         DiskListEntry = DiskListEntry->Blink)
     {
-        DiskEntry = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
+        CurrentDisk = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
+
+        if (CurrentDisk->DiskStyle == PARTITION_STYLE_GPT)
+        {
+            DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
+            continue;
+        }
 
-        PartListEntry = DiskEntry->PrimaryPartListHead.Blink;
-        if (PartListEntry != &DiskEntry->PrimaryPartListHead)
+        PartListEntry = CurrentDisk->PrimaryPartListHead.Blink;
+        if (PartListEntry != &CurrentDisk->PrimaryPartListHead)
         {
-            PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
+            CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
 
-            if ((PartEntry->IsPartitioned != FALSE) &&
-                IsContainerPartition(PartEntry->PartitionType))
+            if (CurrentPart->IsPartitioned &&
+                IsContainerPartition(CurrentPart->PartitionType))
             {
-                PartListEntry = DiskEntry->LogicalPartListHead.Blink;
-                if (PartListEntry != &DiskEntry->LogicalPartListHead)
+                PartListEntry = CurrentDisk->LogicalPartListHead.Blink;
+                if (PartListEntry != &CurrentDisk->LogicalPartListHead)
                 {
-                    PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
-
-                    List->CurrentDisk = DiskEntry;
-                    List->CurrentPartition = PartEntry;
-                    return List->CurrentPartition;
+                    CurrentPart = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
+                    return CurrentPart;
                 }
             }
             else
             {
-                List->CurrentDisk = DiskEntry;
-                List->CurrentPartition = PartEntry;
-                return List->CurrentPartition;
+                return CurrentPart;
             }
         }
-
-        DiskListEntry = DiskListEntry->Blink;
     }
 
     return NULL;
@@ -2036,7 +2217,6 @@ IsSamePrimaryLayoutEntry(
 {
     if (PartitionInfo->StartingOffset.QuadPart == PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector &&
         PartitionInfo->PartitionLength.QuadPart == PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector)
-//        PartitionInfo->PartitionNumber = PartEntry->PartitionNumber &&
 //        PartitionInfo->PartitionType == PartEntry->PartitionType
     {
         return TRUE;
@@ -2054,14 +2234,19 @@ GetPrimaryPartitionCount(
     PPARTENTRY PartEntry;
     ULONG Count = 0;
 
-    Entry = DiskEntry->PrimaryPartListHead.Flink;
-    while (Entry != &DiskEntry->PrimaryPartListHead)
+    if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
+    {
+        DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
+        return 0;
+    }
+
+    for (Entry = DiskEntry->PrimaryPartListHead.Flink;
+         Entry != &DiskEntry->PrimaryPartListHead;
+         Entry = Entry->Flink)
     {
         PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
         if (PartEntry->IsPartitioned)
             Count++;
-
-        Entry = Entry->Flink;
     }
 
     return Count;
@@ -2076,14 +2261,19 @@ GetLogicalPartitionCount(
     PPARTENTRY PartEntry;
     ULONG Count = 0;
 
-    ListEntry = DiskEntry->LogicalPartListHead.Flink;
-    while (ListEntry != &DiskEntry->LogicalPartListHead)
+    if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
+    {
+        DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
+        return 0;
+    }
+
+    for (ListEntry = DiskEntry->LogicalPartListHead.Flink;
+         ListEntry != &DiskEntry->LogicalPartListHead;
+         ListEntry = ListEntry->Flink)
     {
         PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
         if (PartEntry->IsPartitioned)
             Count++;
-
-        ListEntry = ListEntry->Flink;
     }
 
     return Count;
@@ -2107,7 +2297,7 @@ ReAllocateLayoutBuffer(
     if (DiskEntry->LayoutBuffer)
         CurrentPartitionCount = DiskEntry->LayoutBuffer->PartitionCount;
 
-    DPRINT1("CurrentPartitionCount: %lu    NewPartitionCount: %lu\n",
+    DPRINT1("CurrentPartitionCount: %lu ; NewPartitionCount: %lu\n",
             CurrentPartitionCount, NewPartitionCount);
 
     if (CurrentPartitionCount == NewPartitionCount)
@@ -2125,15 +2315,18 @@ ReAllocateLayoutBuffer(
         return FALSE;
     }
 
+    NewLayoutBuffer->PartitionCount = NewPartitionCount;
+
     /* If the layout buffer grows, make sure the new (empty) entries are written to the disk */
     if (NewPartitionCount > CurrentPartitionCount)
     {
         for (i = CurrentPartitionCount; i < NewPartitionCount; i++)
+        {
             NewLayoutBuffer->PartitionEntry[i].RewritePartition = TRUE;
+        }
     }
 
     DiskEntry->LayoutBuffer = NewLayoutBuffer;
-    DiskEntry->LayoutBuffer->PartitionCount = NewPartitionCount;
 
     return TRUE;
 }
@@ -2153,6 +2346,12 @@ UpdateDiskLayout(
 
     DPRINT1("UpdateDiskLayout()\n");
 
+    if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
+    {
+        DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
+        return;
+    }
+
     /* Resize the layout buffer if necessary */
     if (ReAllocateLayoutBuffer(DiskEntry) == FALSE)
     {
@@ -2162,14 +2361,24 @@ UpdateDiskLayout(
 
     /* Update the primary partition table */
     Index = 0;
-    ListEntry = DiskEntry->PrimaryPartListHead.Flink;
-    while (ListEntry != &DiskEntry->PrimaryPartListHead)
+    for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
+         ListEntry != &DiskEntry->PrimaryPartListHead;
+         ListEntry = ListEntry->Flink)
     {
         PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
 
-        if (PartEntry->IsPartitioned != FALSE)
+        if (PartEntry->IsPartitioned)
         {
+            ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED);
+
             PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
+            PartEntry->PartitionIndex = Index;
+
+            /* Reset the current partition number only for newly-created (unmounted) partitions */
+            if (PartEntry->New)
+                PartEntry->PartitionNumber = 0;
+
+            PartEntry->OnDiskPartitionNumber = (!IsContainerPartition(PartEntry->PartitionType) ? PartitionNumber : 0);
 
             if (!IsSamePrimaryLayoutEntry(PartitionInfo, DiskEntry, PartEntry))
             {
@@ -2178,50 +2387,54 @@ UpdateDiskLayout(
                 PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
                 PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
                 PartitionInfo->HiddenSectors = PartEntry->StartSector.LowPart;
-                PartitionInfo->PartitionNumber = (!IsContainerPartition(PartEntry->PartitionType)) ? PartitionNumber : 0;
+                PartitionInfo->PartitionNumber = PartEntry->PartitionNumber;
                 PartitionInfo->PartitionType = PartEntry->PartitionType;
                 PartitionInfo->BootIndicator = PartEntry->BootIndicator;
-                PartitionInfo->RecognizedPartition = FALSE;
+                PartitionInfo->RecognizedPartition = IsRecognizedPartition(PartEntry->PartitionType);
                 PartitionInfo->RewritePartition = TRUE;
             }
 
-            PartEntry->PartitionNumber = (!IsContainerPartition(PartEntry->PartitionType)) ? PartitionNumber : 0;
-            PartEntry->PartitionIndex = Index;
-
             if (!IsContainerPartition(PartEntry->PartitionType))
                 PartitionNumber++;
 
             Index++;
         }
-
-        ListEntry = ListEntry->Flink;
     }
 
+    ASSERT(Index <= 4);
+
     /* Update the logical partition table */
     Index = 4;
-    ListEntry = DiskEntry->LogicalPartListHead.Flink;
-    while (ListEntry != &DiskEntry->LogicalPartListHead)
+    for (ListEntry = DiskEntry->LogicalPartListHead.Flink;
+         ListEntry != &DiskEntry->LogicalPartListHead;
+         ListEntry = ListEntry->Flink)
     {
         PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
 
         if (PartEntry->IsPartitioned)
         {
+            ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED);
+
             PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
+            PartEntry->PartitionIndex = Index;
+
+            /* Reset the current partition number only for newly-created (unmounted) partitions */
+            if (PartEntry->New)
+                PartEntry->PartitionNumber = 0;
+
+            PartEntry->OnDiskPartitionNumber = PartitionNumber;
 
             DPRINT1("Updating logical partition entry %lu\n", Index);
 
             PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
             PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
             PartitionInfo->HiddenSectors = DiskEntry->SectorAlignment;
-            PartitionInfo->PartitionNumber = PartitionNumber;
+            PartitionInfo->PartitionNumber = PartEntry->PartitionNumber;
             PartitionInfo->PartitionType = PartEntry->PartitionType;
             PartitionInfo->BootIndicator = FALSE;
-            PartitionInfo->RecognizedPartition = FALSE;
+            PartitionInfo->RecognizedPartition = IsRecognizedPartition(PartEntry->PartitionType);
             PartitionInfo->RewritePartition = TRUE;
 
-            PartEntry->PartitionNumber = PartitionNumber;
-            PartEntry->PartitionIndex = Index;
-
             /* Fill the link entry of the previous partition entry */
             if (LinkInfo != NULL)
             {
@@ -2242,8 +2455,6 @@ UpdateDiskLayout(
             PartitionNumber++;
             Index += 4;
         }
-
-        ListEntry = ListEntry->Flink;
     }
 
     /* Wipe unused primary partition entries */
@@ -2293,6 +2504,8 @@ UpdateDiskLayout(
         }
     }
 
+    DiskEntry->Dirty = TRUE;
+
 #ifdef DUMP_PARTITION_TABLE
     DumpPartitionTable(DiskEntry);
 #endif
@@ -2301,12 +2514,18 @@ UpdateDiskLayout(
 static
 PPARTENTRY
 GetPrevUnpartitionedEntry(
-    IN PDISKENTRY DiskEntry,
     IN PPARTENTRY PartEntry)
 {
+    PDISKENTRY DiskEntry = PartEntry->DiskEntry;
     PPARTENTRY PrevPartEntry;
     PLIST_ENTRY ListHead;
 
+    if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
+    {
+        DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
+        return NULL;
+    }
+
     if (PartEntry->LogicalPartition)
         ListHead = &DiskEntry->LogicalPartListHead;
     else
@@ -2317,8 +2536,11 @@ GetPrevUnpartitionedEntry(
         PrevPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Blink,
                                           PARTENTRY,
                                           ListEntry);
-        if (PrevPartEntry->IsPartitioned == FALSE)
+        if (!PrevPartEntry->IsPartitioned)
+        {
+            ASSERT(PrevPartEntry->PartitionType == PARTITION_ENTRY_UNUSED);
             return PrevPartEntry;
+        }
     }
 
     return NULL;
@@ -2327,12 +2549,18 @@ GetPrevUnpartitionedEntry(
 static
 PPARTENTRY
 GetNextUnpartitionedEntry(
-    IN PDISKENTRY DiskEntry,
     IN PPARTENTRY PartEntry)
 {
+    PDISKENTRY DiskEntry = PartEntry->DiskEntry;
     PPARTENTRY NextPartEntry;
     PLIST_ENTRY ListHead;
 
+    if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
+    {
+        DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
+        return NULL;
+    }
+
     if (PartEntry->LogicalPartition)
         ListHead = &DiskEntry->LogicalPartListHead;
     else
@@ -2343,97 +2571,53 @@ GetNextUnpartitionedEntry(
         NextPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Flink,
                                           PARTENTRY,
                                           ListEntry);
-        if (NextPartEntry->IsPartitioned == FALSE)
+        if (!NextPartEntry->IsPartitioned)
+        {
+            ASSERT(NextPartEntry->PartitionType == PARTITION_ENTRY_UNUSED);
             return NextPartEntry;
+        }
     }
 
     return NULL;
 }
 
-VOID
+BOOLEAN
 CreatePrimaryPartition(
     IN PPARTLIST List,
+    IN PPARTENTRY SelectedEntry,
     IN ULONGLONG SectorCount,
     IN BOOLEAN AutoCreate)
 {
-    PDISKENTRY DiskEntry;
+    ERROR_NUMBER Error;
     PPARTENTRY PartEntry;
-    PPARTENTRY NewPartEntry;
 
     DPRINT1("CreatePrimaryPartition(%I64u)\n", SectorCount);
 
     if (List == NULL ||
-        List->CurrentDisk == NULL ||
-        List->CurrentPartition == NULL ||
-        List->CurrentPartition->IsPartitioned != FALSE)
+        SelectedEntry == NULL ||
+        SelectedEntry->DiskEntry == NULL ||
+        SelectedEntry->IsPartitioned)
     {
-        return;
+        return FALSE;
     }
 
-    DiskEntry = List->CurrentDisk;
-    PartEntry = List->CurrentPartition;
-
-    DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
-
-    if ((AutoCreate != FALSE) ||
-        (AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart))
-    {
-        DPRINT1("Convert existing partition entry\n");
-
-        /* Convert current entry to 'new (unformatted)' */
-        PartEntry->IsPartitioned = TRUE;
-        PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
-        PartEntry->FormatState = Unformatted;
-        PartEntry->FileSystem  = NULL;
-        PartEntry->AutoCreate = AutoCreate;
-        PartEntry->New = TRUE;
-        PartEntry->BootIndicator = FALSE;
-
-        DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
-        DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
-        DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
-    }
-    else
+    Error = PrimaryPartitionCreationChecks(SelectedEntry);
+    if (Error != NOT_AN_ERROR)
     {
-        DPRINT1("Add new partition entry\n");
-
-        /* Insert and initialize a new partition entry */
-        NewPartEntry = RtlAllocateHeap(ProcessHeap,
-                                       HEAP_ZERO_MEMORY,
-                                       sizeof(PARTENTRY));
-        if (NewPartEntry == NULL)
-            return;
-
-        /* Insert the new entry into the list */
-        InsertTailList(&PartEntry->ListEntry,
-                       &NewPartEntry->ListEntry);
-
-        NewPartEntry->DiskEntry = DiskEntry;
-
-        NewPartEntry->IsPartitioned = TRUE;
-        NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
-        NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
-                                             NewPartEntry->StartSector.QuadPart;
-        NewPartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
-
-        DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
-        DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
-        DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
-
-        NewPartEntry->New = TRUE;
-        NewPartEntry->FormatState = Unformatted;
-        NewPartEntry->FileSystem  = NULL;
-        NewPartEntry->BootIndicator = FALSE;
-
-        PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
-        PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
+        DPRINT1("PrimaryPartitionCreationChecks() failed with error %lu\n", Error);
+        return FALSE;
     }
 
-    UpdateDiskLayout(DiskEntry);
+    /* Convert the current entry, or insert and initialize a new partition entry */
+    PartEntry = InitializePartitionEntry(SelectedEntry->DiskEntry, SelectedEntry, SectorCount, AutoCreate);
+    if (PartEntry == NULL)
+        return FALSE;
 
-    DiskEntry->Dirty = TRUE;
+    UpdateDiskLayout(PartEntry->DiskEntry);
 
     AssignDriveLetters(List);
+
+    return TRUE;
 }
 
 static
@@ -2441,318 +2625,335 @@ VOID
 AddLogicalDiskSpace(
     IN PDISKENTRY DiskEntry)
 {
+    ULONGLONG StartSector;
+    ULONGLONG SectorCount;
     PPARTENTRY NewPartEntry;
 
     DPRINT1("AddLogicalDiskSpace()\n");
 
     /* Create a partition entry that represents the empty space in the container partition */
-    NewPartEntry = RtlAllocateHeap(ProcessHeap,
-                                   HEAP_ZERO_MEMORY,
-                                   sizeof(PARTENTRY));
+
+    StartSector = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
+    SectorCount = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment;
+
+    NewPartEntry = CreateInsertBlankRegion(DiskEntry,
+                                           &DiskEntry->LogicalPartListHead,
+                                           StartSector,
+                                           SectorCount,
+                                           TRUE);
     if (NewPartEntry == NULL)
+    {
+        DPRINT1("Failed to create a new empty region for extended partition space!\n");
         return;
-
-    NewPartEntry->DiskEntry = DiskEntry;
+    }
     NewPartEntry->LogicalPartition = TRUE;
-
-    NewPartEntry->IsPartitioned = FALSE;
-    NewPartEntry->StartSector.QuadPart = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
-    NewPartEntry->SectorCount.QuadPart = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment;
-
-    DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
-    DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
-    DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
-
-    NewPartEntry->FormatState = Unformatted;
-    NewPartEntry->FileSystem  = NULL;
-
-    InsertTailList(&DiskEntry->LogicalPartListHead,
-                   &NewPartEntry->ListEntry);
 }
 
-VOID
+BOOLEAN
 CreateExtendedPartition(
     IN PPARTLIST List,
+    IN PPARTENTRY SelectedEntry,
     IN ULONGLONG SectorCount)
 {
-    PDISKENTRY DiskEntry;
+    ERROR_NUMBER Error;
     PPARTENTRY PartEntry;
-    PPARTENTRY NewPartEntry;
 
     DPRINT1("CreateExtendedPartition(%I64u)\n", SectorCount);
 
     if (List == NULL ||
-        List->CurrentDisk == NULL ||
-        List->CurrentPartition == NULL ||
-        List->CurrentPartition->IsPartitioned != FALSE)
+        SelectedEntry == NULL ||
+        SelectedEntry->DiskEntry == NULL ||
+        SelectedEntry->IsPartitioned)
     {
-        return;
+        return FALSE;
     }
 
-    DiskEntry = List->CurrentDisk;
-    PartEntry = List->CurrentPartition;
-
-    DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
-
-    if (AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart)
+    Error = ExtendedPartitionCreationChecks(SelectedEntry);
+    if (Error != NOT_AN_ERROR)
     {
-        DPRINT1("Convert existing partition entry\n");
-
-        /* Convert current entry to 'new (unformatted)' */
-        PartEntry->IsPartitioned = TRUE;
-        PartEntry->FormatState = Formatted;     // FIXME? Possibly to make GetNextUnformattedPartition work (i.e. skip the extended partition container)
-        PartEntry->FileSystem  = NULL;
-        PartEntry->AutoCreate = FALSE;
-        PartEntry->New = FALSE;
-        PartEntry->BootIndicator = FALSE;
-
-        if (PartEntry->StartSector.QuadPart < 1450560)
-        {
-            /* Partition starts below the 8.4GB boundary ==> CHS partition */
-            PartEntry->PartitionType = PARTITION_EXTENDED;
-        }
-        else
-        {
-            /* Partition starts above the 8.4GB boundary ==> LBA partition */
-            PartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
-        }
+        DPRINT1("ExtendedPartitionCreationChecks() failed with error %lu\n", Error);
+        return FALSE;
+    }
 
-        DiskEntry->ExtendedPartition = PartEntry;
+    /* Convert the current entry, or insert and initialize a new partition entry */
+    PartEntry = InitializePartitionEntry(SelectedEntry->DiskEntry, SelectedEntry, SectorCount, FALSE);
+    if (PartEntry == NULL)
+        return FALSE;
 
-        DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
-        DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
-        DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
+    if (PartEntry->StartSector.QuadPart < 1450560)
+    {
+        /* Partition starts below the 8.4GB boundary ==> CHS partition */
+        PartEntry->PartitionType = PARTITION_EXTENDED;
     }
     else
     {
-        DPRINT1("Add new partition entry\n");
-
-        /* Insert and initialize a new partition entry */
-        NewPartEntry = RtlAllocateHeap(ProcessHeap,
-                                       HEAP_ZERO_MEMORY,
-                                       sizeof(PARTENTRY));
-        if (NewPartEntry == NULL)
-            return;
-
-        /* Insert the new entry into the list */
-        InsertTailList(&PartEntry->ListEntry,
-                       &NewPartEntry->ListEntry);
-
-        NewPartEntry->DiskEntry = DiskEntry;
-
-        NewPartEntry->IsPartitioned = TRUE;
-        NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
-        NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
-                                             NewPartEntry->StartSector.QuadPart;
-
-        NewPartEntry->New = FALSE;
-        NewPartEntry->FormatState = Formatted;     // FIXME? Possibly to make GetNextUnformattedPartition work (i.e. skip the extended partition container)
-        NewPartEntry->FileSystem  = NULL;
-        NewPartEntry->BootIndicator = FALSE;
-
-        if (NewPartEntry->StartSector.QuadPart < 1450560)
-        {
-            /* Partition starts below the 8.4GB boundary ==> CHS partition */
-            NewPartEntry->PartitionType = PARTITION_EXTENDED;
-        }
-        else
-        {
-            /* Partition starts above the 8.4GB boundary ==> LBA partition */
-            NewPartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
-        }
-
-        DiskEntry->ExtendedPartition = NewPartEntry;
-
-        PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
-        PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
-
-        DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
-        DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
-        DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
+        /* Partition starts above the 8.4GB boundary ==> LBA partition */
+        PartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
     }
 
-    AddLogicalDiskSpace(DiskEntry);
+    // FIXME? Possibly to make GetNextUnformattedPartition work (i.e. skip the extended partition container)
+    PartEntry->New = FALSE;
+    PartEntry->FormatState = Formatted;
 
-    UpdateDiskLayout(DiskEntry);
+    PartEntry->DiskEntry->ExtendedPartition = PartEntry;
 
-    DiskEntry->Dirty = TRUE;
+    AddLogicalDiskSpace(PartEntry->DiskEntry);
+
+    UpdateDiskLayout(PartEntry->DiskEntry);
 
     AssignDriveLetters(List);
+
+    return TRUE;
 }
 
-VOID
+BOOLEAN
 CreateLogicalPartition(
     IN PPARTLIST List,
+    IN PPARTENTRY SelectedEntry,
     IN ULONGLONG SectorCount,
     IN BOOLEAN AutoCreate)
 {
-    PDISKENTRY DiskEntry;
+    ERROR_NUMBER Error;
     PPARTENTRY PartEntry;
-    PPARTENTRY NewPartEntry;
 
     DPRINT1("CreateLogicalPartition(%I64u)\n", SectorCount);
 
     if (List == NULL ||
-        List->CurrentDisk == NULL ||
-        List->CurrentPartition == NULL ||
-        List->CurrentPartition->IsPartitioned != FALSE)
+        SelectedEntry == NULL ||
+        SelectedEntry->DiskEntry == NULL ||
+        SelectedEntry->IsPartitioned)
     {
-        return;
+        return FALSE;
     }
 
-    DiskEntry = List->CurrentDisk;
-    PartEntry = List->CurrentPartition;
+    Error = LogicalPartitionCreationChecks(SelectedEntry);
+    if (Error != NOT_AN_ERROR)
+    {
+        DPRINT1("LogicalPartitionCreationChecks() failed with error %lu\n", Error);
+        return FALSE;
+    }
 
-    DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
+    /* Convert the current entry, or insert and initialize a new partition entry */
+    PartEntry = InitializePartitionEntry(SelectedEntry->DiskEntry, SelectedEntry, SectorCount, AutoCreate);
+    if (PartEntry == NULL)
+        return FALSE;
 
-    if ((AutoCreate != FALSE) ||
-        (AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart))
-    {
-        DPRINT1("Convert existing partition entry\n");
+    PartEntry->LogicalPartition = TRUE;
 
-        /* Convert current entry to 'new (unformatted)' */
-        PartEntry->IsPartitioned = TRUE;
-        PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
-        PartEntry->FormatState = Unformatted;
-        PartEntry->FileSystem  = NULL;
-        PartEntry->AutoCreate = FALSE;
-        PartEntry->New = TRUE;
-        PartEntry->BootIndicator = FALSE;
-        PartEntry->LogicalPartition = TRUE;
+    UpdateDiskLayout(PartEntry->DiskEntry);
 
-        DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
-        DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
-        DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
-    }
-    else
-    {
-        DPRINT1("Add new partition entry\n");
+    AssignDriveLetters(List);
 
-        /* Insert and initialize a new partition entry */
-        NewPartEntry = RtlAllocateHeap(ProcessHeap,
-                                       HEAP_ZERO_MEMORY,
-                                       sizeof(PARTENTRY));
-        if (NewPartEntry == NULL)
-            return;
+    return TRUE;
+}
 
-        /* Insert the new entry into the list */
-        InsertTailList(&PartEntry->ListEntry,
-                       &NewPartEntry->ListEntry);
+static
+NTSTATUS
+DismountVolume(
+    IN PPARTENTRY PartEntry)
+{
+    NTSTATUS Status;
+    NTSTATUS LockStatus;
+    UNICODE_STRING Name;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    IO_STATUS_BLOCK IoStatusBlock;
+    HANDLE PartitionHandle;
+    WCHAR Buffer[MAX_PATH];
 
-        NewPartEntry->DiskEntry = DiskEntry;
+    /* Check whether the partition is valid and was mounted by the system */
+    if (!PartEntry->IsPartitioned ||
+        IsContainerPartition(PartEntry->PartitionType)   ||
+        !IsRecognizedPartition(PartEntry->PartitionType) ||
+        PartEntry->FormatState == Unformatted /* || PartEntry->FormatState == UnknownFormat */ ||
+        !*PartEntry->FileSystem ||
+        PartEntry->PartitionNumber == 0)
+    {
+        /* The partition is not mounted, so just return success */
+        return STATUS_SUCCESS;
+    }
 
-        NewPartEntry->IsPartitioned = TRUE;
-        NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
-        NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
-                                             NewPartEntry->StartSector.QuadPart;
-        NewPartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
+    ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED);
 
-        DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
-        DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
-        DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
+    /* Open the volume */
+    RtlStringCchPrintfW(Buffer, ARRAYSIZE(Buffer),
+                        L"\\Device\\Harddisk%lu\\Partition%lu",
+                        PartEntry->DiskEntry->DiskNumber,
+                        PartEntry->PartitionNumber);
+    RtlInitUnicodeString(&Name, Buffer);
 
-        NewPartEntry->New = TRUE;
-        NewPartEntry->FormatState = Unformatted;
-        NewPartEntry->FileSystem  = NULL;
-        NewPartEntry->BootIndicator = FALSE;
-        NewPartEntry->LogicalPartition = TRUE;
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &Name,
+                               OBJ_CASE_INSENSITIVE,
+                               NULL,
+                               NULL);
 
-        PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
-        PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
+    Status = NtOpenFile(&PartitionHandle,
+                        GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
+                        &ObjectAttributes,
+                        &IoStatusBlock,
+                        FILE_SHARE_READ | FILE_SHARE_WRITE,
+                        FILE_SYNCHRONOUS_IO_NONALERT);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("ERROR: Cannot open volume %wZ for dismounting! (Status 0x%lx)\n", &Name, Status);
+        return Status;
     }
 
-    UpdateDiskLayout(DiskEntry);
+    /* Lock the volume */
+    LockStatus = NtFsControlFile(PartitionHandle,
+                                 NULL,
+                                 NULL,
+                                 NULL,
+                                 &IoStatusBlock,
+                                 FSCTL_LOCK_VOLUME,
+                                 NULL,
+                                 0,
+                                 NULL,
+                                 0);
+    if (!NT_SUCCESS(LockStatus))
+    {
+        DPRINT1("WARNING: Failed to lock volume! Operations may fail! (Status 0x%lx)\n", LockStatus);
+    }
 
-    DiskEntry->Dirty = TRUE;
+    /* Dismount the volume */
+    Status = NtFsControlFile(PartitionHandle,
+                             NULL,
+                             NULL,
+                             NULL,
+                             &IoStatusBlock,
+                             FSCTL_DISMOUNT_VOLUME,
+                             NULL,
+                             0,
+                             NULL,
+                             0);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to unmount volume (Status 0x%lx)\n", Status);
+    }
 
-    AssignDriveLetters(List);
+    /* Unlock the volume */
+    LockStatus = NtFsControlFile(PartitionHandle,
+                                 NULL,
+                                 NULL,
+                                 NULL,
+                                 &IoStatusBlock,
+                                 FSCTL_UNLOCK_VOLUME,
+                                 NULL,
+                                 0,
+                                 NULL,
+                                 0);
+    if (!NT_SUCCESS(LockStatus))
+    {
+        DPRINT1("Failed to unlock volume (Status 0x%lx)\n", LockStatus);
+    }
+
+    /* Close the volume */
+    NtClose(PartitionHandle);
+
+    return Status;
 }
 
-VOID
-DeleteCurrentPartition(
-    IN PPARTLIST List)
+BOOLEAN
+DeletePartition(
+    IN PPARTLIST List,
+    IN PPARTENTRY PartEntry,
+    OUT PPARTENTRY* FreeRegion OPTIONAL)
 {
     PDISKENTRY DiskEntry;
-    PPARTENTRY PartEntry;
     PPARTENTRY PrevPartEntry;
     PPARTENTRY NextPartEntry;
     PPARTENTRY LogicalPartEntry;
     PLIST_ENTRY Entry;
 
     if (List == NULL ||
-        List->CurrentDisk == NULL ||
-        List->CurrentPartition == NULL ||
-        List->CurrentPartition->IsPartitioned == FALSE)
+        PartEntry == NULL ||
+        PartEntry->DiskEntry == NULL ||
+        PartEntry->IsPartitioned == FALSE)
     {
-        return;
+        return FALSE;
     }
 
-    /* Clear the system disk and partition pointers if the system partition is being deleted */
-    if (List->SystemPartition == List->CurrentPartition)
+    ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED);
+
+    /* Clear the system partition pointers if it is being deleted */
+    if (List->SystemPartition == PartEntry)
     {
+        ASSERT(List->SystemPartition);
+
+        if (List->SystemPartition == List->OriginalSystemPartition)
+            List->OriginalSystemPartition = NULL;
         List->SystemPartition = NULL;
     }
 
-    DiskEntry = List->CurrentDisk;
-    PartEntry = List->CurrentPartition;
+    DiskEntry = PartEntry->DiskEntry;
 
-    /* Delete all logical partition entries if an extended partition will be deleted */
+    /* Check which type of partition (primary/logical or extended) is being deleted */
     if (DiskEntry->ExtendedPartition == PartEntry)
     {
+        /* An extended partition is being deleted: delete all logical partition entries */
         while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
         {
             Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
             LogicalPartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
 
+            /* Dismount the logical partition */
+            DismountVolume(LogicalPartEntry);
+
+            /* Delete it */
             RtlFreeHeap(ProcessHeap, 0, LogicalPartEntry);
         }
 
         DiskEntry->ExtendedPartition = NULL;
     }
+    else
+    {
+        /* A primary partition is being deleted: dismount it */
+        DismountVolume(PartEntry);
+    }
 
-    /* Adjust unpartitioned disk space entries */
+    /* Adjust the unpartitioned disk space entries */
 
     /* Get pointer to previous and next unpartitioned entries */
-    PrevPartEntry = GetPrevUnpartitionedEntry(DiskEntry, PartEntry);
-    NextPartEntry = GetNextUnpartitionedEntry(DiskEntry, PartEntry);
+    PrevPartEntry = GetPrevUnpartitionedEntry(PartEntry);
+    NextPartEntry = GetNextUnpartitionedEntry(PartEntry);
 
     if (PrevPartEntry != NULL && NextPartEntry != NULL)
     {
-        /* Merge previous, current and next unpartitioned entry */
+        /* Merge the previous, current and next unpartitioned entries */
 
-        /* Adjust the previous entries length */
+        /* Adjust the previous entry length */
         PrevPartEntry->SectorCount.QuadPart += (PartEntry->SectorCount.QuadPart + NextPartEntry->SectorCount.QuadPart);
 
-        /* Remove the current entry */
+        /* Remove the current and next entries */
         RemoveEntryList(&PartEntry->ListEntry);
         RtlFreeHeap(ProcessHeap, 0, PartEntry);
-
-        /* Remove the next entry */
         RemoveEntryList(&NextPartEntry->ListEntry);
         RtlFreeHeap(ProcessHeap, 0, NextPartEntry);
 
-        /* Update current partition */
-        List->CurrentPartition = PrevPartEntry;
+        /* Optionally return the freed region */
+        if (FreeRegion)
+            *FreeRegion = PrevPartEntry;
     }
     else if (PrevPartEntry != NULL && NextPartEntry == NULL)
     {
-        /* Merge current and previous unpartitioned entry */
+        /* Merge the current and the previous unpartitioned entries */
 
-        /* Adjust the previous entries length */
+        /* Adjust the previous entry length */
         PrevPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
 
         /* Remove the current entry */
         RemoveEntryList(&PartEntry->ListEntry);
         RtlFreeHeap(ProcessHeap, 0, PartEntry);
 
-        /* Update current partition */
-        List->CurrentPartition = PrevPartEntry;
+        /* Optionally return the freed region */
+        if (FreeRegion)
+            *FreeRegion = PrevPartEntry;
     }
     else if (PrevPartEntry == NULL && NextPartEntry != NULL)
     {
-        /* Merge current and next unpartitioned entry */
+        /* Merge the current and the next unpartitioned entries */
 
-        /* Adjust the next entries offset and length */
+        /* Adjust the next entry offset and length */
         NextPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
         NextPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
 
@@ -2760,53 +2961,200 @@ DeleteCurrentPartition(
         RemoveEntryList(&PartEntry->ListEntry);
         RtlFreeHeap(ProcessHeap, 0, PartEntry);
 
-        /* Update current partition */
-        List->CurrentPartition = NextPartEntry;
+        /* Optionally return the freed region */
+        if (FreeRegion)
+            *FreeRegion = NextPartEntry;
     }
     else
     {
-        /* Nothing to merge but change current entry */
+        /* Nothing to merge but change the current entry */
         PartEntry->IsPartitioned = FALSE;
         PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
         PartEntry->FormatState = Unformatted;
-        PartEntry->FileSystem  = NULL;
+        PartEntry->FileSystem[0] = L'\0';
         PartEntry->DriveLetter = 0;
+        PartEntry->OnDiskPartitionNumber = 0;
+        PartEntry->PartitionNumber = 0;
+        // PartEntry->PartitionIndex = 0;
+
+        /* Optionally return the freed region */
+        if (FreeRegion)
+            *FreeRegion = PartEntry;
     }
 
     UpdateDiskLayout(DiskEntry);
 
-    DiskEntry->Dirty = TRUE;
-
     AssignDriveLetters(List);
+
+    return TRUE;
 }
 
-VOID
-CheckActiveSystemPartition(
-    IN PPARTLIST List)
+/*
+ * 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)
 {
-    PDISKENTRY DiskEntry;
-    PPARTENTRY PartEntry;
     PLIST_ENTRY ListEntry;
-
-    PFILE_SYSTEM FileSystem;
+    PPARTENTRY PartEntry;
+    PPARTENTRY ActivePartition = NULL;
 
     /* Check for empty disk list */
-    if (IsListEmpty(&List->DiskListHead))
+    // ASSERT(DiskEntry);
+    if (!DiskEntry)
+        return NULL;
+
+    /* Check for empty partition list */
+    if (IsListEmpty(&DiskEntry->PrimaryPartListHead))
+        return NULL;
+
+    if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
     {
-        List->SystemPartition = NULL;
-        List->OriginalSystemPartition = NULL;
-        return;
+        DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
+        return NULL;
     }
 
-    /* Choose the currently selected disk */
-    DiskEntry = List->CurrentDisk;
+    /* 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);
 
-    /* Check for empty partition list */
-    if (IsListEmpty(&DiskEntry->PrimaryPartListHead))
+        // 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(
+    IN PPARTENTRY PartEntry)
+{
+    /* Check the type and the filesystem of this partition */
+
+    /*
+     * We do not support extended partition containers (on MBR disks) marked
+     * as active, and containing code inside their extended boot records.
+     */
+    if (IsContainerPartition(PartEntry->PartitionType))
+    {
+        DPRINT1("System partition %lu in disk %lu is an extended partition container?!\n",
+                PartEntry->PartitionNumber, PartEntry->DiskEntry->DiskNumber);
+        return FALSE;
+    }
+
+    /*
+     * 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.
+     */
+    if ((PartEntry->FormatState == Unformatted ) ||
+        (PartEntry->FormatState == Preformatted) ||
+        (PartEntry->FormatState == Formatted   ))
+    {
+        ASSERT(*PartEntry->FileSystem);
+
+        /* NOTE: Please keep in sync with the RegisteredFileSystems list! */
+        if (wcsicmp(PartEntry->FileSystem, L"FAT")   == 0 ||
+            wcsicmp(PartEntry->FileSystem, L"FAT32") == 0 ||
+         // wcsicmp(PartEntry->FileSystem, L"NTFS")  == 0 ||
+            wcsicmp(PartEntry->FileSystem, L"BTRFS") == 0 ||
+            wcsicmp(PartEntry->FileSystem, L"RAW")   == 0)
+        {
+            return TRUE;
+        }
+        else
+        {
+            // WARNING: We cannot write on this FS yet!
+            DPRINT1("Recognized file system '%S' that doesn't have write support yet!\n",
+                    PartEntry->FileSystem);
+            return FALSE;
+        }
+    }
+    else // if (PartEntry->FormatState == UnknownFormat)
     {
+        ASSERT(!*PartEntry->FileSystem);
+
+        DPRINT1("System partition %lu in disk %lu with no or unknown FS?!\n",
+                PartEntry->PartitionNumber, PartEntry->DiskEntry->DiskNumber);
+        return FALSE;
+    }
+
+    // HACK: WARNING: We cannot write on this FS yet!
+    // See fsutil.c:InferFileSystem()
+    if (PartEntry->PartitionType == PARTITION_IFS)
+    {
+        DPRINT1("Recognized file system '%S' that doesn't have write support yet!\n",
+                PartEntry->FileSystem);
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+VOID
+CheckActiveSystemPartition(
+    IN PPARTLIST List,
+    IN BOOLEAN ForceSelect,
+    IN PDISKENTRY AlternateDisk OPTIONAL,
+    IN PPARTENTRY AlternatePart OPTIONAL)
+{
+    PLIST_ENTRY ListEntry;
+    PDISKENTRY DiskEntry;
+    PPARTENTRY PartEntry;
+    PPARTENTRY ActivePartition;
+    PPARTENTRY CandidatePartition = NULL;
+
+    /* Check for empty disk list */
+    if (IsListEmpty(&List->DiskListHead))
+    {
+        /* No system partition! */
         List->SystemPartition = NULL;
         List->OriginalSystemPartition = NULL;
-        return;
+        goto NoSystemPartition;
     }
 
     if (List->SystemPartition != NULL)
@@ -2819,17 +3167,184 @@ CheckActiveSystemPartition(
         return;
     }
 
-    DPRINT1("We are here (1)!\n");
-
+    /* Start fresh */
     List->SystemPartition = NULL;
     List->OriginalSystemPartition = NULL;
 
+    /* Adjust the optional alternate disk if needed */
+    if (!AlternateDisk && AlternatePart)
+        AlternateDisk = AlternatePart->DiskEntry;
+
+    /* Ensure that the alternate partition is on the alternate disk */
+    if (AlternatePart)
+        ASSERT(AlternateDisk && (AlternatePart->DiskEntry == AlternateDisk));
+
+    /* Ensure that the alternate disk is in the list */
+    if (AlternateDisk)
+        ASSERT(AlternateDisk->PartList == List);
+
+//
+// Pass == 1 : Check the first (system) disk.
+//
+
+    /*
+     * 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("First (system) disk -- GPT-partitioned disk detected, not currently supported by SETUP!\n");
+        goto UseAlternateDisk;
+    }
+
+    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;
+        }
+    }
+
+    /* If this first disk is not the optional alternate disk, perform the minimal checks */
+    if (DiskEntry != AlternateDisk)
+    {
+        /*
+         * No active partition has been recognized. Enumerate all the (primary)
+         * partitions in the first disk, excluding the possible current active
+         * partition, to find a new candidate.
+         */
+        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;
+                }
+            }
+        }
+    }
+
+
+//
+// Pass == 2 : No active partition found: Check the alternate disk if specified.
+//
+
+UseAlternateDisk:
+    if (!AlternateDisk || (!ForceSelect && (DiskEntry != AlternateDisk)))
+        goto NoSystemPartition;
+
+    if (AlternateDisk->DiskStyle == PARTITION_STYLE_GPT)
+    {
+        DPRINT1("Alternate disk -- GPT-partitioned disk detected, not currently supported by SETUP!\n");
+        goto NoSystemPartition;
+    }
+
+    if (DiskEntry != AlternateDisk)
+    {
+        /* Choose the alternate disk */
+        DiskEntry = AlternateDisk;
+
+        ActivePartition = GetActiveDiskPartition(DiskEntry);
+        if (ActivePartition)
+        {
+            /* If we get a candidate active partition, validate it */
+            if (IsSupportedActivePartition(ActivePartition))
+            {
+                CandidatePartition = ActivePartition;
+                goto FindAndUseAlternativeSystemPartition;
+            }
+        }
+    }
+
+    /* We now may have an unsupported active partition, or none */
+
+/***
+ *** 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 using AlternatePart.
+ ***/
+
     /* 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/partlist.c?r1=63355&r2=63354&pathrev=63355#l2318
@@ -2838,11 +3353,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",
@@ -2857,28 +3373,24 @@ CheckActiveSystemPartition(
         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)
+    for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
+         ListEntry != &DiskEntry->PrimaryPartListHead;
+         ListEntry = ListEntry->Flink)
     {
-        /* Retrieve the partition and go to the next one */
-        PartEntry = CONTAINING_RECORD(ListEntry,
-                                      PARTENTRY,
-                                      ListEntry);
+        /* Retrieve the partition */
+        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;
         }
-
-        /* Go to the next one */
-        ListEntry = ListEntry->Flink;
     }
     if (ListEntry == &DiskEntry->PrimaryPartListHead)
     {
@@ -2886,8 +3398,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,
@@ -2897,85 +3410,29 @@ CheckActiveSystemPartition(
         goto SetSystemPartition;
     }
 
-    List->SystemPartition = 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 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;
-            }
-        }
-    }
-
-    /* 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;
-    }
-
-    /* Save it */
-    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.
+     * 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 alternate partition if specified.
      */
-    FileSystem = GetFileSystem(List->OriginalSystemPartition);
-    if (FileSystem == NULL)
+    if (AlternatePart)
     {
-        DPRINT1("System partition %lu in disk %lu with no FS?!\n",
-                List->OriginalSystemPartition->PartitionNumber,
-                List->OriginalSystemPartition->DiskEntry->DiskNumber);
-        goto FindAndUseAlternativeSystemPartition;
+        DPRINT1("No system partition found, use the alternative partition!\n");
+        CandidatePartition = AlternatePart;
+        goto UseAlternativeSystemPartition;
     }
-    // HACK: WARNING: We cannot write on this FS yet!
-    // See fsutil.c:GetFileSystem()
-    if (List->OriginalSystemPartition->PartitionType == PARTITION_IFS)
+    else
     {
-        DPRINT1("Recognized file system %S that doesn't support write support yet!\n",
-                FileSystem->FileSystemName);
-        goto FindAndUseAlternativeSystemPartition;
+NoSystemPartition:
+        DPRINT1("No valid or supported system partition has been found on this system!\n");
+        return;
     }
 
+
+SystemPartitionFound:
+    ASSERT(CandidatePartition);
+    List->SystemPartition = CandidatePartition;
+
     DPRINT1("Use existing active system partition %lu in disk %lu, drive letter %C\n",
             List->SystemPartition->PartitionNumber,
             List->SystemPartition->DiskEntry->DiskNumber,
@@ -2994,13 +3451,17 @@ 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;
+    ASSERT(CandidatePartition);
+    List->SystemPartition = CandidatePartition;
 
     DPRINT1("Use alternative active system partition %lu in disk %lu, drive letter %C\n",
             List->SystemPartition->PartitionNumber,
@@ -3015,22 +3476,28 @@ SetSystemPartition:
     List->SystemPartition->DiskEntry->Dirty = TRUE;
 }
 
-static
 NTSTATUS
 WritePartitions(
-    IN PPARTLIST List,
     IN PDISKENTRY DiskEntry)
 {
-    WCHAR DstPath[MAX_PATH];
+    NTSTATUS Status;
     OBJECT_ATTRIBUTES ObjectAttributes;
-    IO_STATUS_BLOCK Iosb;
     UNICODE_STRING Name;
+    HANDLE FileHandle;
+    IO_STATUS_BLOCK Iosb;
     ULONG BufferSize;
-    HANDLE FileHandle = NULL;
-    NTSTATUS Status;
+    PPARTITION_INFORMATION PartitionInfo;
+    ULONG PartitionCount;
+    PLIST_ENTRY ListEntry;
+    PPARTENTRY PartEntry;
+    WCHAR DstPath[MAX_PATH];
 
     DPRINT("WritePartitions() Disk: %lu\n", DiskEntry->DiskNumber);
 
+    /* If the disk is not dirty, there is nothing to do */
+    if (!DiskEntry->Dirty)
+        return STATUS_SUCCESS;
+
     RtlStringCchPrintfW(DstPath, ARRAYSIZE(DstPath),
                         L"\\Device\\Harddisk%lu\\Partition0",
                         DiskEntry->DiskNumber);
@@ -3064,8 +3531,12 @@ WritePartitions(
     // For this we must ask the user which format to use.
     //
 
+    /* Save the original partition count to be restored later (see comment below) */
+    PartitionCount = DiskEntry->LayoutBuffer->PartitionCount;
+
+    /* Set the new disk layout and retrieve its updated version with possibly modified partition numbers */
     BufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
-                 ((DiskEntry->LayoutBuffer->PartitionCount - 1) * sizeof(PARTITION_INFORMATION));
+                 ((PartitionCount - 1) * sizeof(PARTITION_INFORMATION));
     Status = NtDeviceIoControlFile(FileHandle,
                                    NULL,
                                    NULL,
@@ -3074,15 +3545,61 @@ WritePartitions(
                                    IOCTL_DISK_SET_DRIVE_LAYOUT,
                                    DiskEntry->LayoutBuffer,
                                    BufferSize,
-                                   NULL,
-                                   0);
+                                   DiskEntry->LayoutBuffer,
+                                   BufferSize);
+    NtClose(FileHandle);
+
+    /*
+     * IOCTL_DISK_SET_DRIVE_LAYOUT calls IoWritePartitionTable(), which converts
+     * DiskEntry->LayoutBuffer->PartitionCount into a partition *table* count,
+     * where such a table is expected to enumerate up to 4 partitions:
+     * partition *table* count == ROUND_UP(PartitionCount, 4) / 4 .
+     * Due to this we need to restore the original PartitionCount number.
+     */
+    DiskEntry->LayoutBuffer->PartitionCount = PartitionCount;
+
+    /* Check whether the IOCTL_DISK_SET_DRIVE_LAYOUT call succeeded */
     if (!NT_SUCCESS(Status))
     {
         DPRINT1("IOCTL_DISK_SET_DRIVE_LAYOUT failed (Status 0x%08lx)\n", Status);
+        return Status;
+    }
+
+#ifdef DUMP_PARTITION_TABLE
+    DumpPartitionTable(DiskEntry);
+#endif
+
+    /* Update the partition numbers */
+
+    /* Update the primary partition table */
+    for (ListEntry = DiskEntry->PrimaryPartListHead.Flink;
+         ListEntry != &DiskEntry->PrimaryPartListHead;
+         ListEntry = ListEntry->Flink)
+    {
+        PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
+
+        if (PartEntry->IsPartitioned)
+        {
+            ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED);
+            PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex];
+            PartEntry->PartitionNumber = PartitionInfo->PartitionNumber;
+        }
     }
 
-    if (FileHandle != NULL)
-        NtClose(FileHandle);
+    /* Update the logical partition table */
+    for (ListEntry = DiskEntry->LogicalPartListHead.Flink;
+         ListEntry != &DiskEntry->LogicalPartListHead;
+         ListEntry = ListEntry->Flink)
+    {
+        PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
+
+        if (PartEntry->IsPartitioned)
+        {
+            ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED);
+            PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex];
+            PartEntry->PartitionNumber = PartitionInfo->PartitionNumber;
+        }
+    }
 
     //
     // NOTE: Originally (see r40437), we used to install here also a new MBR
@@ -3094,6 +3611,9 @@ WritePartitions(
     // DiskEntry->NoMbr was TRUE (instead of NewDisk).
     //
 
+    /* The layout has been successfully updated, the disk is not dirty anymore */
+    DiskEntry->Dirty = FALSE;
+
     return Status;
 }
 
@@ -3101,24 +3621,34 @@ BOOLEAN
 WritePartitionsToDisk(
     IN PPARTLIST List)
 {
+    NTSTATUS Status;
     PLIST_ENTRY Entry;
     PDISKENTRY DiskEntry;
 
     if (List == NULL)
         return TRUE;
 
-    Entry = List->DiskListHead.Flink;
-    while (Entry != &List->DiskListHead)
+    for (Entry = List->DiskListHead.Flink;
+         Entry != &List->DiskListHead;
+         Entry = Entry->Flink)
     {
         DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
 
-        if (DiskEntry->Dirty != FALSE)
+        if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
         {
-            WritePartitions(List, DiskEntry);
-            DiskEntry->Dirty = FALSE;
+            DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
+            continue;
         }
 
-        Entry = Entry->Flink;
+        if (DiskEntry->Dirty != FALSE)
+        {
+            Status = WritePartitions(DiskEntry);
+            if (!NT_SUCCESS(Status))
+            {
+                DPRINT1("WritePartitionsToDisk() failed to update disk %lu, Status 0x%08lx\n",
+                        DiskEntry->DiskNumber, Status);
+            }
+        }
     }
 
     return TRUE;
@@ -3198,19 +3728,29 @@ SetMountedDeviceValues(
     if (List == NULL)
         return FALSE;
 
-    Entry1 = List->DiskListHead.Flink;
-    while (Entry1 != &List->DiskListHead)
+    for (Entry1 = List->DiskListHead.Flink;
+         Entry1 != &List->DiskListHead;
+         Entry1 = Entry1->Flink)
     {
         DiskEntry = CONTAINING_RECORD(Entry1,
                                       DISKENTRY,
                                       ListEntry);
 
-        Entry2 = DiskEntry->PrimaryPartListHead.Flink;
-        while (Entry2 != &DiskEntry->PrimaryPartListHead)
+        if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
+        {
+            DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
+            continue;
+        }
+
+        for (Entry2 = DiskEntry->PrimaryPartListHead.Flink;
+             Entry2 != &DiskEntry->PrimaryPartListHead;
+             Entry2 = Entry2->Flink)
         {
             PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
-            if (PartEntry->IsPartitioned)
+            if (PartEntry->IsPartitioned) // && !IsContainerPartition(PartEntry->PartitionType)
             {
+                ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED);
+
                 /* Assign a "\DosDevices\#:" mount point to this partition */
                 if (PartEntry->DriveLetter)
                 {
@@ -3223,16 +3763,17 @@ SetMountedDeviceValues(
                     }
                 }
             }
-
-            Entry2 = Entry2->Flink;
         }
 
-        Entry2 = DiskEntry->LogicalPartListHead.Flink;
-        while (Entry2 != &DiskEntry->LogicalPartListHead)
+        for (Entry2 = DiskEntry->LogicalPartListHead.Flink;
+             Entry2 != &DiskEntry->LogicalPartListHead;
+             Entry2 = Entry2->Flink)
         {
             PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
-            if (PartEntry->IsPartitioned)
+            if (PartEntry->IsPartitioned) // && !IsContainerPartition(PartEntry->PartitionType)
             {
+                ASSERT(PartEntry->PartitionType != PARTITION_ENTRY_UNUSED);
+
                 /* Assign a "\DosDevices\#:" mount point to this partition */
                 if (PartEntry->DriveLetter)
                 {
@@ -3245,11 +3786,7 @@ SetMountedDeviceValues(
                     }
                 }
             }
-
-            Entry2 = Entry2->Flink;
         }
-
-        Entry1 = Entry1->Flink;
     }
 
     return TRUE;
@@ -3266,21 +3803,24 @@ SetPartitionType(
 
     DiskEntry->Dirty = TRUE;
     DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType = PartitionType;
+    DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RecognizedPartition = IsRecognizedPartition(PartitionType);
     DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
 }
 
 ERROR_NUMBER
 PrimaryPartitionCreationChecks(
-    IN PPARTLIST List)
+    IN PPARTENTRY PartEntry)
 {
-    PDISKENTRY DiskEntry;
-    PPARTENTRY PartEntry;
+    PDISKENTRY DiskEntry = PartEntry->DiskEntry;
 
-    DiskEntry = List->CurrentDisk;
-    PartEntry = List->CurrentPartition;
+    if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
+    {
+        DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
+        return ERROR_WARN_PARTITION;
+    }
 
     /* Fail if the partition is already in use */
-    if (PartEntry->IsPartitioned != FALSE)
+    if (PartEntry->IsPartitioned)
         return ERROR_NEW_PARTITION;
 
     /* Fail if there are already 4 primary partitions in the list */
@@ -3292,16 +3832,18 @@ PrimaryPartitionCreationChecks(
 
 ERROR_NUMBER
 ExtendedPartitionCreationChecks(
-    IN PPARTLIST List)
+    IN PPARTENTRY PartEntry)
 {
-    PDISKENTRY DiskEntry;
-    PPARTENTRY PartEntry;
+    PDISKENTRY DiskEntry = PartEntry->DiskEntry;
 
-    DiskEntry = List->CurrentDisk;
-    PartEntry = List->CurrentPartition;
+    if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
+    {
+        DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
+        return ERROR_WARN_PARTITION;
+    }
 
     /* Fail if the partition is already in use */
-    if (PartEntry->IsPartitioned != FALSE)
+    if (PartEntry->IsPartitioned)
         return ERROR_NEW_PARTITION;
 
     /* Fail if there are already 4 primary partitions in the list */
@@ -3317,16 +3859,18 @@ ExtendedPartitionCreationChecks(
 
 ERROR_NUMBER
 LogicalPartitionCreationChecks(
-    IN PPARTLIST List)
+    IN PPARTENTRY PartEntry)
 {
-//    PDISKENTRY DiskEntry;
-    PPARTENTRY PartEntry;
+    PDISKENTRY DiskEntry = PartEntry->DiskEntry;
 
-//    DiskEntry = List->CurrentDisk;
-    PartEntry = List->CurrentPartition;
+    if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
+    {
+        DPRINT1("GPT-partitioned disk detected, not currently supported by SETUP!\n");
+        return ERROR_WARN_PARTITION;
+    }
 
     /* Fail if the partition is already in use */
-    if (PartEntry->IsPartitioned != FALSE)
+    if (PartEntry->IsPartitioned)
         return ERROR_NEW_PARTITION;
 
     return ERROR_SUCCESS;
@@ -3342,15 +3886,23 @@ GetNextUnformattedPartition(
     PDISKENTRY DiskEntry;
     PPARTENTRY PartEntry;
 
-    Entry1 = List->DiskListHead.Flink;
-    while (Entry1 != &List->DiskListHead)
+    for (Entry1 = List->DiskListHead.Flink;
+         Entry1 != &List->DiskListHead;
+         Entry1 = Entry1->Flink)
     {
         DiskEntry = CONTAINING_RECORD(Entry1,
                                       DISKENTRY,
                                       ListEntry);
 
-        Entry2 = DiskEntry->PrimaryPartListHead.Flink;
-        while (Entry2 != &DiskEntry->PrimaryPartListHead)
+        if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
+        {
+            DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
+            continue;
+        }
+
+        for (Entry2 = DiskEntry->PrimaryPartListHead.Flink;
+             Entry2 != &DiskEntry->PrimaryPartListHead;
+             Entry2 = Entry2->Flink)
         {
             PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
             if (PartEntry->IsPartitioned && PartEntry->New)
@@ -3360,12 +3912,11 @@ GetNextUnformattedPartition(
                 *pPartEntry = PartEntry;
                 return TRUE;
             }
-
-            Entry2 = Entry2->Flink;
         }
 
-        Entry2 = DiskEntry->LogicalPartListHead.Flink;
-        while (Entry2 != &DiskEntry->LogicalPartListHead)
+        for (Entry2 = DiskEntry->LogicalPartListHead.Flink;
+             Entry2 != &DiskEntry->LogicalPartListHead;
+             Entry2 = Entry2->Flink)
         {
             PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
             if (PartEntry->IsPartitioned && PartEntry->New)
@@ -3375,11 +3926,7 @@ GetNextUnformattedPartition(
                 *pPartEntry = PartEntry;
                 return TRUE;
             }
-
-            Entry2 = Entry2->Flink;
         }
-
-        Entry1 = Entry1->Flink;
     }
 
     if (pDiskEntry) *pDiskEntry = NULL;
@@ -3398,44 +3945,47 @@ GetNextUncheckedPartition(
     PDISKENTRY DiskEntry;
     PPARTENTRY PartEntry;
 
-    Entry1 = List->DiskListHead.Flink;
-    while (Entry1 != &List->DiskListHead)
+    for (Entry1 = List->DiskListHead.Flink;
+         Entry1 != &List->DiskListHead;
+         Entry1 = Entry1->Flink)
     {
         DiskEntry = CONTAINING_RECORD(Entry1,
                                       DISKENTRY,
                                       ListEntry);
 
-        Entry2 = DiskEntry->PrimaryPartListHead.Flink;
-        while (Entry2 != &DiskEntry->PrimaryPartListHead)
+        if (DiskEntry->DiskStyle == PARTITION_STYLE_GPT)
+        {
+            DPRINT("GPT-partitioned disk detected, not currently supported by SETUP!\n");
+            continue;
+        }
+
+        for (Entry2 = DiskEntry->PrimaryPartListHead.Flink;
+             Entry2 != &DiskEntry->PrimaryPartListHead;
+             Entry2 = Entry2->Flink)
         {
             PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
-            if (PartEntry->NeedsCheck == TRUE)
+            if (PartEntry->IsPartitioned && PartEntry->NeedsCheck)
             {
                 ASSERT(DiskEntry == PartEntry->DiskEntry);
                 if (pDiskEntry) *pDiskEntry = DiskEntry;
                 *pPartEntry = PartEntry;
                 return TRUE;
             }
-
-            Entry2 = Entry2->Flink;
         }
 
-        Entry2 = DiskEntry->LogicalPartListHead.Flink;
-        while (Entry2 != &DiskEntry->LogicalPartListHead)
+        for (Entry2 = DiskEntry->LogicalPartListHead.Flink;
+             Entry2 != &DiskEntry->LogicalPartListHead;
+             Entry2 = Entry2->Flink)
         {
             PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
-            if (PartEntry->NeedsCheck == TRUE)
+            if (PartEntry->IsPartitioned && PartEntry->NeedsCheck)
             {
                 ASSERT(DiskEntry == PartEntry->DiskEntry);
                 if (pDiskEntry) *pDiskEntry = DiskEntry;
                 *pPartEntry = PartEntry;
                 return TRUE;
             }
-
-            Entry2 = Entry2->Flink;
         }
-
-        Entry1 = Entry1->Flink;
     }
 
     if (pDiskEntry) *pDiskEntry = NULL;