[USETUP] Similarly to what was done for GenLists, factor out the UI code from the...
[reactos.git] / base / setup / usetup / partlist.c
index 3f8a98a..31c657f 100644 (file)
@@ -18,7 +18,7 @@
  */
 /* COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS text-mode setup
- * FILE:            subsys/system/usetup/partlist.c
+ * FILE:            base/setup/usetup/partlist.c
  * PURPOSE:         Partition list functions
  * PROGRAMMER:      Eric Kohl
  *                  Casper S. Hornstrup (chorns@users.sourceforge.net)
 
 #include "usetup.h"
 
+#include <ntddscsi.h>
+
 #define NDEBUG
 #include <debug.h>
 
-/* FUNCTIONS ****************************************************************/
+//#define DUMP_PARTITION_TABLE
+
+/* HELPERS FOR PARTITION TYPES **********************************************/
+
+typedef struct _PARTITION_TYPE
+{
+    UCHAR Type;
+    PCHAR Description;
+} PARTITION_TYPE, *PPARTITION_TYPE;
+
+/*
+ * This partition type list was ripped off the kernelDisk.c module from:
+ *
+ * Visopsys Operating System
+ * Copyright (C) 1998-2015 J. Andrew McLaughlin
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ *
+ * See also https://en.wikipedia.org/wiki/Partition_type#List_of_partition_IDs
+ * and http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
+ * for a complete list.
+ */
+
+/* This is a table for keeping known partition type codes and descriptions */
+static PARTITION_TYPE PartitionTypes[] =
+{
+    { 0x00, "(Empty)" },
+    { 0x01, "FAT12" },
+    { 0x02, "XENIX root" },
+    { 0x03, "XENIX /usr" },
+    { 0x04, "FAT16 (small)" },
+    { 0x05, "Extended" },
+    { 0x06, "FAT16" },
+    { 0x07, "NTFS/HPFS/exFAT" },
+    { 0x08, "OS/2 or AIX boot" },
+    { 0x09, "AIX data" },
+    { 0x0A, "OS/2 Boot Manager" },
+    { 0x0B, "FAT32" },
+    { 0x0C, "FAT32 (LBA)" },
+    { 0x0E, "FAT16 (LBA)" },
+    { 0x0F, "Extended (LBA)" },
+    { 0x11, "Hidden FAT12" },
+    { 0x12, "FAT diagnostic" },
+    { 0x14, "Hidden FAT16 (small)" },
+    { 0x16, "Hidden FAT16" },
+    { 0x17, "Hidden HPFS or NTFS" },
+    { 0x1B, "Hidden FAT32" },
+    { 0x1C, "Hidden FAT32 (LBA)" },
+    { 0x1E, "Hidden FAT16 (LBA)" },
+    { 0x35, "JFS" },
+    { 0x39, "Plan 9" },
+    { 0x3C, "PartitionMagic" },
+    { 0x3D, "Hidden Netware" },
+    { 0x41, "PowerPC PReP" },
+    { 0x42, "Win2K dynamic extended" },
+    { 0x43, "Old Linux" },
+    { 0x44, "GoBack" },
+    { 0x4D, "QNX4.x" },
+    { 0x4D, "QNX4.x 2nd" },
+    { 0x4D, "QNX4.x 3rd" },
+    { 0x50, "Ontrack R/O" },
+    { 0x51, "Ontrack R/W or Novell" },
+    { 0x52, "CP/M" },
+    { 0x63, "GNU HURD or UNIX SysV" },
+    { 0x64, "Netware 2" },
+    { 0x65, "Netware 3/4" },
+    { 0x66, "Netware SMS" },
+    { 0x67, "Novell" },
+    { 0x68, "Novell" },
+    { 0x69, "Netware 5+" },
+    { 0x7E, "Veritas VxVM public" },
+    { 0x7F, "Veritas VxVM private" },
+    { 0x80, "Minix" },
+    { 0x81, "Linux or Minix" },
+    { 0x82, "Linux swap or Solaris" },
+    { 0x83, "Linux" },
+    { 0x84, "Hibernation" },
+    { 0x85, "Linux extended" },
+    { 0x86, "HPFS or NTFS mirrored" },
+    { 0x87, "HPFS or NTFS mirrored" },
+    { 0x8E, "Linux LVM" },
+    { 0x93, "Hidden Linux" },
+    { 0x96, "CDFS/ISO-9660" },
+    { 0x9F, "BSD/OS" },
+    { 0xA0, "Laptop hibernation" },
+    { 0xA1, "Laptop hibernation" },
+    { 0xA5, "BSD, NetBSD, FreeBSD" },
+    { 0xA6, "OpenBSD" },
+    { 0xA7, "NeXTSTEP" },
+    { 0xA8, "OS-X UFS" },
+    { 0xA9, "NetBSD" },
+    { 0xAB, "OS-X boot" },
+    { 0xAF, "OS-X HFS" },
+    { 0xB6, "NT corrupt mirror" },
+    { 0xB7, "BSDI" },
+    { 0xB8, "BSDI swap" },
+    { 0xBE, "Solaris 8 boot" },
+    { 0xBF, "Solaris x86" },
+    { 0xC0, "NTFT" },
+    { 0xC1, "DR-DOS FAT12" },
+    { 0xC2, "Hidden Linux" },
+    { 0xC3, "Hidden Linux swap" },
+    { 0xC4, "DR-DOS FAT16 (small)" },
+    { 0xC5, "DR-DOS Extended" },
+    { 0xC6, "DR-DOS FAT16" },
+    { 0xC7, "HPFS mirrored" },
+    { 0xCB, "DR-DOS FAT32" },
+    { 0xCC, "DR-DOS FAT32 (LBA)" },
+    { 0xCE, "DR-DOS FAT16 (LBA)" },
+    { 0xD0, "MDOS" },
+    { 0xD1, "MDOS FAT12" },
+    { 0xD4, "MDOS FAT16 (small)" },
+    { 0xD5, "MDOS Extended" },
+    { 0xD6, "MDOS FAT16" },
+    { 0xD8, "CP/M-86" },
+    { 0xDF, "BootIt EMBRM(FAT16/32)" },
+    { 0xEB, "BeOS BFS" },
+    { 0xEE, "EFI GPT protective" },
+    { 0xEF, "EFI filesystem" },
+    { 0xF0, "Linux/PA-RISC boot" },
+    { 0xF2, "DOS 3.3+ second" },
+    { 0xFA, "Bochs" },
+    { 0xFB, "VmWare" },
+    { 0xFC, "VmWare swap" },
+    { 0xFD, "Linux RAID" },
+    { 0xFE, "NT hidden" },
+};
+
+VOID
+GetPartTypeStringFromPartitionType(
+    IN UCHAR partitionType,
+    OUT PCHAR strPartType,
+    IN ULONG cchPartType)
+{
+    /* Determine partition type */
+
+    if (IsContainerPartition(partitionType))
+    {
+        RtlStringCchCopyA(strPartType, cchPartType, MUIGetString(STRING_EXTENDED_PARTITION));
+    }
+    else if (partitionType == PARTITION_ENTRY_UNUSED)
+    {
+        RtlStringCchCopyA(strPartType, cchPartType, MUIGetString(STRING_FORMATUNUSED));
+    }
+    else
+    {
+        UINT i;
+
+        /* Do the table lookup */
+        for (i = 0; i < ARRAYSIZE(PartitionTypes); i++)
+        {
+            if (partitionType == PartitionTypes[i].Type)
+            {
+                RtlStringCchCopyA(strPartType, cchPartType, PartitionTypes[i].Description);
+                return;
+            }
+        }
+
+        /* We are here because the partition type is unknown */
+        RtlStringCchCopyA(strPartType, cchPartType, MUIGetString(STRING_FORMATUNKNOWN));
+    }
+}
+
+/* FUNCTIONS ****************************************************************/
+
+#ifdef DUMP_PARTITION_TABLE
+static
+VOID
+DumpPartitionTable(
+    PDISKENTRY DiskEntry)
+{
+    PPARTITION_INFORMATION PartitionInfo;
+    ULONG i;
+
+    DbgPrint("\n");
+    DbgPrint("Index  Start         Length        Hidden      Nr  Type  Boot  RW\n");
+    DbgPrint("-----  ------------  ------------  ----------  --  ----  ----  --\n");
+
+    for (i = 0; i < DiskEntry->LayoutBuffer->PartitionCount; i++)
+    {
+        PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[i];
+        DbgPrint("  %3lu  %12I64u  %12I64u  %10lu  %2lu    %2x     %c   %c\n",
+                 i,
+                 PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector,
+                 PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector,
+                 PartitionInfo->HiddenSectors,
+                 PartitionInfo->PartitionNumber,
+                 PartitionInfo->PartitionType,
+                 PartitionInfo->BootIndicator ? '*': ' ',
+                 PartitionInfo->RewritePartition ? 'Y': 'N');
+    }
+
+    DbgPrint("\n");
+}
+#endif
+
+
+ULONGLONG
+AlignDown(
+    IN ULONGLONG Value,
+    IN ULONG Alignment)
+{
+    ULONGLONG Temp;
+
+    Temp = Value / Alignment;
+
+    return Temp * Alignment;
+}
+
+ULONGLONG
+AlignUp(
+    IN ULONGLONG Value,
+    IN ULONG Alignment)
+{
+    ULONGLONG Temp, Result;
+
+    Temp = Value / Alignment;
+
+    Result = Temp * Alignment;
+    if (Value % Alignment)
+        Result += Alignment;
+
+    return Result;
+}
+
+ULONGLONG
+RoundingDivide(
+   IN ULONGLONG Dividend,
+   IN ULONGLONG Divisor)
+{
+    return (Dividend + Divisor / 2) / Divisor;
+}
+
+
+static
+VOID
+GetDriverName(
+    IN PDISKENTRY DiskEntry)
+{
+    RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+    WCHAR KeyName[32];
+    NTSTATUS Status;
+
+    RtlInitUnicodeString(&DiskEntry->DriverName,
+                         NULL);
+
+    swprintf(KeyName,
+             L"\\Scsi\\Scsi Port %hu",
+             DiskEntry->Port);
+
+    RtlZeroMemory(&QueryTable,
+                  sizeof(QueryTable));
+
+    QueryTable[0].Name = L"Driver";
+    QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
+    QueryTable[0].EntryContext = &DiskEntry->DriverName;
+
+    Status = RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP,
+                                    KeyName,
+                                    QueryTable,
+                                    NULL,
+                                    NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
+    }
+}
+
+
+static
+VOID
+AssignDriveLetters(
+    IN PPARTLIST List)
+{
+    PDISKENTRY DiskEntry;
+    PPARTENTRY PartEntry;
+    PLIST_ENTRY Entry1;
+    PLIST_ENTRY Entry2;
+    CHAR Letter;
+
+    Letter = 'C';
+
+    /* Assign drive letters to primary partitions */
+    Entry1 = List->DiskListHead.Flink;
+    while (Entry1 != &List->DiskListHead)
+    {
+        DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
+
+        Entry2 = DiskEntry->PrimaryPartListHead.Flink;
+        while (Entry2 != &DiskEntry->PrimaryPartListHead)
+        {
+            PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
+
+            PartEntry->DriveLetter = 0;
+
+            if (PartEntry->IsPartitioned &&
+                !IsContainerPartition(PartEntry->PartitionType))
+            {
+                if (IsRecognizedPartition(PartEntry->PartitionType) ||
+                    (PartEntry->PartitionType == PARTITION_ENTRY_UNUSED &&
+                     PartEntry->SectorCount.QuadPart != 0LL))
+                {
+                    if (Letter <= 'Z')
+                    {
+                        PartEntry->DriveLetter = Letter;
+                        Letter++;
+                    }
+                }
+            }
+
+            Entry2 = Entry2->Flink;
+        }
+
+        Entry1 = Entry1->Flink;
+    }
+
+    /* Assign drive letters to logical drives */
+    Entry1 = List->DiskListHead.Flink;
+    while (Entry1 != &List->DiskListHead)
+    {
+        DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
+
+        Entry2 = DiskEntry->LogicalPartListHead.Flink;
+        while (Entry2 != &DiskEntry->LogicalPartListHead)
+        {
+            PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
+
+            PartEntry->DriveLetter = 0;
+
+            if (PartEntry->IsPartitioned)
+            {
+                if (IsRecognizedPartition(PartEntry->PartitionType) ||
+                    (PartEntry->PartitionType == PARTITION_ENTRY_UNUSED &&
+                     PartEntry->SectorCount.QuadPart != 0LL))
+                {
+                    if (Letter <= 'Z')
+                    {
+                        PartEntry->DriveLetter = Letter;
+                        Letter++;
+                    }
+                }
+            }
+
+            Entry2 = Entry2->Flink;
+        }
+
+        Entry1 = Entry1->Flink;
+    }
+}
+
+
+static NTSTATUS
+NTAPI
+DiskIdentifierQueryRoutine(
+    PWSTR ValueName,
+    ULONG ValueType,
+    PVOID ValueData,
+    ULONG ValueLength,
+    PVOID Context,
+    PVOID EntryContext)
+{
+    PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context;
+    UNICODE_STRING NameU;
+
+    if (ValueType == REG_SZ &&
+        ValueLength == 20 * sizeof(WCHAR))
+    {
+        NameU.Buffer = (PWCHAR)ValueData;
+        NameU.Length = NameU.MaximumLength = 8 * sizeof(WCHAR);
+        RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Checksum);
+
+        NameU.Buffer = (PWCHAR)ValueData + 9;
+        RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Signature);
+
+        return STATUS_SUCCESS;
+    }
+
+    return STATUS_UNSUCCESSFUL;
+}
+
+
+static NTSTATUS
+NTAPI
+DiskConfigurationDataQueryRoutine(
+    PWSTR ValueName,
+    ULONG ValueType,
+    PVOID ValueData,
+    ULONG ValueLength,
+    PVOID Context,
+    PVOID EntryContext)
+{
+    PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context;
+    PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor;
+    PCM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry;
+    ULONG i;
+
+    if (ValueType != REG_FULL_RESOURCE_DESCRIPTOR ||
+        ValueLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
+        return STATUS_UNSUCCESSFUL;
+
+    FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData;
+
+    /* Hm. Version and Revision are not set on Microsoft Windows XP... */
+#if 0
+    if (FullResourceDescriptor->PartialResourceList.Version != 1 ||
+        FullResourceDescriptor->PartialResourceList.Revision != 1)
+        return STATUS_UNSUCCESSFUL;
+#endif
+
+    for (i = 0; i < FullResourceDescriptor->PartialResourceList.Count; i++)
+    {
+        if (FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].Type != CmResourceTypeDeviceSpecific ||
+            FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize != sizeof(CM_DISK_GEOMETRY_DEVICE_DATA))
+            continue;
+
+        DiskGeometry = (PCM_DISK_GEOMETRY_DEVICE_DATA)&FullResourceDescriptor->PartialResourceList.PartialDescriptors[i + 1];
+        BiosDiskEntry->DiskGeometry = *DiskGeometry;
+
+        return STATUS_SUCCESS;
+    }
+
+    return STATUS_UNSUCCESSFUL;
+}
+
+
+static NTSTATUS
+NTAPI
+SystemConfigurationDataQueryRoutine(
+    PWSTR ValueName,
+    ULONG ValueType,
+    PVOID ValueData,
+    ULONG ValueLength,
+    PVOID Context,
+    PVOID EntryContext)
+{
+    PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor;
+    PCM_INT13_DRIVE_PARAMETER* Int13Drives = (PCM_INT13_DRIVE_PARAMETER*)Context;
+    ULONG i;
+
+    if (ValueType != REG_FULL_RESOURCE_DESCRIPTOR ||
+        ValueLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
+        return STATUS_UNSUCCESSFUL;
+
+    FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData;
+
+    /* Hm. Version and Revision are not set on Microsoft Windows XP... */
+#if 0
+    if (FullResourceDescriptor->PartialResourceList.Version != 1 ||
+        FullResourceDescriptor->PartialResourceList.Revision != 1)
+        return STATUS_UNSUCCESSFUL;
+#endif
+
+    for (i = 0; i < FullResourceDescriptor->PartialResourceList.Count; i++)
+    {
+        if (FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].Type != CmResourceTypeDeviceSpecific ||
+            FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize % sizeof(CM_INT13_DRIVE_PARAMETER) != 0)
+            continue;
+
+        *Int13Drives = (CM_INT13_DRIVE_PARAMETER*)RtlAllocateHeap(ProcessHeap, 0,
+                       FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize);
+        if (*Int13Drives == NULL)
+            return STATUS_NO_MEMORY;
+
+        memcpy(*Int13Drives,
+               &FullResourceDescriptor->PartialResourceList.PartialDescriptors[i + 1],
+               FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize);
+        return STATUS_SUCCESS;
+    }
+
+    return STATUS_UNSUCCESSFUL;
+}
+
+
+#define ROOT_NAME   L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter"
+
+static VOID
+EnumerateBiosDiskEntries(
+    IN PPARTLIST PartList)
+{
+    RTL_QUERY_REGISTRY_TABLE QueryTable[3];
+    WCHAR Name[120];
+    ULONG AdapterCount;
+    ULONG DiskCount;
+    NTSTATUS Status;
+    PCM_INT13_DRIVE_PARAMETER Int13Drives;
+    PBIOSDISKENTRY BiosDiskEntry;
+
+    memset(QueryTable, 0, sizeof(QueryTable));
+
+    QueryTable[1].Name = L"Configuration Data";
+    QueryTable[1].QueryRoutine = SystemConfigurationDataQueryRoutine;
+    Int13Drives = NULL;
+    Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
+                                    L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System",
+                                    &QueryTable[1],
+                                    (PVOID)&Int13Drives,
+                                    NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Unable to query the 'Configuration Data' key in '\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System', status=%lx\n", Status);
+        return;
+    }
+
+    AdapterCount = 0;
+    while (1)
+    {
+        swprintf(Name, L"%s\\%lu", ROOT_NAME, AdapterCount);
+        Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
+                                        Name,
+                                        &QueryTable[2],
+                                        NULL,
+                                        NULL);
+        if (!NT_SUCCESS(Status))
+        {
+            break;
+        }
+
+        swprintf(Name, L"%s\\%lu\\DiskController", ROOT_NAME, AdapterCount);
+        Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
+                                        Name,
+                                        &QueryTable[2],
+                                        NULL,
+                                        NULL);
+        if (NT_SUCCESS(Status))
+        {
+            while (1)
+            {
+                swprintf(Name, L"%s\\%lu\\DiskController\\0", ROOT_NAME, AdapterCount);
+                Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
+                                                Name,
+                                                &QueryTable[2],
+                                                NULL,
+                                                NULL);
+                if (!NT_SUCCESS(Status))
+                {
+                    RtlFreeHeap(ProcessHeap, 0, Int13Drives);
+                    return;
+                }
+
+                swprintf(Name, L"%s\\%lu\\DiskController\\0\\DiskPeripheral", ROOT_NAME, AdapterCount);
+                Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
+                                                Name,
+                                                &QueryTable[2],
+                                                NULL,
+                                                NULL);
+                if (NT_SUCCESS(Status))
+                {
+                    QueryTable[0].Name = L"Identifier";
+                    QueryTable[0].QueryRoutine = DiskIdentifierQueryRoutine;
+                    QueryTable[1].Name = L"Configuration Data";
+                    QueryTable[1].QueryRoutine = DiskConfigurationDataQueryRoutine;
+
+                    DiskCount = 0;
+                    while (1)
+                    {
+                        BiosDiskEntry = (BIOSDISKENTRY*)RtlAllocateHeap(ProcessHeap, HEAP_ZERO_MEMORY, sizeof(BIOSDISKENTRY));
+                        if (BiosDiskEntry == NULL)
+                        {
+                            break;
+                        }
+
+                        swprintf(Name, L"%s\\%lu\\DiskController\\0\\DiskPeripheral\\%lu", ROOT_NAME, AdapterCount, DiskCount);
+                        Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
+                                                        Name,
+                                                        QueryTable,
+                                                        (PVOID)BiosDiskEntry,
+                                                        NULL);
+                        if (!NT_SUCCESS(Status))
+                        {
+                            RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry);
+                            break;
+                        }
+
+                        BiosDiskEntry->DiskNumber = DiskCount;
+                        BiosDiskEntry->Recognized = FALSE;
+
+                        if (DiskCount < Int13Drives[0].NumberDrives)
+                        {
+                            BiosDiskEntry->Int13DiskData = Int13Drives[DiskCount];
+                        }
+                        else
+                        {
+                            DPRINT1("Didn't find int13 drive datas for disk %u\n", DiskCount);
+                        }
+
+                        InsertTailList(&PartList->BiosDiskListHead, &BiosDiskEntry->ListEntry);
+
+                        DPRINT("DiskNumber:        %lu\n", BiosDiskEntry->DiskNumber);
+                        DPRINT("Signature:         %08lx\n", BiosDiskEntry->Signature);
+                        DPRINT("Checksum:          %08lx\n", BiosDiskEntry->Checksum);
+                        DPRINT("BytesPerSector:    %lu\n", BiosDiskEntry->DiskGeometry.BytesPerSector);
+                        DPRINT("NumberOfCylinders: %lu\n", BiosDiskEntry->DiskGeometry.NumberOfCylinders);
+                        DPRINT("NumberOfHeads:     %lu\n", BiosDiskEntry->DiskGeometry.NumberOfHeads);
+                        DPRINT("DriveSelect:       %02x\n", BiosDiskEntry->Int13DiskData.DriveSelect);
+                        DPRINT("MaxCylinders:      %lu\n", BiosDiskEntry->Int13DiskData.MaxCylinders);
+                        DPRINT("SectorsPerTrack:   %d\n", BiosDiskEntry->Int13DiskData.SectorsPerTrack);
+                        DPRINT("MaxHeads:          %d\n", BiosDiskEntry->Int13DiskData.MaxHeads);
+                        DPRINT("NumberDrives:      %d\n", BiosDiskEntry->Int13DiskData.NumberDrives);
+
+                        DiskCount++;
+                    }
+                }
+
+                RtlFreeHeap(ProcessHeap, 0, Int13Drives);
+                return;
+            }
+        }
+
+        AdapterCount++;
+    }
+
+    RtlFreeHeap(ProcessHeap, 0, Int13Drives);
+}
+
+
+static
+VOID
+AddPartitionToDisk(
+    IN ULONG DiskNumber,
+    IN PDISKENTRY DiskEntry,
+    IN ULONG PartitionIndex,
+    IN BOOLEAN LogicalPartition)
+{
+    PPARTITION_INFORMATION PartitionInfo;
+    PPARTENTRY PartEntry;
+
+    PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartitionIndex];
+    if (PartitionInfo->PartitionType == PARTITION_ENTRY_UNUSED ||
+        ((LogicalPartition != FALSE) && IsContainerPartition(PartitionInfo->PartitionType)))
+        return;
+
+    PartEntry = RtlAllocateHeap(ProcessHeap,
+                                HEAP_ZERO_MEMORY,
+                                sizeof(PARTENTRY));
+    if (PartEntry == NULL)
+    {
+        return;
+    }
+
+    PartEntry->DiskEntry = DiskEntry;
+
+    PartEntry->StartSector.QuadPart = (ULONGLONG)PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector;
+    PartEntry->SectorCount.QuadPart = (ULONGLONG)PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector;
+
+    PartEntry->BootIndicator = PartitionInfo->BootIndicator;
+    PartEntry->PartitionType = PartitionInfo->PartitionType;
+    PartEntry->HiddenSectors = PartitionInfo->HiddenSectors;
+
+    PartEntry->LogicalPartition = LogicalPartition;
+    PartEntry->IsPartitioned = TRUE;
+    PartEntry->PartitionNumber = PartitionInfo->PartitionNumber;
+    PartEntry->PartitionIndex = PartitionIndex;
+
+    if (IsContainerPartition(PartEntry->PartitionType))
+    {
+        PartEntry->FormatState = Unformatted;
+        PartEntry->FileSystem  = NULL;
+
+        if (LogicalPartition == FALSE && DiskEntry->ExtendedPartition == NULL)
+            DiskEntry->ExtendedPartition = PartEntry;
+    }
+#if 0
+    else if (IsRecognizedPartition(PartEntry->PartitionType))
+    {
+        // FIXME FIXME! We should completely rework how we get this 'FileSystemList' available...
+        PartEntry->FileSystem = GetFileSystem(FileSystemList, PartEntry);
+        if (!PartEntry->FileSystem)
+            PartEntry->FormatState = Preformatted;
+        else
+            PartEntry->FormatState = Unformatted;
+        // PartEntry->FormatState = UnknownFormat;
+    }
+    else
+    {
+        /* Unknown partition, so unknown partition format (may or may not be actually formatted) */
+        PartEntry->FormatState = UnknownFormat;
+    }
+#endif
+    else if ((PartEntry->PartitionType == PARTITION_FAT_12) ||
+             (PartEntry->PartitionType == PARTITION_FAT_16) ||
+             (PartEntry->PartitionType == PARTITION_HUGE) ||
+             (PartEntry->PartitionType == PARTITION_XINT13) ||
+             (PartEntry->PartitionType == PARTITION_FAT32) ||
+             (PartEntry->PartitionType == PARTITION_FAT32_XINT13))
+    {
+#if 0
+        if (CheckFatFormat())
+        {
+            PartEntry->FormatState = Preformatted;
+        }
+        else
+        {
+            PartEntry->FormatState = Unformatted;
+        }
+#endif
+        PartEntry->FormatState = Preformatted;
+    }
+    else if (PartEntry->PartitionType == PARTITION_EXT2)
+    {
+#if 0
+        if (CheckExt2Format())
+        {
+            PartEntry->FormatState = Preformatted;
+        }
+        else
+        {
+            PartEntry->FormatState = Unformatted;
+        }
+#endif
+        PartEntry->FormatState = Preformatted;
+    }
+    else if (PartEntry->PartitionType == PARTITION_IFS)
+    {
+#if 0
+        if (CheckNtfsFormat())
+        {
+            PartEntry->FormatState = Preformatted;
+        }
+        else if (CheckHpfsFormat())
+        {
+            PartEntry->FormatState = Preformatted;
+        }
+        else
+        {
+            PartEntry->FormatState = Unformatted;
+        }
+#endif
+        PartEntry->FormatState = Preformatted;
+    }
+    else
+    {
+        PartEntry->FormatState = UnknownFormat;
+    }
+
+    if (LogicalPartition)
+        InsertTailList(&DiskEntry->LogicalPartListHead,
+                       &PartEntry->ListEntry);
+    else
+        InsertTailList(&DiskEntry->PrimaryPartListHead,
+                       &PartEntry->ListEntry);
+}
+
+
+static
+VOID
+ScanForUnpartitionedDiskSpace(
+    IN PDISKENTRY DiskEntry)
+{
+    ULONGLONG LastStartSector;
+    ULONGLONG LastSectorCount;
+    ULONGLONG LastUnusedSectorCount;
+    PPARTENTRY PartEntry;
+    PPARTENTRY NewPartEntry;
+    PLIST_ENTRY Entry;
+
+    DPRINT("ScanForUnpartitionedDiskSpace()\n");
+
+    if (IsListEmpty(&DiskEntry->PrimaryPartListHead))
+    {
+        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);
+
+        return;
+    }
+
+    /* Start partition at head 1, cylinder 0 */
+    LastStartSector = DiskEntry->SectorAlignment;
+    LastSectorCount = 0ULL;
+    LastUnusedSectorCount = 0ULL;
+
+    Entry = DiskEntry->PrimaryPartListHead.Flink;
+    while (Entry != &DiskEntry->PrimaryPartListHead)
+    {
+        PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
+
+        if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED ||
+            PartEntry->SectorCount.QuadPart != 0ULL)
+        {
+            LastUnusedSectorCount =
+                PartEntry->StartSector.QuadPart - (LastStartSector + LastSectorCount);
+
+            if (PartEntry->StartSector.QuadPart > (LastStartSector + LastSectorCount) &&
+                LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
+            {
+                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;
+
+                /* 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->SectorCount.QuadPart)
+    {
+        LastUnusedSectorCount = AlignDown(DiskEntry->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));
+            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;
+
+            /* Append the table to the list */
+            InsertTailList(&DiskEntry->PrimaryPartListHead,
+                           &NewPartEntry->ListEntry);
+        }
+    }
+
+    if (DiskEntry->ExtendedPartition != NULL)
+    {
+        if (IsListEmpty(&DiskEntry->LogicalPartListHead))
+        {
+            DPRINT1("No logical partition!\n");
+
+            /* Create a partition entry that represents the empty extended partition */
+            NewPartEntry = RtlAllocateHeap(ProcessHeap,
+                                           HEAP_ZERO_MEMORY,
+                                           sizeof(PARTENTRY));
+            if (NewPartEntry == NULL)
+                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;
+        }
+
+        /* Start partition at head 1, cylinder 0 */
+        LastStartSector = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
+        LastSectorCount = 0ULL;
+        LastUnusedSectorCount = 0ULL;
+
+        Entry = DiskEntry->LogicalPartListHead.Flink;
+        while (Entry != &DiskEntry->LogicalPartListHead)
+        {
+            PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
+
+            if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED ||
+                PartEntry->SectorCount.QuadPart != 0ULL)
+            {
+                LastUnusedSectorCount =
+                    PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment - (LastStartSector + LastSectorCount);
+
+                if ((PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment) > (LastStartSector + LastSectorCount) &&
+                    LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
+                {
+                    DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount);
+
+                    NewPartEntry = RtlAllocateHeap(ProcessHeap,
+                                                   HEAP_ZERO_MEMORY,
+                                                   sizeof(PARTENTRY));
+                    if (NewPartEntry == NULL)
+                        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);
+
+            if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
+            {
+                DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount);
+
+                NewPartEntry = RtlAllocateHeap(ProcessHeap,
+                                               HEAP_ZERO_MEMORY,
+                                               sizeof(PARTENTRY));
+                if (NewPartEntry == NULL)
+                    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);
+            }
+        }
+    }
+
+    DPRINT("ScanForUnpartitionedDiskSpace() done\n");
+}
+
+
+static
+VOID
+SetDiskSignature(
+    IN PPARTLIST List,
+    IN PDISKENTRY DiskEntry)
+{
+    LARGE_INTEGER SystemTime;
+    TIME_FIELDS TimeFields;
+    PLIST_ENTRY Entry2;
+    PDISKENTRY DiskEntry2;
+    PUCHAR Buffer;
+
+    Buffer = (PUCHAR)&DiskEntry->LayoutBuffer->Signature;
+
+    while (1)
+    {
+        NtQuerySystemTime(&SystemTime);
+        RtlTimeToTimeFields(&SystemTime, &TimeFields);
+
+        Buffer[0] = (UCHAR)(TimeFields.Year & 0xFF) + (UCHAR)(TimeFields.Hour & 0xFF);
+        Buffer[1] = (UCHAR)(TimeFields.Year >> 8) + (UCHAR)(TimeFields.Minute & 0xFF);
+        Buffer[2] = (UCHAR)(TimeFields.Month & 0xFF) + (UCHAR)(TimeFields.Second & 0xFF);
+        Buffer[3] = (UCHAR)(TimeFields.Day & 0xFF) + (UCHAR)(TimeFields.Milliseconds & 0xFF);
+
+        if (DiskEntry->LayoutBuffer->Signature == 0)
+        {
+            continue;
+        }
+
+        /* check if the signature already exist */
+        /* FIXME:
+         *   Check also signatures from disks, which are
+         *   not visible (bootable) by the bios.
+         */
+        Entry2 = List->DiskListHead.Flink;
+        while (Entry2 != &List->DiskListHead)
+        {
+            DiskEntry2 = CONTAINING_RECORD(Entry2, DISKENTRY, ListEntry);
+
+            if (DiskEntry != DiskEntry2 &&
+                DiskEntry->LayoutBuffer->Signature == DiskEntry2->LayoutBuffer->Signature)
+                break;
+
+            Entry2 = Entry2->Flink;
+        }
+
+        if (Entry2 == &List->DiskListHead)
+            break;
+    }
+}
+
+
+static
+VOID
+UpdateDiskSignatures(
+    IN PPARTLIST List)
+{
+    PLIST_ENTRY Entry;
+    PDISKENTRY DiskEntry;
+
+    /* Print partition lines */
+    Entry = List->DiskListHead.Flink;
+    while (Entry != &List->DiskListHead)
+    {
+        DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
+
+        if (DiskEntry->LayoutBuffer &&
+            DiskEntry->LayoutBuffer->Signature == 0)
+        {
+            SetDiskSignature(List, DiskEntry);
+            DiskEntry->LayoutBuffer->PartitionEntry[0].RewritePartition = TRUE;
+        }
+
+        Entry = Entry->Flink;
+    }
+}
+
+
+static
+VOID
+AddDiskToList(
+    IN HANDLE FileHandle,
+    IN ULONG DiskNumber,
+    IN PPARTLIST List)
+{
+    DISK_GEOMETRY DiskGeometry;
+    SCSI_ADDRESS ScsiAddress;
+    PDISKENTRY DiskEntry;
+    IO_STATUS_BLOCK Iosb;
+    NTSTATUS Status;
+    PPARTITION_SECTOR Mbr;
+    PULONG Buffer;
+    LARGE_INTEGER FileOffset;
+    WCHAR Identifier[20];
+    ULONG Checksum;
+    ULONG Signature;
+    ULONG i;
+    PLIST_ENTRY ListEntry;
+    PBIOSDISKENTRY BiosDiskEntry;
+    ULONG LayoutBufferSize;
+    PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer;
+
+    Status = NtDeviceIoControlFile(FileHandle,
+                                   NULL,
+                                   NULL,
+                                   NULL,
+                                   &Iosb,
+                                   IOCTL_DISK_GET_DRIVE_GEOMETRY,
+                                   NULL,
+                                   0,
+                                   &DiskGeometry,
+                                   sizeof(DISK_GEOMETRY));
+    if (!NT_SUCCESS(Status))
+        return;
+
+    if (DiskGeometry.MediaType != FixedMedia &&
+        DiskGeometry.MediaType != RemovableMedia)
+    {
+        return;
+    }
+
+    Status = NtDeviceIoControlFile(FileHandle,
+                                   NULL,
+                                   NULL,
+                                   NULL,
+                                   &Iosb,
+                                   IOCTL_SCSI_GET_ADDRESS,
+                                   NULL,
+                                   0,
+                                   &ScsiAddress,
+                                   sizeof(SCSI_ADDRESS));
+    if (!NT_SUCCESS(Status))
+        return;
+
+    /*
+     * Check whether the disk is initialized, by looking at its MBR.
+     * NOTE that this must be generalized to GPT disks as well!
+     */
+
+    Mbr = (PARTITION_SECTOR*)RtlAllocateHeap(ProcessHeap,
+                                             0,
+                                             DiskGeometry.BytesPerSector);
+    if (Mbr == NULL)
+        return;
+
+    FileOffset.QuadPart = 0;
+    Status = NtReadFile(FileHandle,
+                        NULL,
+                        NULL,
+                        NULL,
+                        &Iosb,
+                        (PVOID)Mbr,
+                        DiskGeometry.BytesPerSector,
+                        &FileOffset,
+                        NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        RtlFreeHeap(ProcessHeap, 0, Mbr);
+        DPRINT1("NtReadFile failed, status=%x\n", Status);
+        return;
+    }
+    Signature = Mbr->Signature;
+
+    /* Calculate the MBR checksum */
+    Checksum = 0;
+    Buffer = (PULONG)Mbr;
+    for (i = 0; i < 128; i++)
+    {
+        Checksum += Buffer[i];
+    }
+    Checksum = ~Checksum + 1;
+
+    swprintf(Identifier, L"%08x-%08x-A", Checksum, Signature);
+    DPRINT("Identifier: %S\n", Identifier);
+
+    DiskEntry = RtlAllocateHeap(ProcessHeap,
+                                HEAP_ZERO_MEMORY,
+                                sizeof(DISKENTRY));
+    if (DiskEntry == NULL)
+    {
+        return;
+    }
+
+//    DiskEntry->Checksum = Checksum;
+//    DiskEntry->Signature = Signature;
+    DiskEntry->BiosFound = FALSE;
+
+    /* Check if this disk has a valid MBR */
+    // FIXME: Check for the MBR signature as well, etc...
+    if (Mbr->BootCode[0] == 0 && Mbr->BootCode[1] == 0)
+        DiskEntry->NoMbr = TRUE;
+    else
+        DiskEntry->NoMbr = FALSE;
+
+    /* Free the MBR sector buffer */
+    RtlFreeHeap(ProcessHeap, 0, Mbr);
+
+
+    ListEntry = List->BiosDiskListHead.Flink;
+    while (ListEntry != &List->BiosDiskListHead)
+    {
+        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.
+         */
+        if (BiosDiskEntry->Signature == Signature &&
+            BiosDiskEntry->Checksum == Checksum &&
+            !BiosDiskEntry->Recognized)
+        {
+            if (!DiskEntry->BiosFound)
+            {
+                DiskEntry->BiosDiskNumber = BiosDiskEntry->DiskNumber;
+                DiskEntry->BiosFound = TRUE;
+                BiosDiskEntry->Recognized = TRUE;
+            }
+            else
+            {
+            }
+        }
+        ListEntry = ListEntry->Flink;
+    }
+
+    if (!DiskEntry->BiosFound)
+    {
+#if 0
+        RtlFreeHeap(ProcessHeap, 0, DiskEntry);
+        return;
+#else
+        DPRINT1("WARNING: Setup could not find a matching BIOS disk entry. Disk %d is not be bootable by the BIOS!\n", DiskNumber);
+#endif
+    }
+
+    InitializeListHead(&DiskEntry->PrimaryPartListHead);
+    InitializeListHead(&DiskEntry->LogicalPartListHead);
+
+    DiskEntry->Cylinders = DiskGeometry.Cylinders.QuadPart;
+    DiskEntry->TracksPerCylinder = DiskGeometry.TracksPerCylinder;
+    DiskEntry->SectorsPerTrack = DiskGeometry.SectorsPerTrack;
+    DiskEntry->BytesPerSector = DiskGeometry.BytesPerSector;
+
+    DPRINT("Cylinders %I64u\n", DiskEntry->Cylinders);
+    DPRINT("TracksPerCylinder %lu\n", DiskEntry->TracksPerCylinder);
+    DPRINT("SectorsPerTrack %lu\n", DiskEntry->SectorsPerTrack);
+    DPRINT("BytesPerSector %lu\n", DiskEntry->BytesPerSector);
+
+    DiskEntry->SectorCount.QuadPart = DiskGeometry.Cylinders.QuadPart *
+                                      (ULONGLONG)DiskGeometry.TracksPerCylinder *
+                                      (ULONGLONG)DiskGeometry.SectorsPerTrack;
+
+    DiskEntry->SectorAlignment = DiskGeometry.SectorsPerTrack;
+    DiskEntry->CylinderAlignment = DiskGeometry.TracksPerCylinder *
+                                   DiskGeometry.SectorsPerTrack;
+
+    DPRINT("SectorCount %I64u\n", DiskEntry->SectorCount.QuadPart);
+    DPRINT("SectorAlignment %lu\n", DiskEntry->SectorAlignment);
+
+    DiskEntry->DiskNumber = DiskNumber;
+    DiskEntry->Port = ScsiAddress.PortNumber;
+    DiskEntry->Bus = ScsiAddress.PathId;
+    DiskEntry->Id = ScsiAddress.TargetId;
+
+    GetDriverName(DiskEntry);
+
+    InsertAscendingList(&List->DiskListHead, DiskEntry, DISKENTRY, ListEntry, DiskNumber);
+
+    /* Allocate a layout buffer with 4 partition entries first */
+    LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
+                       ((4 - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION));
+    DiskEntry->LayoutBuffer = RtlAllocateHeap(ProcessHeap,
+                                              HEAP_ZERO_MEMORY,
+                                              LayoutBufferSize);
+    if (DiskEntry->LayoutBuffer == NULL)
+    {
+        DPRINT1("Failed to allocate the disk layout buffer!\n");
+        return;
+    }
+
+    for (;;)
+    {
+        DPRINT1("Buffer size: %lu\n", LayoutBufferSize);
+        Status = NtDeviceIoControlFile(FileHandle,
+                                       NULL,
+                                       NULL,
+                                       NULL,
+                                       &Iosb,
+                                       IOCTL_DISK_GET_DRIVE_LAYOUT,
+                                       NULL,
+                                       0,
+                                       DiskEntry->LayoutBuffer,
+                                       LayoutBufferSize);
+        if (NT_SUCCESS(Status))
+            break;
+
+        if (Status != STATUS_BUFFER_TOO_SMALL)
+        {
+            DPRINT1("NtDeviceIoControlFile() failed (Status: 0x%08lx)\n", Status);
+            return;
+        }
+
+        LayoutBufferSize += 4 * sizeof(PARTITION_INFORMATION);
+        NewLayoutBuffer = RtlReAllocateHeap(ProcessHeap,
+                                            HEAP_ZERO_MEMORY,
+                                            DiskEntry->LayoutBuffer,
+                                            LayoutBufferSize);
+        if (NewLayoutBuffer == NULL)
+        {
+            DPRINT1("Failed to reallocate the disk layout buffer!\n");
+            return;
+        }
+
+        DiskEntry->LayoutBuffer = NewLayoutBuffer;
+    }
+
+    DPRINT1("PartitionCount: %lu\n", DiskEntry->LayoutBuffer->PartitionCount);
+
+#ifdef DUMP_PARTITION_TABLE
+    DumpPartitionTable(DiskEntry);
+#endif
+
+    if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart != 0 &&
+        DiskEntry->LayoutBuffer->PartitionEntry[0].PartitionLength.QuadPart != 0 &&
+        DiskEntry->LayoutBuffer->PartitionEntry[0].PartitionType != PARTITION_ENTRY_UNUSED)
+    {
+        if ((DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart / DiskEntry->BytesPerSector) % DiskEntry->SectorsPerTrack == 0)
+        {
+            DPRINT("Use %lu Sector alignment!\n", DiskEntry->SectorsPerTrack);
+        }
+        else if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart % (1024 * 1024) == 0)
+        {
+            DPRINT1("Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector);
+        }
+        else
+        {
+            DPRINT1("No matching alignment found! Partition 1 starts at %I64u\n", DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart);
+        }
+    }
+    else
+    {
+        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
+    {
+        for (i = 0; i < 4; i++)
+        {
+            AddPartitionToDisk(DiskNumber, DiskEntry, i, FALSE);
+        }
+
+        for (i = 4; i < DiskEntry->LayoutBuffer->PartitionCount; i += 4)
+        {
+            AddPartitionToDisk(DiskNumber, DiskEntry, i, TRUE);
+        }
+    }
+
+    ScanForUnpartitionedDiskSpace(DiskEntry);
+}
+
+
+PPARTLIST
+CreatePartitionList(VOID)
+{
+    PPARTLIST List;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    SYSTEM_DEVICE_INFORMATION Sdi;
+    IO_STATUS_BLOCK Iosb;
+    ULONG ReturnSize;
+    NTSTATUS Status;
+    ULONG DiskNumber;
+    WCHAR Buffer[MAX_PATH];
+    UNICODE_STRING Name;
+    HANDLE FileHandle;
+
+    List = (PPARTLIST)RtlAllocateHeap(ProcessHeap,
+                                      0,
+                                      sizeof (PARTLIST));
+    if (List == NULL)
+        return NULL;
+
+    List->CurrentDisk = NULL;
+    List->CurrentPartition = NULL;
+
+    List->SystemPartition = NULL;
+    List->OriginalSystemPartition = NULL;
+
+    List->TempPartition = NULL;
+    List->FormatState = Start;
+
+    InitializeListHead(&List->DiskListHead);
+    InitializeListHead(&List->BiosDiskListHead);
+
+    EnumerateBiosDiskEntries(List);
+
+    Status = NtQuerySystemInformation(SystemDeviceInformation,
+                                      &Sdi,
+                                      sizeof(Sdi),
+                                      &ReturnSize);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("NtQuerySystemInformation() failed, Status 0x%08lx", Status);
+        RtlFreeHeap(ProcessHeap, 0, List);
+        return NULL;
+    }
+
+    for (DiskNumber = 0; DiskNumber < Sdi.NumberOfDisks; DiskNumber++)
+    {
+        swprintf(Buffer,
+                 L"\\Device\\Harddisk%d\\Partition0",
+                 DiskNumber);
+        RtlInitUnicodeString(&Name,
+                             Buffer);
+
+        InitializeObjectAttributes(&ObjectAttributes,
+                                   &Name,
+                                   0,
+                                   NULL,
+                                   NULL);
+
+        Status = NtOpenFile(&FileHandle,
+                            FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
+                            &ObjectAttributes,
+                            &Iosb,
+                            FILE_SHARE_READ,
+                            FILE_SYNCHRONOUS_IO_NONALERT);
+        if (NT_SUCCESS(Status))
+        {
+            AddDiskToList(FileHandle, DiskNumber, List);
+
+            NtClose(FileHandle);
+        }
+    }
+
+    UpdateDiskSignatures(List);
+
+    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;
+}
+
+
+VOID
+DestroyPartitionList(
+    IN PPARTLIST List)
+{
+    PDISKENTRY DiskEntry;
+    PBIOSDISKENTRY BiosDiskEntry;
+    PPARTENTRY PartEntry;
+    PLIST_ENTRY Entry;
+
+    /* Release disk and partition info */
+    while (!IsListEmpty(&List->DiskListHead))
+    {
+        Entry = RemoveHeadList(&List->DiskListHead);
+        DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
+
+        /* Release driver name */
+        RtlFreeUnicodeString(&DiskEntry->DriverName);
+
+        /* Release primary partition list */
+        while (!IsListEmpty(&DiskEntry->PrimaryPartListHead))
+        {
+            Entry = RemoveHeadList(&DiskEntry->PrimaryPartListHead);
+            PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
+
+            RtlFreeHeap(ProcessHeap, 0, PartEntry);
+        }
+
+        /* Release logical partition list */
+        while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
+        {
+            Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
+            PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
+
+            RtlFreeHeap(ProcessHeap, 0, PartEntry);
+        }
+
+        /* Release layout buffer */
+        if (DiskEntry->LayoutBuffer != NULL)
+            RtlFreeHeap(ProcessHeap, 0, DiskEntry->LayoutBuffer);
+
+
+        /* Release disk entry */
+        RtlFreeHeap(ProcessHeap, 0, DiskEntry);
+    }
+
+    /* Release the bios disk info */
+    while (!IsListEmpty(&List->BiosDiskListHead))
+    {
+        Entry = RemoveHeadList(&List->BiosDiskListHead);
+        BiosDiskEntry = CONTAINING_RECORD(Entry, BIOSDISKENTRY, ListEntry);
+
+        RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry);
+    }
+
+    /* Release list head */
+    RtlFreeHeap(ProcessHeap, 0, List);
+}
+
+
+VOID
+InitPartitionListUi(
+    IN OUT PPARTLIST_UI ListUi,
+    IN PPARTLIST List,
+    IN SHORT Left,
+    IN SHORT Top,
+    IN SHORT Right,
+    IN SHORT Bottom)
+{
+    ListUi->List = List;
+    // ListUi->FirstShown = NULL;
+    // ListUi->LastShown = NULL;
+
+    ListUi->Left = Left;
+    ListUi->Top = Top;
+    ListUi->Right = Right;
+    ListUi->Bottom = Bottom;
+
+    ListUi->Line = 0;
+    ListUi->Offset = 0;
+
+    // ListUi->Redraw = TRUE;
+}
+
+static
+VOID
+PrintEmptyLine(
+    IN PPARTLIST_UI ListUi)
+{
+    COORD coPos;
+    ULONG Written;
+    USHORT Width;
+    USHORT Height;
+
+    Width = ListUi->Right - ListUi->Left - 1;
+    Height = ListUi->Bottom - ListUi->Top - 2;
+
+    coPos.X = ListUi->Left + 1;
+    coPos.Y = ListUi->Top + 1 + ListUi->Line;
+
+    if (ListUi->Line >= 0 && ListUi->Line <= Height)
+    {
+        FillConsoleOutputAttribute(StdOutput,
+                                   FOREGROUND_WHITE | BACKGROUND_BLUE,
+                                   Width,
+                                   coPos,
+                                   &Written);
+
+        FillConsoleOutputCharacterA(StdOutput,
+                                    ' ',
+                                    Width,
+                                    coPos,
+                                    &Written);
+    }
+
+    ListUi->Line++;
+}
+
+
+static
+VOID
+PrintPartitionData(
+    IN PPARTLIST_UI ListUi,
+    IN PDISKENTRY DiskEntry,
+    IN PPARTENTRY PartEntry)
+{
+    PPARTLIST List = ListUi->List;
+    CHAR LineBuffer[128];
+    COORD coPos;
+    ULONG Written;
+    USHORT Width;
+    USHORT Height;
+    LARGE_INTEGER PartSize;
+    PCHAR Unit;
+    UCHAR Attribute;
+    CHAR PartTypeString[32];
+    PCHAR PartType = PartTypeString;
+
+    Width = ListUi->Right - ListUi->Left - 1;
+    Height = ListUi->Bottom - ListUi->Top - 2;
+
+    coPos.X = ListUi->Left + 1;
+    coPos.Y = ListUi->Top + 1 + ListUi->Line;
+
+    if (PartEntry->IsPartitioned == FALSE)
+    {
+        PartSize.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
+#if 0
+        if (PartSize.QuadPart >= 10737418240) /* 10 GB */
+        {
+            PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1073741824);
+            Unit = MUIGetString(STRING_GB);
+        }
+        else
+#endif
+        if (PartSize.QuadPart >= 10485760) /* 10 MB */
+        {
+            PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1048576);
+            Unit = MUIGetString(STRING_MB);
+        }
+        else
+        {
+            PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1024);
+            Unit = MUIGetString(STRING_KB);
+        }
+
+        sprintf(LineBuffer,
+                MUIGetString(STRING_UNPSPACE),
+                PartEntry->LogicalPartition ? "  " : "",
+                PartEntry->LogicalPartition ? "" : "  ",
+                PartSize.u.LowPart,
+                Unit);
+    }
+    else
+    {
+        /* Determine partition type */
+        PartTypeString[0] = '\0';
+        if (PartEntry->New != FALSE)
+        {
+            PartType = MUIGetString(STRING_UNFORMATTED);
+        }
+        else if (PartEntry->IsPartitioned != FALSE)
+        {
+           GetPartTypeStringFromPartitionType(PartEntry->PartitionType,
+                                              PartTypeString,
+                                              ARRAYSIZE(PartTypeString));
+           PartType = PartTypeString;
+        }
+
+        PartSize.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
+#if 0
+        if (PartSize.QuadPart >= 10737418240) /* 10 GB */
+        {
+            PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1073741824);
+            Unit = MUIGetString(STRING_GB);
+        }
+        else
+#endif
+        if (PartSize.QuadPart >= 10485760) /* 10 MB */
+        {
+            PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1048576);
+            Unit = MUIGetString(STRING_MB);
+        }
+        else
+        {
+            PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1024);
+            Unit = MUIGetString(STRING_KB);
+        }
+
+        if (strcmp(PartType, MUIGetString(STRING_FORMATUNKNOWN)) == 0)
+        {
+            sprintf(LineBuffer,
+                    MUIGetString(STRING_HDDINFOUNK5),
+                    (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
+                    (PartEntry->DriveLetter == 0) ? '-' : ':',
+                    PartEntry->BootIndicator ? '*' : ' ',
+                    PartEntry->LogicalPartition ? "  " : "",
+                    PartEntry->PartitionType,
+                    PartEntry->LogicalPartition ? "" : "  ",
+                    PartSize.u.LowPart,
+                    Unit);
+        }
+        else
+        {
+            sprintf(LineBuffer,
+                    "%c%c %c %s%-24s%s     %6lu %s",
+                    (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
+                    (PartEntry->DriveLetter == 0) ? '-' : ':',
+                    PartEntry->BootIndicator ? '*' : ' ',
+                    PartEntry->LogicalPartition ? "  " : "",
+                    PartType,
+                    PartEntry->LogicalPartition ? "" : "  ",
+                    PartSize.u.LowPart,
+                    Unit);
+        }
+    }
+
+    Attribute = (List->CurrentDisk == DiskEntry &&
+                 List->CurrentPartition == PartEntry) ?
+                 FOREGROUND_BLUE | BACKGROUND_WHITE :
+                 FOREGROUND_WHITE | BACKGROUND_BLUE;
+
+    if (ListUi->Line >= 0 && ListUi->Line <= Height)
+    {
+        FillConsoleOutputCharacterA(StdOutput,
+                                    ' ',
+                                    Width,
+                                    coPos,
+                                    &Written);
+    }
+    coPos.X += 4;
+    Width -= 8;
+    if (ListUi->Line >= 0 && ListUi->Line <= Height)
+    {
+        FillConsoleOutputAttribute(StdOutput,
+                                   Attribute,
+                                   Width,
+                                   coPos,
+                                   &Written);
+    }
+    coPos.X++;
+    Width -= 2;
+    if (ListUi->Line >= 0 && ListUi->Line <= Height)
+    {
+        WriteConsoleOutputCharacterA(StdOutput,
+                                     LineBuffer,
+                                     min(strlen(LineBuffer), Width),
+                                     coPos,
+                                     &Written);
+    }
+
+    ListUi->Line++;
+}
+
+
+static
+VOID
+PrintDiskData(
+    IN PPARTLIST_UI ListUi,
+    IN PDISKENTRY DiskEntry)
+{
+    // PPARTLIST List = ListUi->List;
+    PPARTENTRY PrimaryPartEntry, LogicalPartEntry;
+    PLIST_ENTRY PrimaryEntry, LogicalEntry;
+    CHAR LineBuffer[128];
+    COORD coPos;
+    ULONG Written;
+    USHORT Width;
+    USHORT Height;
+    ULARGE_INTEGER DiskSize;
+    PCHAR Unit;
+
+    Width = ListUi->Right - ListUi->Left - 1;
+    Height = ListUi->Bottom - ListUi->Top - 2;
+
+    coPos.X = ListUi->Left + 1;
+    coPos.Y = ListUi->Top + 1 + ListUi->Line;
+
+    DiskSize.QuadPart = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
+    if (DiskSize.QuadPart >= 10737418240) /* 10 GB */
+    {
+        DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, 1073741824);
+        Unit = MUIGetString(STRING_GB);
+    }
+    else
+    {
+        DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, 1048576);
+        if (DiskSize.QuadPart == 0)
+            DiskSize.QuadPart = 1;
+        Unit = MUIGetString(STRING_MB);
+    }
+
+    if (DiskEntry->DriverName.Length > 0)
+    {
+        sprintf(LineBuffer,
+                MUIGetString(STRING_HDINFOPARTSELECT),
+                DiskSize.u.LowPart,
+                Unit,
+                DiskEntry->DiskNumber,
+                DiskEntry->Port,
+                DiskEntry->Bus,
+                DiskEntry->Id,
+                DiskEntry->DriverName.Buffer);
+    }
+    else
+    {
+        sprintf(LineBuffer,
+                MUIGetString(STRING_HDDINFOUNK6),
+                DiskSize.u.LowPart,
+                Unit,
+                DiskEntry->DiskNumber,
+                DiskEntry->Port,
+                DiskEntry->Bus,
+                DiskEntry->Id);
+    }
+
+    if (ListUi->Line >= 0 && ListUi->Line <= Height)
+    {
+        FillConsoleOutputAttribute(StdOutput,
+                                   FOREGROUND_WHITE | BACKGROUND_BLUE,
+                                   Width,
+                                   coPos,
+                                   &Written);
+
+        FillConsoleOutputCharacterA(StdOutput,
+                                    ' ',
+                                    Width,
+                                    coPos,
+                                    &Written);
+    }
+
+    coPos.X++;
+    if (ListUi->Line >= 0 && ListUi->Line <= Height)
+    {
+        WriteConsoleOutputCharacterA(StdOutput,
+                                     LineBuffer,
+                                     min((USHORT)strlen(LineBuffer), Width - 2),
+                                     coPos,
+                                     &Written);
+    }
+
+    ListUi->Line++;
+
+    /* Print separator line */
+    PrintEmptyLine(ListUi);
+
+    /* Print partition lines */
+    PrimaryEntry = DiskEntry->PrimaryPartListHead.Flink;
+    while (PrimaryEntry != &DiskEntry->PrimaryPartListHead)
+    {
+        PrimaryPartEntry = CONTAINING_RECORD(PrimaryEntry, PARTENTRY, ListEntry);
+
+        PrintPartitionData(ListUi,
+                           DiskEntry,
+                           PrimaryPartEntry);
+
+        if (IsContainerPartition(PrimaryPartEntry->PartitionType))
+        {
+            LogicalEntry = DiskEntry->LogicalPartListHead.Flink;
+            while (LogicalEntry != &DiskEntry->LogicalPartListHead)
+            {
+                LogicalPartEntry = CONTAINING_RECORD(LogicalEntry, PARTENTRY, ListEntry);
+
+                PrintPartitionData(ListUi,
+                                   DiskEntry,
+                                   LogicalPartEntry);
+
+                LogicalEntry = LogicalEntry->Flink;
+            }
+        }
+
+        PrimaryEntry = PrimaryEntry->Flink;
+    }
+
+    /* Print separator line */
+    PrintEmptyLine(ListUi);
+}
+
+
+VOID
+DrawPartitionList(
+    IN PPARTLIST_UI ListUi)
+{
+    PPARTLIST List = ListUi->List;
+    PLIST_ENTRY Entry, Entry2;
+    PDISKENTRY DiskEntry;
+    PPARTENTRY PartEntry = NULL;
+    COORD coPos;
+    ULONG Written;
+    SHORT i;
+    SHORT CurrentDiskLine;
+    SHORT CurrentPartLine;
+    SHORT LastLine;
+    BOOLEAN CurrentPartLineFound = FALSE;
+    BOOLEAN CurrentDiskLineFound = FALSE;
+
+    /* Calculate the line of the current disk and partition */
+    CurrentDiskLine = 0;
+    CurrentPartLine = 0;
+    LastLine = 0;
+
+    Entry = List->DiskListHead.Flink;
+    while (Entry != &List->DiskListHead)
+    {
+        DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
+
+        LastLine += 2;
+        if (CurrentPartLineFound == FALSE)
+        {
+            CurrentPartLine += 2;
+        }
+
+        Entry2 = DiskEntry->PrimaryPartListHead.Flink;
+        while (Entry2 != &DiskEntry->PrimaryPartListHead)
+        {
+            PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
+            if (PartEntry == List->CurrentPartition)
+            {
+                CurrentPartLineFound = TRUE;
+            }
+
+            Entry2 = Entry2->Flink;
+            if (CurrentPartLineFound == FALSE)
+            {
+                CurrentPartLine++;
+            }
+
+            LastLine++;
+        }
+
+        if (CurrentPartLineFound == FALSE)
+        {
+            Entry2 = DiskEntry->LogicalPartListHead.Flink;
+            while (Entry2 != &DiskEntry->LogicalPartListHead)
+            {
+                PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
+                if (PartEntry == List->CurrentPartition)
+                {
+                    CurrentPartLineFound = TRUE;
+                }
+
+                Entry2 = Entry2->Flink;
+                if (CurrentPartLineFound == FALSE)
+                {
+                    CurrentPartLine++;
+                }
+
+                LastLine++;
+            }
+        }
+
+        if (DiskEntry == List->CurrentDisk)
+        {
+            CurrentDiskLineFound = TRUE;
+        }
+
+        Entry = Entry->Flink;
+        if (Entry != &List->DiskListHead)
+        {
+            if (CurrentDiskLineFound == FALSE)
+            {
+                CurrentPartLine ++;
+                CurrentDiskLine = CurrentPartLine;
+            }
+
+            LastLine++;
+        }
+        else
+        {
+            LastLine--;
+        }
+    }
+
+    /* If it possible, make the disk name visible */
+    if (CurrentPartLine < ListUi->Offset)
+    {
+        ListUi->Offset = CurrentPartLine;
+    }
+    else if (CurrentPartLine - ListUi->Offset > ListUi->Bottom - ListUi->Top - 2)
+    {
+        ListUi->Offset = CurrentPartLine - (ListUi->Bottom - ListUi->Top - 2);
+    }
+
+    if (CurrentDiskLine < ListUi->Offset && CurrentPartLine - CurrentDiskLine < ListUi->Bottom - ListUi->Top - 2)
+    {
+        ListUi->Offset = CurrentDiskLine;
+    }
+
+    /* Draw upper left corner */
+    coPos.X = ListUi->Left;
+    coPos.Y = ListUi->Top;
+    FillConsoleOutputCharacterA(StdOutput,
+                                0xDA, // '+',
+                                1,
+                                coPos,
+                                &Written);
+
+    /* Draw upper edge */
+    coPos.X = ListUi->Left + 1;
+    coPos.Y = ListUi->Top;
+    if (ListUi->Offset == 0)
+    {
+        FillConsoleOutputCharacterA(StdOutput,
+                                    0xC4, // '-',
+                                    ListUi->Right - ListUi->Left - 1,
+                                    coPos,
+                                    &Written);
+    }
+    else
+    {
+        FillConsoleOutputCharacterA(StdOutput,
+                                    0xC4, // '-',
+                                    ListUi->Right - ListUi->Left - 5,
+                                    coPos,
+                                    &Written);
+        coPos.X = ListUi->Right - 5;
+        WriteConsoleOutputCharacterA(StdOutput,
+                                     "(\x18)", // "(up)"
+                                     3,
+                                     coPos,
+                                     &Written);
+        coPos.X = ListUi->Right - 2;
+        FillConsoleOutputCharacterA(StdOutput,
+                                    0xC4, // '-',
+                                    2,
+                                    coPos,
+                                    &Written);
+    }
+
+    /* Draw upper right corner */
+    coPos.X = ListUi->Right;
+    coPos.Y = ListUi->Top;
+    FillConsoleOutputCharacterA(StdOutput,
+                                0xBF, // '+',
+                                1,
+                                coPos,
+                                &Written);
+
+    /* Draw left and right edge */
+    for (i = ListUi->Top + 1; i < ListUi->Bottom; i++)
+    {
+        coPos.X = ListUi->Left;
+        coPos.Y = i;
+        FillConsoleOutputCharacterA(StdOutput,
+                                    0xB3, // '|',
+                                    1,
+                                    coPos,
+                                    &Written);
+
+        coPos.X = ListUi->Right;
+        FillConsoleOutputCharacterA(StdOutput,
+                                    0xB3, //'|',
+                                    1,
+                                    coPos,
+                                    &Written);
+    }
+
+    /* Draw lower left corner */
+    coPos.X = ListUi->Left;
+    coPos.Y = ListUi->Bottom;
+    FillConsoleOutputCharacterA(StdOutput,
+                                0xC0, // '+',
+                                1,
+                                coPos,
+                                &Written);
+
+    /* Draw lower edge */
+    coPos.X = ListUi->Left + 1;
+    coPos.Y = ListUi->Bottom;
+    if (LastLine - ListUi->Offset <= ListUi->Bottom - ListUi->Top - 2)
+    {
+        FillConsoleOutputCharacterA(StdOutput,
+                                    0xC4, // '-',
+                                    ListUi->Right - ListUi->Left - 1,
+                                    coPos,
+                                    &Written);
+    }
+    else
+    {
+        FillConsoleOutputCharacterA(StdOutput,
+                                    0xC4, // '-',
+                                    ListUi->Right - ListUi->Left - 5,
+                                    coPos,
+                                    &Written);
+        coPos.X = ListUi->Right - 5;
+        WriteConsoleOutputCharacterA(StdOutput,
+                                     "(\x19)", // "(down)"
+                                     3,
+                                     coPos,
+                                     &Written);
+       coPos.X = ListUi->Right - 2;
+       FillConsoleOutputCharacterA(StdOutput,
+                                   0xC4, // '-',
+                                   2,
+                                   coPos,
+                                   &Written);
+    }
+
+    /* Draw lower right corner */
+    coPos.X = ListUi->Right;
+    coPos.Y = ListUi->Bottom;
+    FillConsoleOutputCharacterA(StdOutput,
+                                0xD9, // '+',
+                                1,
+                                coPos,
+                                &Written);
+
+    /* print list entries */
+    ListUi->Line = - ListUi->Offset;
+
+    Entry = List->DiskListHead.Flink;
+    while (Entry != &List->DiskListHead)
+    {
+        DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
+
+        /* Print disk entry */
+        PrintDiskData(ListUi, DiskEntry);
+
+        Entry = Entry->Flink;
+    }
+}
+
+
+ULONG
+SelectPartition(
+    IN PPARTLIST List,
+    IN ULONG DiskNumber,
+    IN ULONG PartitionNumber)
+{
+    PDISKENTRY DiskEntry;
+    PPARTENTRY PartEntry;
+    PLIST_ENTRY Entry1, Entry2;
+
+    /* Check for empty disks */
+    if (IsListEmpty(&List->DiskListHead))
+        return FALSE;
+
+    /* Check for first usable entry on next disk */
+    Entry1 = List->CurrentDisk->ListEntry.Flink;
+    while (Entry1 != &List->DiskListHead)
+    {
+        DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
+
+        if (DiskEntry->DiskNumber == DiskNumber)
+        {
+            Entry2 = DiskEntry->PrimaryPartListHead.Flink;
+            while (Entry2 != &DiskEntry->PrimaryPartListHead)
+            {
+                PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
+
+                if (PartEntry->PartitionNumber == PartitionNumber)
+                {
+                    List->CurrentDisk = DiskEntry;
+                    List->CurrentPartition = PartEntry;
+                    return TRUE;
+                }
+
+                Entry2 = Entry2->Flink;
+            }
+
+            return FALSE;
+        }
+
+        Entry1 = Entry1->Flink;
+    }
+
+    return FALSE;
+}
+
+
+PPARTENTRY
+GetNextPartition(
+    IN PPARTLIST List)
+{
+    PLIST_ENTRY DiskListEntry;
+    PLIST_ENTRY PartListEntry;
+    PDISKENTRY DiskEntry;
+    PPARTENTRY PartEntry;
+
+    /* Fail, if no disks are available */
+    if (IsListEmpty(&List->DiskListHead))
+        return NULL;
+
+    /* Check for next usable entry on current disk */
+    if (List->CurrentPartition != NULL)
+    {
+        if (List->CurrentPartition->LogicalPartition)
+        {
+            /* Logical partition */
+
+            PartListEntry = List->CurrentPartition->ListEntry.Flink;
+            if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
+            {
+                /* Next logical partition */
+                PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
+
+                List->CurrentPartition = PartEntry;
+                return List->CurrentPartition;
+            }
+            else
+            {
+                PartListEntry = List->CurrentDisk->ExtendedPartition->ListEntry.Flink;
+                if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
+                {
+                    PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
+
+                    List->CurrentPartition = PartEntry;
+                    return List->CurrentPartition;
+                }
+            }
+        }
+        else
+        {
+            /* Primary or extended partition */
+
+            if ((List->CurrentPartition->IsPartitioned != FALSE) &&
+                IsContainerPartition(List->CurrentPartition->PartitionType))
+            {
+                /* First logical partition */
+                PartListEntry = List->CurrentDisk->LogicalPartListHead.Flink;
+                if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
+                {
+                    PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
+
+                    List->CurrentPartition = PartEntry;
+                    return List->CurrentPartition;
+                }
+            }
+            else
+            {
+                /* Next primary partition */
+                PartListEntry = List->CurrentPartition->ListEntry.Flink;
+                if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
+                {
+                    PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
+
+                    List->CurrentPartition = PartEntry;
+                    return List->CurrentPartition;
+                }
+            }
+        }
+    }
+
+    /* Search for the first partition entry on the next disk */
+    DiskListEntry = List->CurrentDisk->ListEntry.Flink;
+    while (DiskListEntry != &List->DiskListHead)
+    {
+        DiskEntry = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
+
+        PartListEntry = DiskEntry->PrimaryPartListHead.Flink;
+        if (PartListEntry != &DiskEntry->PrimaryPartListHead)
+        {
+            PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
+
+            List->CurrentDisk = DiskEntry;
+            List->CurrentPartition = PartEntry;
+            return List->CurrentPartition;
+        }
+
+        DiskListEntry = DiskListEntry->Flink;
+    }
+
+    return NULL;
+}
+
+PPARTENTRY
+GetPrevPartition(
+    IN PPARTLIST List)
+{
+    PLIST_ENTRY DiskListEntry;
+    PLIST_ENTRY PartListEntry;
+    PDISKENTRY DiskEntry;
+    PPARTENTRY PartEntry;
+
+    /* Fail, if no disks are available */
+    if (IsListEmpty(&List->DiskListHead))
+        return NULL;
+
+    /* Check for previous usable entry on current disk */
+    if (List->CurrentPartition != NULL)
+    {
+        if (List->CurrentPartition->LogicalPartition)
+        {
+            /* Logical partition */
+            PartListEntry = List->CurrentPartition->ListEntry.Blink;
+            if (PartListEntry != &List->CurrentDisk->LogicalPartListHead)
+            {
+                /* Previous logical partition */
+                PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
+            }
+            else
+            {
+                /* Extended partition */
+                PartEntry = List->CurrentDisk->ExtendedPartition;
+            }
+
+            List->CurrentPartition = PartEntry;
+            return List->CurrentPartition;
+        }
+        else
+        {
+            /* Primary or extended partition */
+
+            PartListEntry = List->CurrentPartition->ListEntry.Blink;
+            if (PartListEntry != &List->CurrentDisk->PrimaryPartListHead)
+            {
+                PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
+
+                if ((PartEntry->IsPartitioned != FALSE) &&
+                    IsContainerPartition(PartEntry->PartitionType))
+                {
+                    PartListEntry = List->CurrentDisk->LogicalPartListHead.Blink;
+                    PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
+                }
+
+                List->CurrentPartition = PartEntry;
+                return List->CurrentPartition;
+            }
+        }
+    }
+
+    /* Search for the last partition entry on the previous disk */
+    DiskListEntry = List->CurrentDisk->ListEntry.Blink;
+    while (DiskListEntry != &List->DiskListHead)
+    {
+        DiskEntry = CONTAINING_RECORD(DiskListEntry, DISKENTRY, ListEntry);
+
+        PartListEntry = DiskEntry->PrimaryPartListHead.Blink;
+        if (PartListEntry != &DiskEntry->PrimaryPartListHead)
+        {
+            PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
+
+            if ((PartEntry->IsPartitioned != FALSE) &&
+                IsContainerPartition(PartEntry->PartitionType))
+            {
+                PartListEntry = DiskEntry->LogicalPartListHead.Blink;
+                if (PartListEntry != &DiskEntry->LogicalPartListHead)
+                {
+                    PartEntry = CONTAINING_RECORD(PartListEntry, PARTENTRY, ListEntry);
+
+                    List->CurrentDisk = DiskEntry;
+                    List->CurrentPartition = PartEntry;
+                    return List->CurrentPartition;
+                }
+            }
+            else
+            {
+                List->CurrentDisk = DiskEntry;
+                List->CurrentPartition = PartEntry;
+                return List->CurrentPartition;
+            }
+        }
+
+        DiskListEntry = DiskListEntry->Blink;
+    }
+
+    return NULL;
+}
+
+
+
+VOID
+ScrollDownPartitionList(
+    IN PPARTLIST_UI ListUi)
+{
+    if (GetNextPartition(ListUi->List))
+        DrawPartitionList(ListUi);
+}
+
+VOID
+ScrollUpPartitionList(
+    IN PPARTLIST_UI ListUi)
+{
+    if (GetPrevPartition(ListUi->List))
+        DrawPartitionList(ListUi);
+}
+
+
+static
+BOOLEAN
+IsEmptyLayoutEntry(
+    IN PPARTITION_INFORMATION PartitionInfo)
+{
+    if (PartitionInfo->StartingOffset.QuadPart == 0 &&
+        PartitionInfo->PartitionLength.QuadPart == 0)
+        return TRUE;
+
+    return FALSE;
+}
+
 
