[SETUPLIB][USETUP] Introduce a 'SetupLib' library. CORE-13544
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Wed, 17 May 2017 23:37:41 +0000 (23:37 +0000)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sun, 27 May 2018 18:18:50 +0000 (20:18 +0200)
- Create the beginnings of a "setuplib" library, whose aim is to be shared between the (currently existing) 1st-stage text-mode installer, and the (future) 1st-stage GUI installer.
- Finish to split the GenList and PartList codes into their UI part, which remain in usetup, and their algorithmic part, which go into setuplib.
- Move SetMountedDeviceValue into the PartList module.
- Split the FileSystem list code into its UI and the algorithmic part (which goes into setuplib under the name fsutil.c).
  * The algo part is meant to be able to manage the filesystems available on the running system, similarly to what is mostly done (in scattered form) in fmifs, format, chkdsk / autochk codes...
    It also manages the partition filesystem recognition, using OS routines.
  * The UI part manages the FS list as it appears on screen, showing only the possible FSes that can be used to format the selected partition (a bit similar to what we do in the shell32's drive.c, etc...).
- Adapt the calling code to these changes.
- Remove some "host" code that was dating back from the dark old times.

svn path=/branches/setup_improvements/; revision=74570
svn path=/branches/setup_improvements/; revision=74659

28 files changed:
base/setup/CMakeLists.txt
base/setup/lib/CMakeLists.txt [new file with mode: 0644]
base/setup/lib/errorcode.h [new file with mode: 0644]
base/setup/lib/fsutil.c [new file with mode: 0644]
base/setup/lib/fsutil.h [new file with mode: 0644]
base/setup/lib/genlist.c [new file with mode: 0644]
base/setup/lib/genlist.h [new file with mode: 0644]
base/setup/lib/linklist.h [new file with mode: 0644]
base/setup/lib/partlist.c [new file with mode: 0644]
base/setup/lib/partlist.h [new file with mode: 0644]
base/setup/lib/precomp.h [new file with mode: 0644]
base/setup/lib/setuplib.h [new file with mode: 0644]
base/setup/usetup/CMakeLists.txt
base/setup/usetup/bootsup.c
base/setup/usetup/chkdsk.c
base/setup/usetup/chkdsk.h
base/setup/usetup/format.c
base/setup/usetup/format.h
base/setup/usetup/fslist.c
base/setup/usetup/fslist.h
base/setup/usetup/genlist.c
base/setup/usetup/genlist.h
base/setup/usetup/partlist.c
base/setup/usetup/partlist.h
base/setup/usetup/registry.c
base/setup/usetup/registry.h
base/setup/usetup/usetup.c
base/setup/usetup/usetup.h

index 91c62d8..ee5a90d 100644 (file)
@@ -1,4 +1,5 @@
 
+add_subdirectory(lib)
 add_subdirectory(reactos)
 add_subdirectory(setup)
 add_subdirectory(usetup)
diff --git a/base/setup/lib/CMakeLists.txt b/base/setup/lib/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e44b2f7
--- /dev/null
@@ -0,0 +1,10 @@
+
+list(APPEND SOURCE
+    fsutil.c
+    genlist.c
+    partlist.c
+    precomp.h)
+
+add_library(setuplib ${SOURCE})
+add_pch(setuplib precomp.h SOURCE)
+add_dependencies(setuplib xdk) # psdk
diff --git a/base/setup/lib/errorcode.h b/base/setup/lib/errorcode.h
new file mode 100644 (file)
index 0000000..963e137
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * PROJECT:     ReactOS Setup Library
+ * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE:     Setup error codes
+ * COPYRIGHT:   Copyright 2007-2018 Johannes Anderwald <johannes.anderwald@reactos.org>
+ */
+
+#pragma once
+
+typedef enum
+{
+    NOT_AN_ERROR = 0,   // ERROR_SUCCESS,
+    ERROR_NOT_INSTALLED,
+    ERROR_NO_HDD,
+    ERROR_NO_SOURCE_DRIVE,
+    ERROR_LOAD_TXTSETUPSIF,
+    ERROR_CORRUPT_TXTSETUPSIF,
+    ERROR_SIGNATURE_TXTSETUPSIF,
+    ERROR_DRIVE_INFORMATION,
+    ERROR_WRITE_BOOT,
+    ERROR_LOAD_COMPUTER,
+    ERROR_LOAD_DISPLAY,
+    ERROR_LOAD_KEYBOARD,
+    ERROR_LOAD_KBLAYOUT,
+    ERROR_WARN_PARTITION,
+    ERROR_NEW_PARTITION,
+    ERROR_DELETE_SPACE,
+    ERROR_INSTALL_BOOTCODE,
+    ERROR_NO_FLOPPY,
+    ERROR_UPDATE_KBSETTINGS,
+    ERROR_UPDATE_DISPLAY_SETTINGS,
+    ERROR_IMPORT_HIVE,
+    ERROR_FIND_REGISTRY,
+    ERROR_CREATE_HIVE,
+    ERROR_INITIALIZE_REGISTRY,
+    ERROR_INVALID_CABINET_INF,
+    ERROR_CABINET_MISSING,
+    ERROR_CABINET_SCRIPT,
+    ERROR_COPY_QUEUE,
+    ERROR_CREATE_DIR,
+    ERROR_TXTSETUP_SECTION,
+    ERROR_CABINET_SECTION,
+    ERROR_CREATE_INSTALL_DIR,
+    ERROR_FIND_SETUPDATA,
+    ERROR_WRITE_PTABLE,
+    ERROR_ADDING_CODEPAGE,
+    ERROR_UPDATE_LOCALESETTINGS,
+    ERROR_ADDING_KBLAYOUTS,
+    ERROR_UPDATE_GEOID,
+    ERROR_DIRECTORY_NAME,
+    ERROR_INSUFFICIENT_PARTITION_SIZE,
+    ERROR_PARTITION_TABLE_FULL,
+    ERROR_ONLY_ONE_EXTENDED,
+    ERROR_FORMATTING_PARTITION,
+
+    ERROR_LAST_ERROR_CODE
+} ERROR_NUMBER;
+
+/* EOF */
diff --git a/base/setup/lib/fsutil.c b/base/setup/lib/fsutil.c
new file mode 100644 (file)
index 0000000..468fed9
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+ * PROJECT:     ReactOS Setup Library
+ * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE:     Filesystem support functions
+ * COPYRIGHT:   Copyright 2002-2018 Eric Kohl
+ *              Copyright 2003-2018 Casper S. Hornstrup (chorns@users.sourceforge.net)
+ *              Copyright 2017-2018 Hermes Belusca-Maito
+ */
+
+//
+// This is basically the code for listing available FileSystem providers
+// (currently hardcoded in a list), and for performing a basic FileSystem
+// recognition for a given disk partition.
+//
+// See also: https://git.reactos.org/?p=reactos.git;a=blob;f=reactos/dll/win32/fmifs/init.c;h=e895f5ef9cae4806123f6bbdd3dfed37ec1c8d33;hb=b9db9a4e377a2055f635b2fb69fef4e1750d219c
+// for how to get FS providers in a dynamic way. In the (near) future we may
+// consider merging some of this code with us into a fmifs / fsutil / fslib library...
+//
+
+/* INCLUDES *****************************************************************/
+
+#include "precomp.h"
+
+#include "fsutil.h"
+#include "partlist.h"
+
+/** For FileSystems **/
+#include <fslib/vfatlib.h>
+#include <fslib/ext2lib.h>
+// #include <fslib/ntfslib.h>
+
+#define NDEBUG
+#include <debug.h>
+
+
+
+FILE_SYSTEM RegisteredFileSystems[] =
+{
+    { L"FAT"  , VfatFormat, VfatChkdsk },
+//  { L"FAT32", VfatFormat, VfatChkdsk },
+#if 0
+    { L"EXT2" , Ext2Format, Ext2Chkdsk },
+    { L"NTFS" , NtfsFormat, NtfsChkdsk }
+#endif
+};
+
+
+/* FUNCTIONS ****************************************************************/
+
+PFILE_SYSTEM
+GetRegisteredFileSystems(OUT PULONG Count)
+{
+    *Count = ARRAYSIZE(RegisteredFileSystems);
+    return RegisteredFileSystems;
+}
+
+PFILE_SYSTEM
+GetFileSystemByName(
+    // IN PFILE_SYSTEM_LIST List,
+    IN PCWSTR FileSystemName)
+{
+#if 0 // Reenable when the list of registered FSes will again be dynamic
+
+    PLIST_ENTRY ListEntry;
+    PFILE_SYSTEM_ITEM Item;
+
+    ListEntry = List->ListHead.Flink;
+    while (ListEntry != &List->ListHead)
+    {
+        Item = CONTAINING_RECORD(ListEntry, FILE_SYSTEM_ITEM, ListEntry);
+        if (Item->FileSystemName && wcsicmp(FileSystemName, Item->FileSystemName) == 0)
+            return Item;
+
+        ListEntry = ListEntry->Flink;
+    }
+
+#else
+
+    ULONG Count;
+    PFILE_SYSTEM FileSystems;
+
+    FileSystems = GetRegisteredFileSystems(&Count);
+    if (!FileSystems || Count == 0)
+        return NULL;
+
+    while (Count--)
+    {
+        if (FileSystems->FileSystemName && wcsicmp(FileSystemName, FileSystems->FileSystemName) == 0)
+            return FileSystems;
+
+        ++FileSystems;
+    }
+
+#endif
+
+    return NULL;
+}
+
+
+//
+// FileSystem recognition (using NT OS functionality)
+//
+
+#if 0 // FIXME: To be fully enabled when our storage stack & al. will work better!
+
+/* NOTE: Ripped & adapted from base/system/autochk/autochk.c */
+static NTSTATUS
+_MyGetFileSystem(
+    IN struct _PARTENTRY* PartEntry,
+    IN OUT PWSTR FileSystemName,
+    IN SIZE_T FileSystemNameSize)
+{
+    NTSTATUS Status;
+    HANDLE FileHandle;
+    IO_STATUS_BLOCK IoStatusBlock;
+    PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttribute;
+    UCHAR Buffer[sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + MAX_PATH * sizeof(WCHAR)];
+
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    UNICODE_STRING PartitionRootPath;
+    WCHAR PathBuffer[MAX_PATH];
+
+    FileFsAttribute = (PFILE_FS_ATTRIBUTE_INFORMATION)Buffer;
+
+    /* Set PartitionRootPath */
+    swprintf(PathBuffer,
+             // L"\\Device\\Harddisk%lu\\Partition%lu", // Should work! But because ReactOS sucks atm. it actually doesn't work!!
+             L"\\Device\\Harddisk%lu\\Partition%lu\\",  // HACK: Use this as a temporary hack!
+             PartEntry->DiskEntry->DiskNumber,
+             PartEntry->PartitionNumber);
+    RtlInitUnicodeString(&PartitionRootPath, PathBuffer);
+    DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath);
+
+    /* Open the partition */
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &PartitionRootPath,
+                               OBJ_CASE_INSENSITIVE,
+                               NULL,
+                               NULL);
+    Status = NtOpenFile(&FileHandle, // PartitionHandle,
+                        FILE_GENERIC_READ /* | SYNCHRONIZE */,
+                        &ObjectAttributes,
+                        &IoStatusBlock,
+                        FILE_SHARE_READ,
+                        0 /* FILE_SYNCHRONOUS_IO_NONALERT */);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to open partition %wZ, Status 0x%08lx\n", &PartitionRootPath, Status);
+        return Status;
+    }
+
+    /* Retrieve the FS attributes */
+    Status = NtQueryVolumeInformationFile(FileHandle,
+                                          &IoStatusBlock,
+                                          FileFsAttribute,
+                                          sizeof(Buffer),
+                                          FileFsAttributeInformation);
+    NtClose(FileHandle);
+
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("NtQueryVolumeInformationFile failed for partition %wZ, Status 0x%08lx\n", &PartitionRootPath, Status);
+        return Status;
+    }
+
+    if (FileSystemNameSize * sizeof(WCHAR) < FileFsAttribute->FileSystemNameLength + sizeof(WCHAR))
+        return STATUS_BUFFER_TOO_SMALL;
+
+    RtlCopyMemory(FileSystemName,
+                  FileFsAttribute->FileSystemName,
+                  FileFsAttribute->FileSystemNameLength);
+    FileSystemName[FileFsAttribute->FileSystemNameLength / sizeof(WCHAR)] = UNICODE_NULL;
+
+    return STATUS_SUCCESS;
+}
+
+#endif
+
+PFILE_SYSTEM
+GetFileSystem(
+    // IN PFILE_SYSTEM_LIST FileSystemList,
+    IN struct _PARTENTRY* PartEntry)
+{
+    PFILE_SYSTEM CurrentFileSystem;
+    PWSTR FileSystemName = NULL;
+#if 0 // For code temporarily disabled below
+    NTSTATUS Status;
+    WCHAR FsRecFileSystemName[MAX_PATH];
+#endif
+
+    CurrentFileSystem = PartEntry->FileSystem;
+
+    /* We have a file system, return it */
+    if (CurrentFileSystem != NULL && CurrentFileSystem->FileSystemName != NULL)
+        return CurrentFileSystem;
+
+    DPRINT1("File system not found, try to guess one...\n");
+
+    CurrentFileSystem = NULL;
+
+#if 0 // FIXME: To be fully enabled when our storage stack & al. will work better!
+
+    /*
+     * We don't have one...
+     *
+     * Try to infer one using NT file system recognition.
+     */
+    Status = _MyGetFileSystem(PartEntry, FsRecFileSystemName, ARRAYSIZE(FsRecFileSystemName));
+    if (NT_SUCCESS(Status) && *FsRecFileSystemName)
+    {
+        /* Temporary HACK: map FAT32 back to FAT */
+        if (wcscmp(FsRecFileSystemName, L"FAT32") == 0)
+            wcscpy(FsRecFileSystemName, L"FAT");
+
+        FileSystemName = FsRecFileSystemName;
+        goto Quit;
+    }
+
+#endif
+
+    /*
+     * We don't have one...
+     *
+     * Try to infer a preferred file system for this partition, given its ID.
+     *
+     * WARNING: This is partly a hack, since partitions with the same ID can
+     * be formatted with different file systems: for example, usual Linux
+     * partitions that are formatted in EXT2/3/4, ReiserFS, etc... have the
+     * same partition ID 0x83.
+     *
+     * The proper fix is to make a function that detects the existing FS
+     * from a given partition (not based on the partition ID).
+     * On the contrary, for unformatted partitions with a given ID, the
+     * following code is OK.
+     */
+    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))
+    {
+        FileSystemName = L"FAT";
+    }
+    else if (PartEntry->PartitionType == PARTITION_EXT2)
+    {
+        // WARNING: See the warning above.
+        FileSystemName = L"EXT2";
+    }
+    else if (PartEntry->PartitionType == PARTITION_IFS)
+    {
+        // WARNING: See the warning above.
+        FileSystemName = L"NTFS"; /* FIXME: Not quite correct! */
+    }
+
+#if 0
+Quit: // For code temporarily disabled above
+#endif
+
+    // HACK: WARNING: We cannot write on this FS yet!
+    if (FileSystemName)
+    {
+        if (PartEntry->PartitionType == PARTITION_EXT2 || PartEntry->PartitionType == PARTITION_IFS)
+            DPRINT1("Recognized file system %S that doesn't support write support yet!\n", FileSystemName);
+    }
+
+    DPRINT1("GetFileSystem -- PartitionType: 0x%02X ; FileSystemName (guessed): %S\n",
+            PartEntry->PartitionType, FileSystemName ? FileSystemName : L"None");
+
+    if (FileSystemName != NULL)
+        CurrentFileSystem = GetFileSystemByName(/*FileSystemList,*/ FileSystemName);
+
+    return CurrentFileSystem;
+}
+
+/* EOF */
diff --git a/base/setup/lib/fsutil.h b/base/setup/lib/fsutil.h
new file mode 100644 (file)
index 0000000..9d6d4a0
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * PROJECT:     ReactOS Setup Library
+ * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE:     Filesystem support functions
+ * COPYRIGHT:   Copyright 2002-2018 Eric Kohl
+ *              Copyright 2003-2018 Casper S. Hornstrup (chorns@users.sourceforge.net)
+ *              Copyright 2017-2018 Hermes Belusca-Maito
+ */
+
+#include <fmifs/fmifs.h>
+
+typedef struct _FILE_SYSTEM
+{
+    PCWSTR FileSystemName;
+    FORMATEX FormatFunc;
+    CHKDSKEX ChkdskFunc;
+} FILE_SYSTEM, *PFILE_SYSTEM;
+
+PFILE_SYSTEM
+GetRegisteredFileSystems(OUT PULONG Count);
+
+PFILE_SYSTEM
+GetFileSystemByName(
+    // IN PFILE_SYSTEM_LIST List,
+    IN PCWSTR FileSystemName);
+
+struct _PARTENTRY; // Defined in partlist.h
+
+PFILE_SYSTEM
+GetFileSystem(
+    // IN PFILE_SYSTEM_LIST FileSystemList,
+    IN struct _PARTENTRY* PartEntry);
+
+/* EOF */
diff --git a/base/setup/lib/genlist.c b/base/setup/lib/genlist.c
new file mode 100644 (file)
index 0000000..dc09ac0
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * PROJECT:     ReactOS Setup Library
+ * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE:     Generic list functions
+ * COPYRIGHT:   Copyright 2004-2018 Eric Kohl
+ *              Copyright 2008-2018 Christoph von Wittich <christoph at reactos.org>
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include "precomp.h"
+
+#include "genlist.h"
+
+#define NDEBUG
+#include <debug.h>
+
+/* FUNCTIONS ****************************************************************/
+
+PGENERIC_LIST
+CreateGenericList(VOID)
+{
+    PGENERIC_LIST List;
+
+    List = (PGENERIC_LIST)RtlAllocateHeap(ProcessHeap,
+                                          0,
+                                          sizeof(GENERIC_LIST));
+    if (List == NULL)
+        return NULL;
+
+    InitializeListHead(&List->ListHead);
+    List->NumOfEntries = 0;
+
+    List->CurrentEntry = NULL;
+    List->BackupEntry = NULL;
+
+    return List;
+}
+
+VOID
+DestroyGenericList(
+    IN OUT PGENERIC_LIST List,
+    IN BOOLEAN FreeUserData)
+{
+    PGENERIC_LIST_ENTRY ListEntry;
+    PLIST_ENTRY Entry;
+
+    /* Release list entries */
+    while (!IsListEmpty(&List->ListHead))
+    {
+        Entry = RemoveHeadList(&List->ListHead);
+        ListEntry = CONTAINING_RECORD(Entry, GENERIC_LIST_ENTRY, Entry);
+
+        /* Release user data */
+        if (FreeUserData && ListEntry->UserData != NULL)
+            RtlFreeHeap(ProcessHeap, 0, ListEntry->UserData);
+
+        /* Release list entry */
+        RtlFreeHeap(ProcessHeap, 0, ListEntry);
+    }
+
+    /* Release list head */
+    RtlFreeHeap(ProcessHeap, 0, List);
+}
+
+BOOLEAN
+AppendGenericListEntry(
+    IN OUT PGENERIC_LIST List,
+    IN PCHAR Text,
+    IN PVOID UserData,
+    IN BOOLEAN Current)
+{
+    PGENERIC_LIST_ENTRY Entry;
+
+    Entry = (PGENERIC_LIST_ENTRY)RtlAllocateHeap(ProcessHeap,
+                                                 0,
+                                                 sizeof(GENERIC_LIST_ENTRY) + strlen(Text));
+    if (Entry == NULL)
+        return FALSE;
+
+    strcpy (Entry->Text, Text);
+    Entry->List = List;
+    Entry->UserData = UserData;
+
+    InsertTailList(&List->ListHead, &Entry->Entry);
+    List->NumOfEntries++;
+
+    if (Current || List->CurrentEntry == NULL)
+    {
+        List->CurrentEntry = Entry;
+    }
+
+    return TRUE;
+}
+
+VOID
+SetCurrentListEntry(
+    IN PGENERIC_LIST List,
+    IN PGENERIC_LIST_ENTRY Entry)
+{
+    if (Entry->List != List)
+        return;
+    List->CurrentEntry = Entry;
+}
+
+PGENERIC_LIST_ENTRY
+GetCurrentListEntry(
+    IN PGENERIC_LIST List)
+{
+    return List->CurrentEntry;
+}
+
+PGENERIC_LIST_ENTRY
+GetFirstListEntry(
+    IN PGENERIC_LIST List)
+{
+    PLIST_ENTRY Entry = List->ListHead.Flink;
+
+    if (Entry == &List->ListHead)
+        return NULL;
+    return CONTAINING_RECORD(Entry, GENERIC_LIST_ENTRY, Entry);
+}
+
+PGENERIC_LIST_ENTRY
+GetNextListEntry(
+    IN PGENERIC_LIST_ENTRY Entry)
+{
+    PLIST_ENTRY Next = Entry->Entry.Flink;
+
+    if (Next == &Entry->List->ListHead)
+        return NULL;
+    return CONTAINING_RECORD(Next, GENERIC_LIST_ENTRY, Entry);
+}
+
+PVOID
+GetListEntryUserData(
+    IN PGENERIC_LIST_ENTRY Entry)
+{
+    return Entry->UserData;
+}
+
+LPCSTR
+GetListEntryText(
+    IN PGENERIC_LIST_ENTRY Entry)
+{
+    return Entry->Text;
+}
+
+ULONG
+GetNumberOfListEntries(
+    IN PGENERIC_LIST List)
+{
+    return List->NumOfEntries;
+}
+
+VOID
+SaveGenericListState(
+    IN PGENERIC_LIST List)
+{
+    List->BackupEntry = List->CurrentEntry;
+}
+
+VOID
+RestoreGenericListState(
+    IN PGENERIC_LIST List)
+{
+    List->CurrentEntry = List->BackupEntry;
+}
+
+BOOLEAN
+GenericListHasSingleEntry(
+    IN PGENERIC_LIST List)
+{
+    if (!IsListEmpty(&List->ListHead) && List->ListHead.Flink == List->ListHead.Blink)
+        return TRUE;
+
+    /* if both list head pointers (which normally point to the first and last list member, respectively)
+       point to the same entry then it means that there's just a single thing in there, otherwise... false! */
+    return FALSE;
+}
+
+/* EOF */
diff --git a/base/setup/lib/genlist.h b/base/setup/lib/genlist.h
new file mode 100644 (file)
index 0000000..9623d3a
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * PROJECT:     ReactOS Setup Library
+ * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE:     Generic list functions
+ * COPYRIGHT:   Copyright 2004-2018 Eric Kohl
+ *              Copyright 2008-2018 Christoph von Wittich <christoph at reactos.org>
+ */
+
+#pragma once
+
+typedef struct _GENERIC_LIST_ENTRY
+{
+    LIST_ENTRY Entry;
+    struct _GENERIC_LIST* List;
+    PVOID UserData;
+    CHAR Text[1];       // FIXME: UI stuff
+
+} GENERIC_LIST_ENTRY, *PGENERIC_LIST_ENTRY;
+
+typedef struct _GENERIC_LIST
+{
+    LIST_ENTRY ListHead;
+    ULONG NumOfEntries;
+
+    PGENERIC_LIST_ENTRY CurrentEntry;
+    PGENERIC_LIST_ENTRY BackupEntry;
+
+} GENERIC_LIST, *PGENERIC_LIST;
+
+
+PGENERIC_LIST
+CreateGenericList(VOID);
+
+VOID
+DestroyGenericList(
+    IN OUT PGENERIC_LIST List,
+    IN BOOLEAN FreeUserData);
+
+BOOLEAN
+AppendGenericListEntry(
+    IN OUT PGENERIC_LIST List,
+    IN PCHAR Text,
+    IN PVOID UserData,
+    IN BOOLEAN Current);
+
+VOID
+SetCurrentListEntry(
+    IN PGENERIC_LIST List,
+    IN PGENERIC_LIST_ENTRY Entry);
+
+PGENERIC_LIST_ENTRY
+GetCurrentListEntry(
+    IN PGENERIC_LIST List);
+
+PGENERIC_LIST_ENTRY
+GetFirstListEntry(
+    IN PGENERIC_LIST List);
+
+PGENERIC_LIST_ENTRY
+GetNextListEntry(
+    IN PGENERIC_LIST_ENTRY Entry);
+
+PVOID
+GetListEntryUserData(
+    IN PGENERIC_LIST_ENTRY Entry);
+
+LPCSTR
+GetListEntryText(
+    IN PGENERIC_LIST_ENTRY Entry);
+
+ULONG
+GetNumberOfListEntries(
+    IN PGENERIC_LIST List);
+
+VOID
+SaveGenericListState(
+    IN PGENERIC_LIST List);
+
+VOID
+RestoreGenericListState(
+    IN PGENERIC_LIST List);
+
+BOOLEAN
+GenericListHasSingleEntry(
+    IN PGENERIC_LIST List);
+
+/* EOF */
diff --git a/base/setup/lib/linklist.h b/base/setup/lib/linklist.h
new file mode 100644 (file)
index 0000000..37f837c
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * PROJECT:     ReactOS Setup Library
+ * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE:     Linked list support macros
+ * COPYRIGHT:   Copyright 2005-2018 ReactOS Team
+ */
+
+#pragma once
+
+#define InsertAscendingList(ListHead, NewEntry, Type, ListEntryField, SortField) \
+do { \
+    PLIST_ENTRY current = (ListHead)->Flink; \
+    while (current != (ListHead)) \
+    { \
+        if (CONTAINING_RECORD(current, Type, ListEntryField)->SortField >= \
+            (NewEntry)->SortField) \
+        { \
+            break; \
+        } \
+        current = current->Flink; \
+    } \
+\
+    InsertTailList(current, &((NewEntry)->ListEntryField)); \
+} while (0)
+
+/* EOF */
diff --git a/base/setup/lib/partlist.c b/base/setup/lib/partlist.c
new file mode 100644 (file)
index 0000000..40661b0
--- /dev/null
@@ -0,0 +1,3056 @@
+/*
+ * PROJECT:     ReactOS Setup Library
+ * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE:     Partition list functions
+ * COPYRIGHT:   Copyright 2002-2018 Eric Kohl
+ *              Copyright 2003-2018 Casper S. Hornstrup (chorns@users.sourceforge.net)
+ */
+
+#include "precomp.h"
+#include <ntddscsi.h>
+
+#include "partlist.h"
+#include "fsutil.h"
+
+#define NDEBUG
+#include <debug.h>
+
+//#define DUMP_PARTITION_TABLE
+
+#include <pshpack1.h>
+
+typedef struct _REG_DISK_MOUNT_INFO
+{
+    ULONG Signature;
+    LARGE_INTEGER StartingOffset;
+} REG_DISK_MOUNT_INFO, *PREG_DISK_MOUNT_INFO;
+
+#include <poppack.h>
+
+
+/* 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);
+}
+
+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;
+}
+
+static
+BOOLEAN
+IsEmptyLayoutEntry(
+    IN PPARTITION_INFORMATION PartitionInfo)
+{
+    if (PartitionInfo->StartingOffset.QuadPart == 0 &&
+        PartitionInfo->PartitionLength.QuadPart == 0)
+    {
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+static
+BOOLEAN
+IsSamePrimaryLayoutEntry(
+    IN PPARTITION_INFORMATION PartitionInfo,
+    IN PDISKENTRY DiskEntry,
+    IN PPARTENTRY PartEntry)
+{
+    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;
+    }
+
+    return FALSE;
+}
+
+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)
+            Count++;
+
+        Entry = Entry->Flink;
+    }
+
+    return Count;
+}
+
+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)
+{
+    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;
+    }
+
+    /* 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;
+}
+
+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)
+    {
+        DPRINT("ReAllocateLayoutBuffer() failed.\n");
+        return;
+    }
+
+    /* Update the primary partition table */
+    Index = 0;
+    ListEntry = DiskEntry->PrimaryPartListHead.Flink;
+    while (ListEntry != &DiskEntry->PrimaryPartListHead)
+    {
+        PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
+
+        if (PartEntry->IsPartitioned != FALSE)
+        {
+            PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
+
+            if (!IsSamePrimaryLayoutEntry(PartitionInfo, DiskEntry, PartEntry))
+            {
+                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;
+    }
+
+    /* Update the logical partition table */
+    Index = 4;
+    ListEntry = DiskEntry->LogicalPartListHead.Flink;
+    while (ListEntry != &DiskEntry->LogicalPartListHead)
+    {
+        PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
+
+        if (PartEntry->IsPartitioned)
+        {
+            PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
+
+            DPRINT1("Updating logical partition entry %lu\n", Index);
+
+            PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
+            PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
+            PartitionInfo->HiddenSectors = DiskEntry->SectorAlignment;
+            PartitionInfo->PartitionNumber = PartitionNumber;
+            PartitionInfo->PartitionType = PartEntry->PartitionType;
+            PartitionInfo->BootIndicator = FALSE;
+            PartitionInfo->RecognizedPartition = FALSE;
+            PartitionInfo->RewritePartition = TRUE;
+
+            PartEntry->PartitionNumber = PartitionNumber;
+            PartEntry->PartitionIndex = Index;
+
+            /* Fill the link entry of the previous partition entry */
+            if (LinkInfo != NULL)
+            {
+                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;
+        }
+
+        ListEntry = ListEntry->Flink;
+    }
+
+    /* Wipe unused primary partition entries */
+    for (Index = GetPrimaryPartitionCount(DiskEntry); Index < 4; Index++)
+    {
+        DPRINT1("Primary partition entry %lu\n", Index);
+
+        PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
+
+        if (!IsEmptyLayoutEntry(PartitionInfo))
+        {
+            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;
+        }
+    }
+
+    /* Wipe unused logical partition entries */
+    for (Index = 4; Index < DiskEntry->LayoutBuffer->PartitionCount; Index++)
+    {
+        if (Index % 4 >= 2)
+        {
+            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;
+            }
+        }
+    }
+
+#ifdef DUMP_PARTITION_TABLE
+    DumpPartitionTable(DiskEntry);
+#endif
+}
+
+static
+PPARTENTRY
+GetPrevUnpartitionedEntry(
+    IN PDISKENTRY DiskEntry,
+    IN PPARTENTRY PartEntry)
+{
+    PPARTENTRY PrevPartEntry;
+    PLIST_ENTRY ListHead;
+
+    if (PartEntry->LogicalPartition)
+        ListHead = &DiskEntry->LogicalPartListHead;
+    else
+        ListHead = &DiskEntry->PrimaryPartListHead;
+
+    if (PartEntry->ListEntry.Blink != ListHead)
+    {
+        PrevPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Blink,
+                                          PARTENTRY,
+                                          ListEntry);
+        if (PrevPartEntry->IsPartitioned == FALSE)
+            return PrevPartEntry;
+    }
+
+    return NULL;
+}
+
+static
+PPARTENTRY
+GetNextUnpartitionedEntry(
+    IN PDISKENTRY DiskEntry,
+    IN PPARTENTRY PartEntry)
+{
+    PPARTENTRY NextPartEntry;
+    PLIST_ENTRY ListHead;
+
+    if (PartEntry->LogicalPartition)
+        ListHead = &DiskEntry->LogicalPartListHead;
+    else
+        ListHead = &DiskEntry->PrimaryPartListHead;
+
+    if (PartEntry->ListEntry.Flink != ListHead)
+    {
+        NextPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Flink,
+                                          PARTENTRY,
+                                          ListEntry);
+        if (NextPartEntry->IsPartitioned == FALSE)
+            return NextPartEntry;
+    }
+
+    return NULL;
+}
+
+VOID
+CreatePrimaryPartition(
+    IN PPARTLIST List,
+    IN ULONGLONG SectorCount,
+    IN BOOLEAN AutoCreate)
+{
+    PDISKENTRY DiskEntry;
+    PPARTENTRY PartEntry;
+    PPARTENTRY NewPartEntry;
+
+    DPRINT1("CreatePrimaryPartition(%I64u)\n", SectorCount);
+
+    if (List == NULL ||
+        List->CurrentDisk == NULL ||
+        List->CurrentPartition == NULL ||
+        List->CurrentPartition->IsPartitioned != FALSE)
+    {
+        return;
+    }
+
+    DiskEntry = List->CurrentDisk;
+    PartEntry = List->CurrentPartition;
+
+    DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
+
+    if ((AutoCreate != FALSE) ||
+        (AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart))
+    {
+        DPRINT1("Convert existing partition entry\n");
+
+        /* Convert current entry to 'new (unformatted)' */
+        PartEntry->IsPartitioned = TRUE;
+        PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
+        PartEntry->FormatState = Unformatted;
+        PartEntry->FileSystem  = NULL;
+        PartEntry->AutoCreate = AutoCreate;
+        PartEntry->New = TRUE;
+        PartEntry->BootIndicator = FALSE;
+
+        DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
+        DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
+        DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
+    }
+    else
+    {
+        DPRINT1("Add new partition entry\n");
+
+        /* Insert and initialize a new partition entry */
+        NewPartEntry = RtlAllocateHeap(ProcessHeap,
+                                       HEAP_ZERO_MEMORY,
+                                       sizeof(PARTENTRY));
+        if (NewPartEntry == NULL)
+            return;
+
+        /* Insert the new entry into the list */
+        InsertTailList(&PartEntry->ListEntry,
+                       &NewPartEntry->ListEntry);
+
+        NewPartEntry->DiskEntry = DiskEntry;
+
+        NewPartEntry->IsPartitioned = TRUE;
+        NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
+        NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
+                                             NewPartEntry->StartSector.QuadPart;
+        NewPartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
+
+        DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
+        DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
+        DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
+
+        NewPartEntry->New = TRUE;
+        NewPartEntry->FormatState = Unformatted;
+        NewPartEntry->FileSystem  = NULL;
+        NewPartEntry->BootIndicator = FALSE;
+
+        PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
+        PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
+    }
+
+    UpdateDiskLayout(DiskEntry);
+
+    DiskEntry->Dirty = TRUE;
+
+    AssignDriveLetters(List);
+}
+
+static
+VOID
+AddLogicalDiskSpace(
+    IN PDISKENTRY DiskEntry)
+{
+    PPARTENTRY NewPartEntry;
+
+    DPRINT1("AddLogicalDiskSpace()\n");
+
+    /* Create a partition entry that represents the empty space in the container partition */
+    NewPartEntry = RtlAllocateHeap(ProcessHeap,
+                                   HEAP_ZERO_MEMORY,
+                                   sizeof(PARTENTRY));
+    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);
+}
+
+VOID
+CreateExtendedPartition(
+    IN PPARTLIST List,
+    IN ULONGLONG SectorCount)
+{
+    PDISKENTRY DiskEntry;
+    PPARTENTRY PartEntry;
+    PPARTENTRY NewPartEntry;
+
+    DPRINT1("CreateExtendedPartition(%I64u)\n", SectorCount);
+
+    if (List == NULL ||
+        List->CurrentDisk == NULL ||
+        List->CurrentPartition == NULL ||
+        List->CurrentPartition->IsPartitioned != FALSE)
+    {
+        return;
+    }
+
+    DiskEntry = List->CurrentDisk;
+    PartEntry = List->CurrentPartition;
+
+    DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
+
+    if (AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart)
+    {
+        DPRINT1("Convert existing partition entry\n");
+
+        /* Convert current entry to 'new (unformatted)' */
+        PartEntry->IsPartitioned = TRUE;
+        PartEntry->FormatState = Formatted;     // FIXME? Possibly to make GetNextUnformattedPartition work (i.e. skip the extended partition container)
+        PartEntry->FileSystem  = NULL;
+        PartEntry->AutoCreate = FALSE;
+        PartEntry->New = FALSE;
+        PartEntry->BootIndicator = FALSE;
+
+        if (PartEntry->StartSector.QuadPart < 1450560)
+        {
+            /* Partition starts below the 8.4GB boundary ==> CHS partition */
+            PartEntry->PartitionType = PARTITION_EXTENDED;
+        }
+        else
+        {
+            /* Partition starts above the 8.4GB boundary ==> LBA partition */
+            PartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
+        }
+
+        DiskEntry->ExtendedPartition = PartEntry;
+
+        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");
+
+        /* Insert and initialize a new partition entry */
+        NewPartEntry = RtlAllocateHeap(ProcessHeap,
+                                       HEAP_ZERO_MEMORY,
+                                       sizeof(PARTENTRY));
+        if (NewPartEntry == NULL)
+            return;
+
+        /* Insert the new entry into the list */
+        InsertTailList(&PartEntry->ListEntry,
+                       &NewPartEntry->ListEntry);
+
+        NewPartEntry->DiskEntry = DiskEntry;
+
+        NewPartEntry->IsPartitioned = TRUE;
+        NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
+        NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
+                                             NewPartEntry->StartSector.QuadPart;
+
+        NewPartEntry->New = FALSE;
+        NewPartEntry->FormatState = Formatted;     // FIXME? Possibly to make GetNextUnformattedPartition work (i.e. skip the extended partition container)
+        NewPartEntry->FileSystem  = NULL;
+        NewPartEntry->BootIndicator = FALSE;
+
+        if (NewPartEntry->StartSector.QuadPart < 1450560)
+        {
+            /* Partition starts below the 8.4GB boundary ==> CHS partition */
+            NewPartEntry->PartitionType = PARTITION_EXTENDED;
+        }
+        else
+        {
+            /* Partition starts above the 8.4GB boundary ==> LBA partition */
+            NewPartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
+        }
+
+        DiskEntry->ExtendedPartition = NewPartEntry;
+
+        PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
+        PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
+
+        DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
+        DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
+        DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
+    }
+
+    AddLogicalDiskSpace(DiskEntry);
+
+    UpdateDiskLayout(DiskEntry);
+
+    DiskEntry->Dirty = TRUE;
+
+    AssignDriveLetters(List);
+}
+
+VOID
+CreateLogicalPartition(
+    IN PPARTLIST List,
+    IN ULONGLONG SectorCount,
+    IN BOOLEAN AutoCreate)
+{
+    PDISKENTRY DiskEntry;
+    PPARTENTRY PartEntry;
+    PPARTENTRY NewPartEntry;
+
+    DPRINT1("CreateLogicalPartition(%I64u)\n", SectorCount);
+
+    if (List == NULL ||
+        List->CurrentDisk == NULL ||
+        List->CurrentPartition == NULL ||
+        List->CurrentPartition->IsPartitioned != FALSE)
+    {
+        return;
+    }
+
+    DiskEntry = List->CurrentDisk;
+    PartEntry = List->CurrentPartition;
+
+    DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
+
+    if ((AutoCreate != FALSE) ||
+        (AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart))
+    {
+        DPRINT1("Convert existing partition entry\n");
+
+        /* Convert current entry to 'new (unformatted)' */
+        PartEntry->IsPartitioned = TRUE;
+        PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
+        PartEntry->FormatState = Unformatted;
+        PartEntry->FileSystem  = NULL;
+        PartEntry->AutoCreate = 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");
+
+        /* Insert and initialize a new partition entry */
+        NewPartEntry = RtlAllocateHeap(ProcessHeap,
+                                       HEAP_ZERO_MEMORY,
+                                       sizeof(PARTENTRY));
+        if (NewPartEntry == NULL)
+            return;
+
+        /* Insert the new entry into the list */
+        InsertTailList(&PartEntry->ListEntry,
+                       &NewPartEntry->ListEntry);
+
+        NewPartEntry->DiskEntry = DiskEntry;
+
+        NewPartEntry->IsPartitioned = TRUE;
+        NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
+        NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
+                                             NewPartEntry->StartSector.QuadPart;
+        NewPartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
+
+        DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
+        DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
+        DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
+
+        NewPartEntry->New = TRUE;
+        NewPartEntry->FormatState = Unformatted;
+        NewPartEntry->FileSystem  = NULL;
+        NewPartEntry->BootIndicator = FALSE;
+        NewPartEntry->LogicalPartition = TRUE;
+
+        PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
+        PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
+    }
+
+    UpdateDiskLayout(DiskEntry);
+
+    DiskEntry->Dirty = TRUE;
+
+    AssignDriveLetters(List);
+}
+
+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)
+    {
+        return;
+    }
+
+    /* Clear the system disk and partition pointers if the system partition is being deleted */
+    if (List->SystemPartition == List->CurrentPartition)
+    {
+        List->SystemPartition = NULL;
+    }
+
+    DiskEntry = List->CurrentDisk;
+    PartEntry = List->CurrentPartition;
+
+    /* Delete all logical partition entries if an extended partition will be deleted */
+    if (DiskEntry->ExtendedPartition == PartEntry)
+    {
+        while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
+        {
+            Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
+            LogicalPartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
+
+            RtlFreeHeap(ProcessHeap, 0, LogicalPartEntry);
+        }
+
+        DiskEntry->ExtendedPartition = NULL;
+    }
+
+    /* 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->SectorCount.QuadPart += (PartEntry->SectorCount.QuadPart + NextPartEntry->SectorCount.QuadPart);
+
+        /* 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->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
+
+        /* 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->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
+        NextPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
+
+        /* 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->IsPartitioned = FALSE;
+        PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
+        PartEntry->FormatState = Unformatted;
+        PartEntry->FileSystem  = NULL;
+        PartEntry->DriveLetter = 0;
+    }
+
+    UpdateDiskLayout(DiskEntry);
+
+    DiskEntry->Dirty = TRUE;
+
+    AssignDriveLetters(List);
+}
+
+VOID
+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 ListEntry;
+
+    PFILE_SYSTEM FileSystem;
+
+    /* Check for empty disk list */
+    if (IsListEmpty(&List->DiskListHead))
+    {
+        List->SystemPartition = NULL;
+        List->OriginalSystemPartition = NULL;
+        return;
+    }
+
+    /* Choose the currently selected disk */
+    DiskEntry = List->CurrentDisk;
+
+    /* Check for empty partition list */
+    if (IsListEmpty(&DiskEntry->PrimaryPartListHead))
+    {
+        List->SystemPartition = NULL;
+        List->OriginalSystemPartition = NULL;
+        return;
+    }
+
+    if (List->SystemPartition != NULL)
+    {
+        /* We already have an active system partition */
+        DPRINT1("Use the current system partition %lu in disk %lu, drive letter %c\n",
+                List->SystemPartition->PartitionNumber,
+                List->SystemPartition->DiskEntry->DiskNumber,
+                (List->SystemPartition->DriveLetter == 0) ? '-' : List->SystemPartition->DriveLetter);
+        return;
+    }
+
+    DPRINT1("We are here (1)!\n");
+
+    List->SystemPartition = NULL;
+    List->OriginalSystemPartition = NULL;
+
+    /* Retrieve the first partition of the disk */
+    PartEntry = CONTAINING_RECORD(DiskEntry->PrimaryPartListHead.Flink,
+                                  PARTENTRY,
+                                  ListEntry);
+    ASSERT(DiskEntry == PartEntry->DiskEntry);
+    List->SystemPartition = PartEntry;
+
+    //
+    // See: https://svn.reactos.org/svn/reactos/trunk/reactos/base/setup/usetup/partlist.c?r1=63355&r2=63354&pathrev=63355#l2318
+    //
+
+    /* 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;
+
+            List->OriginalSystemPartition = List->SystemPartition;
+
+            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);
+
+            goto SetSystemPartition;
+        }
+
+        // FIXME: What to do??
+        DPRINT1("NewDisk TRUE but first partition is used?\n");
+    }
+
+    DPRINT1("We are here (2)!\n");
+
+    /*
+     * The disk is not new, check if any partition is initialized;
+     * if not, the first one becomes the system partition.
+     */
+    ListEntry = DiskEntry->PrimaryPartListHead.Flink;
+    while (ListEntry != &DiskEntry->PrimaryPartListHead)
+    {
+        /* Retrieve the partition and go to the next one */
+        PartEntry = CONTAINING_RECORD(ListEntry,
+                                      PARTENTRY,
+                                      ListEntry);
+
+        /* Check if the partition is partitioned and is used */
+        if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED || PartEntry->BootIndicator != FALSE)
+        {
+            break;
+        }
+
+        /* Go to the next one */
+        ListEntry = ListEntry->Flink;
+    }
+    if (ListEntry == &DiskEntry->PrimaryPartListHead)
+    {
+        /*
+         * OK we haven't encountered any used and active partition,
+         * so use the first one as the system partition.
+         */
+        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;
+    }
+
+    List->SystemPartition = NULL;
+    List->OriginalSystemPartition = NULL;
+
+    DPRINT1("We are here (3)!\n");
+
+    /* The disk is not new, scan all partitions to find the (active) system partition */
+    ListEntry = DiskEntry->PrimaryPartListHead.Flink;
+    while (ListEntry != &DiskEntry->PrimaryPartListHead)
+    {
+        /* Retrieve the partition and go to the next one */
+        PartEntry = CONTAINING_RECORD(ListEntry,
+                                      PARTENTRY,
+                                      ListEntry);
+        ListEntry = ListEntry->Flink;
+
+        /* Check if the partition is partitioned and used */
+        if (PartEntry->IsPartitioned &&
+            PartEntry->PartitionType != PARTITION_ENTRY_UNUSED)
+        {
+            /* Check if the partition is active */
+            if (PartEntry->BootIndicator)
+            {
+                /* Yes, we found it */
+                ASSERT(DiskEntry == PartEntry->DiskEntry);
+                List->SystemPartition = PartEntry;
+
+                DPRINT1("Found active system partition %lu in disk %lu, drive letter %c\n",
+                        PartEntry->PartitionNumber,
+                        DiskEntry->DiskNumber,
+                        (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter);
+                break;
+            }
+        }
+    }
+
+    /* Check if we have found the system partition */
+    if (List->SystemPartition == NULL)
+    {
+        /* Nothing, use the alternative system partition */
+        DPRINT1("No system partition found, use the alternative partition!\n");
+        goto UseAlternativeSystemPartition;
+    }
+
+    /* Save it */
+    List->OriginalSystemPartition = List->SystemPartition;
+
+    /*
+     * ADDITIONAL CHECKS / BIG HACK:
+     *
+     * Retrieve its file system and check whether we have
+     * write support for it. If that is the case we are fine
+     * and we can use it directly. However if we don't have
+     * write support we will need to change the active system
+     * partition.
+     *
+     * NOTE that this is completely useless on architectures
+     * where a real system partition is required, as on these
+     * architectures the partition uses the FAT FS, for which
+     * we do have write support.
+     * NOTE also that for those architectures looking for a
+     * partition boot indicator is insufficient.
+     */
+    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;
+    }
+
+    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);
+
+    return;
+
+FindAndUseAlternativeSystemPartition:
+    /*
+     * We are here because we have not found any (active) candidate
+     * system partition that we know how to support. What we are going
+     * to do is to change the existing system partition and use the
+     * partition on which we install ReactOS as the new system partition,
+     * and then we will need to add in FreeLdr's entry a boot entry to boot
+     * from the original system partition.
+     */
+
+    /* Unset the old system partition */
+    List->SystemPartition->BootIndicator = FALSE;
+    List->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
+NTSTATUS
+WritePartitions(
+    IN PPARTLIST List,
+    IN PDISKENTRY DiskEntry)
+{
+    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;
+    }
+
+#ifdef DUMP_PARTITION_TABLE
+    DumpPartitionTable(DiskEntry);
+#endif
+
+    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);
+    }
+
+    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).
+    //
+
+    return Status;
+}
+
+BOOLEAN
+WritePartitionsToDisk(
+    IN PPARTLIST List)
+{
+    PLIST_ENTRY Entry;
+    PDISKENTRY DiskEntry;
+
+    if (List == NULL)
+        return TRUE;
+
+    Entry = List->DiskListHead.Flink;
+    while (Entry != &List->DiskListHead)
+    {
+        DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
+
+        if (DiskEntry->Dirty != FALSE)
+        {
+            WritePartitions(List, DiskEntry);
+            DiskEntry->Dirty = FALSE;
+        }
+
+        Entry = Entry->Flink;
+    }
+
+    return TRUE;
+}
+
+BOOLEAN
+SetMountedDeviceValue(
+    IN CHAR Letter,
+    IN ULONG Signature,
+    IN LARGE_INTEGER StartingOffset)
+{
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    WCHAR ValueNameBuffer[16];
+    UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\MountedDevices");
+    UNICODE_STRING ValueName;
+    REG_DISK_MOUNT_INFO MountInfo;
+    NTSTATUS Status;
+    HANDLE KeyHandle;
+
+    swprintf(ValueNameBuffer, L"\\DosDevices\\%C:", Letter);
+    RtlInitUnicodeString(&ValueName, ValueNameBuffer);
+
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &KeyName,
+                               OBJ_CASE_INSENSITIVE,
+                               NULL,
+                               NULL);
+    Status =  NtOpenKey(&KeyHandle,
+                        KEY_ALL_ACCESS,
+                        &ObjectAttributes);
+    if (!NT_SUCCESS(Status))
+    {
+        Status = NtCreateKey(&KeyHandle,
+                             KEY_ALL_ACCESS,
+                             &ObjectAttributes,
+                             0,
+                             NULL,
+                             REG_OPTION_NON_VOLATILE,
+                             NULL);
+    }
+
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
+        return FALSE;
+    }
+
+    MountInfo.Signature = Signature;
+    MountInfo.StartingOffset = StartingOffset;
+    Status = NtSetValueKey(KeyHandle,
+                           &ValueName,
+                           0,
+                           REG_BINARY,
+                           (PVOID)&MountInfo,
+                           sizeof(MountInfo));
+    NtClose(KeyHandle);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+BOOLEAN
+SetMountedDeviceValues(
+    IN PPARTLIST List)
+{
+    PLIST_ENTRY Entry1, Entry2;
+    PDISKENTRY DiskEntry;
+    PPARTENTRY PartEntry;
+    LARGE_INTEGER StartingOffset;
+
+    if (List == NULL)
+        return FALSE;
+
+    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);
+            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;
+                    }
+                }
+            }
+
+            Entry2 = Entry2->Flink;
+        }
+
+        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;
+                    }
+                }
+            }
+
+            Entry2 = Entry2->Flink;
+        }
+
+        Entry1 = Entry1->Flink;
+    }
+
+    return TRUE;
+}
+
+VOID
+SetPartitionType(
+    IN PPARTENTRY PartEntry,
+    IN UCHAR PartitionType)
+{
+    PDISKENTRY DiskEntry = PartEntry->DiskEntry;
+
+    PartEntry->PartitionType = PartitionType;
+
+    DiskEntry->Dirty = TRUE;
+    DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType = PartitionType;
+    DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
+}
+
+ERROR_NUMBER
+PrimaryPartitionCreationChecks(
+    IN PPARTLIST List)
+{
+    PDISKENTRY DiskEntry;
+    PPARTENTRY PartEntry;
+
+    DiskEntry = List->CurrentDisk;
+    PartEntry = List->CurrentPartition;
+
+    /* Fail if the partition is already in use */
+    if (PartEntry->IsPartitioned != FALSE)
+        return ERROR_NEW_PARTITION;
+
+    /* Fail if there are already 4 primary partitions in the list */
+    if (GetPrimaryPartitionCount(DiskEntry) >= 4)
+        return ERROR_PARTITION_TABLE_FULL;
+
+    return ERROR_SUCCESS;
+}
+
+ERROR_NUMBER
+ExtendedPartitionCreationChecks(
+    IN PPARTLIST List)
+{
+    PDISKENTRY DiskEntry;
+    PPARTENTRY PartEntry;
+
+    DiskEntry = List->CurrentDisk;
+    PartEntry = List->CurrentPartition;
+
+    /* Fail if the partition is already in use */
+    if (PartEntry->IsPartitioned != FALSE)
+        return ERROR_NEW_PARTITION;
+
+    /* Fail if there are already 4 primary partitions in the list */
+    if (GetPrimaryPartitionCount(DiskEntry) >= 4)
+        return ERROR_PARTITION_TABLE_FULL;
+
+    /* Fail if there is another extended partition in the list */
+    if (DiskEntry->ExtendedPartition != NULL)
+        return ERROR_ONLY_ONE_EXTENDED;
+
+    return ERROR_SUCCESS;
+}
+
+ERROR_NUMBER
+LogicalPartitionCreationChecks(
+    IN PPARTLIST List)
+{
+//    PDISKENTRY DiskEntry;
+    PPARTENTRY PartEntry;
+
+//    DiskEntry = List->CurrentDisk;
+    PartEntry = List->CurrentPartition;
+
+    /* Fail if the partition is already in use */
+    if (PartEntry->IsPartitioned != FALSE)
+        return ERROR_NEW_PARTITION;
+
+    return ERROR_SUCCESS;
+}
+
+BOOLEAN
+GetNextUnformattedPartition(
+    IN PPARTLIST List,
+    OUT PDISKENTRY *pDiskEntry OPTIONAL,
+    OUT PPARTENTRY *pPartEntry)
+{
+    PLIST_ENTRY Entry1, Entry2;
+    PDISKENTRY DiskEntry;
+    PPARTENTRY PartEntry;
+
+    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);
+            if (PartEntry->IsPartitioned && PartEntry->New)
+            {
+                ASSERT(DiskEntry == PartEntry->DiskEntry);
+                if (pDiskEntry) *pDiskEntry = DiskEntry;
+                *pPartEntry = PartEntry;
+                return TRUE;
+            }
+
+            Entry2 = Entry2->Flink;
+        }
+
+        Entry2 = DiskEntry->LogicalPartListHead.Flink;
+        while (Entry2 != &DiskEntry->LogicalPartListHead)
+        {
+            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;
+        }
+
+        Entry1 = Entry1->Flink;
+    }
+
+    if (pDiskEntry) *pDiskEntry = NULL;
+    *pPartEntry = NULL;
+
+    return FALSE;
+}
+
+BOOLEAN
+GetNextUncheckedPartition(
+    IN PPARTLIST List,
+    OUT PDISKENTRY *pDiskEntry OPTIONAL,
+    OUT PPARTENTRY *pPartEntry)
+{
+    PLIST_ENTRY Entry1, Entry2;
+    PDISKENTRY DiskEntry;
+    PPARTENTRY PartEntry;
+
+    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);
+            if (PartEntry->NeedsCheck == TRUE)
+            {
+                ASSERT(DiskEntry == PartEntry->DiskEntry);
+                if (pDiskEntry) *pDiskEntry = DiskEntry;
+                *pPartEntry = PartEntry;
+                return TRUE;
+            }
+
+            Entry2 = Entry2->Flink;
+        }
+
+        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;
+            }
+
+            Entry2 = Entry2->Flink;
+        }
+
+        Entry1 = Entry1->Flink;
+    }
+
+    if (pDiskEntry) *pDiskEntry = NULL;
+    *pPartEntry = NULL;
+
+    return FALSE;
+}
+
+/* EOF */
diff --git a/base/setup/lib/partlist.h b/base/setup/lib/partlist.h
new file mode 100644 (file)
index 0000000..80a8823
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+ * PROJECT:     ReactOS Setup Library
+ * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE:     Partition list functions
+ * COPYRIGHT:   Copyright 2002-2018 Eric Kohl
+ *              Copyright 2003-2018 Casper S. Hornstrup (chorns@users.sourceforge.net)
+ */
+
+#pragma once
+
+typedef enum _FORMATSTATE
+{
+    Unformatted,
+    UnformattedOrDamaged,
+    UnknownFormat,
+    Preformatted,
+    Formatted
+} FORMATSTATE, *PFORMATSTATE;
+
+typedef enum _FORMATMACHINESTATE
+{
+    Start,
+    FormatSystemPartition,
+    FormatInstallPartition,
+    FormatOtherPartition,
+    FormatDone,
+    CheckSystemPartition,
+    CheckInstallPartition,
+    CheckOtherPartition,
+    CheckDone
+} FORMATMACHINESTATE, *PFORMATMACHINESTATE;
+
+struct _FILE_SYSTEM;
+
+typedef struct _PARTENTRY
+{
+    LIST_ENTRY ListEntry;
+
+    /* The disk this partition belongs to */
+    struct _DISKENTRY *DiskEntry;
+
+    /* Partition geometry */
+    ULARGE_INTEGER StartSector;
+    ULARGE_INTEGER SectorCount;
+
+    BOOLEAN BootIndicator;
+    UCHAR PartitionType;
+    ULONG HiddenSectors;
+    ULONG PartitionNumber;  /* Enumerated partition number (primary partitions first -- excluding the extended partition container --, then the logical partitions) */
+    ULONG PartitionIndex;   /* Index in the LayoutBuffer->PartitionEntry[] cached array of the corresponding DiskEntry */
+
+    CHAR DriveLetter;
+
+    BOOLEAN LogicalPartition;
+
+    /* Partition is partitioned disk space */
+    BOOLEAN IsPartitioned;
+
+    /* Partition is new, table does not exist on disk yet */
+    BOOLEAN New;
+
+    /* Partition was created automatically */
+    BOOLEAN AutoCreate;
+
+    /* Partition must be checked */
+    BOOLEAN NeedsCheck;
+
+    FORMATSTATE FormatState;
+    struct _FILE_SYSTEM* FileSystem;
+
+} PARTENTRY, *PPARTENTRY;
+
+
+typedef struct _BIOSDISKENTRY
+{
+    LIST_ENTRY ListEntry;
+    ULONG DiskNumber;
+    ULONG Signature;
+    ULONG Checksum;
+    BOOLEAN Recognized;
+    CM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry;
+    CM_INT13_DRIVE_PARAMETER Int13DiskData;
+} BIOSDISKENTRY, *PBIOSDISKENTRY;
+
+
+typedef struct _DISKENTRY
+{
+    LIST_ENTRY ListEntry;
+
+    /* Disk geometry */
+
+    ULONGLONG Cylinders;
+    ULONG TracksPerCylinder;
+    ULONG SectorsPerTrack;
+    ULONG BytesPerSector;
+
+    ULARGE_INTEGER SectorCount;
+    ULONG SectorAlignment;
+    ULONG CylinderAlignment;
+
+    /* BIOS parameters */
+    BOOLEAN BiosFound;
+    ULONG BiosDiskNumber;
+//    ULONG Signature;
+//    ULONG Checksum;
+
+    /* SCSI parameters */
+    ULONG DiskNumber;
+    USHORT Port;
+    USHORT Bus;
+    USHORT Id;
+
+    /* Has the partition list been modified? */
+    BOOLEAN Dirty;
+
+    BOOLEAN NewDisk;
+    BOOLEAN NoMbr; /* MBR is absent */  // See r40437
+
+    UNICODE_STRING DriverName;
+
+    PDRIVE_LAYOUT_INFORMATION LayoutBuffer;
+    // TODO: When adding support for GPT disks:
+    // Use PDRIVE_LAYOUT_INFORMATION_EX which indicates whether
+    // the disk is MBR, GPT, or unknown (uninitialized).
+    // Depending on the style, either use the MBR or GPT partition info.
+
+    /* Pointer to the unique extended partition on this disk */
+    PPARTENTRY ExtendedPartition;
+
+    LIST_ENTRY PrimaryPartListHead;
+    LIST_ENTRY LogicalPartListHead;
+
+} DISKENTRY, *PDISKENTRY;
+
+
+typedef struct _PARTLIST
+{
+    /*
+     * Disk & Partition iterators.
+     *
+     * NOTE that when CurrentPartition != NULL, then CurrentPartition->DiskEntry
+     * must be the same as CurrentDisk. We should however keep the two members
+     * separated as we can have a current (selected) disk without any current
+     * partition, if the former does not contain any.
+     */
+    PDISKENTRY CurrentDisk;
+    PPARTENTRY CurrentPartition;
+
+    /*
+     * The system partition where the boot manager resides.
+     * The corresponding system disk is obtained via:
+     *    SystemPartition->DiskEntry.
+     */
+    PPARTENTRY SystemPartition;
+    /*
+     * The original system partition in case we are redefining it because
+     * we do not have write support on it.
+     * Please note that this is partly a HACK and MUST NEVER happen on
+     * architectures where real system partitions are mandatory (because then
+     * they are formatted in FAT FS and we support write operation on them).
+     * The corresponding original system disk is obtained via:
+     *    OriginalSystemPartition->DiskEntry.
+     */
+    PPARTENTRY OriginalSystemPartition;
+
+    PPARTENTRY TempPartition;
+    FORMATMACHINESTATE FormatState;
+
+    LIST_ENTRY DiskListHead;
+    LIST_ENTRY BiosDiskListHead;
+
+} PARTLIST, *PPARTLIST;
+
+#define  PARTITION_TBL_SIZE 4
+
+#include <pshpack1.h>
+
+typedef struct _PARTITION
+{
+    unsigned char   BootFlags;        /* bootable?  0=no, 128=yes  */
+    unsigned char   StartingHead;     /* beginning head number */
+    unsigned char   StartingSector;   /* beginning sector number */
+    unsigned char   StartingCylinder; /* 10 bit nmbr, with high 2 bits put in begsect */
+    unsigned char   PartitionType;    /* Operating System type indicator code */
+    unsigned char   EndingHead;       /* ending head number */
+    unsigned char   EndingSector;     /* ending sector number */
+    unsigned char   EndingCylinder;   /* also a 10 bit nmbr, with same high 2 bit trick */
+    unsigned int  StartingBlock;      /* first sector relative to start of disk */
+    unsigned int  SectorCount;        /* number of sectors in partition */
+} PARTITION, *PPARTITION;
+
+typedef struct _PARTITION_SECTOR
+{
+    UCHAR BootCode[440];                     /* 0x000 */
+    ULONG Signature;                         /* 0x1B8 */
+    UCHAR Reserved[2];                       /* 0x1BC */
+    PARTITION Partition[PARTITION_TBL_SIZE]; /* 0x1BE */
+    USHORT Magic;                            /* 0x1FE */
+} PARTITION_SECTOR, *PPARTITION_SECTOR;
+
+#include <poppack.h>
+
+typedef struct
+{
+    LIST_ENTRY ListEntry;
+    ULONG DiskNumber;
+    ULONG Identifier;
+    ULONG Signature;
+} BIOS_DISK, *PBIOS_DISK;
+
+
+
+ULONGLONG
+AlignDown(
+    IN ULONGLONG Value,
+    IN ULONG Alignment);
+
+ULONGLONG
+AlignUp(
+    IN ULONGLONG Value,
+    IN ULONG Alignment);
+
+ULONGLONG
+RoundingDivide(
+   IN ULONGLONG Dividend,
+   IN ULONGLONG Divisor);
+
+
+
+PPARTLIST
+CreatePartitionList(VOID);
+
+VOID
+DestroyPartitionList(
+    IN PPARTLIST List);
+
+ULONG
+SelectPartition(
+    IN PPARTLIST List,
+    IN ULONG DiskNumber,
+    IN ULONG PartitionNumber);
+
+PPARTENTRY
+GetNextPartition(
+    IN PPARTLIST List);
+
+PPARTENTRY
+GetPrevPartition(
+    IN PPARTLIST List);
+
+VOID
+CreatePrimaryPartition(
+    IN PPARTLIST List,
+    IN ULONGLONG SectorCount,
+    IN BOOLEAN AutoCreate);
+
+VOID
+CreateExtendedPartition(
+    IN PPARTLIST List,
+    IN ULONGLONG SectorCount);
+
+VOID
+CreateLogicalPartition(
+    IN PPARTLIST List,
+    IN ULONGLONG SectorCount,
+    IN BOOLEAN AutoCreate);
+
+VOID
+DeleteCurrentPartition(
+    IN PPARTLIST List);
+
+VOID
+CheckActiveSystemPartition(
+    IN PPARTLIST List // ,
+    // IN PFILE_SYSTEM_LIST FileSystemList /* Needed for checking the FS of the candidate system partition */
+    );
+
+BOOLEAN
+WritePartitionsToDisk(
+    IN PPARTLIST List);
+
+BOOLEAN
+SetMountedDeviceValue(
+    IN CHAR Letter,
+    IN ULONG Signature,
+    IN LARGE_INTEGER StartingOffset);
+
+BOOLEAN
+SetMountedDeviceValues(
+    IN PPARTLIST List);
+
+VOID
+SetPartitionType(
+    IN PPARTENTRY PartEntry,
+    IN UCHAR PartitionType);
+
+ERROR_NUMBER
+PrimaryPartitionCreationChecks(
+    IN PPARTLIST List);
+
+ERROR_NUMBER
+ExtendedPartitionCreationChecks(
+    IN PPARTLIST List);
+
+ERROR_NUMBER
+LogicalPartitionCreationChecks(
+    IN PPARTLIST List);
+
+BOOLEAN
+GetNextUnformattedPartition(
+    IN PPARTLIST List,
+    OUT PDISKENTRY *pDiskEntry OPTIONAL,
+    OUT PPARTENTRY *pPartEntry);
+
+BOOLEAN
+GetNextUncheckedPartition(
+    IN PPARTLIST List,
+    OUT PDISKENTRY *pDiskEntry OPTIONAL,
+    OUT PPARTENTRY *pPartEntry);
+
+/* EOF */
diff --git a/base/setup/lib/precomp.h b/base/setup/lib/precomp.h
new file mode 100644 (file)
index 0000000..1f84862
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * PROJECT:     ReactOS Setup Library
+ * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE:     Precompiled header
+ * COPYRIGHT:   Copyright 2017-2018 Hermes Belusca-Maito
+ */
+
+/* C Headers */
+#include <stdio.h>
+#include <stdlib.h>
+
+/* PSDK/NDK Headers */
+#define WIN32_NO_STATUS
+#include <windef.h>
+#include <winbase.h>
+#include <winreg.h>
+#include <winuser.h>
+
+#include <strsafe.h>
+
+#define NTOS_MODE_USER
+#include <ndk/cmfuncs.h>
+#include <ndk/exfuncs.h>
+#include <ndk/iofuncs.h>
+#include <ndk/kefuncs.h>
+#include <ndk/mmfuncs.h>
+#include <ndk/obfuncs.h>
+#include <ndk/psfuncs.h>
+#include <ndk/rtlfuncs.h>
+#include <ndk/setypes.h>
+
+/* Filesystem headers */
+#include <reactos/rosioctl.h>   // For extra partition IDs
+
+/** For FileSystems **/
+// #include <fslib/vfatlib.h>
+// #include <fslib/ext2lib.h>
+// // #include <fslib/ntfslib.h>
+
+//
+///* Internal Headers */
+//#include "interface/consup.h"
+//#include "inffile.h"
+//#include "inicache.h"
+//#include "progress.h"
+//#ifdef __REACTOS__
+//#include "infros.h"
+//#include "filequeue.h"
+//#endif
+
+//#include "registry.h"
+//#include "fslist.h"
+//#include "partlist.h"
+//#include "cabinet.h"
+//#include "filesup.h"
+//#include "genlist.h"
+
+
+extern HANDLE ProcessHeap;
+
+#include "errorcode.h"
+#include "linklist.h"
diff --git a/base/setup/lib/setuplib.h b/base/setup/lib/setuplib.h
new file mode 100644 (file)
index 0000000..f9ed75e
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * PROJECT:     ReactOS Setup Library
+ * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
+ * PURPOSE:     Public header
+ * COPYRIGHT:   Copyright 2017-2018 Hermes Belusca-Maito
+ */
+
+#pragma once
+
+/* Needed PSDK headers when using this library */
+#if 0
+
+#define WIN32_NO_STATUS
+#define _INC_WINDOWS
+#define COM_NO_WINDOWS_H
+
+#include <wingdi.h> // For LF_FACESIZE and TranslateCharsetInfo()
+#include <wincon.h>
+#include <winnls.h> // For code page support
+#include <winreg.h>
+
+#endif
+
+/* NOTE: Please keep the header inclusion order! */
+
+extern HANDLE ProcessHeap;
+
+#include "errorcode.h"
+#include "linklist.h"
+#include "fsutil.h"
+#include "genlist.h"
+#include "partlist.h"
+
+/* EOF */
index 8dff7a5..69d1e6b 100644 (file)
@@ -3,6 +3,8 @@ add_definitions(${I18N_DEFS})
 
 include_directories(
     ${CMAKE_CURRENT_SOURCE_DIR}
+    ${CMAKE_CURRENT_SOURCE_DIR}/../lib
+#    ${REACTOS_SOURCE_DIR}/base/setup/lib
     ${REACTOS_SOURCE_DIR}/sdk/lib/inflib
     ${REACTOS_SOURCE_DIR}/sdk/include/reactos/libs/zlib
     ${REACTOS_SOURCE_DIR}/sdk/include/reactos/drivers)
@@ -38,8 +40,8 @@ if(USE_CLANG_CL)
     add_target_compile_flags(usetup "-Wno-invalid-source-encoding")
 endif()
 
-target_link_libraries(usetup zlib_solo inflib ext2lib vfatlib)
+add_pch(usetup usetup.h SOURCE)
 set_module_type(usetup nativecui)
+target_link_libraries(usetup inflib setuplib zlib_solo ext2lib vfatlib)
 add_importlibs(usetup ntdll)
-add_pch(usetup usetup.h SOURCE)
 add_cd_file(TARGET usetup DESTINATION reactos/system32 NO_CAB NAME_ON_CD smss.exe FOR bootcd regtest)
index 674808a..cd57940 100644 (file)
@@ -2659,17 +2659,24 @@ InstallFatBootcodeToFloppy(
     PUNICODE_STRING DestinationArcPath)
 {
     NTSTATUS Status;
+    PFILE_SYSTEM FatFS;
     UNICODE_STRING FloppyDevice = RTL_CONSTANT_STRING(L"\\Device\\Floppy0");
     WCHAR SrcPath[MAX_PATH];
     WCHAR DstPath[MAX_PATH];
 
     /* Format the floppy first */
-    Status = VfatFormat(&FloppyDevice,
-                        FMIFS_FLOPPY,
-                        NULL,
-                        TRUE,
-                        0,
-                        NULL);
+    FatFS = GetFileSystemByName(L"FAT");
+    if (!FatFS)
+    {
+        DPRINT1("FAT FS non existent on this system?!\n");
+        return STATUS_NOT_SUPPORTED;
+    }
+    Status = FatFS->FormatFunc(&FloppyDevice,
+                               FMIFS_FLOPPY,
+                               NULL,
+                               TRUE,
+                               0,
+                               NULL);
     if (!NT_SUCCESS(Status))
     {
         DPRINT1("VfatFormat() failed (Status %lx)\n", Status);
index 6d8df5d..26f9b79 100644 (file)
@@ -56,11 +56,13 @@ ChkdskCallback(
 NTSTATUS
 ChkdskPartition(
     IN PUNICODE_STRING DriveRoot,
-    IN PFILE_SYSTEM_ITEM FileSystem)
+    /*IN PFILE_SYSTEM_ITEM FileSystemItem*/
+    IN PFILE_SYSTEM FileSystem)
 {
     NTSTATUS Status;
+    // PFILE_SYSTEM FileSystem = FileSystemItem->FileSystem;
 
-    if (!FileSystem->ChkdskFunc)
+    if (!FileSystem || !FileSystem->ChkdskFunc)
         return STATUS_NOT_SUPPORTED;
 
     ChkdskProgressBar = CreateProgressBar(6,
index 95894e3..0eb2bed 100644 (file)
@@ -28,6 +28,7 @@
 NTSTATUS
 ChkdskPartition(
     IN PUNICODE_STRING DriveRoot,
-    IN PFILE_SYSTEM_ITEM FileSystem);
+    /*IN PFILE_SYSTEM_ITEM FileSystemItem*/
+    IN PFILE_SYSTEM FileSystem);
 
 /* EOF */
index 5dab49f..db8c14d 100644 (file)
@@ -88,11 +88,12 @@ FormatCallback(
 NTSTATUS
 FormatPartition(
     IN PUNICODE_STRING DriveRoot,
-    IN PFILE_SYSTEM_ITEM FileSystem)
+    IN PFILE_SYSTEM_ITEM FileSystemItem)
 {
     NTSTATUS Status;
+    PFILE_SYSTEM FileSystem = FileSystemItem->FileSystem;
 
-    if (!FileSystem->FormatFunc)
+    if (!FileSystem || !FileSystem->FormatFunc)
         return STATUS_NOT_SUPPORTED;
 
     FormatProgressBar = CreateProgressBar(6,
@@ -107,11 +108,11 @@ FormatPartition(
     ProgressSetStepCount(FormatProgressBar, 100);
 
     Status = FileSystem->FormatFunc(DriveRoot,
-                                    FMIFS_HARDDISK,          /* MediaFlag */
-                                    NULL,                    /* Label */
-                                    FileSystem->QuickFormat, /* QuickFormat */
-                                    0,                       /* ClusterSize */
-                                    FormatCallback);         /* Callback */
+                                    FMIFS_HARDDISK,              /* MediaFlag */
+                                    NULL,                        /* Label */
+                                    FileSystemItem->QuickFormat, /* QuickFormat */
+                                    0,                           /* ClusterSize */
+                                    FormatCallback);             /* Callback */
 
     DestroyProgressBar(FormatProgressBar);
     FormatProgressBar = NULL;
index 7da0f15..3032f49 100644 (file)
@@ -29,6 +29,6 @@
 NTSTATUS
 FormatPartition(
     IN PUNICODE_STRING DriveRoot,
-    IN PFILE_SYSTEM_ITEM FileSystem);
+    IN PFILE_SYSTEM_ITEM FileSystemItem);
 
 /* EOF */
index 1eb158b..d29d0df 100644 (file)
 
 /* FUNCTIONS ****************************************************************/
 
-VOID
+static VOID
 AddProvider(
     IN OUT PFILE_SYSTEM_LIST List,
-    IN PCWSTR FileSystemName,
-    IN FORMATEX FormatFunc,
-    IN CHKDSKEX ChkdskFunc)
+    IN PCWSTR FileSystemName, // Redundant, I need to check whether this is reaaaaally needed....
+    IN PFILE_SYSTEM FileSystem)
 {
     PFILE_SYSTEM_ITEM Item;
 
-    Item = (PFILE_SYSTEM_ITEM)RtlAllocateHeap(ProcessHeap, 0, sizeof(FILE_SYSTEM_ITEM));
+    Item = (PFILE_SYSTEM_ITEM)RtlAllocateHeap(ProcessHeap, 0, sizeof(*Item));
     if (!Item)
         return;
 
     Item->FileSystemName = FileSystemName;
-    Item->FormatFunc = FormatFunc;
-    Item->ChkdskFunc = ChkdskFunc;
+    Item->FileSystem = FileSystem;
     Item->QuickFormat = TRUE;
     InsertTailList(&List->ListHead, &Item->ListEntry);
 
-    if (!FormatFunc)
+    if (!FileSystem)
         return;
 
-    Item = (PFILE_SYSTEM_ITEM)RtlAllocateHeap(ProcessHeap, 0, sizeof(FILE_SYSTEM_ITEM));
+    Item = (PFILE_SYSTEM_ITEM)RtlAllocateHeap(ProcessHeap, 0, sizeof(*Item));
     if (!Item)
         return;
 
     Item->FileSystemName = FileSystemName;
-    Item->FormatFunc = FormatFunc;
-    Item->ChkdskFunc = ChkdskFunc;
+    Item->FileSystem = FileSystem;
     Item->QuickFormat = FALSE;
     InsertTailList(&List->ListHead, &Item->ListEntry);
 }
 
-
-PFILE_SYSTEM_ITEM
-GetFileSystemByName(
-    IN PFILE_SYSTEM_LIST List,
-    IN PWSTR FileSystemName)
-{
-    PLIST_ENTRY ListEntry;
-    PFILE_SYSTEM_ITEM Item;
-
-    ListEntry = List->ListHead.Flink;
-    while (ListEntry != &List->ListHead)
-    {
-        Item = CONTAINING_RECORD(ListEntry, FILE_SYSTEM_ITEM, ListEntry);
-        if (Item->FileSystemName && wcsicmp(FileSystemName, Item->FileSystemName) == 0)
-            return Item;
-
-        ListEntry = ListEntry->Flink;
-    }
-
-    return NULL;
-}
-
-#if 0 // FIXME: To be fully enabled when our storage stack & al. will work better!
-
-/* NOTE: Ripped & adapted from base/system/autochk/autochk.c */
-static NTSTATUS
-_MyGetFileSystem(
-    IN struct _PARTENTRY* PartEntry,
-    IN OUT PWSTR FileSystemName,
-    IN SIZE_T FileSystemNameSize)
-{
-    NTSTATUS Status;
-    HANDLE FileHandle;
-    IO_STATUS_BLOCK IoStatusBlock;
-    PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttribute;
-    UCHAR Buffer[sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + MAX_PATH * sizeof(WCHAR)];
-
-    OBJECT_ATTRIBUTES ObjectAttributes;
-    UNICODE_STRING PartitionRootPath;
-    WCHAR PathBuffer[MAX_PATH];
-
-    FileFsAttribute = (PFILE_FS_ATTRIBUTE_INFORMATION)Buffer;
-
-    /* Set PartitionRootPath */
-    swprintf(PathBuffer,
-             // L"\\Device\\Harddisk%lu\\Partition%lu", // Should work! But because ReactOS sucks atm. it actually doesn't work!!
-             L"\\Device\\Harddisk%lu\\Partition%lu\\",  // HACK: Use this as a temporary hack!
-             PartEntry->DiskEntry->DiskNumber,
-             PartEntry->PartitionNumber);
-    RtlInitUnicodeString(&PartitionRootPath, PathBuffer);
-    DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath);
-
-    /* Open the partition */
-    InitializeObjectAttributes(&ObjectAttributes,
-                               &PartitionRootPath,
-                               OBJ_CASE_INSENSITIVE,
-                               NULL,
-                               NULL);
-    Status = NtOpenFile(&FileHandle, // PartitionHandle,
-                        FILE_GENERIC_READ /* | SYNCHRONIZE */,
-                        &ObjectAttributes,
-                        &IoStatusBlock,
-                        FILE_SHARE_READ,
-                        0 /* FILE_SYNCHRONOUS_IO_NONALERT */);
-    if (!NT_SUCCESS(Status))
-    {
-        DPRINT1("Failed to open partition %wZ, Status 0x%08lx\n", &PartitionRootPath, Status);
-        return Status;
-    }
-
-    /* Retrieve the FS attributes */
-    Status = NtQueryVolumeInformationFile(FileHandle,
-                                          &IoStatusBlock,
-                                          FileFsAttribute,
-                                          sizeof(Buffer),
-                                          FileFsAttributeInformation);
-    NtClose(FileHandle);
-
-    if (!NT_SUCCESS(Status))
-    {
-        DPRINT1("NtQueryVolumeInformationFile failed for partition %wZ, Status 0x%08lx\n", &PartitionRootPath, Status);
-        return Status;
-    }
-
-    if (FileSystemNameSize * sizeof(WCHAR) < FileFsAttribute->FileSystemNameLength + sizeof(WCHAR))
-        return STATUS_BUFFER_TOO_SMALL;
-
-    RtlCopyMemory(FileSystemName,
-                  FileFsAttribute->FileSystemName,
-                  FileFsAttribute->FileSystemNameLength);
-    FileSystemName[FileFsAttribute->FileSystemNameLength / sizeof(WCHAR)] = UNICODE_NULL;
-
-    return STATUS_SUCCESS;
-}
-
-#endif
-
-PFILE_SYSTEM_ITEM
-GetFileSystem(
-    IN PFILE_SYSTEM_LIST FileSystemList,
-    IN struct _PARTENTRY* PartEntry)
+static VOID
+InitializeFileSystemList(
+    IN PFILE_SYSTEM_LIST List)
 {
-    PFILE_SYSTEM_ITEM CurrentFileSystem;
-    PWSTR FileSystemName = NULL;
-#if 0 // For code temporarily disabled below
-    NTSTATUS Status;
-    WCHAR FsRecFileSystemName[MAX_PATH];
-#endif
-
-    CurrentFileSystem = PartEntry->FileSystem;
-
-    /* We have a file system, return it */
-    if (CurrentFileSystem != NULL && CurrentFileSystem->FileSystemName != NULL)
-        return CurrentFileSystem;
-
-    DPRINT1("File system not found, try to guess one...\n");
-
-    CurrentFileSystem = NULL;
-
-#if 0 // FIXME: To be fully enabled when our storage stack & al. will work better!
-
-    /*
-     * We don't have one...
-     *
-     * Try to infer one using NT file system recognition.
-     */
-    Status = _MyGetFileSystem(PartEntry, FsRecFileSystemName, ARRAYSIZE(FsRecFileSystemName));
-    if (NT_SUCCESS(Status) && *FsRecFileSystemName)
-    {
-        /* Temporary HACK: map FAT32 back to FAT */
-        if (wcscmp(FsRecFileSystemName, L"FAT32") == 0)
-            wcscpy(FsRecFileSystemName, L"FAT");
-
-        FileSystemName = FsRecFileSystemName;
-        goto Quit;
-    }
-
-#endif
-
-    /*
-     * We don't have one...
-     *
-     * Try to infer a preferred file system for this partition, given its ID.
-     *
-     * WARNING: This is partly a hack, since partitions with the same ID can
-     * be formatted with different file systems: for example, usual Linux
-     * partitions that are formatted in EXT2/3/4, ReiserFS, etc... have the
-     * same partition ID 0x83.
-     *
-     * The proper fix is to make a function that detects the existing FS
-     * from a given partition (not based on the partition ID).
-     * On the contrary, for unformatted partitions with a given ID, the
-     * following code is OK.
-     */
-    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))
-    {
-        FileSystemName = L"FAT";
-    }
-    else if (PartEntry->PartitionType == PARTITION_EXT2)
-    {
-        // WARNING: See the warning above.
-        FileSystemName = L"EXT2";
-    }
-    else if (PartEntry->PartitionType == PARTITION_IFS)
-    {
-        // WARNING: See the warning above.
-        FileSystemName = L"NTFS"; /* FIXME: Not quite correct! */
-    }
+    ULONG Count;
+    PFILE_SYSTEM FileSystems;
 
-#if 0
-Quit: // For code temporarily disabled above
-#endif
+    FileSystems = GetRegisteredFileSystems(&Count);
+    if (!FileSystems || Count == 0)
+        return;
 
-    // HACK: WARNING: We cannot write on this FS yet!
-    if (FileSystemName)
+    while (Count--)
     {
-        if (PartEntry->PartitionType == PARTITION_EXT2 || PartEntry->PartitionType == PARTITION_IFS)
-            DPRINT1("Recognized file system %S that doesn't support write support yet!\n", FileSystemName);
+        AddProvider(List, FileSystems->FileSystemName, FileSystems);
+        ++FileSystems;
     }
-
-    DPRINT1("GetFileSystem -- PartitionType: 0x%02X ; FileSystemName (guessed): %S\n",
-            PartEntry->PartitionType, FileSystemName ? FileSystemName : L"None");
-
-    if (FileSystemName != NULL)
-        CurrentFileSystem = GetFileSystemByName(FileSystemList, FileSystemName);
-
-    return CurrentFileSystem;
 }
 