-static VOID
-GetDriverName (PDISKENTRY DiskEntry)
+static
+BOOLEAN
+IsSamePrimaryLayoutEntry(
+    IN PPARTITION_INFORMATION PartitionInfo,
+    IN PDISKENTRY DiskEntry,
+    IN PPARTENTRY PartEntry)
 {
-  RTL_QUERY_REGISTRY_TABLE QueryTable[2];
-  WCHAR KeyName[32];
-  NTSTATUS Status;
+    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;
 
-  RtlInitUnicodeString (&DiskEntry->DriverName,
-                        NULL);
+    return FALSE;
+}
 
-  swprintf (KeyName,
-            L"\\Scsi\\Scsi Port %lu",
-            DiskEntry->Port);
 
-  RtlZeroMemory (&QueryTable,
-                 sizeof(QueryTable));
+static
+ULONG
+GetPrimaryPartitionCount(
+    IN PDISKENTRY DiskEntry)
+{
+    PLIST_ENTRY Entry;
+    PPARTENTRY PartEntry;
+    ULONG Count = 0;
+
+    Entry = DiskEntry->PrimaryPartListHead.Flink;
+    while (Entry != &DiskEntry->PrimaryPartListHead)
+    {
+        PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
+        if (PartEntry->IsPartitioned == TRUE)
+            Count++;
 
-  QueryTable[0].Name = L"Driver";
-  QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
-  QueryTable[0].EntryContext = &DiskEntry->DriverName;
+        Entry = Entry->Flink;
+    }
 
-  Status = RtlQueryRegistryValues (RTL_REGISTRY_DEVICEMAP,
-                                   KeyName,
-                                   QueryTable,
-                                   NULL,
-                                   NULL);
-  if (!NT_SUCCESS (Status))
-  {
-    DPRINT1 ("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
-  }
+    return Count;
 }
 
 
-static VOID
-AssignDriverLetters (PPARTLIST List)
+static
+ULONG
+GetLogicalPartitionCount(
+    IN PDISKENTRY DiskEntry)
+{
+    PLIST_ENTRY ListEntry;
+    PPARTENTRY PartEntry;
+    ULONG Count = 0;
+
+    ListEntry = DiskEntry->LogicalPartListHead.Flink;
+    while (ListEntry != &DiskEntry->LogicalPartListHead)
+    {
+        PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
+        if (PartEntry->IsPartitioned)
+            Count++;
+
+        ListEntry = ListEntry->Flink;
+    }
+
+    return Count;
+}
+
+
+static
+BOOLEAN
+ReAllocateLayoutBuffer(
+    IN PDISKENTRY DiskEntry)
 {
-  PDISKENTRY DiskEntry;
-  PPARTENTRY PartEntry;
-  PLIST_ENTRY Entry1;
-  //PLIST_ENTRY Entry2;
-  CHAR Letter;
-  UCHAR i;
+    PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer;
+    ULONG NewPartitionCount;
+    ULONG CurrentPartitionCount = 0;
+    ULONG LayoutBufferSize;
+    ULONG i;
+
+    DPRINT1("ReAllocateLayoutBuffer()\n");
+
+    NewPartitionCount = 4 + GetLogicalPartitionCount(DiskEntry) * 4;
+
+    if (DiskEntry->LayoutBuffer)
+        CurrentPartitionCount = DiskEntry->LayoutBuffer->PartitionCount;
+
+    DPRINT1("CurrentPartitionCount: %lu    NewPartitionCount: %lu\n",
+            CurrentPartitionCount, NewPartitionCount);
+
+    if (CurrentPartitionCount == NewPartitionCount)
+        return TRUE;
+
+    LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
+                       ((NewPartitionCount - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION));
+    NewLayoutBuffer = RtlReAllocateHeap(ProcessHeap,
+                                        HEAP_ZERO_MEMORY,
+                                        DiskEntry->LayoutBuffer,
+                                        LayoutBufferSize);
+    if (NewLayoutBuffer == NULL)
+    {
+        DPRINT1("Failed to allocate the new layout buffer (size: %lu)\n", LayoutBufferSize);
+        return FALSE;
+    }
 
-  Letter = 'C';
+    /* 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;
+}
 
-  /* Assign drive letters to primary partitions */
-  Entry1 = List->DiskListHead.Flink;
-  while (Entry1 != &List->DiskListHead)
-  {
-    DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
 
-    if (!IsListEmpty (&DiskEntry->PartListHead))
+static
+VOID
+UpdateDiskLayout(
+    IN PDISKENTRY DiskEntry)
+{
+    PPARTITION_INFORMATION PartitionInfo;
+    PPARTITION_INFORMATION LinkInfo = NULL;
+    PLIST_ENTRY ListEntry;
+    PPARTENTRY PartEntry;
+    LARGE_INTEGER HiddenSectors64;
+    ULONG Index;
+    ULONG PartitionNumber = 1;
+
+    DPRINT1("UpdateDiskLayout()\n");
+
+    /* Resize the layout buffer if necessary */
+    if (ReAllocateLayoutBuffer(DiskEntry) == FALSE)
     {
-      PartEntry = CONTAINING_RECORD (DiskEntry->PartListHead.Flink,
-                                     PARTENTRY,
-                                     ListEntry);
+        DPRINT("ReAllocateLayoutBuffer() failed.\n");
+        return;
+    }
 
-      for (i=0; i<4; i++)
-        PartEntry->DriveLetter[i] = 0;
+    /* Update the primary partition table */
+    Index = 0;
+    ListEntry = DiskEntry->PrimaryPartListHead.Flink;
+    while (ListEntry != &DiskEntry->PrimaryPartListHead)
+    {
+        PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
 
-      if (PartEntry->Unpartitioned == FALSE)
-      {
-        for (i=0; i<4; i++)
+        if (PartEntry->IsPartitioned != FALSE)
         {
-          if (IsContainerPartition (PartEntry->PartInfo[i].PartitionType))
-            continue;
+            PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
 
-          if (IsRecognizedPartition (PartEntry->PartInfo[i].PartitionType) ||
-             (PartEntry->PartInfo[i].PartitionType == PARTITION_ENTRY_UNUSED &&
-             PartEntry->PartInfo[i].PartitionLength.QuadPart != 0LL))
-          {
-            if (Letter <= 'Z')
+            if (!IsSamePrimaryLayoutEntry(PartitionInfo, DiskEntry, PartEntry))
             {
-              PartEntry->DriveLetter[i] = Letter;
-              Letter++;
+                DPRINT1("Updating primary partition entry %lu\n", Index);
+
+                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->PartitionType = PartEntry->PartitionType;
+                PartitionInfo->BootIndicator = PartEntry->BootIndicator;
+                PartitionInfo->RecognizedPartition = FALSE;
+                PartitionInfo->RewritePartition = TRUE;
             }
-          }
+
+            PartEntry->PartitionNumber = (!IsContainerPartition(PartEntry->PartitionType)) ? PartitionNumber : 0;
+            PartEntry->PartitionIndex = Index;
+
+            if (!IsContainerPartition(PartEntry->PartitionType))
+                PartitionNumber++;
+
+            Index++;
         }
-      }
+
+        ListEntry = ListEntry->Flink;
     }
 
-    Entry1 = Entry1->Flink;
-  }
+    /* Update the logical partition table */
+    Index = 4;
+    ListEntry = DiskEntry->LogicalPartListHead.Flink;
+    while (ListEntry != &DiskEntry->LogicalPartListHead)
+    {
+        PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
 
-  /* Assign drive letters to logical drives */
-#if 0
-  Entry1 = List->DiskListHead.Flink;
-  while (Entry1 != &List->DiskListHead)
-  {
-    DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
+        if (PartEntry->IsPartitioned)
+        {
+            PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
 
-    Entry2 = DiskEntry->PartListHead.Flink;
-    if (Entry2 != &DiskEntry->PartListHead)
-    {
-      Entry2 = Entry2->Flink;
-      while (Entry2 != &DiskEntry->PartListHead)
-      {
-        PartEntry = CONTAINING_RECORD (Entry2,
-                                       PARTENTRY,
-                                       ListEntry);
+            DPRINT1("Updating logical partition entry %lu\n", Index);
 
-        PartEntry->DriveLetter = 0;
+            PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
+            PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
+            PartitionInfo->HiddenSectors = DiskEntry->SectorAlignment;
+            PartitionInfo->PartitionNumber = PartitionNumber;
+            PartitionInfo->PartitionType = PartEntry->PartitionType;
+            PartitionInfo->BootIndicator = FALSE;
+            PartitionInfo->RecognizedPartition = FALSE;
+            PartitionInfo->RewritePartition = TRUE;
 
-        if (PartEntry->Unpartitioned == FALSE &&
-            !IsContainerPartition (PartEntry->PartInfo[0].PartitionType))
-        {
-          if (IsRecognizedPartition (PartEntry->PartInfo[0].PartitionType) ||
-             (PartEntry->PartInfo[0].PartitionType == PARTITION_ENTRY_UNUSED &&
-              PartEntry->PartInfo[0].PartitionLength.QuadPart != 0LL))
-          {
-            if (Letter <= 'Z')
+            PartEntry->PartitionNumber = PartitionNumber;
+            PartEntry->PartitionIndex = Index;
+
+            /* Fill the link entry of the previous partition entry */
+            if (LinkInfo != NULL)
             {
-              PartEntry->DriveLetter = Letter;
-              Letter++;
+                LinkInfo->StartingOffset.QuadPart = (PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector;
+                LinkInfo->PartitionLength.QuadPart = (PartEntry->StartSector.QuadPart + DiskEntry->SectorAlignment) * DiskEntry->BytesPerSector;
+                HiddenSectors64.QuadPart = PartEntry->StartSector.QuadPart - DiskEntry->SectorAlignment - DiskEntry->ExtendedPartition->StartSector.QuadPart;
+                LinkInfo->HiddenSectors = HiddenSectors64.LowPart;
+                LinkInfo->PartitionNumber = 0;
+                LinkInfo->PartitionType = PARTITION_EXTENDED;
+                LinkInfo->BootIndicator = FALSE;
+                LinkInfo->RecognizedPartition = FALSE;
+                LinkInfo->RewritePartition = TRUE;
             }
-          }
+
+            /* Save a pointer to the link entry of the current partition entry */
+            LinkInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index + 1];
+
+            PartitionNumber++;
+            Index += 4;
         }
 
-        Entry2 = Entry2->Flink;
-      }
+        ListEntry = ListEntry->Flink;
     }
 
-    Entry1 = Entry1->Flink;
-  }
-#endif
-}
+    /* Wipe unused primary partition entries */
+    for (Index = GetPrimaryPartitionCount(DiskEntry); Index < 4; Index++)
+    {
+        DPRINT1("Primary partition entry %lu\n", Index);
 
+        PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
 
-static VOID
-UpdatePartitionNumbers (PDISKENTRY DiskEntry)
-{
-  PPARTENTRY PartEntry;
-  PLIST_ENTRY Entry;
-  ULONG PartNumber;
-  ULONG i;
-
-  PartNumber = 1;
-  Entry = DiskEntry->PartListHead.Flink;
-  while (Entry != &DiskEntry->PartListHead)
-  {
-    PartEntry = CONTAINING_RECORD (Entry,
-                                   PARTENTRY,
-                                   ListEntry);
-
-    if (PartEntry->Unpartitioned == TRUE)
-    {
-      for (i = 0; i < 4; i++)
-      {
-        PartEntry->PartInfo[i].PartitionNumber = 0;
-      }
-    }
-    else
-    {
-      for (i = 0; i < 4; i++)
-      {
-        if (IsContainerPartition (PartEntry->PartInfo[i].PartitionType))
-        {
-          PartEntry->PartInfo[i].PartitionNumber = 0;
-        }
-        else if (PartEntry->PartInfo[i].PartitionType == PARTITION_ENTRY_UNUSED &&
-                 PartEntry->PartInfo[i].PartitionLength.QuadPart == 0ULL)
+        if (!IsEmptyLayoutEntry(PartitionInfo))
         {
-          PartEntry->PartInfo[i].PartitionNumber = 0;
+            DPRINT1("Wiping primary partition entry %lu\n", Index);
+
+            PartitionInfo->StartingOffset.QuadPart = 0;
+            PartitionInfo->PartitionLength.QuadPart = 0;
+            PartitionInfo->HiddenSectors = 0;
+            PartitionInfo->PartitionNumber = 0;
+            PartitionInfo->PartitionType = PARTITION_ENTRY_UNUSED;
+            PartitionInfo->BootIndicator = FALSE;
+            PartitionInfo->RecognizedPartition = FALSE;
+            PartitionInfo->RewritePartition = TRUE;
         }
-        else
+    }
+
+    /* Wipe unused logical partition entries */
+    for (Index = 4; Index < DiskEntry->LayoutBuffer->PartitionCount; Index++)
+    {
+        if (Index % 4 >= 2)
         {
-          PartEntry->PartInfo[i].PartitionNumber = PartNumber;
-          PartNumber++;
+            DPRINT1("Logical partition entry %lu\n", Index);
+
+            PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
+
+            if (!IsEmptyLayoutEntry(PartitionInfo))
+            {
+                DPRINT1("Wiping partition entry %lu\n", Index);
+
+                PartitionInfo->StartingOffset.QuadPart = 0;
+                PartitionInfo->PartitionLength.QuadPart = 0;
+                PartitionInfo->HiddenSectors = 0;
+                PartitionInfo->PartitionNumber = 0;
+                PartitionInfo->PartitionType = PARTITION_ENTRY_UNUSED;
+                PartitionInfo->BootIndicator = FALSE;
+                PartitionInfo->RecognizedPartition = FALSE;
+                PartitionInfo->RewritePartition = TRUE;
+            }
         }
-      }
     }
 
-    Entry = Entry->Flink;
-  }
+#ifdef DUMP_PARTITION_TABLE
+    DumpPartitionTable(DiskEntry);
+#endif
 }
 
 
-static VOID
-AddPartitionToList (ULONG DiskNumber,
-                    PDISKENTRY DiskEntry,
-                    DRIVE_LAYOUT_INFORMATION *LayoutBuffer)
+static
+PPARTENTRY
+GetPrevUnpartitionedEntry(
+    IN PDISKENTRY DiskEntry,
+    IN PPARTENTRY PartEntry)
 {
-  PPARTENTRY PartEntry;
-  ULONG i;
-  ULONG j;
+    PPARTENTRY PrevPartEntry;
+    PLIST_ENTRY ListHead;
 
-  for (i = 0; i < LayoutBuffer->PartitionCount; i += 4)
-  {
-    for (j = 0; j < 4; j++)
-    {
-      if (LayoutBuffer->PartitionEntry[i+j].PartitionType != PARTITION_ENTRY_UNUSED ||
-          LayoutBuffer->PartitionEntry[i+j].PartitionLength.QuadPart != 0ULL)
-      {
-        break;
-      }
-    }
-    if (j >= 4)
-    {
-      continue;
-    }
+    if (PartEntry->LogicalPartition)
+        ListHead = &DiskEntry->LogicalPartListHead;
+    else
+        ListHead = &DiskEntry->PrimaryPartListHead;
 
-    PartEntry = (PPARTENTRY)RtlAllocateHeap (ProcessHeap,
-                 0,
-                 sizeof(PARTENTRY));
-    if (PartEntry == NULL)
+    if (PartEntry->ListEntry.Blink != ListHead)
     {
-      return;
+        PrevPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Blink,
+                                          PARTENTRY,
+                                          ListEntry);
+        if (PrevPartEntry->IsPartitioned == FALSE)
+            return PrevPartEntry;
     }
 
-    RtlZeroMemory (PartEntry,
-                   sizeof(PARTENTRY));
+    return NULL;
+}
 
-    PartEntry->Unpartitioned = FALSE;
 
-    for (j = 0; j < 4; j++)
-    {
-      RtlCopyMemory (&PartEntry->PartInfo[j],
-                     &LayoutBuffer->PartitionEntry[i+j],
-                     sizeof(PARTITION_INFORMATION));
-    }
+static
+PPARTENTRY
+GetNextUnpartitionedEntry(
+    IN PDISKENTRY DiskEntry,
+    IN PPARTENTRY PartEntry)
+{
+    PPARTENTRY NextPartEntry;
+    PLIST_ENTRY ListHead;
 
-    if (IsContainerPartition(PartEntry->PartInfo[0].PartitionType))
-    {
-      PartEntry->FormatState = Unformatted;
-    }
-    else if ((PartEntry->PartInfo[0].PartitionType == PARTITION_FAT_12) ||
-            (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT_16) ||
-            (PartEntry->PartInfo[0].PartitionType == PARTITION_HUGE) ||
-            (PartEntry->PartInfo[0].PartitionType == PARTITION_XINT13) ||
-            (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32) ||
-            (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32_XINT13))
-    {
-#if 0
-      if (CheckFatFormat())
-      {
-        PartEntry->FormatState = Preformatted;
-      }
-      else
-      {
-        PartEntry->FormatState = Unformatted;
-      }
-#endif
-      PartEntry->FormatState = Preformatted;
-    }
-    else if (PartEntry->PartInfo[0].PartitionType == PARTITION_EXT2)
-    {
-#if 0
-      if (CheckExt2Format())
-      {
-        PartEntry->FormatState = Preformatted;
-      }
-      else
-      {
-        PartEntry->FormatState = Unformatted;
-      }
-#endif
-      PartEntry->FormatState = Preformatted;
-    }
-    else if (PartEntry->PartInfo[0].PartitionType == PARTITION_IFS)
-    {
-#if 0
-      if (CheckNtfsFormat())
-      {
-        PartEntry->FormatState = Preformatted;
-      }
-      else if (CheckHpfsFormat())
-      {
-        PartEntry->FormatState = Preformatted;
-      }
-      else
-      {
-        PartEntry->FormatState = Unformatted;
-      }
-#endif
-      PartEntry->FormatState = Preformatted;
-    }
+    if (PartEntry->LogicalPartition)
+        ListHead = &DiskEntry->LogicalPartListHead;
     else
+        ListHead = &DiskEntry->PrimaryPartListHead;
+
+    if (PartEntry->ListEntry.Flink != ListHead)
     {
-      PartEntry->FormatState = UnknownFormat;
+        NextPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Flink,
+                                          PARTENTRY,
+                                          ListEntry);
+        if (NextPartEntry->IsPartitioned == FALSE)
+            return NextPartEntry;
     }
 
-    InsertTailList (&DiskEntry->PartListHead,
-                    &PartEntry->ListEntry);
-  }
+    return NULL;
 }
 
 
-static VOID
-ScanForUnpartitionedDiskSpace (PDISKENTRY DiskEntry)
+VOID
+CreatePrimaryPartition(
+    IN PPARTLIST List,
+    IN ULONGLONG SectorCount,
+    IN BOOLEAN AutoCreate)
 {
-  ULONGLONG LastStartingOffset;
-  ULONGLONG LastPartitionLength;
-  ULONGLONG LastUnusedPartitionLength;
-  PPARTENTRY PartEntry;
-  PPARTENTRY NewPartEntry;
-  PLIST_ENTRY Entry;
-  ULONG i;
-  ULONG j;
-
-  if (IsListEmpty (&DiskEntry->PartListHead))
-  {
-    /* Create a partition table that represents the empty disk */
-    PartEntry = (PPARTENTRY)RtlAllocateHeap (ProcessHeap,
-                 0,
-                 sizeof(PARTENTRY));
-    if (PartEntry == NULL)
-      return;
+    PDISKENTRY DiskEntry;
+    PPARTENTRY PartEntry;
+    PPARTENTRY NewPartEntry;
 
-    RtlZeroMemory (PartEntry,
-                   sizeof(PARTENTRY));
+    DPRINT1("CreatePrimaryPartition(%I64u)\n", SectorCount);
 
-    PartEntry->Unpartitioned = TRUE;
-    PartEntry->UnpartitionedOffset = 0ULL;
-    PartEntry->UnpartitionedLength = DiskEntry->DiskSize;
+    if (List == NULL ||
+        List->CurrentDisk == NULL ||
+        List->CurrentPartition == NULL ||
+        List->CurrentPartition->IsPartitioned != FALSE)
+    {
+        return;
+    }
 
-    PartEntry->FormatState = Unformatted;
+    DiskEntry = List->CurrentDisk;
+    PartEntry = List->CurrentPartition;
 
-    InsertTailList (&DiskEntry->PartListHead,
-                    &PartEntry->ListEntry);
-  }
-  else
-  {
-    /* Start partition at head 1, cylinder 0 */
-    LastStartingOffset = DiskEntry->TrackSize;
-    LastPartitionLength = 0ULL;
-    LastUnusedPartitionLength = 0ULL;
-
-    i = 0;
-    Entry = DiskEntry->PartListHead.Flink;
-    while (Entry != &DiskEntry->PartListHead)
-    {
-      PartEntry = CONTAINING_RECORD (Entry, PARTENTRY, ListEntry);
-
-      for (j = 0; j < 4; j++)
-      {
-        if ((!IsContainerPartition (PartEntry->PartInfo[j].PartitionType)) &&
-            (PartEntry->PartInfo[j].PartitionType != PARTITION_ENTRY_UNUSED ||
-             PartEntry->PartInfo[j].PartitionLength.QuadPart != 0LL))
-        {
-          LastUnusedPartitionLength =
-          PartEntry->PartInfo[j].StartingOffset.QuadPart -
-          (LastStartingOffset + LastPartitionLength);
-
-          if (PartEntry->PartInfo[j].StartingOffset.QuadPart > (LastStartingOffset + LastPartitionLength) &&
-              LastUnusedPartitionLength >= DiskEntry->CylinderSize)
-          {
-            DPRINT ("Unpartitioned disk space %I64u\n", LastUnusedPartitionLength);
-
-            NewPartEntry = (PPARTENTRY)RtlAllocateHeap (ProcessHeap,
-                            0,
-                            sizeof(PARTENTRY));
-            if (NewPartEntry == NULL)
-              return;
+    DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
 
-            RtlZeroMemory (NewPartEntry,
-                           sizeof(PARTENTRY));
+    if ((AutoCreate != FALSE) ||
+        (AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart))
+    {
+        DPRINT1("Convert existing partition entry\n");
 
-            NewPartEntry->Unpartitioned = TRUE;
-            NewPartEntry->UnpartitionedOffset = LastStartingOffset + LastPartitionLength;
-            NewPartEntry->UnpartitionedLength = LastUnusedPartitionLength;
-            if (j == 0)
-              NewPartEntry->UnpartitionedLength -= DiskEntry->TrackSize;
+        /* 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
+    {
+        DPRINT1("Add new partition entry\n");
 
-            NewPartEntry->FormatState = Unformatted;
+        /* Insert and initialize a new partition entry */
+        NewPartEntry = RtlAllocateHeap(ProcessHeap,
+                                       HEAP_ZERO_MEMORY,
+                                       sizeof(PARTENTRY));
+        if (NewPartEntry == NULL)
+            return;
 
-            /* Insert the table into the list */
-            InsertTailList (&PartEntry->ListEntry,
-                            &NewPartEntry->ListEntry);
-          }
+        /* Insert the new entry into the list */
+        InsertTailList(&PartEntry->ListEntry,
+                       &NewPartEntry->ListEntry);
 
-          LastStartingOffset = PartEntry->PartInfo[j].StartingOffset.QuadPart;
-          LastPartitionLength = PartEntry->PartInfo[j].PartitionLength.QuadPart;
-        }
-      }
+        NewPartEntry->DiskEntry = DiskEntry;
 
-      i += 4;
-      Entry = Entry->Flink;
-    }
+        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;
 
-    /* Check for trailing unpartitioned disk space */
-    if (DiskEntry->DiskSize > (LastStartingOffset + LastPartitionLength))
-    {
-      /* Round-down to cylinder size */
-      LastUnusedPartitionLength =
-        (DiskEntry->DiskSize - (LastStartingOffset + LastPartitionLength))
-        & ~(DiskEntry->CylinderSize - 1);
+        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);
 
-      if (LastUnusedPartitionLength >= DiskEntry->CylinderSize)
-      {
-        DPRINT ("Unpartitioned disk space %I64u\n", LastUnusedPartitionLength);
+        NewPartEntry->New = TRUE;
+        NewPartEntry->FormatState = Unformatted;
+        NewPartEntry->FileSystem  = NULL;
+        NewPartEntry->BootIndicator = FALSE;
 
-        NewPartEntry = (PPARTENTRY)RtlAllocateHeap (ProcessHeap,
-                                                    0,
-                                                    sizeof(PARTENTRY));
-        if (NewPartEntry == NULL)
-          return;
+        PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
+        PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
+    }
 
-        RtlZeroMemory (NewPartEntry,
-                       sizeof(PARTENTRY));
+    UpdateDiskLayout(DiskEntry);
 
-        NewPartEntry->Unpartitioned = TRUE;
-        NewPartEntry->UnpartitionedOffset = LastStartingOffset + LastPartitionLength;
-        NewPartEntry->UnpartitionedLength = LastUnusedPartitionLength;
+    DiskEntry->Dirty = TRUE;
 
-        /* Append the table to the list */
-        InsertTailList (&DiskEntry->PartListHead,
-                        &NewPartEntry->ListEntry);
-      }
-    }
-  }
+    AssignDriveLetters(List);
 }
 
-NTSTATUS
-NTAPI
-DiskIdentifierQueryRoutine(PWSTR ValueName,
-                           ULONG ValueType,
-                           PVOID ValueData,
-                           ULONG ValueLength,
-                           PVOID Context,
-                           PVOID EntryContext)
-{
-  PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context;
-  UNICODE_STRING NameU;
-
-  if (ValueType == REG_SZ &&
-      ValueLength == 20 * sizeof(WCHAR))
-  {
-    NameU.Buffer = (PWCHAR)ValueData;
-    NameU.Length = NameU.MaximumLength = 8 * sizeof(WCHAR);
-    RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Checksum);
-
-    NameU.Buffer = (PWCHAR)ValueData + 9;
-    RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Signature);
-
-    return STATUS_SUCCESS;
-  }
-  return STATUS_UNSUCCESSFUL;
-}
 