-
 PFILE_SYSTEM_LIST
 CreateFileSystemList(
     IN SHORT Left,
@@ -271,7 +91,7 @@ CreateFileSystemList(
     PFILE_SYSTEM_ITEM Item;
     PLIST_ENTRY ListEntry;
 
-    List = (PFILE_SYSTEM_LIST)RtlAllocateHeap(ProcessHeap, 0, sizeof(FILE_SYSTEM_LIST));
+    List = (PFILE_SYSTEM_LIST)RtlAllocateHeap(ProcessHeap, 0, sizeof(*List));
     if (List == NULL)
         return NULL;
 
@@ -280,16 +100,11 @@ CreateFileSystemList(
     List->Selected = NULL;
     InitializeListHead(&List->ListHead);
 
-    AddProvider(List, L"FAT", VfatFormat, VfatChkdsk);
-#if 0
-    AddProvider(List, L"EXT2", Ext2Format, Ext2Chkdsk);
-    AddProvider(List, L"NTFS", NtfsFormat, NtfsChkdsk);
-#endif
-
+    InitializeFileSystemList(List);
     if (!ForceFormat)
     {
         /* Add the 'Keep existing filesystem' dummy provider */
-        AddProvider(List, NULL, NULL, NULL);
+        AddProvider(List, NULL, NULL);
     }
 
     /* Search for SelectFileSystem in list */
@@ -314,19 +129,17 @@ VOID
 DestroyFileSystemList(
     IN PFILE_SYSTEM_LIST List)
 {
-    PLIST_ENTRY ListEntry = List->ListHead.Flink;
+    PLIST_ENTRY ListEntry;
     PFILE_SYSTEM_ITEM Item;
-    PLIST_ENTRY Next;
 
-    while (ListEntry != &List->ListHead)
+    ListEntry = List->ListHead.Flink;
+    while (!IsListEmpty(&List->ListHead))
     {
+        ListEntry = RemoveHeadList(&List->ListHead);
         Item = CONTAINING_RECORD(ListEntry, FILE_SYSTEM_ITEM, ListEntry);
-        Next = ListEntry->Flink;
-
         RtlFreeHeap(ProcessHeap, 0, Item);
-
-        ListEntry = Next;
     }
+
     RtlFreeHeap(ProcessHeap, 0, List);
 }
 
index 4433d38..16388e2 100644 (file)
@@ -31,9 +31,8 @@
 typedef struct _FILE_SYSTEM_ITEM
 {
     LIST_ENTRY ListEntry;
-    PCWSTR FileSystemName; /* Not owned by the item */
-    FORMATEX FormatFunc;
-    CHKDSKEX ChkdskFunc;
+    PCWSTR FileSystemName; /* Not owned by the item */ // Redundant, I need to check whether this is reaaaaally needed....
+    PFILE_SYSTEM FileSystem;
     BOOLEAN QuickFormat;
 } FILE_SYSTEM_ITEM, *PFILE_SYSTEM_ITEM;
 
@@ -45,24 +44,6 @@ typedef struct _FILE_SYSTEM_LIST
     LIST_ENTRY ListHead; /* List of FILE_SYSTEM_ITEM */
 } FILE_SYSTEM_LIST, *PFILE_SYSTEM_LIST;
 
-VOID
-AddProvider(
-    IN OUT PFILE_SYSTEM_LIST List,
-    IN PCWSTR FileSystemName,
-    IN FORMATEX FormatFunc,
-    IN CHKDSKEX ChkdskFunc);
-
-PFILE_SYSTEM_ITEM
-GetFileSystemByName(
-    IN PFILE_SYSTEM_LIST List,
-    IN PWSTR FileSystemName);
-
-struct _PARTENTRY; // Defined in partlist.h
-PFILE_SYSTEM_ITEM
-GetFileSystem(
-    IN PFILE_SYSTEM_LIST FileSystemList,
-    IN struct _PARTENTRY* PartEntry);
-
 PFILE_SYSTEM_LIST
 CreateFileSystemList(
     IN SHORT Left,
index 1ff2275..991d6d0 100644 (file)
 
 /* FUNCTIONS ****************************************************************/
 
-typedef struct _GENERIC_LIST_ENTRY
-{
-    LIST_ENTRY Entry;
-    PGENERIC_LIST List;
-    PVOID UserData;
-    CHAR Text[1];       // FIXME: UI stuff
-} GENERIC_LIST_ENTRY;
-
-
-typedef struct _GENERIC_LIST
-{
-    LIST_ENTRY ListHead;
-    ULONG NumOfEntries;
-
-    PGENERIC_LIST_ENTRY CurrentEntry;
-    PGENERIC_LIST_ENTRY BackupEntry;
-} GENERIC_LIST;
-
-
-PGENERIC_LIST
-CreateGenericList(VOID)
-{
-    PGENERIC_LIST List;
-
-    List = (PGENERIC_LIST)RtlAllocateHeap(ProcessHeap,
-                                          0,
-                                          sizeof(GENERIC_LIST));
-    if (List == NULL)
-        return NULL;
-
-    InitializeListHead(&List->ListHead);
-    List->NumOfEntries = 0;
-
-    List->CurrentEntry = NULL;
-    List->BackupEntry = NULL;
-
-    return List;
-}
-
-VOID
-DestroyGenericList(
-    IN OUT PGENERIC_LIST List,
-    IN BOOLEAN FreeUserData)
-{
-    PGENERIC_LIST_ENTRY ListEntry;
-    PLIST_ENTRY Entry;
-
-    /* Release list entries */
-    while (!IsListEmpty (&List->ListHead))
-    {
-        Entry = RemoveHeadList (&List->ListHead);
-        ListEntry = CONTAINING_RECORD (Entry, GENERIC_LIST_ENTRY, Entry);
-
-        /* Release user data */
-        if (FreeUserData && ListEntry->UserData != NULL)
-            RtlFreeHeap (ProcessHeap, 0, ListEntry->UserData);
-
-        /* Release list entry */
-        RtlFreeHeap (ProcessHeap, 0, ListEntry);
-    }
-
-    /* Release list head */
-    RtlFreeHeap (ProcessHeap, 0, List);
-}
-
-BOOLEAN
-AppendGenericListEntry(
-    IN OUT PGENERIC_LIST List,
-    IN PCHAR Text,
-    IN PVOID UserData,
-    IN BOOLEAN Current)
-{
-    PGENERIC_LIST_ENTRY Entry;
-
-    Entry = (PGENERIC_LIST_ENTRY)RtlAllocateHeap(ProcessHeap,
-                                                 0,
-                                                 sizeof(GENERIC_LIST_ENTRY) + strlen(Text));
-    if (Entry == NULL)
-        return FALSE;
-
-    strcpy (Entry->Text, Text);
-    Entry->List = List;
-    Entry->UserData = UserData;
-
-    InsertTailList(&List->ListHead,
-                   &Entry->Entry);
-    List->NumOfEntries++;
-
-    if (Current || List->CurrentEntry == NULL)
-    {
-        List->CurrentEntry = Entry;
-    }
-
-    return TRUE;
-}
-
-
 VOID
 InitGenericListUi(
     IN OUT PGENERIC_LIST_UI ListUi,
@@ -229,7 +132,6 @@ DrawListFrame(
                                  &Written);
 }
 
-
 static
 VOID
 DrawListEntries(
@@ -249,7 +151,7 @@ DrawListEntries(
     Entry = ListUi->FirstShown;
     while (Entry != &List->ListHead)
     {
-        ListEntry = CONTAINING_RECORD (Entry, GENERIC_LIST_ENTRY, Entry);
+        ListEntry = CONTAINING_RECORD(Entry, GENERIC_LIST_ENTRY, Entry);
 
         if (coPos.Y == ListUi->Bottom)
             break;
@@ -298,7 +200,6 @@ DrawListEntries(
     }
 }
 
-
 static
 VOID
 DrawScrollBarGenericList(
@@ -347,7 +248,6 @@ DrawScrollBarGenericList(
     }
 }
 
-
 static
 VOID
 CenterCurrentListItem(
@@ -398,7 +298,6 @@ CenterCurrentListItem(
     }
 }
 
-
 VOID
 DrawGenericList(
     IN PGENERIC_LIST_UI ListUi,
@@ -426,6 +325,61 @@ DrawGenericList(
     DrawScrollBarGenericList(ListUi);
 }
 
+VOID
+ScrollDownGenericList(
+    IN PGENERIC_LIST_UI ListUi)
+{
+    PGENERIC_LIST List = ListUi->List;
+    PLIST_ENTRY Entry;
+
+    if (List->CurrentEntry == NULL)
+        return;
+
+    if (List->CurrentEntry->Entry.Flink != &List->ListHead)
+    {
+        Entry = List->CurrentEntry->Entry.Flink;
+        if (ListUi->LastShown == &List->CurrentEntry->Entry)
+        {
+            ListUi->FirstShown = ListUi->FirstShown->Flink;
+            ListUi->LastShown = ListUi->LastShown->Flink;
+        }
+        List->CurrentEntry = CONTAINING_RECORD(Entry, GENERIC_LIST_ENTRY, Entry);
+
+        if (ListUi->Redraw)
+        {
+            DrawListEntries(ListUi);
+            DrawScrollBarGenericList(ListUi);
+        }
+    }
+}
+
+VOID
+ScrollUpGenericList(
+    IN PGENERIC_LIST_UI ListUi)
+{
+    PGENERIC_LIST List = ListUi->List;
+    PLIST_ENTRY Entry;
+
+    if (List->CurrentEntry == NULL)
+        return;
+
+    if (List->CurrentEntry->Entry.Blink != &List->ListHead)
+    {
+        Entry = List->CurrentEntry->Entry.Blink;
+        if (ListUi->FirstShown == &List->CurrentEntry->Entry)
+        {
+            ListUi->FirstShown = ListUi->FirstShown->Blink;
+            ListUi->LastShown = ListUi->LastShown->Blink;
+        }
+        List->CurrentEntry = CONTAINING_RECORD(Entry, GENERIC_LIST_ENTRY, Entry);
+
+        if (ListUi->Redraw)
+        {
+            DrawListEntries(ListUi);
+            DrawScrollBarGenericList(ListUi);
+        }
+    }
+}
 
 VOID
 ScrollPageDownGenericList(
@@ -449,7 +403,6 @@ ScrollPageDownGenericList(
     ListUi->Redraw = TRUE;
 }
 
-
 VOID
 ScrollPageUpGenericList(
     IN PGENERIC_LIST_UI ListUi)
@@ -472,36 +425,6 @@ ScrollPageUpGenericList(
     ListUi->Redraw = TRUE;
 }
 
-
-VOID
-ScrollDownGenericList(
-    IN PGENERIC_LIST_UI ListUi)
-{
-    PGENERIC_LIST List = ListUi->List;
-    PLIST_ENTRY Entry;
-
-    if (List->CurrentEntry == NULL)
-        return;
-
-    if (List->CurrentEntry->Entry.Flink != &List->ListHead)
-    {
-        Entry = List->CurrentEntry->Entry.Flink;
-        if (ListUi->LastShown == &List->CurrentEntry->Entry)
-        {
-            ListUi->FirstShown = ListUi->FirstShown->Flink;
-            ListUi->LastShown = ListUi->LastShown->Flink;
-        }
-        List->CurrentEntry = CONTAINING_RECORD(Entry, GENERIC_LIST_ENTRY, Entry);
-
-        if (ListUi->Redraw)
-        {
-            DrawListEntries(ListUi);
-            DrawScrollBarGenericList(ListUi);
-        }
-    }
-}
-
-
 VOID
 ScrollToPositionGenericList(
     IN PGENERIC_LIST_UI ListUi,
@@ -537,36 +460,6 @@ ScrollToPositionGenericList(
     }
 }
 
-
-VOID
-ScrollUpGenericList(
-    IN PGENERIC_LIST_UI ListUi)
-{
-    PGENERIC_LIST List = ListUi->List;
-    PLIST_ENTRY Entry;
-
-    if (List->CurrentEntry == NULL)
-        return;
-
-    if (List->CurrentEntry->Entry.Blink != &List->ListHead)
-    {
-        Entry = List->CurrentEntry->Entry.Blink;
-        if (ListUi->FirstShown == &List->CurrentEntry->Entry)
-        {
-            ListUi->FirstShown = ListUi->FirstShown->Blink;
-            ListUi->LastShown = ListUi->LastShown->Blink;
-        }
-        List->CurrentEntry = CONTAINING_RECORD(Entry, GENERIC_LIST_ENTRY, Entry);
-
-        if (ListUi->Redraw)
-        {
-            DrawListEntries(ListUi);
-            DrawScrollBarGenericList(ListUi);
-        }
-    }
-}
-
-
 VOID
 RedrawGenericList(
     IN PGENERIC_LIST_UI ListUi)
@@ -581,76 +474,6 @@ RedrawGenericList(
     }
 }
 
-
-
-VOID
-SetCurrentListEntry(
-    IN PGENERIC_LIST List,
-    IN PGENERIC_LIST_ENTRY Entry)
-{
-    if (Entry->List != List)
-        return;
-    List->CurrentEntry = Entry;
-}
-
-
-PGENERIC_LIST_ENTRY
-GetCurrentListEntry(
-    IN PGENERIC_LIST List)
-{
-    return List->CurrentEntry;
-}
-
-
-PGENERIC_LIST_ENTRY
-GetFirstListEntry(
-    IN PGENERIC_LIST List)
-{
-    PLIST_ENTRY Entry = List->ListHead.Flink;
-
-    if (Entry == &List->ListHead)
-        return NULL;
-    return CONTAINING_RECORD(Entry, GENERIC_LIST_ENTRY, Entry);
-}
-
-
-PGENERIC_LIST_ENTRY
-GetNextListEntry(
-    IN PGENERIC_LIST_ENTRY Entry)
-{
-    PLIST_ENTRY Next = Entry->Entry.Flink;
-
-    if (Next == &Entry->List->ListHead)
-        return NULL;
-    return CONTAINING_RECORD(Next, GENERIC_LIST_ENTRY, Entry);
-}
-
-
-PVOID
-GetListEntryUserData(
-    IN PGENERIC_LIST_ENTRY Entry)
-{
-    return Entry->UserData;
-}
-
-
-LPCSTR
-GetListEntryText(
-    IN PGENERIC_LIST_ENTRY Entry)
-{
-    return Entry->Text;
-}
-
-
-ULONG
-GetNumberOfListEntries(
-    IN PGENERIC_LIST List)
-{
-    return List->NumOfEntries;
-}
-
-
-
 VOID
 GenericListKeyPress(
     IN PGENERIC_LIST_UI ListUi,
@@ -714,33 +537,4 @@ End:
     ListUi->Redraw = TRUE;
 }
 
-
-VOID
-SaveGenericListState(
-    IN PGENERIC_LIST List)
-{
-    List->BackupEntry = List->CurrentEntry;
-}
-
-
-VOID
-RestoreGenericListState(
-    IN PGENERIC_LIST List)
-{
-    List->CurrentEntry = List->BackupEntry;
-}
-
-
-BOOLEAN
-GenericListHasSingleEntry(
-    IN PGENERIC_LIST List)
-{
-    if (!IsListEmpty(&List->ListHead) && List->ListHead.Flink == List->ListHead.Blink)
-        return TRUE;
-
-    /* if both list head pointers (which normally point to the first and last list member, respectively)
-       point to the same entry then it means that there's just a single thing in there, otherwise... false! */
-    return FALSE;
-}
-
 /* EOF */
index 1c07ec3..ebe4069 100644 (file)
 
 #pragma once
 
-struct _GENERIC_LIST_ENTRY;
-typedef struct _GENERIC_LIST_ENTRY *PGENERIC_LIST_ENTRY;
-struct _GENERIC_LIST;
-typedef struct _GENERIC_LIST *PGENERIC_LIST;
-
-PGENERIC_LIST
-CreateGenericList(VOID);
-
-VOID
-DestroyGenericList(
-    IN OUT PGENERIC_LIST List,
-    IN BOOLEAN FreeUserData);
-
-BOOLEAN
-AppendGenericListEntry(
-    IN OUT PGENERIC_LIST List,
-    IN PCHAR Text,
-    IN PVOID UserData,
-    IN BOOLEAN Current);
-
-VOID
-SetCurrentListEntry(
-    IN PGENERIC_LIST List,
-    IN PGENERIC_LIST_ENTRY Entry);
-
-PGENERIC_LIST_ENTRY
-GetCurrentListEntry(
-    IN PGENERIC_LIST List);
-
-PGENERIC_LIST_ENTRY
-GetFirstListEntry(
-    IN PGENERIC_LIST List);
-
-PGENERIC_LIST_ENTRY
-GetNextListEntry(
-    IN PGENERIC_LIST_ENTRY Entry);
-
-PVOID
-GetListEntryUserData(
-    IN PGENERIC_LIST_ENTRY Entry);
-
-LPCSTR
-GetListEntryText(
-    IN PGENERIC_LIST_ENTRY Entry);
-
-ULONG
-GetNumberOfListEntries(
-    IN PGENERIC_LIST List);
-
-VOID
-SaveGenericListState(
-    IN PGENERIC_LIST List);
-
-VOID
-RestoreGenericListState(
-    IN PGENERIC_LIST List);
-
-BOOLEAN
-GenericListHasSingleEntry(
-    IN PGENERIC_LIST List);
-
-
-
+#include "../lib/genlist.h"
 
 typedef struct _GENERIC_LIST_UI
 {
index 31c657f..ca8f132 100644 (file)
 
 #include "usetup.h"
 
-#include <ntddscsi.h>
-
 #define NDEBUG
 #include <debug.h>
 
-//#define DUMP_PARTITION_TABLE
-
 /* HELPERS FOR PARTITION TYPES **********************************************/
 
 typedef struct _PARTITION_TYPE
@@ -207,3598 +203,602 @@ GetPartTypeStringFromPartitionType(
     }
 }
 
+
 /* 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)
+InitPartitionListUi(
+    IN OUT PPARTLIST_UI ListUi,
+    IN PPARTLIST List,
+    IN SHORT Left,
+    IN SHORT Top,
+    IN SHORT Right,
+    IN SHORT Bottom)
 {
-    ULONGLONG Temp, Result;
-
-    Temp = Value / Alignment;
-
-    Result = Temp * Alignment;
-    if (Value % Alignment)
-        Result += Alignment;
-
-    return Result;
-}
+    ListUi->List = List;
+    // ListUi->FirstShown = NULL;
+    // ListUi->LastShown = NULL;
 
-ULONGLONG
-RoundingDivide(
-   IN ULONGLONG Dividend,
-   IN ULONGLONG Divisor)
-{
-    return (Dividend + Divisor / 2) / Divisor;
-}
+    ListUi->Left = Left;
+    ListUi->Top = Top;
+    ListUi->Right = Right;
+    ListUi->Bottom = Bottom;
 
+    ListUi->Line = 0;
+    ListUi->Offset = 0;
 
-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);
-    }
+    // ListUi->Redraw = TRUE;
 }
 
-
 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)
+PrintEmptyLine(
+    IN PPARTLIST_UI ListUi)
 {
-    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;
-}
-
+    COORD coPos;
+    ULONG Written;
+    USHORT Width;
+    USHORT Height;
 
-#define ROOT_NAME   L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter"
+    Width = ListUi->Right - ListUi->Left - 1;
+    Height = ListUi->Bottom - ListUi->Top - 2;
 
-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;
-    }
+    coPos.X = ListUi->Left + 1;
+    coPos.Y = ListUi->Top + 1 + ListUi->Line;
 
-    AdapterCount = 0;
-    while (1)
+    if (ListUi->Line >= 0 && ListUi->Line <= Height)
     {
-        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;
-            }
-        }
+        FillConsoleOutputAttribute(StdOutput,
+                                   FOREGROUND_WHITE | BACKGROUND_BLUE,
+                                   Width,
+                                   coPos,
+                                   &Written);
 
-        AdapterCount++;
+        FillConsoleOutputCharacterA(StdOutput,
+                                    ' ',
+                                    Width,
+                                    coPos,
+                                    &Written);
     }
 
-    RtlFreeHeap(ProcessHeap, 0, Int13Drives);
+    ListUi->Line++;
 }
 
-
 static
 VOID
-AddPartitionToDisk(
-    IN ULONG DiskNumber,
+PrintPartitionData(
+    IN PPARTLIST_UI ListUi,
     IN PDISKENTRY DiskEntry,
-    IN ULONG PartitionIndex,
-    IN BOOLEAN LogicalPartition)
+    IN PPARTENTRY PartEntry)
 {
-    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;
+    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;
 
-    PartEntry->BootIndicator = PartitionInfo->BootIndicator;
-    PartEntry->PartitionType = PartitionInfo->PartitionType;
-    PartEntry->HiddenSectors = PartitionInfo->HiddenSectors;
+    Width = ListUi->Right - ListUi->Left - 1;
+    Height = ListUi->Bottom - ListUi->Top - 2;
 
-    PartEntry->LogicalPartition = LogicalPartition;
-    PartEntry->IsPartitioned = TRUE;
-    PartEntry->PartitionNumber = PartitionInfo->PartitionNumber;
-    PartEntry->PartitionIndex = PartitionIndex;
+    coPos.X = ListUi->Left + 1;
+    coPos.Y = ListUi->Top + 1 + ListUi->Line;
 
-    if (IsContainerPartition(PartEntry->PartitionType))
+    if (PartEntry->IsPartitioned == FALSE)
     {
-        PartEntry->FormatState = Unformatted;
-        PartEntry->FileSystem  = NULL;
-
-        if (LogicalPartition == FALSE && DiskEntry->ExtendedPartition == NULL)
-            DiskEntry->ExtendedPartition = PartEntry;
-    }
+        PartSize.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
 #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;
+        if (PartSize.QuadPart >= 10737418240) /* 10 GB */
+        {
+            PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1073741824);
+            Unit = MUIGetString(STRING_GB);
+        }
         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())
+        if (PartSize.QuadPart >= 10485760) /* 10 MB */
         {
-            PartEntry->FormatState = Preformatted;
+            PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1048576);
+            Unit = MUIGetString(STRING_MB);
         }
         else
         {
-            PartEntry->FormatState = Unformatted;
+            PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1024);
+            Unit = MUIGetString(STRING_KB);
         }
-#endif
-        PartEntry->FormatState = Preformatted;
+
+        sprintf(LineBuffer,
+                MUIGetString(STRING_UNPSPACE),
+                PartEntry->LogicalPartition ? "  " : "",
+                PartEntry->LogicalPartition ? "" : "  ",
+                PartSize.u.LowPart,
+                Unit);
     }
-    else if (PartEntry->PartitionType == PARTITION_EXT2)
+    else
     {
-#if 0
-        if (CheckExt2Format())
+        /* Determine partition type */
+        PartTypeString[0] = '\0';
+        if (PartEntry->New != FALSE)
         {
-            PartEntry->FormatState = Preformatted;
+            PartType = MUIGetString(STRING_UNFORMATTED);
         }
-        else
+        else if (PartEntry->IsPartitioned != FALSE)
         {
-            PartEntry->FormatState = Unformatted;
+            GetPartTypeStringFromPartitionType(PartEntry->PartitionType,
+                                               PartTypeString,
+                                               ARRAYSIZE(PartTypeString));
+            PartType = PartTypeString;
         }
-#endif
-        PartEntry->FormatState = Preformatted;
-    }
-    else if (PartEntry->PartitionType == PARTITION_IFS)
-    {
+
+        PartSize.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
 #if 0
-        if (CheckNtfsFormat())
+        if (PartSize.QuadPart >= 10737418240) /* 10 GB */
         {
-            PartEntry->FormatState = Preformatted;
+            PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1073741824);
+            Unit = MUIGetString(STRING_GB);
         }
-        else if (CheckHpfsFormat())
+        else
+#endif
+        if (PartSize.QuadPart >= 10485760) /* 10 MB */
         {
-            PartEntry->FormatState = Preformatted;
+            PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1048576);
+            Unit = MUIGetString(STRING_MB);
         }
         else
         {
-            PartEntry->FormatState = Unformatted;
+            PartSize.QuadPart = RoundingDivide(PartSize.QuadPart, 1024);
+            Unit = MUIGetString(STRING_KB);
         }