-NTSTATUS
-NTAPI
-DiskConfigurationDataQueryRoutine(PWSTR ValueName,
-                                  ULONG ValueType,
-                                  PVOID ValueData,
-                                  ULONG ValueLength,
-                                  PVOID Context,
-                                  PVOID EntryContext)
+static
+VOID
+AddLogicalDiskSpace(
+    IN PDISKENTRY DiskEntry)
 {
-  PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context;
-  PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor;
-  PCM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry;
-  ULONG i;
-
-  if (ValueType != REG_FULL_RESOURCE_DESCRIPTOR ||
-      ValueLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
-    return STATUS_UNSUCCESSFUL;
+    PPARTENTRY NewPartEntry;
 
-  FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData;
-  /* Hm. Version and Revision are not set on Microsoft Windows XP... */
-  /*if (FullResourceDescriptor->PartialResourceList.Version != 1 ||
-    FullResourceDescriptor->PartialResourceList.Revision != 1)
-    return STATUS_UNSUCCESSFUL;*/
+    DPRINT1("AddLogicalDiskSpace()\n");
 
-  for (i = 0; i < FullResourceDescriptor->PartialResourceList.Count; i++)
-  {
-    if (FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].Type != CmResourceTypeDeviceSpecific ||
-        FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize != sizeof(CM_DISK_GEOMETRY_DEVICE_DATA))
-      continue;
+    /* Create a partition entry that represents the empty space in the container partition */
+    NewPartEntry = RtlAllocateHeap(ProcessHeap,
+                                   HEAP_ZERO_MEMORY,
+                                   sizeof(PARTENTRY));
+    if (NewPartEntry == NULL)
+        return;
 
-    DiskGeometry = (PCM_DISK_GEOMETRY_DEVICE_DATA)&FullResourceDescriptor->PartialResourceList.PartialDescriptors[i + 1];
-    BiosDiskEntry->DiskGeometry = *DiskGeometry;
+    NewPartEntry->DiskEntry = DiskEntry;
+    NewPartEntry->LogicalPartition = TRUE;
 
-    return STATUS_SUCCESS;
-  }
-  return STATUS_UNSUCCESSFUL;
-}
+    NewPartEntry->IsPartitioned = FALSE;
+    NewPartEntry->StartSector.QuadPart = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
+    NewPartEntry->SectorCount.QuadPart = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment;
 