-#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;
+        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);
+        }
     }
 
-    /* Start partition at head 1, cylinder 0 */
-    LastStartSector = DiskEntry->SectorAlignment;
-    LastSectorCount = 0ULL;
-    LastUnusedSectorCount = 0ULL;
+    Attribute = (List->CurrentDisk == DiskEntry &&
+                 List->CurrentPartition == PartEntry) ?
+                 FOREGROUND_BLUE | BACKGROUND_WHITE :
+                 FOREGROUND_WHITE | BACKGROUND_BLUE;
 
-    Entry = DiskEntry->PrimaryPartListHead.Flink;
-    while (Entry != &DiskEntry->PrimaryPartListHead)
+    if (ListUi->Line >= 0 && ListUi->Line <= Height)
     {
-        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;
+        FillConsoleOutputCharacterA(StdOutput,
+                                    ' ',
+                                    Width,
+                                    coPos,
+                                    &Written);
     }
-
-    /* Check for trailing unpartitioned disk space */
-    if ((LastStartSector + LastSectorCount) < DiskEntry->SectorCount.QuadPart)
+    coPos.X += 4;
+    Width -= 8;
+    if (ListUi->Line >= 0 && ListUi->Line <= Height)
     {
-        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;
+        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);
+    }
 
-            NewPartEntry->DiskEntry = DiskEntry;
+    ListUi->Line++;
+}
 
-            NewPartEntry->IsPartitioned = FALSE;
-            NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
-            NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
-                                                 NewPartEntry->StartSector.QuadPart;
+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;
 
-            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);
+    Width = ListUi->Right - ListUi->Left - 1;
+    Height = ListUi->Bottom - ListUi->Top - 2;
 
-            NewPartEntry->FormatState = Unformatted;
-            NewPartEntry->FileSystem  = NULL;
+    coPos.X = ListUi->Left + 1;
+    coPos.Y = ListUi->Top + 1 + ListUi->Line;
 
-            /* Append the table to the list */
-            InsertTailList(&DiskEntry->PrimaryPartListHead,
-                           &NewPartEntry->ListEntry);
-        }
+    DiskSize.QuadPart = DiskEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
+    if (DiskSize.QuadPart >= 10737418240) /* 10 GB */
+    {
+        DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, 1073741824);
+        Unit = MUIGetString(STRING_GB);
     }
-
-    if (DiskEntry->ExtendedPartition != NULL)
+    else
     {
-        if (IsListEmpty(&DiskEntry->LogicalPartListHead))
-        {
-            DPRINT1("No logical partition!\n");
+        DiskSize.QuadPart = RoundingDivide(DiskSize.QuadPart, 1048576);
+        if (DiskSize.QuadPart == 0)
+            DiskSize.QuadPart = 1;
+        Unit = MUIGetString(STRING_MB);
+    }
 
-            /* Create a partition entry that represents the empty extended partition */
-            NewPartEntry = RtlAllocateHeap(ProcessHeap,
-                                           HEAP_ZERO_MEMORY,
-                                           sizeof(PARTENTRY));
-            if (NewPartEntry == NULL)
-                return;
+    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);
+    }
 