-NTSTATUS
-NTAPI
-SystemConfigurationDataQueryRoutine(PWSTR ValueName,
-                                    ULONG ValueType,
-                                    PVOID ValueData,
-                                    ULONG ValueLength,
-                                    PVOID Context,
-                                    PVOID EntryContext)
-{
-  PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor;
-  PCM_INT13_DRIVE_PARAMETER* Int13Drives = (PCM_INT13_DRIVE_PARAMETER*)Context;
-  ULONG i;
+    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);
 
-  if (ValueType != REG_FULL_RESOURCE_DESCRIPTOR ||
-      ValueLength < sizeof (CM_FULL_RESOURCE_DESCRIPTOR))
-    return STATUS_UNSUCCESSFUL;
+    NewPartEntry->FormatState = Unformatted;
+    NewPartEntry->FileSystem  = NULL;
 
-  FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData;
-  /* Hm. Version and Revision are not set on Microsoft Windows XP... */
-  /*if (FullResourceDescriptor->PartialResourceList.Version != 1 ||
-    FullResourceDescriptor->PartialResourceList.Revision != 1)
-    return STATUS_UNSUCCESSFUL;*/
-
-  for (i = 0; i < FullResourceDescriptor->PartialResourceList.Count; i++)
-  {
-    if (FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].Type != CmResourceTypeDeviceSpecific ||
-        FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize % sizeof(CM_INT13_DRIVE_PARAMETER) != 0)
-      continue;
-
-    *Int13Drives = (CM_INT13_DRIVE_PARAMETER*) RtlAllocateHeap(ProcessHeap, 0, FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize);
-    if (*Int13Drives == NULL)
-      return STATUS_NO_MEMORY;
-    memcpy(*Int13Drives,
-           &FullResourceDescriptor->PartialResourceList.PartialDescriptors[i + 1],
-           FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize);
-    return STATUS_SUCCESS;
-  }
-  return STATUS_UNSUCCESSFUL;
+    InsertTailList(&DiskEntry->LogicalPartListHead,
+                   &NewPartEntry->ListEntry);
 }