-            NewPartEntry->DiskEntry = DiskEntry;
-            NewPartEntry->LogicalPartition = TRUE;
+    if (ListUi->Line >= 0 && ListUi->Line <= Height)
+    {
+        FillConsoleOutputAttribute(StdOutput,
+                                   FOREGROUND_WHITE | BACKGROUND_BLUE,
+                                   Width,
+                                   coPos,
+                                   &Written);
 
-            NewPartEntry->IsPartitioned = FALSE;
-            NewPartEntry->StartSector.QuadPart = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
-            NewPartEntry->SectorCount.QuadPart = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment;
+        FillConsoleOutputCharacterA(StdOutput,
+                                    ' ',
+                                    Width,
+                                    coPos,
+                                    &Written);
+    }
 
-            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);
+    coPos.X++;
+    if (ListUi->Line >= 0 && ListUi->Line <= Height)
+    {
+        WriteConsoleOutputCharacterA(StdOutput,
+                                     LineBuffer,
+                                     min((USHORT)strlen(LineBuffer), Width - 2),
+                                     coPos,
+                                     &Written);
+    }
 
-            NewPartEntry->FormatState = Unformatted;
-            NewPartEntry->FileSystem  = NULL;
+    ListUi->Line++;
 
-            InsertTailList(&DiskEntry->LogicalPartListHead,
-                           &NewPartEntry->ListEntry);
+    /* Print separator line */
+    PrintEmptyLine(ListUi);
 
-            return;
-        }
+    /* Print partition lines */
+    PrimaryEntry = DiskEntry->PrimaryPartListHead.Flink;
+    while (PrimaryEntry != &DiskEntry->PrimaryPartListHead)
+    {
+        PrimaryPartEntry = CONTAINING_RECORD(PrimaryEntry, PARTENTRY, ListEntry);
 
-        /* Start partition at head 1, cylinder 0 */
-        LastStartSector = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
-        LastSectorCount = 0ULL;
-        LastUnusedSectorCount = 0ULL;
+        PrintPartitionData(ListUi,
+                           DiskEntry,
+                           PrimaryPartEntry);
 
-        Entry = DiskEntry->LogicalPartListHead.Flink;
-        while (Entry != &DiskEntry->LogicalPartListHead)
+        if (IsContainerPartition(PrimaryPartEntry->PartitionType))
         {
-            PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
-
-            if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED ||
-                PartEntry->SectorCount.QuadPart != 0ULL)
+            LogicalEntry = DiskEntry->LogicalPartListHead.Flink;
+            while (LogicalEntry != &DiskEntry->LogicalPartListHead)
             {
-                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;
+                LogicalPartEntry = CONTAINING_RECORD(LogicalEntry, PARTENTRY, ListEntry);
 
-                    /* Insert the table into the list */
-                    InsertTailList(&PartEntry->ListEntry,
-                                   &NewPartEntry->ListEntry);
-                }
+                PrintPartitionData(ListUi,
+                                   DiskEntry,
+                                   LogicalPartEntry);
 
-                LastStartSector = PartEntry->StartSector.QuadPart;
-                LastSectorCount = PartEntry->SectorCount.QuadPart;
+                LogicalEntry = LogicalEntry->Flink;
             }
-
-            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);
-            }
-        }
+        PrimaryEntry = PrimaryEntry->Flink;
     }
 
-    DPRINT("ScanForUnpartitionedDiskSpace() done\n");
+    /* Print separator line */
+    PrintEmptyLine(ListUi);
 }
 
-
-static
 VOID
-SetDiskSignature(
-    IN PPARTLIST List,
-    IN PDISKENTRY DiskEntry)
+DrawPartitionList(
+    IN PPARTLIST_UI ListUi)
 {
-    LARGE_INTEGER SystemTime;
-    TIME_FIELDS TimeFields;
-    PLIST_ENTRY Entry2;
-    PDISKENTRY DiskEntry2;
-    PUCHAR Buffer;
+    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;
 
-    Buffer = (PUCHAR)&DiskEntry->LayoutBuffer->Signature;
+    /* Calculate the line of the current disk and partition */
+    CurrentDiskLine = 0;
+    CurrentPartLine = 0;
+    LastLine = 0;
 
-    while (1)
+    Entry = List->DiskListHead.Flink;
+    while (Entry != &List->DiskListHead)
     {
-        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);
+        DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
 
-        if (DiskEntry->LayoutBuffer->Signature == 0)
+        LastLine += 2;
+        if (CurrentPartLineFound == FALSE)
         {
-            continue;
+            CurrentPartLine += 2;
         }
 
-        /* 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)
+        Entry2 = DiskEntry->PrimaryPartListHead.Flink;
+        while (Entry2 != &DiskEntry->PrimaryPartListHead)
         {
-            DiskEntry2 = CONTAINING_RECORD(Entry2, DISKENTRY, ListEntry);
-
-            if (DiskEntry != DiskEntry2 &&
-                DiskEntry->LayoutBuffer->Signature == DiskEntry2->LayoutBuffer->Signature)
-                break;
+            PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
+            if (PartEntry == List->CurrentPartition)
+            {
+                CurrentPartLineFound = TRUE;
+            }
 
             Entry2 = Entry2->Flink;
-        }
-
-        if (Entry2 == &List->DiskListHead)
-            break;
-    }
-}
+            if (CurrentPartLineFound == FALSE)
+            {
+                CurrentPartLine++;
+            }
 
+            LastLine++;
+        }
 
-static
-VOID
-UpdateDiskSignatures(
-    IN PPARTLIST List)
-{
-    PLIST_ENTRY Entry;
-    PDISKENTRY DiskEntry;
+        if (CurrentPartLineFound == FALSE)
+        {
+            Entry2 = DiskEntry->LogicalPartListHead.Flink;
+            while (Entry2 != &DiskEntry->LogicalPartListHead)
+            {
+                PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
+                if (PartEntry == List->CurrentPartition)
+                {
+                    CurrentPartLineFound = TRUE;
+                }
 
-    /* Print partition lines */
-    Entry = List->DiskListHead.Flink;
-    while (Entry != &List->DiskListHead)
-    {
-        DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
+                Entry2 = Entry2->Flink;
+                if (CurrentPartLineFound == FALSE)
+                {
+                    CurrentPartLine++;
+                }
+
+                LastLine++;
+            }
+        }
 
-        if (DiskEntry->LayoutBuffer &&
-            DiskEntry->LayoutBuffer->Signature == 0)
+        if (DiskEntry == List->CurrentDisk)
         {
-            SetDiskSignature(List, DiskEntry);
-            DiskEntry->LayoutBuffer->PartitionEntry[0].RewritePartition = TRUE;
+            CurrentDiskLineFound = 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 (Entry != &List->DiskListHead)
         {
-            if (!DiskEntry->BiosFound)
-            {
-                DiskEntry->BiosDiskNumber = BiosDiskEntry->DiskNumber;
-                DiskEntry->BiosFound = TRUE;
-                BiosDiskEntry->Recognized = TRUE;
-            }
-            else
+            if (CurrentDiskLineFound == FALSE)
             {
+                CurrentPartLine ++;
+                CurrentDiskLine = CurrentPartLine;
             }
-        }
-        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;
+            LastLine++;
         }
-
-        LayoutBufferSize += 4 * sizeof(PARTITION_INFORMATION);
-        NewLayoutBuffer = RtlReAllocateHeap(ProcessHeap,
-                                            HEAP_ZERO_MEMORY,
-                                            DiskEntry->LayoutBuffer,
-                                            LayoutBufferSize);
-        if (NewLayoutBuffer == NULL)
+        else
         {
-            DPRINT1("Failed to reallocate the disk layout buffer!\n");
-            return;
+            LastLine--;
         }
-
-        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 it possible, make the disk name visible */
+    if (CurrentPartLine < ListUi->Offset)
     {
-        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);
-        }
+        ListUi->Offset = CurrentPartLine;
     }
-    else
+    else if (CurrentPartLine - ListUi->Offset > ListUi->Bottom - ListUi->Top - 2)
     {
-        DPRINT1("No valid partition table found! Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector);
+        ListUi->Offset = CurrentPartLine - (ListUi->Bottom - ListUi->Top - 2);
     }
 
-
-    if (DiskEntry->LayoutBuffer->PartitionCount == 0)
+    if (CurrentDiskLine < ListUi->Offset && CurrentPartLine - CurrentDiskLine < ListUi->Bottom - ListUi->Top - 2)
     {
-        DiskEntry->NewDisk = TRUE;
-        DiskEntry->LayoutBuffer->PartitionCount = 4;
+        ListUi->Offset = CurrentDiskLine;
+    }
+
+    /* Draw upper left corner */
+    coPos.X = ListUi->Left;
+    coPos.Y = ListUi->Top;
+    FillConsoleOutputCharacterA(StdOutput,
+                                0xDA, // '+',
+                                1,
+                                coPos,
+                                &Written);
 
-        for (i = 0; i < 4; i++)
-            DiskEntry->LayoutBuffer->PartitionEntry[i].RewritePartition = TRUE;
+    /* 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
     {
-        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);
-        }
+        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);
     }
 
-    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;
-    }
+    /* Draw upper right corner */
+    coPos.X = ListUi->Right;
+    coPos.Y = ListUi->Top;
+    FillConsoleOutputCharacterA(StdOutput,
+                                0xBF, // '+',
+                                1,
+                                coPos,
+                                &Written);
 
-    for (DiskNumber = 0; DiskNumber < Sdi.NumberOfDisks; DiskNumber++)
+    /* Draw left and right edge */
+    for (i = ListUi->Top + 1; i < ListUi->Bottom; i++)
     {
-        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);
+        coPos.X = ListUi->Left;
+        coPos.Y = i;
+        FillConsoleOutputCharacterA(StdOutput,
+                                    0xB3, // '|',
+                                    1,
+                                    coPos,
+                                    &Written);
 
-            NtClose(FileHandle);
-        }
+        coPos.X = ListUi->Right;
+        FillConsoleOutputCharacterA(StdOutput,
+                                    0xB3, //'|',
+                                    1,
+                                    coPos,
+                                    &Written);
     }
 
-    UpdateDiskSignatures(List);
-
-    AssignDriveLetters(List);
+    /* Draw lower left corner */
+    coPos.X = ListUi->Left;
+    coPos.Y = ListUi->Bottom;
+    FillConsoleOutputCharacterA(StdOutput,
+                                0xC0, // '+',
+                                1,
+                                coPos,
+                                &Written);
 
-    /* Search for first usable disk and partition */
-    if (IsListEmpty(&List->DiskListHead))
+    /* Draw lower edge */
+    coPos.X = ListUi->Left + 1;
+    coPos.Y = ListUi->Bottom;
+    if (LastLine - ListUi->Offset <= ListUi->Bottom - ListUi->Top - 2)
     {
-        List->CurrentDisk = NULL;
-        List->CurrentPartition = NULL;
+        FillConsoleOutputCharacterA(StdOutput,
+                                    0xC4, // '-',
+                                    ListUi->Right - ListUi->Left - 1,
+                                    coPos,
+                                    &Written);
     }
     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);
-        }
+        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);
     }
 
-    return List;
-}
-
+    /* Draw lower right corner */
+    coPos.X = ListUi->Right;
+    coPos.Y = ListUi->Bottom;
+    FillConsoleOutputCharacterA(StdOutput,
+                                0xD9, // '+',
+                                1,
+                                coPos,
+                                &Written);
 
-VOID
-DestroyPartitionList(
-    IN PPARTLIST List)
-{
-    PDISKENTRY DiskEntry;
-    PBIOSDISKENTRY BiosDiskEntry;
-    PPARTENTRY PartEntry;
-    PLIST_ENTRY Entry;
+    /* print list entries */
+    ListUi->Line = - ListUi->Offset;
 
-    /* Release disk and partition info */
-    while (!IsListEmpty(&List->DiskListHead))
+    Entry = List->DiskListHead.Flink;
+    while (Entry != &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);
+        /* Print disk entry */
+        PrintDiskData(ListUi, DiskEntry);
 
-        RtlFreeHeap(ProcessHeap, 0, BiosDiskEntry);
+        Entry = Entry->Flink;
     }