-#define ROOT_NAME   L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter"
 
-static VOID
-EnumerateBiosDiskEntries(PPARTLIST PartList)
+
+VOID
+CreateExtendedPartition(
+    IN PPARTLIST List,
+    IN ULONGLONG SectorCount)
 {
-  RTL_QUERY_REGISTRY_TABLE QueryTable[3];
-  WCHAR Name[120];
-  ULONG AdapterCount;
-  ULONG DiskCount;
-  NTSTATUS Status;
-  PCM_INT13_DRIVE_PARAMETER Int13Drives;
-  PBIOSDISKENTRY BiosDiskEntry;
-
-  memset(QueryTable, 0, sizeof(QueryTable));
-
-  QueryTable[1].Name = L"Configuration Data";
-  QueryTable[1].QueryRoutine = SystemConfigurationDataQueryRoutine;
-  Int13Drives = NULL;
-  Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
-                                  L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System",
-                                  &QueryTable[1],
-                                  (PVOID)&Int13Drives,
-                                  NULL);
-  if (!NT_SUCCESS(Status))
-  {
-    DPRINT1("Unable to query the 'Configuration Data' key in '\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System', status=%lx\n", Status);
-    return;
-  }
+    PDISKENTRY DiskEntry;
+    PPARTENTRY PartEntry;
+    PPARTENTRY NewPartEntry;
 
-  AdapterCount = 0;
-  while (1)
-  {
-    swprintf(Name, L"%s\\%lu", ROOT_NAME, AdapterCount);
-    Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
-                                    Name,
-                                    &QueryTable[2],
-                                    NULL,
-                                    NULL);
-    if (!NT_SUCCESS(Status))
-    {
-      break;
-    }
+    DPRINT1("CreateExtendedPartition(%I64u)\n", SectorCount);
 
-    swprintf(Name, L"%s\\%lu\\DiskController", ROOT_NAME, AdapterCount);
-    Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
-                                    Name,
-                                    &QueryTable[2],
-                                    NULL,
-                                    NULL);
-    if (NT_SUCCESS(Status))
+    if (List == NULL ||
+        List->CurrentDisk == NULL ||
+        List->CurrentPartition == NULL ||
+        List->CurrentPartition->IsPartitioned != FALSE)
     {
-      while (1)
-      {
-        swprintf(Name, L"%s\\%lu\\DiskController\\0", ROOT_NAME, AdapterCount);
-        Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
-                                        Name,
-                                        &QueryTable[2],
-                                        NULL,
-                                        NULL);
-        if (!NT_SUCCESS(Status))
-        {
-          RtlFreeHeap(ProcessHeap, 0, Int13Drives);
-          return;
-        }
-
-        swprintf(Name, L"%s\\%lu\\DiskController\\0\\DiskPeripheral", ROOT_NAME, AdapterCount);
-        Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
-                                        Name,
-                                        &QueryTable[2],
-                                        NULL,
-                                        NULL);
-        if (NT_SUCCESS(Status))
-        {
-          QueryTable[0].Name = L"Identifier";
-          QueryTable[0].QueryRoutine = DiskIdentifierQueryRoutine;
-          QueryTable[1].Name = L"Configuration Data";
-          QueryTable[1].QueryRoutine = DiskConfigurationDataQueryRoutine;
-          DiskCount = 0;
-          while (1)
-          {
-            BiosDiskEntry = (BIOSDISKENTRY*) RtlAllocateHeap(ProcessHeap, HEAP_ZERO_MEMORY, sizeof(BIOSDISKENTRY));
-            if (BiosDiskEntry == NULL)
-            {
-              break;
-            }
-            swprintf(Name, L"%s\\%lu\\DiskController\\0\\DiskPeripheral\\%lu", ROOT_NAME, AdapterCount, DiskCount);
-            Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
-                                            Name,
-                                            QueryTable,
-                                            (PVOID)BiosDiskEntry,
-                                            NULL);
-            if (!NT_SUCCESS(Status))
-            {
-              RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry);
-              break;
-            }
-            BiosDiskEntry->DiskNumber = DiskCount;
-            BiosDiskEntry->Recognized = FALSE;
+        return;
+    }
 
-            if (DiskCount < Int13Drives[0].NumberDrives)
-            {
-              BiosDiskEntry->Int13DiskData = Int13Drives[DiskCount];
-            }
-            else
-            {
-              DPRINT1("Didn't find int13 drive datas for disk %u\n", DiskCount);
-            }
+    DiskEntry = List->CurrentDisk;
+    PartEntry = List->CurrentPartition;
 
+    DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
 
-            InsertTailList(&PartList->BiosDiskListHead, &BiosDiskEntry->ListEntry);
+    if (AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart)
+    {
+        DPRINT1("Convert existing partition entry\n");
 
-            DPRINT("DiskNumber:        %lu\n", BiosDiskEntry->DiskNumber);
-            DPRINT("Signature:         %08lx\n", BiosDiskEntry->Signature);
-            DPRINT("Checksum:          %08lx\n", BiosDiskEntry->Checksum);
-            DPRINT("BytesPerSector:    %lu\n", BiosDiskEntry->DiskGeometry.BytesPerSector);
-            DPRINT("NumberOfCylinders: %lu\n", BiosDiskEntry->DiskGeometry.NumberOfCylinders);
-            DPRINT("NumberOfHeads:     %lu\n", BiosDiskEntry->DiskGeometry.NumberOfHeads);
-            DPRINT("DriveSelect:       %02x\n", BiosDiskEntry->Int13DiskData.DriveSelect);
-            DPRINT("MaxCylinders:      %lu\n", BiosDiskEntry->Int13DiskData.MaxCylinders);
-            DPRINT("SectorsPerTrack:   %d\n", BiosDiskEntry->Int13DiskData.SectorsPerTrack);
-            DPRINT("MaxHeads:          %d\n", BiosDiskEntry->Int13DiskData.MaxHeads);
-            DPRINT("NumberDrives:      %d\n", BiosDiskEntry->Int13DiskData.NumberDrives);
+        /* 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;
 
-            DiskCount++;
-          }
+        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;
         }
-        RtlFreeHeap(ProcessHeap, 0, Int13Drives);
-        return;
-      }
-    }
-    AdapterCount++;
-  }
-  RtlFreeHeap(ProcessHeap, 0, Int13Drives);
-}
 
-static VOID
-AddDiskToList (HANDLE FileHandle,
-               ULONG DiskNumber,
-               PPARTLIST List)
-{
-  DRIVE_LAYOUT_INFORMATION *LayoutBuffer;
-  DISK_GEOMETRY DiskGeometry;
-  SCSI_ADDRESS ScsiAddress;
-  PDISKENTRY DiskEntry;
-  IO_STATUS_BLOCK Iosb;
-  NTSTATUS Status;
-  PPARTITION_SECTOR Mbr;
-  PULONG Buffer;
-  LARGE_INTEGER FileOffset;
-  WCHAR Identifier[20];
-  ULONG Checksum;
-  ULONG Signature;
-  ULONG i;
-  PLIST_ENTRY ListEntry;
-  PBIOSDISKENTRY BiosDiskEntry;
-  ULONG LayoutBufferSize;
-
-  Status = NtDeviceIoControlFile (FileHandle,
-                                  NULL,
-                                  NULL,
-                                  NULL,
-                                  &Iosb,
-                                  IOCTL_DISK_GET_DRIVE_GEOMETRY,
-                                  NULL,
-                                  0,
-                                  &DiskGeometry,
-                                  sizeof(DISK_GEOMETRY));
-  if (!NT_SUCCESS (Status))
-  {
-    return;
-  }
+        DiskEntry->ExtendedPartition = PartEntry;
 
-  if (DiskGeometry.MediaType != FixedMedia &&
-      DiskGeometry.MediaType != RemovableMedia)
-  {
-    return;
-  }
-
-  Status = NtDeviceIoControlFile (FileHandle,
-                                  NULL,
-                                  NULL,
-                                  NULL,
-                                  &Iosb,
-                                  IOCTL_SCSI_GET_ADDRESS,
-                                  NULL,
-                                  0,
-                                  &ScsiAddress,
-                                  sizeof(SCSI_ADDRESS));
-  if (!NT_SUCCESS(Status))
-  {
-    return;
-  }
+        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");
 
-  Mbr = (PARTITION_SECTOR*) RtlAllocateHeap(ProcessHeap,
-                                            0,
-                                            DiskGeometry.BytesPerSector);
+        /* Insert and initialize a new partition entry */
+        NewPartEntry = RtlAllocateHeap(ProcessHeap,
+                                       HEAP_ZERO_MEMORY,
+                                       sizeof(PARTENTRY));
+        if (NewPartEntry == NULL)
+            return;
 
-  if (Mbr == NULL)
-  {
-    return;
-  }
-
-  FileOffset.QuadPart = 0;
-  Status = NtReadFile(FileHandle,
-                      NULL,
-                      NULL,
-                      NULL,
-                      &Iosb,
-                      (PVOID)Mbr,
-                      DiskGeometry.BytesPerSector,
-                      &FileOffset,
-                      NULL);
-  if (!NT_SUCCESS(Status))
-  {
-    RtlFreeHeap(ProcessHeap,
-                0,
-                Mbr);
-    DPRINT1("NtReadFile failed, status=%x\n", Status);
-    return;
-  }
-  Signature = Mbr->Signature;
-
-  /* Calculate the MBR checksum */
-  Checksum = 0;
-  Buffer = (PULONG)Mbr;
-  for (i = 0; i < 128; i++)
-  {
-    Checksum += Buffer[i];
-  }
-  Checksum = ~Checksum + 1;
-
-  swprintf(Identifier, L"%08x-%08x-A", Checksum, Signature);
-  DPRINT("Identifier: %S\n", Identifier);
-
-  DiskEntry = (PDISKENTRY)RtlAllocateHeap (ProcessHeap,
-                                           0,
-                                           sizeof(DISKENTRY));
-  if (DiskEntry == NULL)
-  {
-    return;
-  }
-
-  DiskEntry->Checksum = Checksum;
-  DiskEntry->Signature = Signature;
-  if (Signature == 0)
-  {
-    /* If we have no signature, set the disk to dirty. WritePartitionsToDisk creates a new signature */
-    DiskEntry->Modified = TRUE;
-  }
-  DiskEntry->BiosFound = FALSE;
-
-  /* Check if this disk has a valid MBR */
-  if (Mbr->BootCode[0] == 0 && Mbr->BootCode[1] == 0)
-    DiskEntry->NoMbr = TRUE;
-  else
-    DiskEntry->NoMbr = FALSE;
-
-  /* Free Mbr sector buffer */
-  RtlFreeHeap (ProcessHeap,
-               0,
-               Mbr);
-
-  ListEntry = List->BiosDiskListHead.Flink;
-  while(ListEntry != &List->BiosDiskListHead)
-  {
-    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 signatur
-     *   we must create new signatures and reboot. After the reboot,
-     *   it is possible to identify the disks.
-     */
-    if (BiosDiskEntry->Signature == Signature &&
-        BiosDiskEntry->Checksum == Checksum &&
-        !BiosDiskEntry->Recognized)
-    {
-      if (!DiskEntry->BiosFound)
-      {
-        DiskEntry->BiosDiskNumber = BiosDiskEntry->DiskNumber;
-        DiskEntry->BiosFound = TRUE;
-        BiosDiskEntry->Recognized = TRUE;
-      }
-      else
-      {
-      }
-    }
-    ListEntry = ListEntry->Flink;
-  }
-
-  if (!DiskEntry->BiosFound)
-  {
-#if 0
-    RtlFreeHeap(ProcessHeap, 0, DiskEntry);
-    return;
-#else
-    DPRINT1("WARNING: Setup could not find a matching BIOS disk entry. Disk %d is not be bootable by the BIOS!\n", DiskNumber);
-#endif
-  }
-
-  InitializeListHead (&DiskEntry->PartListHead);
-
-  DiskEntry->Cylinders = DiskGeometry.Cylinders.QuadPart;
-  DiskEntry->TracksPerCylinder = DiskGeometry.TracksPerCylinder;
-  DiskEntry->SectorsPerTrack = DiskGeometry.SectorsPerTrack;
-  DiskEntry->BytesPerSector = DiskGeometry.BytesPerSector;
-
-  DPRINT ("Cylinders %I64u\n", DiskEntry->Cylinders);
-  DPRINT ("TracksPerCylinder %I64u\n", DiskEntry->TracksPerCylinder);
-  DPRINT ("SectorsPerTrack %I64u\n", DiskEntry->SectorsPerTrack);
-  DPRINT ("BytesPerSector %I64u\n", DiskEntry->BytesPerSector);
-
-  DiskEntry->TrackSize =
-    (ULONGLONG)DiskGeometry.SectorsPerTrack *
-    (ULONGLONG)DiskGeometry.BytesPerSector;
-  DiskEntry->CylinderSize =
-    (ULONGLONG)DiskGeometry.TracksPerCylinder *
-    DiskEntry->TrackSize;
-  DiskEntry->DiskSize =
-    DiskGeometry.Cylinders.QuadPart *
-    DiskEntry->CylinderSize;
-
-  DiskEntry->DiskNumber = DiskNumber;
-  DiskEntry->Port = ScsiAddress.PortNumber;
-  DiskEntry->Bus = ScsiAddress.PathId;
-  DiskEntry->Id = ScsiAddress.TargetId;
-
-  GetDriverName (DiskEntry);
-
-  InsertAscendingList(&List->DiskListHead, DiskEntry, DISKENTRY, ListEntry, DiskNumber);
-
-  /*
-   * Allocate a buffer for 26 logical drives (2 entries each == 52) 
-   * plus the main partiton table (4 entries). Total 56 entries.
-   */
-  LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
-                     ((56 - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION));
-  LayoutBuffer = (DRIVE_LAYOUT_INFORMATION*)RtlAllocateHeap (ProcessHeap,
-                  0,
-                  LayoutBufferSize);
-  if (LayoutBuffer == NULL)
-  {
-    return;
-  }
-
-  Status = NtDeviceIoControlFile (FileHandle,
-                                  NULL,
-                                  NULL,
-                                  NULL,
-                                  &Iosb,
-                                  IOCTL_DISK_GET_DRIVE_LAYOUT,
-                                  NULL,
-                                  0,
-                                  LayoutBuffer,
-                                  LayoutBufferSize);
-  if (NT_SUCCESS (Status))
-  {
-    if (LayoutBuffer->PartitionCount == 0)
-    {
-      DiskEntry->NewDisk = TRUE;
-    }
-
-    AddPartitionToList (DiskNumber,
-                        DiskEntry,
-                        LayoutBuffer);
-
-    ScanForUnpartitionedDiskSpace (DiskEntry);
-  }
-
-  RtlFreeHeap (ProcessHeap,
-               0,
-               LayoutBuffer);
-}
+        /* Insert the new entry into the list */
+        InsertTailList(&PartEntry->ListEntry,
+                       &NewPartEntry->ListEntry);
 
+        NewPartEntry->DiskEntry = DiskEntry;
 
-PPARTLIST
-CreatePartitionList (SHORT Left,
-                     SHORT Top,
-                     SHORT Right,
-                     SHORT Bottom)
-{
-  PPARTLIST List;
-  OBJECT_ATTRIBUTES ObjectAttributes;
-  SYSTEM_DEVICE_INFORMATION Sdi;
-  IO_STATUS_BLOCK Iosb;
-  ULONG ReturnSize;
-  NTSTATUS Status;
-  ULONG DiskNumber;
-  WCHAR Buffer[MAX_PATH];
-  UNICODE_STRING Name;
-  HANDLE FileHandle;
-
-  List = (PPARTLIST)RtlAllocateHeap (ProcessHeap,
-                                     0,
-                                     sizeof (PARTLIST));
-  if (List == NULL)
-    return NULL;
+        NewPartEntry->IsPartitioned = TRUE;
+        NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
+        NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
+                                             NewPartEntry->StartSector.QuadPart;
 
-  List->Left = Left;
-  List->Top = Top;
-  List->Right = Right;
-  List->Bottom = Bottom;
+        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;
 
-  List->Line = 0;
-  List->Offset = 0;
+        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;
+        }
 
-  List->TopDisk = (ULONG)-1;
-  List->TopPartition = (ULONG)-1;
+        DiskEntry->ExtendedPartition = NewPartEntry;
 
-  List->CurrentDisk = NULL;
-  List->CurrentPartition = NULL;
-  List->CurrentPartitionNumber = 0;
+        PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
+        PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
 
-  InitializeListHead (&List->DiskListHead);
-  InitializeListHead (&List->BiosDiskListHead);
+        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);
+    }
 
-  EnumerateBiosDiskEntries(List);
+    AddLogicalDiskSpace(DiskEntry);
 
-  Status = NtQuerySystemInformation (SystemDeviceInformation,
-                                     &Sdi,
-                                     sizeof(SYSTEM_DEVICE_INFORMATION),
-                                     &ReturnSize);
-  if (!NT_SUCCESS (Status))
-  {
-    RtlFreeHeap (ProcessHeap, 0, List);
-    return NULL;
-  }
-
-  for (DiskNumber = 0; DiskNumber < Sdi.NumberOfDisks; DiskNumber++)
-  {
-    swprintf (Buffer,
-              L"\\Device\\Harddisk%d\\Partition0",
-              DiskNumber);
-    RtlInitUnicodeString (&Name,
-                          Buffer);
-
-    InitializeObjectAttributes (&ObjectAttributes,
-                                &Name,
-                                0,
-                                NULL,
-                                NULL);
-
-    Status = NtOpenFile (&FileHandle,
-                         FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
-                         &ObjectAttributes,
-                         &Iosb,
-                         FILE_SHARE_READ,
-                         FILE_SYNCHRONOUS_IO_NONALERT);
-    if (NT_SUCCESS(Status))
-    {
-      AddDiskToList (FileHandle,
-                     DiskNumber,
-                     List);
-
-      NtClose(FileHandle);
-    }
-  }
-
-  AssignDriverLetters (List);
-
-  List->TopDisk = 0;
-  List->TopPartition = 0;
-
-  /* Search for first usable disk and partition */
-  if (IsListEmpty (&List->DiskListHead))
-  {
-    List->CurrentDisk = NULL;
-    List->CurrentPartition = NULL;
-    List->CurrentPartitionNumber = 0;
-  }
-  else
-  {
-    List->CurrentDisk =
-      CONTAINING_RECORD (List->DiskListHead.Flink,
-                         DISKENTRY,
-                         ListEntry);
+    UpdateDiskLayout(DiskEntry);
 
-    if (IsListEmpty (&List->CurrentDisk->PartListHead))
-    {
-      List->CurrentPartition = 0;
-      List->CurrentPartitionNumber = 0;
-    }
-    else
-    {
-      List->CurrentPartition =
-        CONTAINING_RECORD (List->CurrentDisk->PartListHead.Flink,
-                           PARTENTRY,
-                           ListEntry);
-      List->CurrentPartitionNumber = 0;
-    }
-  }
+    DiskEntry->Dirty = TRUE;
 
-  return List;
+    AssignDriveLetters(List);
 }
 
 
 VOID
-DestroyPartitionList (PPARTLIST List)
+CreateLogicalPartition(
+    IN PPARTLIST List,
+    IN ULONGLONG SectorCount,
+    IN BOOLEAN AutoCreate)
 {
-  PDISKENTRY DiskEntry;
-  PBIOSDISKENTRY BiosDiskEntry;
-  PPARTENTRY PartEntry;
-  PLIST_ENTRY Entry;
+    PDISKENTRY DiskEntry;
+    PPARTENTRY PartEntry;
+    PPARTENTRY NewPartEntry;
 
-  /* Release disk and partition info */
-  while (!IsListEmpty (&List->DiskListHead))
-  {
-    Entry = RemoveHeadList (&List->DiskListHead);
-    DiskEntry = CONTAINING_RECORD (Entry, DISKENTRY, ListEntry);
+    DPRINT1("CreateLogicalPartition(%I64u)\n", SectorCount);
 
-    /* Release driver name */
-    RtlFreeUnicodeString(&DiskEntry->DriverName);
-
-    /* Release partition array */
-    while (!IsListEmpty (&DiskEntry->PartListHead))
+    if (List == NULL ||
+        List->CurrentDisk == NULL ||
+        List->CurrentPartition == NULL ||
+        List->CurrentPartition->IsPartitioned != FALSE)
     {
-      Entry = RemoveHeadList (&DiskEntry->PartListHead);
-      PartEntry = CONTAINING_RECORD (Entry, PARTENTRY, ListEntry);
-
-      RtlFreeHeap (ProcessHeap,
-                   0,
-                   PartEntry);
+        return;
     }
 
-    /* Release disk entry */
-    RtlFreeHeap (ProcessHeap, 0, DiskEntry);
-  }
-
-  /* release the bios disk info */
-  while(!IsListEmpty(&List->BiosDiskListHead))
-  {
-    Entry = RemoveHeadList(&List->BiosDiskListHead);
-    BiosDiskEntry = CONTAINING_RECORD(Entry, BIOSDISKENTRY, ListEntry);
+    DiskEntry = List->CurrentDisk;
+    PartEntry = List->CurrentPartition;
 
-    RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry);
-  }
-
-  /* Release list head */
-  RtlFreeHeap (ProcessHeap, 0, List);
-}
+    DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
 
+    if (AutoCreate == TRUE ||
+        AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart)
+    {
+        DPRINT1("Convert existing partition entry\n");
 
-static VOID
-PrintEmptyLine (PPARTLIST List)
-{
-  COORD coPos;
-  DWORD Written;
-  USHORT Width;
-  USHORT Height;
+        /* 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;
+
+        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");
 
-  Width = List->Right - List->Left - 1;
-  Height = List->Bottom - List->Top - 2;
+        /* 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);
 
-  coPos.X = List->Left + 1;
-  coPos.Y = List->Top + 1 + List->Line;
+        NewPartEntry->DiskEntry = DiskEntry;
 
-  if (List->Line >= 0 && List->Line <= Height)
-  {
-    FillConsoleOutputAttribute (StdOutput,
-                                FOREGROUND_WHITE | BACKGROUND_BLUE,
-                                Width,
-                                coPos,
-                                &Written);
+        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;
 
-    FillConsoleOutputCharacterA (StdOutput,
-                                 ' ',
-                                 Width,
-                                 coPos,
-                                 &Written);
-  }
-  List->Line++;
-}
+        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;
+        NewPartEntry->LogicalPartition = TRUE;
 
-static VOID
-PrintPartitionData (PPARTLIST List,
-                    PDISKENTRY DiskEntry,
-                    PPARTENTRY PartEntry,
-                    ULONG PartNumber)
-{
-  CHAR LineBuffer[128];
-  COORD coPos;
-  DWORD Written;
-  USHORT Width;
-  USHORT Height;
+        PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
+        PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
+    }
 
-  LARGE_INTEGER PartSize;
-  PCHAR Unit;
-  UCHAR Attribute;
-  PCHAR PartType;
+    UpdateDiskLayout(DiskEntry);
 
-  Width = List->Right - List->Left - 1;
-  Height = List->Bottom - List->Top - 2;
+    DiskEntry->Dirty = TRUE;
 
+    AssignDriveLetters(List);
+}
 
-  coPos.X = List->Left + 1;
-  coPos.Y = List->Top + 1 + List->Line;
 
-  if (PartEntry->Unpartitioned == TRUE)
-  {
-#if 0
-    if (PartEntry->UnpartitionledLength >= 0x280000000ULL) /* 10 GB */
+VOID
+DeleteCurrentPartition(
+    IN PPARTLIST List)
+{
+    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)
     {
-      PartSize.QuadPart = (PartEntry->UnpartitionedLength + (1 << 29)) >> 30;
-      Unit = MUIGetString(STRING_GB);
-    }
-    else
-#endif
-      if (PartEntry->UnpartitionedLength >= 0xA00000ULL) /* 10 MB */
-      {
-        PartSize.QuadPart = (PartEntry->UnpartitionedLength + (1 << 19)) >> 20;
-        Unit = MUIGetString(STRING_MB);
-      }
-      else
-      {
-        PartSize.QuadPart = (PartEntry->UnpartitionedLength + (1 << 9)) >> 10;
-        Unit = MUIGetString(STRING_KB);
-      }
-
-      sprintf (LineBuffer,
-               MUIGetString(STRING_UNPSPACE),
-               PartSize.u.LowPart,
-               Unit);
-  }
-  else
-  {
-    /* Determine partition type */
-    PartType = NULL;
-    if (PartEntry->New == TRUE)
-    {
-      PartType = MUIGetString(STRING_UNFORMATTED);
-    }
-    else if (PartEntry->Unpartitioned == FALSE)
-    {
-      if ((PartEntry->PartInfo[PartNumber].PartitionType == PARTITION_FAT_12) ||
-          (PartEntry->PartInfo[PartNumber].PartitionType == PARTITION_FAT_16) ||
-          (PartEntry->PartInfo[PartNumber].PartitionType == PARTITION_HUGE) ||
-          (PartEntry->PartInfo[PartNumber].PartitionType == PARTITION_XINT13))
-      {
-        PartType = "FAT";
-      }
-      else if ((PartEntry->PartInfo[PartNumber].PartitionType == PARTITION_FAT32) ||
-               (PartEntry->PartInfo[PartNumber].PartitionType == PARTITION_FAT32_XINT13))
-      {
-        PartType = "FAT32";
-      }
-      else if (PartEntry->PartInfo[PartNumber].PartitionType == PARTITION_EXT2)
-      {
-        PartType = "EXT2";
-      }
-      else if (PartEntry->PartInfo[PartNumber].PartitionType == PARTITION_IFS)
-      {
-        PartType = "NTFS"; /* FIXME: Not quite correct! */
-      }
+        return;
     }
 
-#if 0
-    if (PartEntry->PartInfo[PartNumber].PartitionLength.QuadPart >= 0x280000000LL) /* 10 GB */
-    {
-      PartSize.QuadPart = (PartEntry->PartInfo[PartNumber].PartitionLength.QuadPart + (1 << 29)) >> 30;
-      Unit = MUIGetString(STRING_GB);
-    }
-    else
-#endif
-    if (PartEntry->PartInfo[PartNumber].PartitionLength.QuadPart >= 0xA00000LL) /* 10 MB */
-    {
-      PartSize.QuadPart = (PartEntry->PartInfo[PartNumber].PartitionLength.QuadPart + (1 << 19)) >> 20;
-      Unit = MUIGetString(STRING_MB);
-    }
-    else
+    /* Clear the system disk and partition pointers if the system partition is being deleted */
+    if (List->SystemPartition == List->CurrentPartition)
     {
-      PartSize.QuadPart = (PartEntry->PartInfo[PartNumber].PartitionLength.QuadPart + (1 << 9)) >> 10;
-      Unit = MUIGetString(STRING_KB);
+        List->SystemPartition = NULL;
     }
 
-    if (PartType == NULL)
-    {
-      sprintf (LineBuffer,
-               MUIGetString(STRING_HDDINFOUNK5),
-               (PartEntry->DriveLetter[PartNumber] == 0) ? '-' : PartEntry->DriveLetter[PartNumber],
-               (PartEntry->DriveLetter[PartNumber] == 0) ? '-' : ':',
-               PartEntry->PartInfo[PartNumber].PartitionType,
-               PartSize.u.LowPart,
-               Unit);
-    }
-    else
+    DiskEntry = List->CurrentDisk;
+    PartEntry = List->CurrentPartition;
+
+    /* Delete all logical partition entries if an extended partition will be deleted */
+    if (DiskEntry->ExtendedPartition == PartEntry)
     {
-      sprintf (LineBuffer,
-               "%c%c  %-24s         %6lu %s",
-               (PartEntry->DriveLetter[PartNumber] == 0) ? '-' : PartEntry->DriveLetter[PartNumber],
-               (PartEntry->DriveLetter[PartNumber] == 0) ? '-' : ':',
-               PartType,
-               PartSize.u.LowPart,
-               Unit);
-    }
-  }
-
-  Attribute = (List->CurrentDisk == DiskEntry &&
-               List->CurrentPartition == PartEntry &&
-               List->CurrentPartitionNumber == PartNumber) ?
-               FOREGROUND_BLUE | BACKGROUND_WHITE :
-               FOREGROUND_WHITE | BACKGROUND_BLUE;
-
-  if (List->Line >= 0 && List->Line <= Height)
-  {
-    FillConsoleOutputCharacterA (StdOutput,
-                                 ' ',
-                                 Width,
-                                 coPos,
-                                 &Written);
-  }
-  coPos.X += 4;
-  Width -= 8;
-  if (List->Line >= 0 && List->Line <= Height)
-  {
-    FillConsoleOutputAttribute (StdOutput,
-                                Attribute,
-                                Width,
-                                coPos,
-                                &Written);
-  }
-  coPos.X++;
-  Width -= 2;
-  if (List->Line >= 0 && List->Line <= Height)
-  {
-    WriteConsoleOutputCharacterA (StdOutput,
-                                  LineBuffer,
-                                  min (strlen (LineBuffer), Width),
-                                  coPos,
-                                  &Written);
-  }
-  List->Line++;
-}
+        while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
+        {
+            Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
+            LogicalPartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
 
+            RtlFreeHeap(ProcessHeap, 0, LogicalPartEntry);
+        }
 
-static VOID
-PrintDiskData (PPARTLIST List,
-               PDISKENTRY DiskEntry)
-{
-  PPARTENTRY PartEntry;
-  PLIST_ENTRY Entry;
-  CHAR LineBuffer[128];
-  COORD coPos;
-  DWORD Written;
-  USHORT Width;
-  USHORT Height;
-  ULARGE_INTEGER DiskSize;
-  PCHAR Unit;
-  ULONG i;
+        DiskEntry->ExtendedPartition = NULL;
+    }
 
-  Width = List->Right - List->Left - 1;
-  Height = List->Bottom - List->Top - 2;
+    /* Adjust unpartitioned disk space entries */
 
+    /* Get pointer to previous and next unpartitioned entries */
+    PrevPartEntry = GetPrevUnpartitionedEntry(DiskEntry, PartEntry);
+    NextPartEntry = GetNextUnpartitionedEntry(DiskEntry, PartEntry);
 
-  coPos.X = List->Left + 1;
-  coPos.Y = List->Top + 1 + List->Line;
+    if (PrevPartEntry != NULL && NextPartEntry != NULL)
+    {
+        /* Merge previous, current and next unpartitioned entry */
 
-#if 0
-  if (DiskEntry->DiskSize >= 0x280000000ULL) /* 10 GB */
-  {
-    DiskSize.QuadPart = (DiskEntry->DiskSize + (1 << 29)) >> 30;
-    Unit = MUIGetString(STRING_GB);
-  }
-  else
-#endif
-  {
-    DiskSize.QuadPart = (DiskEntry->DiskSize + (1 << 19)) >> 20;
-    if (DiskSize.QuadPart == 0)
-      DiskSize.QuadPart = 1;
-    Unit = MUIGetString(STRING_MB);
-  }
-
-  if (DiskEntry->DriverName.Length > 0)
-  {
-    sprintf (LineBuffer,
-             MUIGetString(STRING_HDINFOPARTSELECT),
-             DiskSize.u.LowPart,
-             Unit,
-             DiskEntry->DiskNumber,
-             DiskEntry->Port,
-             DiskEntry->Bus,
-             DiskEntry->Id,
-             DiskEntry->DriverName.Buffer);
-  }
-  else
-  {
-    sprintf (LineBuffer,
-             MUIGetString(STRING_HDDINFOUNK6),
-             DiskSize.u.LowPart,
-             Unit,
-             DiskEntry->DiskNumber,
-             DiskEntry->Port,
-             DiskEntry->Bus,
-             DiskEntry->Id);
-  }
-  if (List->Line >= 0 && List->Line <= Height)
-  {
-    FillConsoleOutputAttribute (StdOutput,
-                                FOREGROUND_WHITE | BACKGROUND_BLUE,
-                                Width,
-                                coPos,
-                                &Written);
+        /* Adjust the previous entries length */
+        PrevPartEntry->SectorCount.QuadPart += (PartEntry->SectorCount.QuadPart + NextPartEntry->SectorCount.QuadPart);
 
-    FillConsoleOutputCharacterA (StdOutput,
-                                 ' ',
-                                 Width,
-                                 coPos,
-                                 &Written);
-  }
-
-  coPos.X++;
-  if (List->Line >= 0 && List->Line <= Height)
-  {
-    WriteConsoleOutputCharacterA (StdOutput,
-                                  LineBuffer,
-                                  min ((USHORT)strlen (LineBuffer), Width - 2),
-                                  coPos,
-                                  &Written);
-  }
-  List->Line++;
-
-  /* Print separator line */
-  PrintEmptyLine (List);
-
-  /* Print partition lines*/
-  Entry = DiskEntry->PartListHead.Flink;
-  while (Entry != &DiskEntry->PartListHead)
-  {
-    PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
-
-    /* Print disk entry */
-    for (i=0; i<4; i++)
-    {
-      if (PartEntry->PartInfo[i].PartitionType != PARTITION_ENTRY_UNUSED ||
-          PartEntry->PartInfo[i].PartitionLength.QuadPart != 0ULL)
-      {
-        PrintPartitionData (List,
-                            DiskEntry,
-                            PartEntry,
-                            i);
-      }
-    }
-
-    /* Print unpartitioned entry */
-    if (PartEntry->Unpartitioned)
-    {
-        PrintPartitionData (List,
-                            DiskEntry,
-                            PartEntry,
-                            0);
-    }
-
-    Entry = Entry->Flink;
-  }
-
-  /* Print separator line */
-  PrintEmptyLine (List);
-}
+        /* Remove the current entry */
+        RemoveEntryList(&PartEntry->ListEntry);
+        RtlFreeHeap(ProcessHeap, 0, PartEntry);
 
+        /* Remove the next entry */
+        RemoveEntryList (&NextPartEntry->ListEntry);
+        RtlFreeHeap(ProcessHeap, 0, NextPartEntry);
 
-VOID
-DrawPartitionList (PPARTLIST List)
-{
-  PLIST_ENTRY Entry, Entry2;
-  PDISKENTRY DiskEntry;
-  PPARTENTRY PartEntry = NULL;
-  COORD coPos;
-  DWORD Written;
-  SHORT i;
-  SHORT CurrentDiskLine;
-  SHORT CurrentPartLine;
-  SHORT LastLine;
-  BOOL CurrentPartLineFound = FALSE;
-  BOOL CurrentDiskLineFound = FALSE;
-
-  /* Calculate the line of the current disk and partition */
-  CurrentDiskLine = 0;
-  CurrentPartLine = 0;
-  LastLine = 0;
-  Entry = List->DiskListHead.Flink;
-  while (Entry != &List->DiskListHead)
-  {
-    DiskEntry = CONTAINING_RECORD (Entry, DISKENTRY, ListEntry);
-    LastLine += 2;
-    if (CurrentPartLineFound == FALSE)
-    {
-      CurrentPartLine += 2;
-    }
-    Entry2 = DiskEntry->PartListHead.Flink;
-    while (Entry2 != &DiskEntry->PartListHead)
-    {
-      PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
-      if (PartEntry == List->CurrentPartition)
-      {
-        CurrentPartLineFound = TRUE;
-      }
-      Entry2 = Entry2->Flink;
-      if (CurrentPartLineFound == FALSE)
-      {
-        CurrentPartLine++;
-      }
-      LastLine++;
-    }
-    if (DiskEntry == List->CurrentDisk)
-    {
-      CurrentDiskLineFound = TRUE;
-    }
-    Entry = Entry->Flink;
-    if (Entry != &List->DiskListHead)
-    {
-      if (CurrentDiskLineFound == FALSE)
-      {
-        CurrentPartLine ++;
-        CurrentDiskLine = CurrentPartLine;
-      }
-      LastLine++;
+        /* Update current partition */
+        List->CurrentPartition = PrevPartEntry;
     }
-    else
+    else if (PrevPartEntry != NULL && NextPartEntry == NULL)
     {
-      LastLine--;
-    }
-  }
-
-  /* If it possible, make the disk name visible */
-  if (CurrentPartLine < List->Offset)
-  {
-    List->Offset = CurrentPartLine;
-  }
-  else if (CurrentPartLine - List->Offset > List->Bottom - List->Top - 2)
-  {
-    List->Offset = CurrentPartLine - (List->Bottom - List->Top - 2);
-  }
-  if (CurrentDiskLine < List->Offset && CurrentPartLine - CurrentDiskLine < List->Bottom - List->Top - 2)
-  {
-    List->Offset = CurrentDiskLine;
-  }
-
-
-  /* draw upper left corner */
-  coPos.X = List->Left;
-  coPos.Y = List->Top;
-  FillConsoleOutputCharacterA (StdOutput,
-                               0xDA, // '+',
-                               1,
-                               coPos,
-                               &Written);
-
-  /* draw upper edge */
-  coPos.X = List->Left + 1;
-  coPos.Y = List->Top;
-  if (List->Offset == 0)
-  {
-    FillConsoleOutputCharacterA (StdOutput,
-                                 0xC4, // '-',
-                                 List->Right - List->Left - 1,
-                                 coPos,
-                                 &Written);
-  }
-  else
-  {
-    FillConsoleOutputCharacterA (StdOutput,
-                                 0xC4, // '-',
-                                 List->Right - List->Left - 5,
-                                 coPos,
-                                 &Written);
-    coPos.X = List->Right - 5;
-    WriteConsoleOutputCharacterA (StdOutput,
-                                  "(\x18)", // "(up)"
-                                  3,
-                                  coPos,
-                                  &Written);
-    coPos.X = List->Right - 2;
-    FillConsoleOutputCharacterA (StdOutput,
-                                 0xC4, // '-',
-                                 2,
-                                 coPos,
-                                 &Written);
-  }
-
-  /* draw upper right corner */
-  coPos.X = List->Right;
-  coPos.Y = List->Top;
-  FillConsoleOutputCharacterA (StdOutput,
-                               0xBF, // '+',
-                               1,
-                               coPos,
-                               &Written);
-
-  /* draw left and right edge */
-  for (i = List->Top + 1; i < List->Bottom; i++)
-  {
-    coPos.X = List->Left;
-    coPos.Y = i;
-    FillConsoleOutputCharacterA (StdOutput,
-                                 0xB3, // '|',
-                                 1,
-                                 coPos,
-                                 &Written);
-
-    coPos.X = List->Right;
-    FillConsoleOutputCharacterA (StdOutput,
-                                 0xB3, //'|',
-                                 1,
-                                 coPos,
-                                 &Written);
-  }
-
-  /* draw lower left corner */
-  coPos.X = List->Left;
-  coPos.Y = List->Bottom;
-  FillConsoleOutputCharacterA (StdOutput,
-                               0xC0, // '+',
-                               1,
-                               coPos,
-                               &Written);
-
-  /* draw lower edge */
-  coPos.X = List->Left + 1;
-  coPos.Y = List->Bottom;
-  if (LastLine - List->Offset <= List->Bottom - List->Top - 2)
-  {
-    FillConsoleOutputCharacterA (StdOutput,
-                                 0xC4, // '-',
-                                 List->Right - List->Left - 1,
-                                 coPos,
-                                 &Written);
-  }
-  else
-  {
-    FillConsoleOutputCharacterA (StdOutput,
-                                 0xC4, // '-',
-                                 List->Right - List->Left - 5,
-                                 coPos,
-                                 &Written);
-    coPos.X = List->Right - 5;
-    WriteConsoleOutputCharacterA (StdOutput,
-                                 "(\x19)", // "(down)"
-                                 3,
-                                 coPos,
-                                 &Written);
-    coPos.X = List->Right - 2;
-    FillConsoleOutputCharacterA (StdOutput,
-                                 0xC4, // '-',
-                                 2,
-                                 coPos,
-                                 &Written);
-  }
-
-  /* draw lower right corner */
-  coPos.X = List->Right;
-  coPos.Y = List->Bottom;
-  FillConsoleOutputCharacterA (StdOutput,
-                               0xD9, // '+',
-                               1,
-                               coPos,
-                               &Written);
-
-  /* print list entries */
-  List->Line = - List->Offset;
-
-  Entry = List->DiskListHead.Flink;
-  while (Entry != &List->DiskListHead)
-  {
-    DiskEntry = CONTAINING_RECORD (Entry, DISKENTRY, ListEntry);
-
-    /* Print disk entry */
-    PrintDiskData (List,
-                   DiskEntry);
-
-    Entry = Entry->Flink;
-  }
-}
+        /* Merge current and previous unpartitioned entry */
 
+        /* Adjust the previous entries length */
+        PrevPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
 
-DWORD
-SelectPartition(PPARTLIST List, ULONG DiskNumber, ULONG PartitionNumber)
-{
-  PDISKENTRY DiskEntry;
-  PPARTENTRY PartEntry;
-  PLIST_ENTRY Entry1;
-  PLIST_ENTRY Entry2;
-  UCHAR i;
-
-  /* Check for empty disks */
-  if (IsListEmpty (&List->DiskListHead))
-    return FALSE;
+        /* Remove the current entry */
+        RemoveEntryList(&PartEntry->ListEntry);
+        RtlFreeHeap(ProcessHeap, 0, PartEntry);
+
+        /* Update current partition */
+        List->CurrentPartition = PrevPartEntry;
+    }
+    else if (PrevPartEntry == NULL && NextPartEntry != NULL)
+    {
+        /* Merge current and next unpartitioned entry */
 
-  /* Check for first usable entry on next disk */
-  Entry1 = List->CurrentDisk->ListEntry.Flink;
-  while (Entry1 != &List->DiskListHead)
-  {
-    DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
+        /* Adjust the next entries offset and length */
+        NextPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
+        NextPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
 
-    if (DiskEntry->DiskNumber == DiskNumber)
+        /* Remove the current entry */
+        RemoveEntryList(&PartEntry->ListEntry);
+        RtlFreeHeap(ProcessHeap, 0, PartEntry);
+
+        /* Update current partition */
+        List->CurrentPartition = NextPartEntry;
+    }
+    else
     {
-      Entry2 = DiskEntry->PartListHead.Flink;
-      while (Entry2 != &DiskEntry->PartListHead)
-      {
-        PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
+        /* Nothing to merge but change current entry */
+        PartEntry->IsPartitioned = FALSE;
+        PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
+        PartEntry->FormatState = Unformatted;
+        PartEntry->FileSystem  = NULL;
+        PartEntry->DriveLetter = 0;
+    }
 
-        for (i = 0; i < 4; i++)
-        {
-          if (PartEntry->PartInfo[i].PartitionNumber == PartitionNumber)
-          {
-            List->CurrentDisk = DiskEntry;
-            List->CurrentPartition = PartEntry;
-            List->CurrentPartitionNumber = i;
-            DrawPartitionList (List);
-            return TRUE;
-          }
-        }
-        Entry2 = Entry2->Flink;
-      }
-      return FALSE;
-    }
-    Entry1 = Entry1->Flink;
-  }
-  return FALSE;
+    UpdateDiskLayout(DiskEntry);
+
+    DiskEntry->Dirty = TRUE;
+
+    AssignDriveLetters(List);
 }
 
 
 VOID
-ScrollDownPartitionList (PPARTLIST List)
+CheckActiveSystemPartition(
+    IN PPARTLIST List,
+    IN PFILE_SYSTEM_LIST FileSystemList /* Needed for checking the FS of the candidate system partition */
+    )
 {
-  PDISKENTRY DiskEntry;
-  PPARTENTRY PartEntry;
-  PLIST_ENTRY Entry1;
-  PLIST_ENTRY Entry2;
-  UCHAR i;
-
-  /* Check for empty disks */
-  if (IsListEmpty (&List->DiskListHead))
-    return;
+    PDISKENTRY DiskEntry;
+    PPARTENTRY PartEntry;
+    PLIST_ENTRY ListEntry;
 
-  /* Check for next usable entry on current disk */
-  if (List->CurrentPartition != NULL)
-  {
-    Entry2 = &List->CurrentPartition->ListEntry;
-    PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
+    PFILE_SYSTEM_ITEM FileSystem;
 
-    /* Check if we can move inside primary partitions */
-    for (i = List->CurrentPartitionNumber + 1; i < 4; i++)
+    /* Check for empty disk list */
+    if (IsListEmpty(&List->DiskListHead))
     {
-        if (PartEntry->PartInfo[i].PartitionType != PARTITION_ENTRY_UNUSED)
-            break;
+        List->SystemPartition = NULL;
+        List->OriginalSystemPartition = NULL;
+        return;
     }
 
-    if (i == 4)
-    {
-        /* We're out of partitions in the current partition table.
-           Try to move to the next one if possible. */
-        Entry2 = Entry2->Flink;
-    }
-    else
+    /* Choose the currently selected disk */
+    DiskEntry = List->CurrentDisk;
+
+    /* Check for empty partition list */
+    if (IsListEmpty(&DiskEntry->PrimaryPartListHead))
     {
-        /* Just advance to the next partition */
-        List->CurrentPartitionNumber = i;
-        DrawPartitionList (List);
+        List->SystemPartition = NULL;
+        List->OriginalSystemPartition = NULL;
         return;
     }
 
-    while (Entry2 != &List->CurrentDisk->PartListHead)
+    if (List->SystemPartition != NULL)
     {
-      PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
-
-//       if (PartEntry->HidePartEntry == FALSE)
-      {
-        List->CurrentPartition = PartEntry;
-        List->CurrentPartitionNumber = 0;
-        DrawPartitionList (List);
+        /* We already have an active system partition */
+        DPRINT1("Use the current system partition %lu in disk %lu, drive letter %c\n",
+                List->SystemPartition->PartitionNumber,
+                List->SystemPartition->DiskEntry->DiskNumber,
+                (List->SystemPartition->DriveLetter == 0) ? '-' : List->SystemPartition->DriveLetter);
         return;
-      }
-      Entry2 = Entry2->Flink;
     }
-  }
-
-  /* Check for first usable entry on next disk */
-  if (List->CurrentDisk != NULL)
-  {
-    Entry1 = List->CurrentDisk->ListEntry.Flink;
-    while (Entry1 != &List->DiskListHead)
-    {
-      DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
 
-      Entry2 = DiskEntry->PartListHead.Flink;
-      while (Entry2 != &DiskEntry->PartListHead)
-      {
-        PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
+    DPRINT1("We are here (1)!\n");
 
-//           if (PartEntry->HidePartEntry == FALSE)
-        {
-          List->CurrentDisk = DiskEntry;
-          List->CurrentPartition = PartEntry;
-          List->CurrentPartitionNumber = 0;
-          DrawPartitionList (List);
-          return;
-        }
+    List->SystemPartition = NULL;
+    List->OriginalSystemPartition = NULL;
 
-        Entry2 = Entry2->Flink;
-      }
+    /* Retrieve the first partition of the disk */
+    PartEntry = CONTAINING_RECORD(DiskEntry->PrimaryPartListHead.Flink,
+                                  PARTENTRY,
+                                  ListEntry);
+    ASSERT(DiskEntry == PartEntry->DiskEntry);
+    List->SystemPartition = PartEntry;
 
-      Entry1 = Entry1->Flink;
-    }
-  }
-}
+    //
+    // See: https://svn.reactos.org/svn/reactos/trunk/reactos/base/setup/usetup/partlist.c?r1=63355&r2=63354&pathrev=63355#l2318
+    //
 