-
-    /* 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(
+ScrollDownPartitionList(
     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++;
+    if (GetNextPartition(ListUi->List))
+        DrawPartitionList(ListUi);
 }
 
-
-static
 VOID
-PrintDiskData(
-    IN PPARTLIST_UI ListUi,
-    IN PDISKENTRY DiskEntry)
+ScrollUpPartitionList(
+    IN PPARTLIST_UI ListUi)
 {
-    // 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
-BOOLEAN
-IsSamePrimaryLayoutEntry(
-    IN PPARTITION_INFORMATION PartitionInfo,
-    IN PDISKENTRY DiskEntry,
-    IN PPARTENTRY PartEntry)
-{
-    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;
-
-    return FALSE;
-}
-
-
-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++;
-
-        Entry = Entry->Flink;
-    }
-
-    return Count;
-}
-
-
-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)
-{
-    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;
-    }
-
-    /* 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;
-}
-
-
-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)
-    {
-        DPRINT("ReAllocateLayoutBuffer() failed.\n");
-        return;
-    }
-
-    /* Update the primary partition table */
-    Index = 0;
-    ListEntry = DiskEntry->PrimaryPartListHead.Flink;
-    while (ListEntry != &DiskEntry->PrimaryPartListHead)
-    {
-        PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
-
-        if (PartEntry->IsPartitioned != FALSE)
-        {
-            PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
-
-            if (!IsSamePrimaryLayoutEntry(PartitionInfo, DiskEntry, PartEntry))
-            {
-                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;
-    }
-
-    /* Update the logical partition table */
-    Index = 4;
-    ListEntry = DiskEntry->LogicalPartListHead.Flink;
-    while (ListEntry != &DiskEntry->LogicalPartListHead)
-    {
-        PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
-
-        if (PartEntry->IsPartitioned)
-        {
-            PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
-
-            DPRINT1("Updating logical partition entry %lu\n", Index);
-
-            PartitionInfo->StartingOffset.QuadPart = PartEntry->StartSector.QuadPart * DiskEntry->BytesPerSector;
-            PartitionInfo->PartitionLength.QuadPart = PartEntry->SectorCount.QuadPart * DiskEntry->BytesPerSector;
-            PartitionInfo->HiddenSectors = DiskEntry->SectorAlignment;
-            PartitionInfo->PartitionNumber = PartitionNumber;
-            PartitionInfo->PartitionType = PartEntry->PartitionType;
-            PartitionInfo->BootIndicator = FALSE;
-            PartitionInfo->RecognizedPartition = FALSE;
-            PartitionInfo->RewritePartition = TRUE;
-
-            PartEntry->PartitionNumber = PartitionNumber;
-            PartEntry->PartitionIndex = Index;
-
-            /* Fill the link entry of the previous partition entry */
-            if (LinkInfo != NULL)
-            {
-                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;
-        }
-
-        ListEntry = ListEntry->Flink;
-    }
-
-    /* Wipe unused primary partition entries */
-    for (Index = GetPrimaryPartitionCount(DiskEntry); Index < 4; Index++)
-    {
-        DPRINT1("Primary partition entry %lu\n", Index);
-
-        PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[Index];
-
-        if (!IsEmptyLayoutEntry(PartitionInfo))
-        {
-            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;
-        }
-    }
-
-    /* Wipe unused logical partition entries */
-    for (Index = 4; Index < DiskEntry->LayoutBuffer->PartitionCount; Index++)
-    {
-        if (Index % 4 >= 2)
-        {
-            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;
-            }
-        }
-    }
-
-#ifdef DUMP_PARTITION_TABLE
-    DumpPartitionTable(DiskEntry);
-#endif
-}
-
-
-static
-PPARTENTRY
-GetPrevUnpartitionedEntry(
-    IN PDISKENTRY DiskEntry,
-    IN PPARTENTRY PartEntry)
-{
-    PPARTENTRY PrevPartEntry;
-    PLIST_ENTRY ListHead;
-
-    if (PartEntry->LogicalPartition)
-        ListHead = &DiskEntry->LogicalPartListHead;
-    else
-        ListHead = &DiskEntry->PrimaryPartListHead;
-
-    if (PartEntry->ListEntry.Blink != ListHead)
-    {
-        PrevPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Blink,
-                                          PARTENTRY,
-                                          ListEntry);
-        if (PrevPartEntry->IsPartitioned == FALSE)
-            return PrevPartEntry;
-    }
-
-    return NULL;
-}
-
-
-static
-PPARTENTRY
-GetNextUnpartitionedEntry(
-    IN PDISKENTRY DiskEntry,
-    IN PPARTENTRY PartEntry)
-{
-    PPARTENTRY NextPartEntry;
-    PLIST_ENTRY ListHead;
-
-    if (PartEntry->LogicalPartition)
-        ListHead = &DiskEntry->LogicalPartListHead;
-    else
-        ListHead = &DiskEntry->PrimaryPartListHead;
-
-    if (PartEntry->ListEntry.Flink != ListHead)
-    {
-        NextPartEntry = CONTAINING_RECORD(PartEntry->ListEntry.Flink,
-                                          PARTENTRY,
-                                          ListEntry);
-        if (NextPartEntry->IsPartitioned == FALSE)
-            return NextPartEntry;
-    }
-
-    return NULL;
-}
-
-
-VOID
-CreatePrimaryPartition(
-    IN PPARTLIST List,
-    IN ULONGLONG SectorCount,
-    IN BOOLEAN AutoCreate)
-{
-    PDISKENTRY DiskEntry;
-    PPARTENTRY PartEntry;
-    PPARTENTRY NewPartEntry;
-
-    DPRINT1("CreatePrimaryPartition(%I64u)\n", SectorCount);
-
-    if (List == NULL ||
-        List->CurrentDisk == NULL ||
-        List->CurrentPartition == NULL ||
-        List->CurrentPartition->IsPartitioned != FALSE)
-    {
-        return;
-    }
-
-    DiskEntry = List->CurrentDisk;
-    PartEntry = List->CurrentPartition;
-
-    DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
-
-    if ((AutoCreate != FALSE) ||
-        (AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart))
-    {
-        DPRINT1("Convert existing partition entry\n");
-
-        /* Convert current entry to 'new (unformatted)' */
-        PartEntry->IsPartitioned = TRUE;
-        PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
-        PartEntry->FormatState = Unformatted;
-        PartEntry->FileSystem  = NULL;
-        PartEntry->AutoCreate = AutoCreate;
-        PartEntry->New = TRUE;
-        PartEntry->BootIndicator = FALSE;
-
-        DPRINT1("First Sector: %I64u\n", PartEntry->StartSector.QuadPart);
-        DPRINT1("Last Sector: %I64u\n", PartEntry->StartSector.QuadPart + PartEntry->SectorCount.QuadPart - 1);
-        DPRINT1("Total Sectors: %I64u\n", PartEntry->SectorCount.QuadPart);
-    }
-    else
-    {
-        DPRINT1("Add new partition entry\n");
-
-        /* Insert and initialize a new partition entry */
-        NewPartEntry = RtlAllocateHeap(ProcessHeap,
-                                       HEAP_ZERO_MEMORY,
-                                       sizeof(PARTENTRY));
-        if (NewPartEntry == NULL)
-            return;
-
-        /* Insert the new entry into the list */
-        InsertTailList(&PartEntry->ListEntry,
-                       &NewPartEntry->ListEntry);
-
-        NewPartEntry->DiskEntry = DiskEntry;
-
-        NewPartEntry->IsPartitioned = TRUE;
-        NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
-        NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
-                                             NewPartEntry->StartSector.QuadPart;
-        NewPartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
-
-        DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
-        DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
-        DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
-
-        NewPartEntry->New = TRUE;
-        NewPartEntry->FormatState = Unformatted;
-        NewPartEntry->FileSystem  = NULL;
-        NewPartEntry->BootIndicator = FALSE;
-
-        PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
-        PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
-    }
-
-    UpdateDiskLayout(DiskEntry);
-
-    DiskEntry->Dirty = TRUE;
-
-    AssignDriveLetters(List);
-}
-
-
-static
-VOID
-AddLogicalDiskSpace(
-    IN PDISKENTRY DiskEntry)
-{
-    PPARTENTRY NewPartEntry;
-
-    DPRINT1("AddLogicalDiskSpace()\n");
-
-    /* Create a partition entry that represents the empty space in the container partition */
-    NewPartEntry = RtlAllocateHeap(ProcessHeap,
-                                   HEAP_ZERO_MEMORY,
-                                   sizeof(PARTENTRY));
-    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);
-}
-
-
-VOID
-CreateExtendedPartition(
-    IN PPARTLIST List,
-    IN ULONGLONG SectorCount)
-{
-    PDISKENTRY DiskEntry;
-    PPARTENTRY PartEntry;
-    PPARTENTRY NewPartEntry;
-
-    DPRINT1("CreateExtendedPartition(%I64u)\n", SectorCount);
-
-    if (List == NULL ||
-        List->CurrentDisk == NULL ||
-        List->CurrentPartition == NULL ||
-        List->CurrentPartition->IsPartitioned != FALSE)
-    {
-        return;
-    }
-
-    DiskEntry = List->CurrentDisk;
-    PartEntry = List->CurrentPartition;
-
-    DPRINT1("Current partition sector count: %I64u\n", PartEntry->SectorCount.QuadPart);
-
-    if (AlignDown(PartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) - PartEntry->StartSector.QuadPart == PartEntry->SectorCount.QuadPart)
-    {
-        DPRINT1("Convert existing partition entry\n");
-
-        /* Convert current entry to 'new (unformatted)' */
-        PartEntry->IsPartitioned = TRUE;
-        PartEntry->FormatState = Formatted;     // FIXME? Possibly to make GetNextUnformattedPartition work (i.e. skip the extended partition container)
-        PartEntry->FileSystem  = NULL;
-        PartEntry->AutoCreate = FALSE;
-        PartEntry->New = FALSE;
-        PartEntry->BootIndicator = FALSE;
-
-        if (PartEntry->StartSector.QuadPart < 1450560)
-        {
-            /* Partition starts below the 8.4GB boundary ==> CHS partition */
-            PartEntry->PartitionType = PARTITION_EXTENDED;
-        }
-        else
-        {
-            /* Partition starts above the 8.4GB boundary ==> LBA partition */
-            PartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
-        }
-
-        DiskEntry->ExtendedPartition = PartEntry;
-
-        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");
-
-        /* Insert and initialize a new partition entry */
-        NewPartEntry = RtlAllocateHeap(ProcessHeap,
-                                       HEAP_ZERO_MEMORY,
-                                       sizeof(PARTENTRY));
-        if (NewPartEntry == NULL)
-            return;
-
-        /* Insert the new entry into the list */
-        InsertTailList(&PartEntry->ListEntry,
-                       &NewPartEntry->ListEntry);
-
-        NewPartEntry->DiskEntry = DiskEntry;
-
-        NewPartEntry->IsPartitioned = TRUE;
-        NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
-        NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
-                                             NewPartEntry->StartSector.QuadPart;
-
-        NewPartEntry->New = FALSE;
-        NewPartEntry->FormatState = Formatted;     // FIXME? Possibly to make GetNextUnformattedPartition work (i.e. skip the extended partition container)
-        NewPartEntry->FileSystem  = NULL;
-        NewPartEntry->BootIndicator = FALSE;
-
-        if (NewPartEntry->StartSector.QuadPart < 1450560)
-        {
-            /* Partition starts below the 8.4GB boundary ==> CHS partition */
-            NewPartEntry->PartitionType = PARTITION_EXTENDED;
-        }
-        else
-        {
-            /* Partition starts above the 8.4GB boundary ==> LBA partition */
-            NewPartEntry->PartitionType = PARTITION_XINT13_EXTENDED;
-        }
-
-        DiskEntry->ExtendedPartition = NewPartEntry;
-
-        PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
-        PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
-
-        DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
-        DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
-        DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
-    }
-
-    AddLogicalDiskSpace(DiskEntry);
-
-    UpdateDiskLayout(DiskEntry);
-
-    DiskEntry->Dirty = TRUE;
-
-    AssignDriveLetters(List);
-}
-
-
-VOID
-CreateLogicalPartition(
-    IN PPARTLIST List,
-    IN ULONGLONG SectorCount,
-    IN BOOLEAN AutoCreate)
-{
-    PDISKENTRY DiskEntry;
-    PPARTENTRY PartEntry;
-    PPARTENTRY NewPartEntry;
-
-    DPRINT1("CreateLogicalPartition(%I64u)\n", SectorCount);
-
-    if (List == NULL ||
-        List->CurrentDisk == NULL ||
-        List->CurrentPartition == NULL ||
-        List->CurrentPartition->IsPartitioned != FALSE)
-    {
-        return;
-    }
-
-    DiskEntry = List->CurrentDisk;
-    PartEntry = List->CurrentPartition;
-
-    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");
-
-        /* 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");
-
-        /* Insert and initialize a new partition entry */
-        NewPartEntry = RtlAllocateHeap(ProcessHeap,
-                                       HEAP_ZERO_MEMORY,
-                                       sizeof(PARTENTRY));
-        if (NewPartEntry == NULL)
-            return;
-
-        /* Insert the new entry into the list */
-        InsertTailList(&PartEntry->ListEntry,
-                       &NewPartEntry->ListEntry);
-
-        NewPartEntry->DiskEntry = DiskEntry;
-
-        NewPartEntry->IsPartitioned = TRUE;
-        NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
-        NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + SectorCount, DiskEntry->SectorAlignment) -
-                                             NewPartEntry->StartSector.QuadPart;
-        NewPartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
-
-        DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
-        DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
-        DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
-
-        NewPartEntry->New = TRUE;
-        NewPartEntry->FormatState = Unformatted;
-        NewPartEntry->FileSystem  = NULL;
-        NewPartEntry->BootIndicator = FALSE;
-        NewPartEntry->LogicalPartition = TRUE;
-
-        PartEntry->StartSector.QuadPart = NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart;
-        PartEntry->SectorCount.QuadPart -= (PartEntry->StartSector.QuadPart - NewPartEntry->StartSector.QuadPart);
-    }
-
-    UpdateDiskLayout(DiskEntry);
-
-    DiskEntry->Dirty = TRUE;
-
-    AssignDriveLetters(List);
-}
-
-
-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)
-    {
-        return;
-    }
-
-    /* Clear the system disk and partition pointers if the system partition is being deleted */
-    if (List->SystemPartition == List->CurrentPartition)
-    {
-        List->SystemPartition = NULL;
-    }
-
-    DiskEntry = List->CurrentDisk;
-    PartEntry = List->CurrentPartition;
-
-    /* Delete all logical partition entries if an extended partition will be deleted */
-    if (DiskEntry->ExtendedPartition == PartEntry)
-    {
-        while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
-        {
-            Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
-            LogicalPartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
-
-            RtlFreeHeap(ProcessHeap, 0, LogicalPartEntry);
-        }
-
-        DiskEntry->ExtendedPartition = NULL;
-    }
-
-    /* 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->SectorCount.QuadPart += (PartEntry->SectorCount.QuadPart + NextPartEntry->SectorCount.QuadPart);
-
-        /* 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->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
-
-        /* 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->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
-        NextPartEntry->SectorCount.QuadPart += PartEntry->SectorCount.QuadPart;
-
-        /* 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->IsPartitioned = FALSE;
-        PartEntry->PartitionType = PARTITION_ENTRY_UNUSED;
-        PartEntry->FormatState = Unformatted;
-        PartEntry->FileSystem  = NULL;
-        PartEntry->DriveLetter = 0;
-    }
-
-    UpdateDiskLayout(DiskEntry);
-
-    DiskEntry->Dirty = TRUE;
-
-    AssignDriveLetters(List);
-}
-
-
-VOID
-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 ListEntry;
-
-    PFILE_SYSTEM_ITEM FileSystem;
-
-    /* Check for empty disk list */
-    if (IsListEmpty(&List->DiskListHead))
-    {
-        List->SystemPartition = NULL;
-        List->OriginalSystemPartition = NULL;
-        return;
-    }
-
-    /* Choose the currently selected disk */
-    DiskEntry = List->CurrentDisk;
-
-    /* Check for empty partition list */
-    if (IsListEmpty(&DiskEntry->PrimaryPartListHead))
-    {
-        List->SystemPartition = NULL;
-        List->OriginalSystemPartition = NULL;
-        return;
-    }
-
-    if (List->SystemPartition != NULL)
-    {
-        /* We already have an active system partition */
-        DPRINT1("Use the current system partition %lu in disk %lu, drive letter %c\n",
-                List->SystemPartition->PartitionNumber,
-                List->SystemPartition->DiskEntry->DiskNumber,
-                (List->SystemPartition->DriveLetter == 0) ? '-' : List->SystemPartition->DriveLetter);
-        return;
-    }
-
-    DPRINT1("We are here (1)!\n");
-
-    List->SystemPartition = NULL;
-    List->OriginalSystemPartition = NULL;
-
-    /* Retrieve the first partition of the disk */
-    PartEntry = CONTAINING_RECORD(DiskEntry->PrimaryPartListHead.Flink,
-                                  PARTENTRY,
-                                  ListEntry);
-    ASSERT(DiskEntry == PartEntry->DiskEntry);
-    List->SystemPartition = PartEntry;
-
-    //
-    // See: https://svn.reactos.org/svn/reactos/trunk/reactos/base/setup/usetup/partlist.c?r1=63355&r2=63354&pathrev=63355#l2318
-    //
-
-    /* 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;
-
-            List->OriginalSystemPartition = List->SystemPartition;
-
-            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);
-
-            goto SetSystemPartition;
-        }
-
-        // FIXME: What to do??
-        DPRINT1("NewDisk TRUE but first partition is used?\n");
-    }
-
-    DPRINT1("We are here (2)!\n");
-
-    /*
-     * The disk is not new, check if any partition is initialized;
-     * if not, the first one becomes the system partition.
-     */
-    ListEntry = DiskEntry->PrimaryPartListHead.Flink;
-    while (ListEntry != &DiskEntry->PrimaryPartListHead)
-    {
-        /* Retrieve the partition and go to the next one */
-        PartEntry = CONTAINING_RECORD(ListEntry,
-                                      PARTENTRY,
-                                      ListEntry);
-
-        /* Check if the partition is partitioned and is used */
-        if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED || PartEntry->BootIndicator != FALSE)
-        {
-            break;
-        }
-
-        /* Go to the next one */
-        ListEntry = ListEntry->Flink;
-    }
-    if (ListEntry == &DiskEntry->PrimaryPartListHead)
-    {
-        /*
-         * OK we haven't encountered any used and active partition,
-         * so use the first one as the system partition.
-         */
-        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;
-    }
-
-    List->SystemPartition = NULL;
-    List->OriginalSystemPartition = NULL;
-
-    DPRINT1("We are here (3)!\n");
-
-    /* The disk is not new, scan all partitions to find the (active) system partition */
-    ListEntry = DiskEntry->PrimaryPartListHead.Flink;
-    while (ListEntry != &DiskEntry->PrimaryPartListHead)
-    {
-        /* Retrieve the partition and go to the next one */
-        PartEntry = CONTAINING_RECORD(ListEntry,
-                                      PARTENTRY,
-                                      ListEntry);
-        ListEntry = ListEntry->Flink;
-
-        /* Check if the partition is partitioned and used */
-        if (PartEntry->IsPartitioned &&
-            PartEntry->PartitionType != PARTITION_ENTRY_UNUSED)
-        {
-            /* Check if the partition is active */
-            if (PartEntry->BootIndicator)
-            {
-                /* Yes, we found it */
-                ASSERT(DiskEntry == PartEntry->DiskEntry);
-                List->SystemPartition = PartEntry;
-
-                DPRINT1("Found active system partition %lu in disk %lu, drive letter %c\n",
-                        PartEntry->PartitionNumber,
-                        DiskEntry->DiskNumber,
-                        (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter);
-                break;
-            }
-        }
-    }
-
-    /* Check if we have found the system partition */
-    if (List->SystemPartition == NULL)
-    {
-        /* Nothing, use the alternative system partition */
-        DPRINT1("No system partition found, use the alternative partition!\n");
-        goto UseAlternativeSystemPartition;
-    }
-
-    /* Save it */
-    List->OriginalSystemPartition = List->SystemPartition;
-
-    /*
-     * ADDITIONAL CHECKS / BIG HACK:
-     *
-     * Retrieve its file system and check whether we have
-     * write support for it. If that is the case we are fine
-     * and we can use it directly. However if we don't have
-     * write support we will need to change the active system
-     * partition.
-     *
-     * NOTE that this is completely useless on architectures
-     * where a real system partition is required, as on these
-     * architectures the partition uses the FAT FS, for which
-     * we do have write support.
-     * NOTE also that for those architectures looking for a
-     * partition boot indicator is insufficient.
-     */
-    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;
-    }
-
-    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);
-
-    return;
-
-FindAndUseAlternativeSystemPartition:
-    /*
-     * We are here because we have not found any (active) candidate
-     * system partition that we know how to support. What we are going
-     * to do is to change the existing system partition and use the
-     * partition on which we install ReactOS as the new system partition,
-     * and then we will need to add in FreeLdr's entry a boot entry to boot
-     * from the original system partition.
-     */
-
-    /* Unset the old system partition */
-    List->SystemPartition->BootIndicator = FALSE;
-    List->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
-NTSTATUS
-WritePartitions(
-    IN PPARTLIST List,
-    IN PDISKENTRY DiskEntry)
-{
-    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;
-    }
-
-#ifdef DUMP_PARTITION_TABLE
-    DumpPartitionTable(DiskEntry);
-#endif
-
-    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);
-    }
-
-    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).
-    //
-
-    return Status;
-}
-
-
-BOOLEAN
-WritePartitionsToDisk(
-    IN PPARTLIST List)
-{
-    PLIST_ENTRY Entry;
-    PDISKENTRY DiskEntry;
-
-    if (List == NULL)
-        return TRUE;
-
-    Entry = List->DiskListHead.Flink;
-    while (Entry != &List->DiskListHead)
-    {
-        DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
-
-        if (DiskEntry->Dirty != FALSE)
-        {
-            WritePartitions(List, DiskEntry);
-            DiskEntry->Dirty = FALSE;
-        }
-
-        Entry = Entry->Flink;
-    }
-
-    return TRUE;
-}
-
-
-BOOLEAN
-SetMountedDeviceValues(
-    IN PPARTLIST List)
-{
-    PLIST_ENTRY Entry1, Entry2;
-    PDISKENTRY DiskEntry;
-    PPARTENTRY PartEntry;
-    LARGE_INTEGER StartingOffset;
-
-    if (List == NULL)
-        return FALSE;
-
-    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);
-            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;
-                    }
-                }
-            }
-
-            Entry2 = Entry2->Flink;
-        }
-
-        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;
-                    }
-                }
-            }
-
-            Entry2 = Entry2->Flink;
-        }
-
-        Entry1 = Entry1->Flink;
-    }
-
-    return TRUE;
-}
-
-VOID
-SetPartitionType(
-    IN PPARTENTRY PartEntry,
-    IN UCHAR PartitionType)
-{
-    PDISKENTRY DiskEntry = PartEntry->DiskEntry;
-
-    PartEntry->PartitionType = PartitionType;
-
-    DiskEntry->Dirty = TRUE;
-    DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].PartitionType = PartitionType;
-    DiskEntry->LayoutBuffer->PartitionEntry[PartEntry->PartitionIndex].RewritePartition = TRUE;
-}
-
-ULONG
-PrimaryPartitionCreationChecks(
-    IN PPARTLIST List)
-{
-    PDISKENTRY DiskEntry;
-    PPARTENTRY PartEntry;
-
-    DiskEntry = List->CurrentDisk;
-    PartEntry = List->CurrentPartition;
-
-    /* Fail if partition is already in use */
-    if (PartEntry->IsPartitioned != FALSE)
-        return ERROR_NEW_PARTITION;
-
-    /* Fail if there are already 4 primary partitions in the list */
-    if (GetPrimaryPartitionCount(DiskEntry) >= 4)
-        return ERROR_PARTITION_TABLE_FULL;
-
-    return ERROR_SUCCESS;
-}
-
-
-ULONG
-ExtendedPartitionCreationChecks(
-    IN PPARTLIST List)
-{
-    PDISKENTRY DiskEntry;
-    PPARTENTRY PartEntry;
-
-    DiskEntry = List->CurrentDisk;
-    PartEntry = List->CurrentPartition;
-
-    /* Fail if partition is already in use */
-    if (PartEntry->IsPartitioned != FALSE)
-        return ERROR_NEW_PARTITION;
-
-    /* Fail if there are already 4 primary partitions in the list */
-    if (GetPrimaryPartitionCount(DiskEntry) >= 4)
-        return ERROR_PARTITION_TABLE_FULL;
-
-    /* Fail if there is another extended partition in the list */
-    if (DiskEntry->ExtendedPartition != NULL)
-        return ERROR_ONLY_ONE_EXTENDED;
-
-    return ERROR_SUCCESS;
-}
-
-
-ULONG
-LogicalPartitionCreationChecks(
-    IN PPARTLIST List)
-{
-//    PDISKENTRY DiskEntry;
-    PPARTENTRY PartEntry;
-
-//    DiskEntry = List->CurrentDisk;
-    PartEntry = List->CurrentPartition;
-
-    /* Fail if partition is already in use */
-    if (PartEntry->IsPartitioned != FALSE)
-        return ERROR_NEW_PARTITION;
-
-    return ERROR_SUCCESS;
-}
-
-
-BOOLEAN
-GetNextUnformattedPartition(
-    IN PPARTLIST List,
-    OUT PDISKENTRY *pDiskEntry OPTIONAL,
-    OUT PPARTENTRY *pPartEntry)
-{
-    PLIST_ENTRY Entry1, Entry2;
-    PDISKENTRY DiskEntry;
-    PPARTENTRY PartEntry;
-
-    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);
-            if (PartEntry->IsPartitioned && PartEntry->New)
-            {
-                ASSERT(DiskEntry == PartEntry->DiskEntry);
-                if (pDiskEntry) *pDiskEntry = DiskEntry;
-                *pPartEntry = PartEntry;
-                return TRUE;
-            }
-
-            Entry2 = Entry2->Flink;
-        }
-
-        Entry2 = DiskEntry->LogicalPartListHead.Flink;
-        while (Entry2 != &DiskEntry->LogicalPartListHead)
-        {
-            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;
-        }
-
-        Entry1 = Entry1->Flink;
-    }
-
-    if (pDiskEntry) *pDiskEntry = NULL;
-    *pPartEntry = NULL;
-
-    return FALSE;
-}
-
-BOOLEAN
-GetNextUncheckedPartition(
-    IN PPARTLIST List,
-    OUT PDISKENTRY *pDiskEntry OPTIONAL,
-    OUT PPARTENTRY *pPartEntry)
-{
-    PLIST_ENTRY Entry1, Entry2;
-    PDISKENTRY DiskEntry;
-    PPARTENTRY PartEntry;
-
-    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);
-            if (PartEntry->NeedsCheck == TRUE)
-            {
-                ASSERT(DiskEntry == PartEntry->DiskEntry);
-                if (pDiskEntry) *pDiskEntry = DiskEntry;