+    /* 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)
+        {
+            ASSERT(DiskEntry == PartEntry->DiskEntry);
+            List->SystemPartition = PartEntry;
 
-VOID
-ScrollUpPartitionList (PPARTLIST List)
-{
-  PDISKENTRY DiskEntry;
-  PPARTENTRY PartEntry;
-  PLIST_ENTRY Entry1;
-  PLIST_ENTRY Entry2;
-  UCHAR i;
-
-  /* Check for empty disks */
-  if (IsListEmpty (&List->DiskListHead))
-    return;
+            List->OriginalSystemPartition = List->SystemPartition;
 
-  /* check for previous usable entry on current disk */
-  if (List->CurrentPartition != NULL)
-  {
-    Entry2 = &List->CurrentPartition->ListEntry;
-    PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
+            DPRINT1("Use new first active system partition %lu in disk %lu, drive letter %c\n",
+                    List->SystemPartition->PartitionNumber,
+                    List->SystemPartition->DiskEntry->DiskNumber,
+                    (List->SystemPartition->DriveLetter == 0) ? '-' : List->SystemPartition->DriveLetter);
 
-    /* Check if we can move inside primary partitions */
-    if (List->CurrentPartitionNumber > 0)
-    {
-        /* Find a previous partition */
-        for (i = List->CurrentPartitionNumber - 1; i > 0; i--)
-        {
-            if (PartEntry->PartInfo[i].PartitionType != PARTITION_ENTRY_UNUSED)
-                break;
+            goto SetSystemPartition;
         }
 
-        /* Move to it and return */
-        List->CurrentPartitionNumber = i;
-        DrawPartitionList (List);
-        return;
+        // FIXME: What to do??
+        DPRINT1("NewDisk TRUE but first partition is used?\n");
     }
 
-    /* Move to the previous entry */
-    Entry2 = Entry2->Blink;
+    DPRINT1("We are here (2)!\n");
 
-    while (Entry2 != &List->CurrentDisk->PartListHead)
+    /*
+     * 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)
     {
-      PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
-
-//       if (PartEntry->HidePartEntry == FALSE)
-      {
-        List->CurrentPartition = PartEntry;
+        /* Retrieve the partition and go to the next one */
+        PartEntry = CONTAINING_RECORD(ListEntry,
+                                      PARTENTRY,
+                                      ListEntry);
 
-        /* Find last existing partition in the table */
-        for (i = 3; i > 0; i--)
+        /* Check if the partition is partitioned and is used */
+        if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED || PartEntry->BootIndicator != FALSE)
         {
-            if (PartEntry->PartInfo[i].PartitionType != PARTITION_ENTRY_UNUSED)
-                break;
+            break;
         }
 
-        /* Move to it */
-        List->CurrentPartitionNumber = i;
-
-        /* Draw partition list and return */
-        DrawPartitionList (List);
-        return;
-      }
-      Entry2 = Entry2->Blink;
+        /* Go to the next one */
+        ListEntry = ListEntry->Flink;
     }
-  }
-
-
-  /* check for last usable entry on previous disk */
-  if (List->CurrentDisk != NULL)
-  {
-    Entry1 = List->CurrentDisk->ListEntry.Blink;
-    while (Entry1 != &List->DiskListHead)
+    if (ListEntry == &DiskEntry->PrimaryPartListHead)
     {
-      DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
-
-      Entry2 = DiskEntry->PartListHead.Blink;
-      while (Entry2 != &DiskEntry->PartListHead)
-      {
-        PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
-
-//           if (PartEntry->HidePartEntry == FALSE)
-        {
-          List->CurrentDisk = DiskEntry;
-          List->CurrentPartition = PartEntry;
+        /*
+         * 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
+
+        DPRINT1("Use first active system partition %lu in disk %lu, drive letter %c\n",
+                List->SystemPartition->PartitionNumber,
+                List->SystemPartition->DiskEntry->DiskNumber,
+                (List->SystemPartition->DriveLetter == 0) ? '-' : List->SystemPartition->DriveLetter);
+
+        goto SetSystemPartition;
+    }
 
-          /* Find last existing partition in the table */
-          for (i = 3; i > 0; i--)
-          {
-            if (PartEntry->PartInfo[i].PartitionType != PARTITION_ENTRY_UNUSED)
-              break;
-          }
+    List->SystemPartition = NULL;
+    List->OriginalSystemPartition = NULL;
 
-          /* Move to it */
-          List->CurrentPartitionNumber = i;
+    DPRINT1("We are here (3)!\n");
 
-          /* Draw partition list and return */
-          DrawPartitionList (List);
-          return;
+    /* 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) ? '-' : PartEntry->DriveLetter);
+                break;
+            }
         }
+    }
 
-        Entry2 = Entry2->Blink;
-      }
-
-      Entry1 = Entry1->Blink;
+    /* 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;
 
-static PPARTENTRY
-GetPrevPartitionedEntry (PDISKENTRY DiskEntry,
-                         PPARTENTRY CurrentEntry)
-{
-  PPARTENTRY PrevEntry;
-  PLIST_ENTRY Entry;
+    /*
+     * ADDITIONAL CHECKS / BIG HACK:
+     *
+     * Retrieve its file system and check whether we have
+     * write support for it. If that is the case we are fine
+     * and we can use it directly. However if we don't have
+     * write support we will need to change the active system
+     * partition.
+     *
+     * NOTE that this is completely useless on architectures
+     * where a real system partition is required, as on these
+     * architectures the partition uses the FAT FS, for which
+     * we do have write support.
+     * NOTE also that for those architectures looking for a
+     * partition boot indicator is insufficient.
+     */
+    FileSystem = GetFileSystem(FileSystemList, List->OriginalSystemPartition);
+    if (FileSystem == NULL)
+    {
+        DPRINT1("System partition %lu in disk %lu with no FS?!\n",
+                List->OriginalSystemPartition->PartitionNumber,
+                List->OriginalSystemPartition->DiskEntry->DiskNumber);
+        goto FindAndUseAlternativeSystemPartition;
+    }
+    // HACK: WARNING: We cannot write on this FS yet!
+    // See fslist.c:GetFileSystem()
+    if (List->OriginalSystemPartition->PartitionType == PARTITION_EXT2 ||
+        List->OriginalSystemPartition->PartitionType == PARTITION_IFS)
+    {
+        DPRINT1("Recognized file system %S that doesn't support write support yet!\n",
+                FileSystem->FileSystemName);
+        goto FindAndUseAlternativeSystemPartition;
+    }
 
-  if (CurrentEntry->ListEntry.Blink == &DiskEntry->PartListHead)
-    return NULL;
+    DPRINT1("Use existing active system partition %lu in disk %lu, drive letter %c\n",
+            List->SystemPartition->PartitionNumber,
+            List->SystemPartition->DiskEntry->DiskNumber,
+            (List->SystemPartition->DriveLetter == 0) ? '-' : List->SystemPartition->DriveLetter);
 
-  Entry = CurrentEntry->ListEntry.Blink;
-  while (Entry != &DiskEntry->PartListHead)
-  {
-    PrevEntry = CONTAINING_RECORD (Entry,
-                                   PARTENTRY,
-                                   ListEntry);
-    if (PrevEntry->Unpartitioned == FALSE)
-      return PrevEntry;
+    return;
 
-    Entry = Entry->Blink;
-  }
+FindAndUseAlternativeSystemPartition:
+    /*
+     * We are here because we have not found any (active) candidate
+     * system partition that we know how to support. What we are going
+     * to do is to change the existing system partition and use the
+     * partition on which we install ReactOS as the new system partition,
+     * and then we will need to add in FreeLdr's entry a boot entry to boot
+     * from the original system partition.
+     */
 
-  return NULL;
+    /* 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;
+
+UseAlternativeSystemPartition:
+    List->SystemPartition = List->CurrentPartition;
+
+    DPRINT1("Use alternative active system partition %lu in disk %lu, drive letter %c\n",
+            List->SystemPartition->PartitionNumber,
+            List->SystemPartition->DiskEntry->DiskNumber,
+            (List->SystemPartition->DriveLetter == 0) ? '-' : List->SystemPartition->DriveLetter);
+
+SetSystemPartition:
+    /* Set the new active system partition */
+    List->SystemPartition->BootIndicator = TRUE;
+    List->SystemPartition->DiskEntry->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].BootIndicator = TRUE;
+    List->SystemPartition->DiskEntry->LayoutBuffer->PartitionEntry[List->SystemPartition->PartitionIndex].RewritePartition = TRUE;
+    List->SystemPartition->DiskEntry->Dirty = TRUE;
 }
 
 
-static PPARTENTRY
-GetNextPartitionedEntry (PDISKENTRY DiskEntry,
-                         PPARTENTRY CurrentEntry)
+static
+NTSTATUS
+WritePartitions(
+    IN PPARTLIST List,
+    IN PDISKENTRY DiskEntry)
 {
-  PPARTENTRY NextEntry;
-  PLIST_ENTRY Entry;
-
-  if (CurrentEntry->ListEntry.Flink == &DiskEntry->PartListHead)
-    return NULL;
+    WCHAR DstPath[MAX_PATH];
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    IO_STATUS_BLOCK Iosb;
+    UNICODE_STRING Name;
+    ULONG BufferSize;
+    HANDLE FileHandle = NULL;
+    NTSTATUS Status;
+
+    DPRINT("WritePartitions() Disk: %lu\n", DiskEntry->DiskNumber);
+
+    swprintf(DstPath,
+             L"\\Device\\Harddisk%d\\Partition0",
+             DiskEntry->DiskNumber);
+    RtlInitUnicodeString(&Name,
+                         DstPath);
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &Name,
+                               0,
+                               NULL,
+                               NULL);
+
+    Status = NtOpenFile(&FileHandle,
+                        GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
+                        &ObjectAttributes,
+                        &Iosb,
+                        0,
+                        FILE_SYNCHRONOUS_IO_NONALERT);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("NtOpenFile() failed (Status %lx)\n", Status);
+        return Status;
+    }
 
-  Entry = CurrentEntry->ListEntry.Flink;
-  while (Entry != &DiskEntry->PartListHead)
-  {
-    NextEntry = CONTAINING_RECORD (Entry,
-                                   PARTENTRY,
-                                   ListEntry);
-    if (NextEntry->Unpartitioned == FALSE)
-      return NextEntry;
+#ifdef DUMP_PARTITION_TABLE
+    DumpPartitionTable(DiskEntry);
+#endif
 
-    Entry = Entry->Flink;
-  }
+    BufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
+                 ((DiskEntry->LayoutBuffer->PartitionCount - 1) * sizeof(PARTITION_INFORMATION));
+    Status = NtDeviceIoControlFile(FileHandle,
+                                   NULL,
+                                   NULL,
+                                   NULL,
+                                   &Iosb,
+                                   IOCTL_DISK_SET_DRIVE_LAYOUT,
+                                   DiskEntry->LayoutBuffer,
+                                   BufferSize,
+                                   NULL,
+                                   0);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("IOCTL_DISK_SET_DRIVE_LAYOUT failed (Status 0x%08lx)\n", Status);
+    }
 
-  return NULL;
-}
+    if (FileHandle != NULL)
+        NtClose(FileHandle);
 
+    //
+    // NOTE: Originally (see r40437), we used to install here also a new MBR
+    // for this disk (by calling InstallMbrBootCodeToDisk), only if:
+    // DiskEntry->NewDisk == TRUE and DiskEntry->BiosDiskNumber == 0.
+    // Then after that, both DiskEntry->NewDisk and DiskEntry->NoMbr were set
+    // to FALSE. In the other place (in usetup.c) where InstallMbrBootCodeToDisk
+    // was called too, the installation test was modified by checking whether
+    // DiskEntry->NoMbr was TRUE (instead of NewDisk).
+    //
 
-static PPARTENTRY
-GetPrevUnpartitionedEntry (PDISKENTRY DiskEntry,
-                           PPARTENTRY PartEntry)
-{
-  PPARTENTRY PrevPartEntry;
-
-  if (PartEntry->ListEntry.Blink != &DiskEntry->PartListHead)
-  {
-    PrevPartEntry = CONTAINING_RECORD (PartEntry->ListEntry.Blink,
-                                       PARTENTRY,
-                                       ListEntry);
-    if (PrevPartEntry->Unpartitioned == TRUE)
-      return PrevPartEntry;
-  }
-
-  return NULL;
+    return Status;
 }
 
 
-static PPARTENTRY
-GetNextUnpartitionedEntry (PDISKENTRY DiskEntry,
-                           PPARTENTRY PartEntry)
+BOOLEAN
+WritePartitionsToDisk(
+    IN PPARTLIST List)
 {
-  PPARTENTRY NextPartEntry;
-
-  if (PartEntry->ListEntry.Flink != &DiskEntry->PartListHead)
-  {
-    NextPartEntry = CONTAINING_RECORD (PartEntry->ListEntry.Flink,
-                                       PARTENTRY,
-                                       ListEntry);
-    if (NextPartEntry->Unpartitioned == TRUE)
-      return NextPartEntry;
-  }
-
-  return NULL;
-}
-
+    PLIST_ENTRY Entry;
+    PDISKENTRY DiskEntry;
 
-VOID
-CreateNewPartition (PPARTLIST List,
-                    ULONGLONG PartitionSize,
-                    BOOLEAN AutoCreate)
-{
-  PDISKENTRY DiskEntry;
-  PPARTENTRY PartEntry;
-  PPARTENTRY PrevPartEntry;
-  PPARTENTRY NextPartEntry;
-  PPARTENTRY NewPartEntry;
-
-  if (List == NULL ||
-      List->CurrentDisk == NULL ||
-      List->CurrentPartition == NULL ||
-      List->CurrentPartition->Unpartitioned == FALSE)
-  {
-    return;
-  }
-
-  DiskEntry = List->CurrentDisk;
-  PartEntry = List->CurrentPartition;
-
-  if (AutoCreate == TRUE ||
-      PartitionSize == PartEntry->UnpartitionedLength)
-  {
-    /* Convert current entry to 'new (unformatted)' */
-    PartEntry->FormatState = Unformatted;
-    PartEntry->PartInfo[0].StartingOffset.QuadPart =
-      PartEntry->UnpartitionedOffset + DiskEntry->TrackSize;
-    PartEntry->PartInfo[0].HiddenSectors = 
-      (ULONG)(PartEntry->PartInfo[0].StartingOffset.QuadPart / DiskEntry->BytesPerSector);
-    PartEntry->PartInfo[0].PartitionLength.QuadPart =
-      PartEntry->UnpartitionedLength - DiskEntry->TrackSize;
-    PartEntry->PartInfo[0].PartitionType = PARTITION_ENTRY_UNUSED;
-    PartEntry->PartInfo[0].BootIndicator = FALSE; /* FIXME */
-    PartEntry->PartInfo[0].RewritePartition = TRUE;
-    PartEntry->PartInfo[1].RewritePartition = TRUE;
-    PartEntry->PartInfo[2].RewritePartition = TRUE;
-    PartEntry->PartInfo[3].RewritePartition = TRUE;
-
-    /* Get previous and next partition entries */
-    PrevPartEntry = GetPrevPartitionedEntry (DiskEntry,
-                                             PartEntry);
-    NextPartEntry = GetNextPartitionedEntry (DiskEntry,
-                                             PartEntry);
+    if (List == NULL)
+        return TRUE;
 
-    if (PrevPartEntry != NULL && NextPartEntry != NULL)
+    Entry = List->DiskListHead.Flink;
+    while (Entry != &List->DiskListHead)
     {
-      /* Current entry is in the middle of the list */
+        DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
 
-      /* Copy previous container partition data to current entry */
-      RtlCopyMemory (&PartEntry->PartInfo[1],
-                     &PrevPartEntry->PartInfo[1],
-                     sizeof(PARTITION_INFORMATION));
-      PartEntry->PartInfo[1].RewritePartition = TRUE;
-
-      /* Update previous container partition data */
-
-      PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
-        PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
-      PrevPartEntry->PartInfo[1].HiddenSectors = 
-        (ULONG)(PrevPartEntry->PartInfo[1].StartingOffset.QuadPart / DiskEntry->BytesPerSector);
-
-      if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
-      {
-        /* Special case - previous partition is first partition */
-        PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
-          DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
-      }
-      else
-      {
-        PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
-          PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
-      }
+        if (DiskEntry->Dirty != FALSE)
+        {
+            WritePartitions(List, DiskEntry);
+            DiskEntry->Dirty = FALSE;
+        }
 
-      PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
-    }
-    else if (PrevPartEntry == NULL && NextPartEntry != NULL)
-    {
-      /* Current entry is the first entry */
-      return;
+        Entry = Entry->Flink;
     }
-    else if (PrevPartEntry != NULL && NextPartEntry == NULL)
-    {
-      /* Current entry is the last entry */
-
-      PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
-        PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
-      PrevPartEntry->PartInfo[1].HiddenSectors = 
-        (ULONG)(PrevPartEntry->PartInfo[1].StartingOffset.QuadPart / DiskEntry->BytesPerSector);
-
-      if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
-      {
-        /* Special case - previous partition is first partition */
-        PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
-          DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
-      }
-      else
-      {
-        PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
-          PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
-      }
-
-      if ((PartEntry->PartInfo[1].StartingOffset.QuadPart +
-           PartEntry->PartInfo[1].PartitionLength.QuadPart) <
-          (1024LL * 255LL * 63LL * 512LL))
-      {
-        PrevPartEntry->PartInfo[1].PartitionType = PARTITION_EXTENDED;
-      }
-      else
-      {
-        PrevPartEntry->PartInfo[1].PartitionType = PARTITION_XINT13_EXTENDED;
-      }
-
-      PrevPartEntry->PartInfo[1].BootIndicator = FALSE;
-      PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
-    }
-
-    PartEntry->AutoCreate = AutoCreate;
-    PartEntry->New = TRUE;
-    PartEntry->Unpartitioned = FALSE;
-    PartEntry->UnpartitionedOffset = 0ULL;
-    PartEntry->UnpartitionedLength = 0ULL;
-  }
-  else
-  {
-    /* Insert an initialize a new partition entry */
-    NewPartEntry = (PPARTENTRY)RtlAllocateHeap (ProcessHeap,
-                                                0,
-                                                sizeof(PARTENTRY));
-    if (NewPartEntry == NULL)
-      return;
 
-    RtlZeroMemory (NewPartEntry,
-                   sizeof(PARTENTRY));
+    return TRUE;
+}
 
-    /* Insert the new entry into the list */
-    InsertTailList (&PartEntry->ListEntry,
-                    &NewPartEntry->ListEntry);
 
-    NewPartEntry->New = TRUE;
+BOOLEAN
+SetMountedDeviceValues(
+    IN PPARTLIST List)
+{
+    PLIST_ENTRY Entry1, Entry2;
+    PDISKENTRY DiskEntry;
+    PPARTENTRY PartEntry;
+    LARGE_INTEGER StartingOffset;
 
-    NewPartEntry->FormatState = Unformatted;
-    NewPartEntry->PartInfo[0].StartingOffset.QuadPart =
-      PartEntry->UnpartitionedOffset + DiskEntry->TrackSize;
-    NewPartEntry->PartInfo[0].HiddenSectors = 
-      (ULONG)(NewPartEntry->PartInfo[0].StartingOffset.QuadPart / DiskEntry->BytesPerSector);
-    NewPartEntry->PartInfo[0].PartitionLength.QuadPart =
-      PartitionSize - DiskEntry->TrackSize;
-    NewPartEntry->PartInfo[0].PartitionType = PARTITION_ENTRY_UNUSED;
-    NewPartEntry->PartInfo[0].BootIndicator = FALSE; /* FIXME */
-    NewPartEntry->PartInfo[0].RewritePartition = TRUE;
-    NewPartEntry->PartInfo[1].RewritePartition = TRUE;
-    NewPartEntry->PartInfo[2].RewritePartition = TRUE;
-    NewPartEntry->PartInfo[3].RewritePartition = TRUE;
-
-    /* Get previous and next partition entries */
-    PrevPartEntry = GetPrevPartitionedEntry (DiskEntry,
-                                             NewPartEntry);
-    NextPartEntry = GetNextPartitionedEntry (DiskEntry,
-                                             NewPartEntry);
+    if (List == NULL)
+        return FALSE;
 
-    if (PrevPartEntry != NULL && NextPartEntry != NULL)
+    Entry1 = List->DiskListHead.Flink;
+    while (Entry1 != &List->DiskListHead)
     {
-      /* Current entry is in the middle of the list */
+        DiskEntry = CONTAINING_RECORD(Entry1,
+                                      DISKENTRY,
+                                      ListEntry);
 
-      /* Copy previous container partition data to current entry */
-      RtlCopyMemory (&NewPartEntry->PartInfo[1],
-                     &PrevPartEntry->PartInfo[1],
-                     sizeof(PARTITION_INFORMATION));
-      NewPartEntry->PartInfo[1].RewritePartition = TRUE;
+        Entry2 = DiskEntry->PrimaryPartListHead.Flink;
+        while (Entry2 != &DiskEntry->PrimaryPartListHead)
+        {
+            PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
+            if (PartEntry->IsPartitioned)
+            {
+                /* Assign a "\DosDevices\#:" mount point to this partition */
+                if (PartEntry->DriveLetter)
+                {
+                    StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
+                    if (!SetMountedDeviceValue(PartEntry->DriveLetter,
+                                               DiskEntry->LayoutBuffer->Signature,
+                                               StartingOffset))
+                    {
+                        return FALSE;
+                    }
+                }
+            }
 
-      /* Update previous container partition data */
+            Entry2 = Entry2->Flink;
+        }
 
-      PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
-        NewPartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
-      PrevPartEntry->PartInfo[1].HiddenSectors = 
-        (ULONG)(PrevPartEntry->PartInfo[1].StartingOffset.QuadPart / DiskEntry->BytesPerSector);
+        Entry2 = DiskEntry->LogicalPartListHead.Flink;
+        while (Entry2 != &DiskEntry->LogicalPartListHead)
+        {
+            PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
+            if (PartEntry->IsPartitioned)
+            {
+                /* Assign a "\DosDevices\#:" mount point to this partition */
+                if (PartEntry->DriveLetter)
+                {
+                    StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
+                    if (!SetMountedDeviceValue(PartEntry->DriveLetter,
+                                               DiskEntry->LayoutBuffer->Signature,
+                                               StartingOffset))
+                    {
+                        return FALSE;
+                    }
+                }
+            }
 
-      if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
-      {
-        /* Special case - previous partition is first partition */
-        PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
-          DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
-      }
-      else
-      {
-        PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
-          NewPartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
-      }
+            Entry2 = Entry2->Flink;
+        }
 
-      PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
-    }
-    else if (PrevPartEntry == NULL && NextPartEntry != NULL)
-    {
-      /* Current entry is the first entry */
-      return;
+        Entry1 = Entry1->Flink;
     }
-    else if (PrevPartEntry != NULL && NextPartEntry == NULL)
-    {
-      /* Current entry is the last entry */
-
-      PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
-        NewPartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
-      PrevPartEntry->PartInfo[1].HiddenSectors = 
-        (ULONG)(PrevPartEntry->PartInfo[1].StartingOffset.QuadPart / DiskEntry->BytesPerSector);
-
-      if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
-      {
-        /* Special case - previous partition is first partition */
-        PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
-          DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
-      }
-      else
-      {
-        PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
-          NewPartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
-      }
-
-      if ((PartEntry->PartInfo[1].StartingOffset.QuadPart +
-           PartEntry->PartInfo[1].PartitionLength.QuadPart) <
-          (1024LL * 255LL * 63LL * 512LL))
-      {
-        PrevPartEntry->PartInfo[1].PartitionType = PARTITION_EXTENDED;
-      }
-      else
-      {
-        PrevPartEntry->PartInfo[1].PartitionType = PARTITION_XINT13_EXTENDED;
-      }
-
-      PrevPartEntry->PartInfo[1].BootIndicator = FALSE;
-      PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
-    }
-
-    /* Update offset and size of the remaining unpartitioned disk space */
-    PartEntry->UnpartitionedOffset += PartitionSize;
-    PartEntry->UnpartitionedLength -= PartitionSize;
-  }
-
-  DiskEntry->Modified = TRUE;
-
-  UpdatePartitionNumbers (DiskEntry);
-
-  AssignDriverLetters (List);
-}
 
+    return TRUE;
+}
 
 VOID
-DeleteCurrentPartition (PPARTLIST List)
+SetPartitionType(
+    IN PPARTENTRY PartEntry,
+    IN UCHAR PartitionType)
 {
-  PDISKENTRY DiskEntry;
-  PPARTENTRY PartEntry;
-  PPARTENTRY PrevPartEntry;
-  PPARTENTRY NextPartEntry;
-
-  if (List == NULL ||
-      List->CurrentDisk == NULL ||
-      List->CurrentPartition == NULL ||
-      List->CurrentPartition->Unpartitioned == TRUE)
-  {
-    return;
-  }
+    PDISKENTRY DiskEntry = PartEntry->DiskEntry;
+
+    PartEntry->PartitionType = PartitionType;
+
+    DiskEntry->Dirty = TRUE;
+    DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType = PartitionType;
+    DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
+}
 
-  DiskEntry = List->CurrentDisk;
-  PartEntry = List->CurrentPartition;
+ULONG
+PrimaryPartitionCreationChecks(
+    IN PPARTLIST List)
+{
+    PDISKENTRY DiskEntry;
+    PPARTENTRY PartEntry;
 
-  /* Adjust container partition entries */
+    DiskEntry = List->CurrentDisk;
+    PartEntry = List->CurrentPartition;
 
-  /* Get previous and next partition entries */
-  PrevPartEntry = GetPrevPartitionedEntry (DiskEntry,
-                                           PartEntry);
-  NextPartEntry = GetNextPartitionedEntry (DiskEntry,
-                                           PartEntry);
+    /* Fail if partition is already in use */
+    if (PartEntry->IsPartitioned != FALSE)
+        return ERROR_NEW_PARTITION;
 
-  if (PrevPartEntry != NULL && NextPartEntry != NULL)
-  {
-    /* Current entry is in the middle of the list */
+    /* Fail if there are already 4 primary partitions in the list */
+    if (GetPrimaryPartitionCount(DiskEntry) >= 4)
+        return ERROR_PARTITION_TABLE_FULL;
 
-    /*
-     * The first extended partition can not be deleted
-     * as long as other extended partitions are present.
-     */
-    if (PrevPartEntry->ListEntry.Blink == &DiskEntry->PartListHead)
-      return;
-
-    /* Copy previous container partition data to current entry */
-    RtlCopyMemory (&PrevPartEntry->PartInfo[1],
-                   &PartEntry->PartInfo[1],
-                   sizeof(PARTITION_INFORMATION));
-    PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
-  }
-  else if (PrevPartEntry == NULL && NextPartEntry != NULL)
-  {
-    /*
-     * A primary partition can not be deleted as long as
-     * extended partitions are present.
-     */
-    return;
-  }
-  else if (PrevPartEntry != NULL && NextPartEntry == NULL)
-  {
-    /* Current entry is the last entry */
-    RtlZeroMemory (&PrevPartEntry->PartInfo[1],
-                   sizeof(PARTITION_INFORMATION));
-    PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
-  }
-
-
-  /* Adjust unpartitioned disk space entries */
-
-  /* Get pointer to previous and next unpartitioned entries */
-  PrevPartEntry = GetPrevUnpartitionedEntry (DiskEntry,
-                                             PartEntry);
-
-  NextPartEntry = GetNextUnpartitionedEntry (DiskEntry,
-                                             PartEntry);
-
-  if (PrevPartEntry != NULL && NextPartEntry != NULL)
-  {
-    /* Merge previous, current and next unpartitioned entry */
-
-    /* Adjust the previous entries length */
-    PrevPartEntry->UnpartitionedLength +=
-      (PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize +
-      NextPartEntry->UnpartitionedLength);
-
-    /* Remove the current entry */
-    RemoveEntryList (&PartEntry->ListEntry);
-    RtlFreeHeap (ProcessHeap,
-                 0,
-                 PartEntry);
-
-    /* Remove the next entry */
-    RemoveEntryList (&NextPartEntry->ListEntry);
-    RtlFreeHeap (ProcessHeap,
-                 0,
-    NextPartEntry);
-
-    /* Update current partition */
-    List->CurrentPartition = PrevPartEntry;
-  }
-  else if (PrevPartEntry != NULL && NextPartEntry == NULL)
-  {
-    /* Merge current and previous unpartitioned entry */
-
-    /* Adjust the previous entries length */
-    PrevPartEntry->UnpartitionedLength +=
-      (PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize);
-
-    /* Remove the current entry */
-    RemoveEntryList (&PartEntry->ListEntry);
-    RtlFreeHeap (ProcessHeap,
-                 0,
-                 PartEntry);
-
-    /* Update current partition */
-    List->CurrentPartition = PrevPartEntry;
-  }
-  else if (PrevPartEntry == NULL && NextPartEntry != NULL)
-  {
-    /* Merge current and next unpartitioned entry */
-
-    /* Adjust the next entries offset and length */
-    NextPartEntry->UnpartitionedOffset =
-      PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
-    NextPartEntry->UnpartitionedLength +=
-      (PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize);
-
-    /* Remove the current entry */
-    RemoveEntryList (&PartEntry->ListEntry);
-    RtlFreeHeap (ProcessHeap,
-                 0,
-                 PartEntry);
-
-    /* Update current partition */
-    List->CurrentPartition = NextPartEntry;
-  }
-  else
-  {
-    /* Nothing to merge but change current entry */
-    PartEntry->New = FALSE;
-    PartEntry->Unpartitioned = TRUE;
-    PartEntry->UnpartitionedOffset =
-      PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
-    PartEntry->UnpartitionedLength =
-      PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
-
-    /* Wipe the partition table */
-    RtlZeroMemory (&PartEntry->PartInfo,
-                   sizeof(PartEntry->PartInfo));
-  }
-
-  DiskEntry->Modified = TRUE;
-
-  UpdatePartitionNumbers (DiskEntry);
-
-  AssignDriverLetters (List);
+    return ERROR_SUCCESS;
 }
 
 
-VOID
-CheckActiveBootPartition (PPARTLIST List)
+ULONG
+ExtendedPartitionCreationChecks(
+    IN PPARTLIST List)
 {
-  PDISKENTRY DiskEntry;
-  PPARTENTRY PartEntry;
-  PLIST_ENTRY ListEntry;
-  UCHAR i;
-
-  /* Check for empty disk list */
-  if (IsListEmpty (&List->DiskListHead))
-  {
-    List->ActiveBootDisk = NULL;
-    List->ActiveBootPartition = NULL;
-    List->ActiveBootPartitionNumber = 0;
-    return;
-  }
+    PDISKENTRY DiskEntry;
+    PPARTENTRY PartEntry;
 
-#if 0
-  if (List->ActiveBootDisk != NULL &&
-      List->ActiveBootPartition != NULL)
-  {
-    /* We already have an active boot partition */
-    return;
-  }
-#endif
+    DiskEntry = List->CurrentDisk;
+    PartEntry = List->CurrentPartition;
 
-  /* Choose the currently selected disk */
-  DiskEntry = List->CurrentDisk;
+    /* Fail if partition is already in use */
+    if (PartEntry->IsPartitioned != FALSE)
+        return ERROR_NEW_PARTITION;
 
-  /* Check for empty partition list */
-  if (IsListEmpty (&DiskEntry->PartListHead))
-  {
-    List->ActiveBootDisk = NULL;
-    List->ActiveBootPartition = NULL;
-    List->ActiveBootPartitionNumber = 0;
-    return;
-  }
-
-  PartEntry = CONTAINING_RECORD (DiskEntry->PartListHead.Flink,
-                                 PARTENTRY,
-                                 ListEntry);
-
-  /* Set active boot partition */
-  if ((DiskEntry->NewDisk == TRUE) ||
-      (PartEntry->PartInfo[0].BootIndicator == FALSE &&
-       PartEntry->PartInfo[1].BootIndicator == FALSE &&
-       PartEntry->PartInfo[2].BootIndicator == FALSE &&
-       PartEntry->PartInfo[3].BootIndicator == FALSE))
-  {
-    PartEntry->PartInfo[0].BootIndicator = TRUE;
-    PartEntry->PartInfo[0].RewritePartition = TRUE;
-    DiskEntry->Modified = TRUE;
-
-    /* FIXME: Might be incorrect if partitions were created by Linux FDISK */
-    List->ActiveBootDisk = DiskEntry;
-    List->ActiveBootPartition = PartEntry;
-    List->ActiveBootPartitionNumber = 0;
+    /* Fail if there are already 4 primary partitions in the list */
+    if (GetPrimaryPartitionCount(DiskEntry) >= 4)
+        return ERROR_PARTITION_TABLE_FULL;
 
-    return;
-  }
+    /* Fail if there is another extended partition in the list */
+    if (DiskEntry->ExtendedPartition != NULL)
+        return ERROR_ONLY_ONE_EXTENDED;
 
-  /* Disk is not new, scan all partitions to find a bootable one */
-  List->ActiveBootDisk = NULL;
-  List->ActiveBootPartition = NULL;
-  List->ActiveBootPartitionNumber = 0;
+    return ERROR_SUCCESS;
+}
 
-  ListEntry = DiskEntry->PartListHead.Flink;
-  while (ListEntry != &DiskEntry->PartListHead)
-  {
-    PartEntry = CONTAINING_RECORD(ListEntry,
-                                  PARTENTRY,
-                                  ListEntry);
 
-    /* Check if it's partitioned */
-    if (!PartEntry->Unpartitioned)
-    {
-      /* Go through all of its 4 partitions */
-      for (i=0; i<4; i++)
-      {
-        if (PartEntry->PartInfo[i].PartitionType != PARTITION_ENTRY_UNUSED &&
-            PartEntry->PartInfo[i].BootIndicator)
-        {
-          /* Yes, we found it */
-          List->ActiveBootDisk = DiskEntry;
-          List->ActiveBootPartition = PartEntry;
-          List->ActiveBootPartitionNumber = i;
+ULONG
+LogicalPartitionCreationChecks(
+    IN PPARTLIST List)
+{
+//    PDISKENTRY DiskEntry;
+    PPARTENTRY PartEntry;
 
-          DPRINT("Found bootable partition disk %d, drive letter %c\n",
-              DiskEntry->DiskNumber, PartEntry->DriveLetter[i]);
+//    DiskEntry = List->CurrentDisk;
+    PartEntry = List->CurrentPartition;
 
-          break;
-        }
-      }
-    }
-    /* Go to the next one */
-    ListEntry = ListEntry->Flink;
-  }
+    /* Fail if partition is already in use */
+    if (PartEntry->IsPartitioned != FALSE)
+        return ERROR_NEW_PARTITION;
+
+    return ERROR_SUCCESS;
 }
 
 
 BOOLEAN
-CheckForLinuxFdiskPartitions (PPARTLIST List)
+GetNextUnformattedPartition(
+    IN PPARTLIST List,
+    OUT PDISKENTRY *pDiskEntry OPTIONAL,
+    OUT PPARTENTRY *pPartEntry)
 {
-  PDISKENTRY DiskEntry;
-  PPARTENTRY PartEntry;
-  PLIST_ENTRY Entry1;
-  PLIST_ENTRY Entry2;
-  ULONG PartitionCount;
-  ULONG i;
-
-  Entry1 = List->DiskListHead.Flink;
-  while (Entry1 != &List->DiskListHead)
-  {
-    DiskEntry = CONTAINING_RECORD (Entry1,
-                                   DISKENTRY,
-                                   ListEntry);
-
-    Entry2 = DiskEntry->PartListHead.Flink;
-    while (Entry2 != &DiskEntry->PartListHead)
-    {
-      PartEntry = CONTAINING_RECORD (Entry2,
-                                     PARTENTRY,
-                                     ListEntry);
-
-      if (PartEntry->Unpartitioned == FALSE)
-      {
-        PartitionCount = 0;
+    PLIST_ENTRY Entry1, Entry2;
+    PDISKENTRY DiskEntry;
+    PPARTENTRY PartEntry;
 
-        for (i = 0; i < 4; i++)
+    Entry1 = List->DiskListHead.Flink;
+    while (Entry1 != &List->DiskListHead)
+    {
+        DiskEntry = CONTAINING_RECORD(Entry1,
+                                      DISKENTRY,
+                                      ListEntry);
+
+        Entry2 = DiskEntry->PrimaryPartListHead.Flink;
+        while (Entry2 != &DiskEntry->PrimaryPartListHead)
         {
-          if (!IsContainerPartition (PartEntry->PartInfo[i].PartitionType) &&
-              PartEntry->PartInfo[i].PartitionLength.QuadPart != 0ULL)
-          {
-            PartitionCount++;
-          }
+            PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
+            if (PartEntry->IsPartitioned && PartEntry->New)
+            {
+                ASSERT(DiskEntry == PartEntry->DiskEntry);
+                if (pDiskEntry) *pDiskEntry = DiskEntry;
+                *pPartEntry = PartEntry;
+                return TRUE;
+            }
+
+            Entry2 = Entry2->Flink;
         }
 
-        if (PartitionCount > 1)
+        Entry2 = DiskEntry->LogicalPartListHead.Flink;
+        while (Entry2 != &DiskEntry->LogicalPartListHead)
         {
-          return TRUE;
+            PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
+            if (PartEntry->IsPartitioned && PartEntry->New)
+            {
+                ASSERT(DiskEntry == PartEntry->DiskEntry);
+                if (pDiskEntry) *pDiskEntry = DiskEntry;
+                *pPartEntry = PartEntry;
+                return TRUE;
+            }
+
+            Entry2 = Entry2->Flink;
         }
-      }
 
-      Entry2 = Entry2->Flink;
+        Entry1 = Entry1->Flink;
     }
 
-    Entry1 = Entry1->Flink;
-  }
+    if (pDiskEntry) *pDiskEntry = NULL;
+    *pPartEntry = NULL;
 
-  return FALSE;
+    return FALSE;
 }
 
-
 BOOLEAN
-WritePartitionsToDisk (PPARTLIST List)
+GetNextUncheckedPartition(
+    IN PPARTLIST List,
+    OUT PDISKENTRY *pDiskEntry OPTIONAL,
+    OUT PPARTENTRY *pPartEntry)
 {
-  PDRIVE_LAYOUT_INFORMATION DriveLayout;
-  OBJECT_ATTRIBUTES ObjectAttributes;
-  IO_STATUS_BLOCK Iosb;
-  WCHAR DstPath[MAX_PATH];
-  UNICODE_STRING Name;
-  HANDLE FileHandle;
-  PDISKENTRY DiskEntry1;
-  PDISKENTRY DiskEntry2;
-  PPARTENTRY PartEntry;
-  PLIST_ENTRY Entry1;
-  PLIST_ENTRY Entry2;
-  ULONG PartitionCount;
-  ULONG DriveLayoutSize;
-  ULONG Index;
-  NTSTATUS Status;
-
-  if (List == NULL)
-  {
-    return TRUE;
-  }
-
-  Entry1 = List->DiskListHead.Flink;
-  while (Entry1 != &List->DiskListHead)
-  {
-    DiskEntry1 = CONTAINING_RECORD (Entry1,
-                                    DISKENTRY,
-                                    ListEntry);
-
-    if (DiskEntry1->Modified == TRUE)
-    {
-      /* Count partitioned entries */
-      PartitionCount = 0;
-      Entry2 = DiskEntry1->PartListHead.Flink;
-      while (Entry2 != &DiskEntry1->PartListHead)
-      {
-        PartEntry = CONTAINING_RECORD (Entry2,
-                                       PARTENTRY,
-                                       ListEntry);
-        if (PartEntry->Unpartitioned == FALSE)
-        {
-          PartitionCount += 4;
-        }
-
-        Entry2 = Entry2->Flink;
-      }
-      if (PartitionCount == 0)
-      {
-        DriveLayoutSize = sizeof (DRIVE_LAYOUT_INFORMATION) +
-          ((4 - 1) * sizeof (PARTITION_INFORMATION));
-      }
-      else
-      {
-        DriveLayoutSize = sizeof (DRIVE_LAYOUT_INFORMATION) +
-          ((PartitionCount - 1) * sizeof (PARTITION_INFORMATION));
-      }
-      DriveLayout = (PDRIVE_LAYOUT_INFORMATION)RtlAllocateHeap (ProcessHeap,
-                                                                0,
-                                                                DriveLayoutSize);
-      if (DriveLayout == NULL)
-      {
-        DPRINT1 ("RtlAllocateHeap() failed\n");
-        return FALSE;
-      }
-
-      RtlZeroMemory (DriveLayout,
-                     DriveLayoutSize);
-
-      if (PartitionCount == 0)
-      {
-        /* delete all partitions in the mbr */
-        DriveLayout->PartitionCount = 4;
-        for (Index = 0; Index < 4; Index++)
-        {
-          DriveLayout->PartitionEntry[Index].RewritePartition = TRUE;
-        }
-      }
-      else
-      {
-        DriveLayout->PartitionCount = PartitionCount;
-
-        Index = 0;
-        Entry2 = DiskEntry1->PartListHead.Flink;
-        while (Entry2 != &DiskEntry1->PartListHead)
-        {
-          PartEntry = CONTAINING_RECORD (Entry2,
-                                         PARTENTRY,
-                                         ListEntry);
-          if (PartEntry->Unpartitioned == FALSE)
-          {
-            RtlCopyMemory (&DriveLayout->PartitionEntry[Index],
-                           &PartEntry->PartInfo[0],
-                           4 * sizeof (PARTITION_INFORMATION));
-            Index += 4;
-          }
+    PLIST_ENTRY Entry1, Entry2;
+    PDISKENTRY DiskEntry;
+    PPARTENTRY PartEntry;
 
-          Entry2 = Entry2->Flink;
-        }
-      }
-      if (DiskEntry1->Signature == 0)
-      {
-        LARGE_INTEGER SystemTime;
-        TIME_FIELDS TimeFields;
-        PUCHAR Buffer;
-        Buffer = (PUCHAR)&DiskEntry1->Signature;
+    Entry1 = List->DiskListHead.Flink;
+    while (Entry1 != &List->DiskListHead)
+    {
+        DiskEntry = CONTAINING_RECORD(Entry1,
+                                      DISKENTRY,
+                                      ListEntry);
 
-        while (1)
+        Entry2 = DiskEntry->PrimaryPartListHead.Flink;
+        while (Entry2 != &DiskEntry->PrimaryPartListHead)
         {
-          NtQuerySystemTime (&SystemTime);
-          RtlTimeToTimeFields (&SystemTime, &TimeFields);
-
-          Buffer[0] = (UCHAR)(TimeFields.Year & 0xFF) + (UCHAR)(TimeFields.Hour & 0xFF);
-          Buffer[1] = (UCHAR)(TimeFields.Year >> 8) + (UCHAR)(TimeFields.Minute & 0xFF);
-          Buffer[2] = (UCHAR)(TimeFields.Month & 0xFF) + (UCHAR)(TimeFields.Second & 0xFF);
-          Buffer[3] = (UCHAR)(TimeFields.Day & 0xFF) + (UCHAR)(TimeFields.Milliseconds & 0xFF);
-
-          if (DiskEntry1->Signature == 0)
-          {
-            continue;
-          }
-
-          /* check if the signature already exist */
-          /* FIXME:
-           *   Check also signatures from disks, which are
-           *   not visible (bootable) by the bios.
-           */
-          Entry2 = List->DiskListHead.Flink;
-          while (Entry2 != &List->DiskListHead)
-          {
-            DiskEntry2 = CONTAINING_RECORD(Entry2, DISKENTRY, ListEntry);
-            if (DiskEntry1 != DiskEntry2 &&
-                DiskEntry1->Signature == DiskEntry2->Signature)
+            PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
+            if (PartEntry->NeedsCheck == TRUE)
             {
-              break;
+                ASSERT(DiskEntry == PartEntry->DiskEntry);
+                if (pDiskEntry) *pDiskEntry = DiskEntry;
+                *pPartEntry = PartEntry;
+                return TRUE;
             }
+
             Entry2 = Entry2->Flink;
-          }
-          if (Entry2 == &List->DiskListHead)
-          {
-            break;
-          }
         }
 
-        /* set one partition entry to dirty, this will update the signature */
-        DriveLayout->PartitionEntry[0].RewritePartition = TRUE;
-
-      }
-
-      DriveLayout->Signature = DiskEntry1->Signature;
-
-
-      swprintf (DstPath,
-                L"\\Device\\Harddisk%d\\Partition0",
-                DiskEntry1->DiskNumber);
-      RtlInitUnicodeString (&Name,
-                            DstPath);
-      InitializeObjectAttributes (&ObjectAttributes,
-                                  &Name,
-                                  0,
-                                  NULL,
-                                  NULL);
-
-      Status = NtOpenFile (&FileHandle,
-                           FILE_ALL_ACCESS,
-                           &ObjectAttributes,
-                           &Iosb,
-                           0,
-                           FILE_SYNCHRONOUS_IO_NONALERT);
-
-      if (!NT_SUCCESS (Status))
-      {
-        DPRINT1 ("NtOpenFile() failed (Status %lx)\n", Status);
-        return FALSE;
-      }
-
-      Status = NtDeviceIoControlFile (FileHandle,
-                                      NULL,
-                                      NULL,
-                                      NULL,
-                                      &Iosb,
-                                      IOCTL_DISK_SET_DRIVE_LAYOUT,
-                                      DriveLayout,
-                                      DriveLayoutSize,
-                                      NULL,
-                                      0);
-      if (!NT_SUCCESS (Status))
-      {
-        DPRINT1 ("NtDeviceIoControlFile() failed (Status %lx)\n", Status);
-        NtClose (FileHandle);
-        return FALSE;
-      }
+        Entry2 = DiskEntry->LogicalPartListHead.Flink;
+        while (Entry2 != &DiskEntry->LogicalPartListHead)
+        {
+            PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
+            if (PartEntry->NeedsCheck == TRUE)
+            {
+                ASSERT(DiskEntry == PartEntry->DiskEntry);
+                if (pDiskEntry) *pDiskEntry = DiskEntry;
+                *pPartEntry = PartEntry;
+                return TRUE;
+            }
 
-      RtlFreeHeap (ProcessHeap,
-                   0,
-                   DriveLayout);
+            Entry2 = Entry2->Flink;
+        }
 
-      NtClose (FileHandle);
+        Entry1 = Entry1->Flink;
     }
 
-    Entry1 = Entry1->Flink;
-  }
-
-  return TRUE;
-}
-
-BOOL SetMountedDeviceValues(PPARTLIST List)
-{
-  PLIST_ENTRY Entry1, Entry2;
-  PDISKENTRY DiskEntry;
-  PPARTENTRY PartEntry;
-  UCHAR i;
+    if (pDiskEntry) *pDiskEntry = NULL;
+    *pPartEntry = NULL;
 
-  if (List == NULL)
-  {
     return FALSE;
-  }
-
-  Entry1 = List->DiskListHead.Flink;
-  while (Entry1 != &List->DiskListHead)
-  {
-    DiskEntry = CONTAINING_RECORD (Entry1,
-                                   DISKENTRY,
-                                   ListEntry);
-
-    Entry2 = DiskEntry->PartListHead.Flink;
-    while (Entry2 != &DiskEntry->PartListHead)
-    {
-      PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
-      if (!PartEntry->Unpartitioned)
-      {
-        for (i=0; i<4; i++)
-        {
-          if (PartEntry->DriveLetter[i])
-          {
-            if (!SetMountedDeviceValue(PartEntry->DriveLetter[i], DiskEntry->Signature, PartEntry->PartInfo[i].StartingOffset))
-            {
-              return FALSE;
-            }
-          }
-        }
-      }
-      Entry2 = Entry2->Flink;
-    }
-    Entry1 = Entry1->Flink;
-  }
-  return TRUE;
 }
 
-
-
 /* EOF */