- Don't use STATIC
[reactos.git] / reactos / subsys / system / usetup / partlist.c
index 37ca285..0b61519 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  ReactOS kernel
- *  Copyright (C) 2002 ReactOS Team
+ *  Copyright (C) 2002, 2003, 2004, 2005 ReactOS Team
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-/* $Id: partlist.c,v 1.11 2003/08/02 16:49:36 ekohl Exp $
+/* $Id$
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS text-mode setup
  * FILE:            subsys/system/usetup/partlist.c
  * PURPOSE:         Partition list functions
  * PROGRAMMER:      Eric Kohl
  *                  Casper S. Hornstrup (chorns@users.sourceforge.net)
+ *                  Hartmut Birr
  */
 
-#include <ddk/ntddk.h>
-#include <ddk/ntddscsi.h>
-
-#include <ntdll/rtl.h>
-
-#include <ntos/minmax.h>
-
-#include "usetup.h"
-#include "console.h"
-#include "partlist.h"
-#include "drivesup.h"
+#include <usetup.h>
 
+#define NDEBUG
+#include <debug.h>
 
 /* FUNCTIONS ****************************************************************/
 
 static VOID
-GetDriverName(PDISKENTRY DiskEntry)
+GetDriverName (PDISKENTRY DiskEntry)
 {
   RTL_QUERY_REGISTRY_TABLE QueryTable[2];
   WCHAR KeyName[32];
   NTSTATUS Status;
 
-  RtlInitUnicodeString(&DiskEntry->DriverName,
-                      NULL);
+  RtlInitUnicodeString (&DiskEntry->DriverName,
+                       NULL);
 
-  swprintf(KeyName,
-          L"\\Scsi\\Scsi Port %lu",
-          DiskEntry->Port);
+  swprintf (KeyName,
+           L"\\Scsi\\Scsi Port %lu",
+           DiskEntry->Port);
 
-  RtlZeroMemory(&QueryTable,
-               sizeof(QueryTable));
+  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))
+  Status = RtlQueryRegistryValues (RTL_REGISTRY_DEVICEMAP,
+                                  KeyName,
+                                  QueryTable,
+                                  NULL,
+                                  NULL);
+  if (!NT_SUCCESS (Status))
     {
-      DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
+      DPRINT1 ("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
     }
 }
 
 
 static VOID
-AddPartitionToList (ULONG DiskNumber,
-                   PDISKENTRY DiskEntry,
-                   DRIVE_LAYOUT_INFORMATION *LayoutBuffer)
+AssignDriverLetters (PPARTLIST List)
 {
+  PDISKENTRY DiskEntry;
   PPARTENTRY PartEntry;
-  ULONG i;
-  ULONG EntryCount;
-  BOOLEAN LastEntryWasUnused;
-  ULONGLONG LastStartingOffset;
-  ULONGLONG LastPartitionSize;
-  ULONGLONG LastUnusedPartitionSize;
-  ULONG LastUnusedEntry;
+  PLIST_ENTRY Entry1;
+  PLIST_ENTRY Entry2;
+  CHAR Letter;
 
-  /*
-   * FIXME:
-   * Determine required number of partiton entries.
-   * This must include entries for unused disk space.
-   */
+  Letter = 'C';
 
-  /* Check for unpartitioned disk */
-  if (LayoutBuffer->PartitionCount == 0)
+  /* Assign drive letters to primary partitions */
+  Entry1 = List->DiskListHead.Flink;
+  while (Entry1 != &List->DiskListHead)
     {
-      EntryCount = 1;
+      DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
+
+      if (!IsListEmpty (&DiskEntry->PartListHead))
+       {
+         PartEntry = CONTAINING_RECORD (DiskEntry->PartListHead.Flink,
+                                        PARTENTRY,
+                                        ListEntry);
+
+         PartEntry->DriveLetter = 0;
+
+         if (PartEntry->Unpartitioned == FALSE &&
+             !IsContainerPartition (PartEntry->PartInfo[0].PartitionType))
+           {
+             if (IsRecognizedPartition (PartEntry->PartInfo[0].PartitionType) ||
+                 (PartEntry->PartInfo[0].PartitionType == PARTITION_ENTRY_UNUSED &&
+                  PartEntry->PartInfo[0].PartitionLength.QuadPart != 0LL))
+               {
+                 if (Letter <= 'Z')
+                   {
+                     PartEntry->DriveLetter = Letter;
+                     Letter++;
+                   }
+               }
+           }
+       }
+
+      Entry1 = Entry1->Flink;
     }
-  else
+
+
+  /* Assign drive letters to logical drives */
+  Entry1 = List->DiskListHead.Flink;
+  while (Entry1 != &List->DiskListHead)
+    {
+      DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
+
+      Entry2 = DiskEntry->PartListHead.Flink;
+      if (Entry2 != &DiskEntry->PartListHead)
+       {
+         Entry2 = Entry2->Flink;
+         while (Entry2 != &DiskEntry->PartListHead)
+           {
+             PartEntry = CONTAINING_RECORD (Entry2,
+                                            PARTENTRY,
+                                            ListEntry);
+
+             PartEntry->DriveLetter = 0;
+
+             if (PartEntry->Unpartitioned == FALSE &&
+                 !IsContainerPartition (PartEntry->PartInfo[0].PartitionType))
+               {
+                 if (IsRecognizedPartition (PartEntry->PartInfo[0].PartitionType) ||
+                     (PartEntry->PartInfo[0].PartitionType == PARTITION_ENTRY_UNUSED &&
+                      PartEntry->PartInfo[0].PartitionLength.QuadPart != 0LL))
+                   {
+                     if (Letter <= 'Z')
+                       {
+                         PartEntry->DriveLetter = Letter;
+                         Letter++;
+                       }
+                   }
+               }
+
+             Entry2 = Entry2->Flink;
+           }
+       }
+
+      Entry1 = Entry1->Flink;
+    }
+}
+
+
+static VOID
+UpdatePartitionNumbers (PDISKENTRY DiskEntry)
+{
+  PPARTENTRY PartEntry;
+  PLIST_ENTRY Entry;
+  ULONG PartNumber;
+  ULONG i;
+
+  PartNumber = 1;
+  Entry = DiskEntry->PartListHead.Flink;
+  while (Entry != &DiskEntry->PartListHead)
     {
-      EntryCount = LayoutBuffer->PartitionCount;
+      PartEntry = CONTAINING_RECORD (Entry,
+                                    PARTENTRY,
+                                    ListEntry);
+
+      if (PartEntry->Unpartitioned == TRUE)
+       {
+         for (i = 0; i < 4; i++)
+           {
+             PartEntry->PartInfo[i].PartitionNumber = 0;
+           }
+       }
+      else
+       {
+         for (i = 0; i < 4; i++)
+           {
+             if (IsContainerPartition (PartEntry->PartInfo[i].PartitionType))
+               {
+                 PartEntry->PartInfo[i].PartitionNumber = 0;
+               }
+             else if (PartEntry->PartInfo[i].PartitionType == PARTITION_ENTRY_UNUSED &&
+                      PartEntry->PartInfo[i].PartitionLength.QuadPart == 0ULL)
+               {
+                 PartEntry->PartInfo[i].PartitionNumber = 0;
+               }
+             else
+               {
+                 PartEntry->PartInfo[i].PartitionNumber = PartNumber;
+                 PartNumber++;
+               }
+           }
+       }
+
+      Entry = Entry->Flink;
     }
+}
+
+
+static VOID
+AddPartitionToList (ULONG DiskNumber,
+                   PDISKENTRY DiskEntry,
+                   DRIVE_LAYOUT_INFORMATION *LayoutBuffer)
+{
+  PPARTENTRY PartEntry;
+  ULONG i;
+  ULONG j;
+
+  for (i = 0; i < LayoutBuffer->PartitionCount; i += 4)
+    {
+      for (j = 0; j < 4; j++)
+       {
+         if (LayoutBuffer->PartitionEntry[j].PartitionType != PARTITION_ENTRY_UNUSED ||
+             LayoutBuffer->PartitionEntry[j].PartitionLength.QuadPart != 0ULL)
+           {
+             break;
+           }
+       }
+      if (j >= 4)
+       {
+         continue;
+       }
+
+      PartEntry = (PPARTENTRY)RtlAllocateHeap (ProcessHeap,
+                                              0,
+                                              sizeof(PARTENTRY));
+      if (PartEntry == NULL)
+       {
+         return;
+       }
+
+      RtlZeroMemory (PartEntry,
+                    sizeof(PARTENTRY));
+
+      PartEntry->Unpartitioned = FALSE;
+
+      for (j = 0; j < 4; j++)
+       {
+         RtlCopyMemory (&PartEntry->PartInfo[j],
+                        &LayoutBuffer->PartitionEntry[i+j],
+                        sizeof(PARTITION_INFORMATION));
+       }
+
+      if (IsContainerPartition(PartEntry->PartInfo[0].PartitionType))
+       {
+         PartEntry->FormatState = Unformatted;
+       }
+      else if ((PartEntry->PartInfo[0].PartitionType == PARTITION_FAT_12) ||
+              (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT_16) ||
+              (PartEntry->PartInfo[0].PartitionType == PARTITION_HUGE) ||
+              (PartEntry->PartInfo[0].PartitionType == PARTITION_XINT13) ||
+              (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32) ||
+              (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32_XINT13))
+       {
+#if 0
+         if (CheckFatFormat())
+           {
+             PartEntry->FormatState = Preformatted;
+           }
+         else
+           {
+             PartEntry->FormatState = Unformatted;
+           }
+#endif
+         PartEntry->FormatState = Preformatted;
+       }
+      else if (PartEntry->PartInfo[0].PartitionType == PARTITION_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 = Unknown;
+       }
 
+      InsertTailList (&DiskEntry->PartListHead,
+                     &PartEntry->ListEntry);
+    }
+}
 
-  DiskEntry->PartArray = (PPARTENTRY)RtlAllocateHeap(ProcessHeap,
-                                                    0,
-                                                    EntryCount * sizeof(PARTENTRY));
-  DiskEntry->PartCount = EntryCount;
 
-  RtlZeroMemory(DiskEntry->PartArray,
-               EntryCount * sizeof(PARTENTRY));
+static VOID
+ScanForUnpartitionedDiskSpace (PDISKENTRY DiskEntry)
+{
+  ULONGLONG LastStartingOffset;
+  ULONGLONG LastPartitionLength;
+  ULONGLONG LastUnusedPartitionLength;
+  PPARTENTRY PartEntry;
+  PPARTENTRY NewPartEntry;
+  PLIST_ENTRY Entry;
+  ULONG i;
+  ULONG j;
 
-  if (LayoutBuffer->PartitionCount == 0)
+  if (IsListEmpty (&DiskEntry->PartListHead))
     {
-      /* Initialize an 'Unpartitioned space' entry */
-      PartEntry = &DiskEntry->PartArray[0];
+      /* Create a partition table that represents the empty disk */
+      PartEntry = (PPARTENTRY)RtlAllocateHeap (ProcessHeap,
+                                              0,
+                                              sizeof(PARTENTRY));
+      if (PartEntry == NULL)
+       return;
+
+      RtlZeroMemory (PartEntry,
+                    sizeof(PARTENTRY));
 
       PartEntry->Unpartitioned = TRUE;
-      // Start partition at head 1, cylinder 0
-      PartEntry->StartingOffset = DiskEntry->SectorsPerTrack * DiskEntry->BytesPerSector;
-      PartEntry->PartSize = DiskEntry->DiskSize - PartEntry->StartingOffset;
-      PartEntry->Used = FALSE;
-      PartEntry->HidePartEntry = FALSE;
-      PartEntry->PartNumber = 1;
+      PartEntry->UnpartitionedOffset = 0ULL;
+      PartEntry->UnpartitionedLength = DiskEntry->DiskSize;
+
+      PartEntry->FormatState = Unformatted;
+
+      InsertTailList (&DiskEntry->PartListHead,
+                     &PartEntry->ListEntry);
     }
   else
     {
-      LastEntryWasUnused = FALSE;
-      // Start partition at head 1, cylinder 0
-      LastStartingOffset = DiskEntry->SectorsPerTrack * DiskEntry->BytesPerSector;
-      LastPartitionSize = 0;
-      LastUnusedEntry = -1;
-      LastUnusedPartitionSize = 0;
-      for (i = 0; i < LayoutBuffer->PartitionCount; i++)
+      /* Start partition at head 1, cylinder 0 */
+      LastStartingOffset = DiskEntry->TrackSize;
+      LastPartitionLength = 0ULL;
+      LastUnusedPartitionLength = 0ULL;
+
+      i = 0;
+      Entry = DiskEntry->PartListHead.Flink;
+      while (Entry != &DiskEntry->PartListHead)
        {
-         PartEntry = &DiskEntry->PartArray[i];
+         PartEntry = CONTAINING_RECORD (Entry, PARTENTRY, ListEntry);
 
-         if ((LayoutBuffer->PartitionEntry[i].PartitionType != PARTITION_ENTRY_UNUSED) &&
-             (!IsContainerPartition(LayoutBuffer->PartitionEntry[i].PartitionType)))
+         for (j = 0; j < 4; j++)
            {
-        LastUnusedPartitionSize = LayoutBuffer->PartitionEntry[i].StartingOffset.QuadPart
-          - (LastStartingOffset + LastPartitionSize);
-        if (LastUnusedEntry != -1)
-          {
-            DiskEntry->PartArray[LastUnusedEntry].StartingOffset = LastStartingOffset + LastPartitionSize;
-            DiskEntry->PartArray[LastUnusedEntry].PartSize = LastUnusedPartitionSize;
-            DiskEntry->PartArray[LastUnusedEntry].PartNumber = LastUnusedEntry + 1; /* FIXME: Is this always correct? */
-          }
-        LastStartingOffset = LayoutBuffer->PartitionEntry[i].StartingOffset.QuadPart;
-        LastPartitionSize = LayoutBuffer->PartitionEntry[i].PartitionLength.QuadPart;
-
-        PartEntry->StartingOffset = LayoutBuffer->PartitionEntry[i].StartingOffset.QuadPart;
-             PartEntry->PartSize = LayoutBuffer->PartitionEntry[i].PartitionLength.QuadPart;
-             PartEntry->PartNumber = LayoutBuffer->PartitionEntry[i].PartitionNumber,
-             PartEntry->PartType = LayoutBuffer->PartitionEntry[i].PartitionType;
-             PartEntry->Active = LayoutBuffer->PartitionEntry[i].BootIndicator;
-
-             PartEntry->DriveLetter = GetDriveLetter(DiskNumber,
-                                                     LayoutBuffer->PartitionEntry[i].PartitionNumber);
-
-             PartEntry->Unpartitioned = FALSE;
-
-             PartEntry->Used = TRUE;
-        PartEntry->HidePartEntry = FALSE;
-        LastEntryWasUnused = FALSE;
-        LastUnusedEntry = -1;
+             if ((!IsContainerPartition (PartEntry->PartInfo[j].PartitionType)) &&
+                 (PartEntry->PartInfo[j].PartitionType != PARTITION_ENTRY_UNUSED ||
+                  PartEntry->PartInfo[j].PartitionLength.QuadPart != 0LL))
+               {
+                 LastUnusedPartitionLength =
+                   PartEntry->PartInfo[j].StartingOffset.QuadPart -
+                   (LastStartingOffset + LastPartitionLength);
+
+                 if (LastUnusedPartitionLength >= DiskEntry->CylinderSize)
+                   {
+                     DPRINT ("Unpartitioned disk space %I64u\n", LastUnusedPartitionLength);
+
+                     NewPartEntry = (PPARTENTRY)RtlAllocateHeap (ProcessHeap,
+                                                                 0,
+                                                                 sizeof(PARTENTRY));
+                     if (NewPartEntry == NULL)
+                       return;
+
+                     RtlZeroMemory (NewPartEntry,
+                                    sizeof(PARTENTRY));
+
+                     NewPartEntry->Unpartitioned = TRUE;
+                     NewPartEntry->UnpartitionedOffset = LastStartingOffset + LastPartitionLength;
+                     NewPartEntry->UnpartitionedLength = LastUnusedPartitionLength;
+                     if (j == 0)
+                       NewPartEntry->UnpartitionedLength -= DiskEntry->TrackSize;
+
+                     NewPartEntry->FormatState = Unformatted;
+
+                     /* Insert the table into the list */
+                     InsertTailList (&PartEntry->ListEntry,
+                                     &NewPartEntry->ListEntry);
+                   }
+
+                 LastStartingOffset = PartEntry->PartInfo[j].StartingOffset.QuadPart;
+                 LastPartitionLength = PartEntry->PartInfo[j].PartitionLength.QuadPart;
+               }
            }
-         else
+
+         i += 4;
+         Entry = Entry->Flink;
+       }
+
+      /* Check for trailing unpartitioned disk space */
+      if (DiskEntry->DiskSize > (LastStartingOffset + LastPartitionLength))
+       {
+         /* Round-down to cylinder size */
+         LastUnusedPartitionLength =
+           ROUND_DOWN (DiskEntry->DiskSize - (LastStartingOffset + LastPartitionLength),
+                       DiskEntry->CylinderSize);
+
+         if (LastUnusedPartitionLength >= DiskEntry->CylinderSize)
            {
-        if (LastEntryWasUnused)
-          {
-            /* Group unused entries into one unpartitioned disk space area */
-            PartEntry->HidePartEntry = TRUE;
-            PartEntry->PartSize = 0;
-          }
-        else
-          {
-            LastUnusedEntry = i;
-          }
+             DPRINT ("Unpartitioned disk space %I64u\n", LastUnusedPartitionLength);
+
+             NewPartEntry = (PPARTENTRY)RtlAllocateHeap (ProcessHeap,
+                                                         0,
+                                                         sizeof(PARTENTRY));
+             if (NewPartEntry == NULL)
+               return;
+
+             RtlZeroMemory (NewPartEntry,
+                            sizeof(PARTENTRY));
 
-        PartEntry->Unpartitioned = TRUE;
+             NewPartEntry->Unpartitioned = TRUE;
+             NewPartEntry->UnpartitionedOffset = LastStartingOffset + LastPartitionLength;
+             NewPartEntry->UnpartitionedLength = LastUnusedPartitionLength;
 
-             PartEntry->Used = FALSE;
-        LastEntryWasUnused = TRUE;
+             /* Append the table to the list */
+             InsertTailList (&DiskEntry->PartListHead,
+                             &NewPartEntry->ListEntry);
            }
        }
-      LastUnusedPartitionSize = DiskEntry->DiskSize
-        - (LastStartingOffset + LastPartitionSize);
-      if (LastUnusedEntry != -1)
+    }
+}
+
+NTSTATUS
+STDCALL
+DiskIdentifierQueryRoutine(PWSTR ValueName,
+                           ULONG ValueType,
+                           PVOID ValueData,
+                           ULONG ValueLength,
+                           PVOID Context,
+                           PVOID EntryContext)
+{
+  PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context;
+  UNICODE_STRING NameU;
+
+  if (ValueType == REG_SZ &&
+      ValueLength == 20 * sizeof(WCHAR))
+    {
+      NameU.Buffer = (PWCHAR)ValueData;
+      NameU.Length = NameU.MaximumLength = 8 * sizeof(WCHAR);
+      RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Checksum);
+
+      NameU.Buffer = (PWCHAR)ValueData + 9;
+      RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Signature);
+
+      return STATUS_SUCCESS;
+    }
+    return STATUS_UNSUCCESSFUL;
+}
+
+NTSTATUS
+STDCALL
+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;
+
+  if (ValueType == REG_FULL_RESOURCE_DESCRIPTOR &&
+      ValueLength == sizeof(CM_FULL_RESOURCE_DESCRIPTOR) + sizeof(CM_DISK_GEOMETRY_DEVICE_DATA))
+    {
+      FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData;
+      /* FIXME:
+       *   Is this 'paranoia' check correct ?
+       */
+      if (FullResourceDescriptor->InterfaceType != InterfaceTypeUndefined ||
+          FullResourceDescriptor->BusNumber != 0 ||
+          FullResourceDescriptor->PartialResourceList.Count != 1 ||
+          FullResourceDescriptor->PartialResourceList.PartialDescriptors[0].Type != CmResourceTypeDeviceSpecific ||
+          FullResourceDescriptor->PartialResourceList.PartialDescriptors[0].u.DeviceSpecificData.DataSize != sizeof(CM_DISK_GEOMETRY_DEVICE_DATA))
+        {
+          return STATUS_UNSUCCESSFUL;
+        }
+      DiskGeometry = (PCM_DISK_GEOMETRY_DEVICE_DATA)(FullResourceDescriptor + 1);
+      BiosDiskEntry->DiskGeometry = *DiskGeometry;
+
+      return STATUS_SUCCESS;
+    }
+  return STATUS_UNSUCCESSFUL;
+}
+
+NTSTATUS
+STDCALL
+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;
+
+  if (ValueType == REG_FULL_RESOURCE_DESCRIPTOR &&
+      ValueLength >= sizeof (CM_FULL_RESOURCE_DESCRIPTOR) &&
+      (ValueLength - sizeof(CM_FULL_RESOURCE_DESCRIPTOR)) % sizeof(CM_INT13_DRIVE_PARAMETER) == 0)
+    {
+      FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData;
+      if (FullResourceDescriptor->InterfaceType != InterfaceTypeUndefined ||
+          FullResourceDescriptor->BusNumber != -1 ||
+          FullResourceDescriptor->PartialResourceList.Count != 1 ||
+          FullResourceDescriptor->PartialResourceList.PartialDescriptors[0].Type != CmResourceTypeDeviceSpecific)
+        {
+          return STATUS_UNSUCCESSFUL;
+        }
+      *Int13Drives = RtlAllocateHeap(ProcessHeap, 0, ValueLength - sizeof (CM_FULL_RESOURCE_DESCRIPTOR));
+      if (*Int13Drives == NULL)
         {
-          DiskEntry->PartArray[LastUnusedEntry].StartingOffset = LastStartingOffset + LastPartitionSize;
-          DiskEntry->PartArray[LastUnusedEntry].PartSize = LastUnusedPartitionSize;
-          DiskEntry->PartArray[LastUnusedEntry].PartNumber = LastUnusedEntry + 1; /* FIXME: Is this always correct? */
+          return STATUS_NO_MEMORY;
         }
+      memcpy(*Int13Drives, FullResourceDescriptor + 1, ValueLength - sizeof (CM_FULL_RESOURCE_DESCRIPTOR));
+      return STATUS_SUCCESS;
     }
+  return STATUS_UNSUCCESSFUL;
+
 }
+#define ROOT_NAME   L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter"
+
+static VOID
+EnumerateBiosDiskEntries(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 = 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:        %d\n", BiosDiskEntry->DiskNumber);
+                      DPRINT("Signature:         %08x\n", BiosDiskEntry->Signature);
+                      DPRINT("Checksum:          %08x\n", BiosDiskEntry->Checksum);
+                      DPRINT("BytesPerSector:    %d\n", BiosDiskEntry->DiskGeometry.BytesPerSector);
+                      DPRINT("NumberOfCylinders: %d\n", BiosDiskEntry->DiskGeometry.NumberOfCylinders);
+                      DPRINT("NumberOfHeads:     %d\n", BiosDiskEntry->DiskGeometry.NumberOfHeads);
+                      DPRINT("DriveSelect:       %02x\n", BiosDiskEntry->Int13DiskData.DriveSelect);
+                      DPRINT("MaxCylinders:      %d\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
 AddDiskToList (HANDLE FileHandle,
@@ -209,6 +666,15 @@ AddDiskToList (HANDLE FileHandle,
   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;
 
   Status = NtDeviceIoControlFile (FileHandle,
                                  NULL,
@@ -220,7 +686,7 @@ AddDiskToList (HANDLE FileHandle,
                                  0,
                                  &DiskGeometry,
                                  sizeof(DISK_GEOMETRY));
-  if (!NT_SUCCESS(Status))
+  if (!NT_SUCCESS (Status))
     {
       return;
     }
@@ -245,6 +711,51 @@ AddDiskToList (HANDLE FileHandle,
       return;
     }
 
+  Mbr = 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;
+
+  RtlFreeHeap (ProcessHeap,
+              0,
+              Mbr);
+
+  swprintf(Identifier, L"%08x-%08x-A", Checksum, Signature);
+  DPRINT("Identifier: %S\n", Identifier);
+
   DiskEntry = (PDISKENTRY)RtlAllocateHeap (ProcessHeap,
                                           0,
                                           sizeof(DISKENTRY));
@@ -253,21 +764,73 @@ AddDiskToList (HANDLE FileHandle,
       return;
     }
 
+  DiskEntry->Checksum = Checksum;
+  DiskEntry->Signature = Signature;
+  if (Signature == 0)
+    {
+      /* If we have no signature, set the disk to dirty. WritePartitionsToDisk creates a new signature */
+      DiskEntry->Modified = TRUE;
+    }
+  DiskEntry->BiosFound = FALSE;
+
+  ListEntry = List->BiosDiskListHead.Flink;
+  while(ListEntry != &List->BiosDiskListHead)
+  {
+     BiosDiskEntry = CONTAINING_RECORD(ListEntry, BIOSDISKENTRY, ListEntry);
+     /* FIXME:
+      *   Compare the size from bios and the reported size from driver.
+      *   If we have more than one disk with a zero or with the same signatur
+      *   we must create new signatures and reboot. After the reboot, 
+      *   it is possible to identify the disks.
+      */
+     if (BiosDiskEntry->Signature == Signature &&
+         BiosDiskEntry->Checksum == Checksum &&
+         !BiosDiskEntry->Recognized)
+     {
+        if (!DiskEntry->BiosFound)
+        {
+           DiskEntry->BiosDiskNumber = BiosDiskEntry->DiskNumber;
+           DiskEntry->BiosFound = TRUE;
+           BiosDiskEntry->Recognized = TRUE;
+        }
+        else
+        {
+        }
+     }
+     ListEntry = ListEntry->Flink;
+  }
+
+  if (!DiskEntry->BiosFound)
+  {
+     RtlFreeHeap(ProcessHeap, 0, DiskEntry);
+     return;
+  }
+
+  InitializeListHead (&DiskEntry->PartListHead);
+
   DiskEntry->Cylinders = DiskGeometry.Cylinders.QuadPart;
   DiskEntry->TracksPerCylinder = DiskGeometry.TracksPerCylinder;
   DiskEntry->SectorsPerTrack = DiskGeometry.SectorsPerTrack;
   DiskEntry->BytesPerSector = DiskGeometry.BytesPerSector;
 
-  DPRINT("Cylinders %d\n", DiskEntry->Cylinders);
-  DPRINT("TracksPerCylinder %d\n", DiskEntry->TracksPerCylinder);
-  DPRINT("SectorsPerTrack %d\n", DiskEntry->SectorsPerTrack);
-  DPRINT("BytesPerSector %d\n", DiskEntry->BytesPerSector);
+  DPRINT ("Cylinders %d\n", DiskEntry->Cylinders);
+  DPRINT ("TracksPerCylinder %d\n", DiskEntry->TracksPerCylinder);
+  DPRINT ("SectorsPerTrack %d\n", DiskEntry->SectorsPerTrack);
+  DPRINT ("BytesPerSector %d\n", DiskEntry->BytesPerSector);
 
-  DiskEntry->DiskSize = 
+  DiskEntry->DiskSize =
     DiskGeometry.Cylinders.QuadPart *
     (ULONGLONG)DiskGeometry.TracksPerCylinder *
     (ULONGLONG)DiskGeometry.SectorsPerTrack *
     (ULONGLONG)DiskGeometry.BytesPerSector;
+  DiskEntry->CylinderSize =
+    (ULONGLONG)DiskGeometry.TracksPerCylinder *
+    (ULONGLONG)DiskGeometry.SectorsPerTrack *
+    (ULONGLONG)DiskGeometry.BytesPerSector;
+  DiskEntry->TrackSize =
+    (ULONGLONG)DiskGeometry.SectorsPerTrack *
+    (ULONGLONG)DiskGeometry.BytesPerSector;
+
   DiskEntry->DiskNumber = DiskNumber;
   DiskEntry->Port = ScsiAddress.PortNumber;
   DiskEntry->Bus = ScsiAddress.PathId;
@@ -275,7 +838,7 @@ AddDiskToList (HANDLE FileHandle,
 
   GetDriverName (DiskEntry);
 
-  InsertTailList (&List->DiskList, &DiskEntry->ListEntry);
+  InsertAscendingList(&List->DiskListHead, DiskEntry, DISKENTRY, ListEntry, BiosDiskNumber);
 
   LayoutBuffer = (DRIVE_LAYOUT_INFORMATION*)RtlAllocateHeap (ProcessHeap,
                                                             0,
@@ -297,9 +860,16 @@ AddDiskToList (HANDLE FileHandle,
                                  8192);
   if (NT_SUCCESS (Status))
     {
+      if (LayoutBuffer->PartitionCount == 0)
+       {
+         DiskEntry->NewDisk = TRUE;
+       }
+
       AddPartitionToList (DiskNumber,
                          DiskEntry,
                          LayoutBuffer);
+
+      ScanForUnpartitionedDiskSpace (DiskEntry);
     }
 
   RtlFreeHeap (ProcessHeap,
@@ -309,12 +879,14 @@ AddDiskToList (HANDLE FileHandle,
 
 
 PPARTLIST
-InitializePartitionList(VOID)
+CreatePartitionList (SHORT Left,
+                    SHORT Top,
+                    SHORT Right,
+                    SHORT Bottom)
 {
   PPARTLIST List;
   OBJECT_ATTRIBUTES ObjectAttributes;
   SYSTEM_DEVICE_INFORMATION Sdi;
-  DISK_GEOMETRY DiskGeometry;
   IO_STATUS_BLOCK Iosb;
   ULONG ReturnSize;
   NTSTATUS Status;
@@ -323,14 +895,16 @@ InitializePartitionList(VOID)
   UNICODE_STRING Name;
   HANDLE FileHandle;
 
-  List = (PPARTLIST)RtlAllocateHeap(ProcessHeap, 0, sizeof(PARTLIST));
+  List = (PPARTLIST)RtlAllocateHeap (ProcessHeap,
+                                    0,
+                                    sizeof (PARTLIST));
   if (List == NULL)
-    return(NULL);
+    return NULL;
 
-  List->Left = 0;
-  List->Top = 0;
-  List->Right = 0;
-  List->Bottom = 0;
+  List->Left = Left;
+  List->Top = Top;
+  List->Right = Right;
+  List->Bottom = Bottom;
 
   List->Line = 0;
 
@@ -338,40 +912,43 @@ InitializePartitionList(VOID)
   List->TopPartition = (ULONG)-1;
 
   List->CurrentDisk = NULL;
-  List->CurrentPartition = (ULONG)-1;
+  List->CurrentPartition = NULL;
 
-  InitializeListHead (&List->DiskList);
+  InitializeListHead (&List->DiskListHead);
+  InitializeListHead (&List->BiosDiskListHead);
 
-  Status = NtQuerySystemInformation(SystemDeviceInformation,
-                                   &Sdi,
-                                   sizeof(SYSTEM_DEVICE_INFORMATION),
-                                   &ReturnSize);
-  if (!NT_SUCCESS(Status))
+  EnumerateBiosDiskEntries(List);
+
+  Status = NtQuerySystemInformation (SystemDeviceInformation,
+                                    &Sdi,
+                                    sizeof(SYSTEM_DEVICE_INFORMATION),
+                                    &ReturnSize);
+  if (!NT_SUCCESS (Status))
     {
-      RtlFreeHeap(ProcessHeap, 0, List);
-      return(NULL);
+      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,
-                         0x10001,
-                         &ObjectAttributes,
-                         &Iosb,
-                         1,
-                         FILE_SYNCHRONOUS_IO_NONALERT);
+      swprintf (Buffer,
+               L"\\Device\\Harddisk%d\\Partition0",
+               DiskNumber);
+      RtlInitUnicodeString (&Name,
+                           Buffer);
+
+      InitializeObjectAttributes (&ObjectAttributes,
+                                 &Name,
+                                 0,
+                                 NULL,
+                                 NULL);
+
+      Status = NtOpenFile (&FileHandle,
+                          FILE_GENERIC_READ,
+                          &ObjectAttributes,
+                          &Iosb,
+                          FILE_SHARE_READ,
+                          FILE_SYNCHRONOUS_IO_NONALERT);
       if (NT_SUCCESS(Status))
        {
          AddDiskToList (FileHandle,
@@ -382,144 +959,89 @@ InitializePartitionList(VOID)
        }
     }
 
+  AssignDriverLetters (List);
+
   List->TopDisk = 0;
   List->TopPartition = 0;
 
   /* Search for first usable disk and partition */
-  if (IsListEmpty (&List->DiskList))
+  if (IsListEmpty (&List->DiskListHead))
     {
       List->CurrentDisk = NULL;
-      List->CurrentPartition = (ULONG)-1;
+      List->CurrentPartition = NULL;
     }
   else
     {
-      List->CurrentDisk = CONTAINING_RECORD(List->DiskList.Flink, DISKENTRY, ListEntry);
-      List->CurrentPartition = 0;
+      List->CurrentDisk =
+       CONTAINING_RECORD (List->DiskListHead.Flink,
+                          DISKENTRY,
+                          ListEntry);
+
+      if (IsListEmpty (&List->CurrentDisk->PartListHead))
+       {
+         List->CurrentPartition = 0;
+       }
+      else
+       {
+         List->CurrentPartition =
+           CONTAINING_RECORD (List->CurrentDisk->PartListHead.Flink,
+                              PARTENTRY,
+                              ListEntry);
+       }
     }
 
-  return(List);
+  return List;
 }
 
 
-PPARTLIST
-CreatePartitionList(SHORT Left,
-                   SHORT Top,
-                   SHORT Right,
-                   SHORT Bottom)
+VOID
+DestroyPartitionList (PPARTLIST List)
 {
-  PPARTLIST List;
+  PDISKENTRY DiskEntry;
+  PBIOSDISKENTRY BiosDiskEntry;
+  PPARTENTRY PartEntry;
+  PLIST_ENTRY Entry;
 
-  List = InitializePartitionList();
-  if (List == NULL)
-    return(NULL);
-
-  List->Left = Left;
-  List->Top = Top;
-  List->Right = Right;
-  List->Bottom = Bottom;
-
-  DrawPartitionList(List);
-
-  return(List);
-}
-
-
-PPARTENTRY
-GetPartitionInformation(PPARTLIST List,
-                       ULONG DiskNumber,
-                       ULONG PartitionNumber,
-                       PULONG PartEntryNumber)
-{
-  PPARTENTRY PartEntry;
-  ULONG i;
-
-  if (IsListEmpty(&List->DiskList))
-    {
-      return NULL;
-    }
-
-#if 0
-  if (DiskNumber >= List->DiskCount)
-    {
-      return NULL;
-    }
-
-  if (PartitionNumber >= List->DiskArray[DiskNumber].PartCount)
-    {
-      return NULL;
-    }
-
-  if (List->DiskArray[DiskNumber].FixedDisk != TRUE)
-    {
-      return NULL;
-    }
-
-  for (i = 0; i < List->DiskArray[DiskNumber].PartCount; i++)
-    {
-      PartEntry = &List->DiskArray[DiskNumber].PartArray[i];
-      if (PartEntry->PartNumber == PartitionNumber)
-        {
-          *PartEntryNumber = i;
-          return PartEntry;
-        }
-    }
-#endif
-  return NULL;
-}
-
-
-VOID
-DestroyPartitionList(PPARTLIST List)
-{
-  PLIST_ENTRY Entry;
-  PDISKENTRY DiskEntry;
-#if 0
-  COORD coPos;
-  USHORT Width;
-
-  /* clear occupied screen area */
-  coPos.X = List->Left;
-  Width = List->Right - List->Left + 1;
-  for (coPos.Y = List->Top; coPos.Y <= List->Bottom; coPos.Y++)
-    {
-      FillConsoleOutputAttribute(0x17,
-                                Width,
-                                coPos,
-                                &i);
-
-      FillConsoleOutputCharacter(' ',
-                                Width,
-                                coPos,
-                                &i);
-    }
-#endif
-
-  /* Release disk and partition info */
-  while (!IsListEmpty (&List->DiskList))
-    {
-      Entry = RemoveHeadList (&List->DiskList);
-      DiskEntry = CONTAINING_RECORD (Entry, DISKENTRY, ListEntry);
+  /* 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 partition array */
-      if (DiskEntry->PartArray != NULL)
+      while (!IsListEmpty (&DiskEntry->PartListHead))
        {
-         RtlFreeHeap(ProcessHeap, 0, DiskEntry->PartArray);
+         Entry = RemoveHeadList (&DiskEntry->PartListHead);
+         PartEntry = CONTAINING_RECORD (Entry, PARTENTRY, ListEntry);
+
+         RtlFreeHeap (ProcessHeap,
+                      0,
+                      PartEntry);
        }
 
       /* 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);
 }
 
 
 static VOID
-PrintEmptyLine(PPARTLIST List)
+PrintEmptyLine (PPARTLIST List)
 {
   COORD coPos;
   ULONG Written;
@@ -527,34 +1049,33 @@ PrintEmptyLine(PPARTLIST List)
   USHORT Height;
 
   Width = List->Right - List->Left - 1;
-  Height = List->Bottom - List->Top - 1;
+  Height = List->Bottom - List->Top - 2;
 
-  if (List->Line < 0 || List->Line > Height)
-    return;
 
   coPos.X = List->Left + 1;
   coPos.Y = List->Top + 1 + List->Line;
 
-  FillConsoleOutputAttribute(0x17,
-                            Width,
-                            coPos,
-                            &Written);
-
-  FillConsoleOutputCharacter(' ',
-                            Width,
-                            coPos,
-                            &Written);
-
+  if (List->Line >= 0 && List->Line <= Height)
+    {
+      FillConsoleOutputAttribute (0x17,
+                                 Width,
+                                 coPos,
+                                 &Written);
+
+      FillConsoleOutputCharacter (' ',
+                                 Width,
+                                 coPos,
+                                 &Written);
+    }
   List->Line++;
 }
 
 
 static VOID
-PrintPartitionData(PPARTLIST List,
-                  PDISKENTRY DiskEntry,
-                  SHORT PartIndex)
+PrintPartitionData (PPARTLIST List,
+                   PDISKENTRY DiskEntry,
+                   PPARTENTRY PartEntry)
 {
-  PPARTENTRY PartEntry;
   CHAR LineBuffer[128];
   COORD coPos;
   ULONG Written;
@@ -567,126 +1088,143 @@ PrintPartitionData(PPARTLIST List,
   PCHAR PartType;
 
   Width = List->Right - List->Left - 1;
-  Height = List->Bottom - List->Top - 1;
+  Height = List->Bottom - List->Top - 2;
 
-  if (List->Line < 0 || List->Line > Height)
-    return;
 
   coPos.X = List->Left + 1;
   coPos.Y = List->Top + 1 + List->Line;
 
-  PartEntry = &DiskEntry->PartArray[PartIndex];
-
-  /* Determine partition type */
-  PartType = NULL;
-  if (PartEntry->Unpartitioned == FALSE)
+  if (PartEntry->Unpartitioned == TRUE)
     {
-      if ((PartEntry->PartType == PARTITION_FAT_12) ||
-         (PartEntry->PartType == PARTITION_FAT_16) ||
-         (PartEntry->PartType == PARTITION_HUGE) ||
-         (PartEntry->PartType == PARTITION_XINT13))
+#if 0
+      if (PartEntry->UnpartitionledLength >= 0x280000000ULL) /* 10 GB */
        {
-         PartType = "FAT";
+         PartSize = (PartEntry->UnpartitionedLength + (1 << 29)) >> 30;
+         Unit = "GB";
        }
-      else if ((PartEntry->PartType == PARTITION_FAT32) ||
-              (PartEntry->PartType == PARTITION_FAT32_XINT13))
+      else
+#endif
+      if (PartEntry->UnpartitionedLength >= 0xA00000ULL) /* 10 MB */
        {
-         PartType = "FAT32";
+         PartSize = (PartEntry->UnpartitionedLength + (1 << 19)) >> 20;
+         Unit = "MB";
        }
-     else if (PartEntry->PartType == PARTITION_IFS)
+      else
        {
-         PartType = "NTFS"; /* FIXME: Not quite correct! */
+         PartSize = (PartEntry->UnpartitionedLength + (1 << 9)) >> 10;
+         Unit = "KB";
        }
-    }
 
-
-#if 0
-  if (PartEntry->PartSize >= 0x280000000ULL) /* 10 GB */
-    {
-      PartSize = (PartEntry->PartSize + (1 << 29)) >> 30;
-      Unit = "GB";
-    }
-  else
-#endif
-  if (PartEntry->PartSize >= 0xA00000ULL) /* 10 MB */
-    {
-      PartSize = (PartEntry->PartSize + (1 << 19)) >> 20;
-      Unit = "MB";
+      sprintf (LineBuffer,
+              "    Unpartitioned space              %6I64u %s",
+              PartSize,
+              Unit);
     }
   else
     {
-      PartSize = (PartEntry->PartSize + (1 << 9)) >> 10;
-      Unit = "KB";
-    }
+      /* Determine partition type */
+      PartType = NULL;
+      if (PartEntry->New == TRUE)
+       {
+         PartType = "New (Unformatted)";
+       }
+      else if (PartEntry->Unpartitioned == FALSE)
+       {
+         if ((PartEntry->PartInfo[0].PartitionType == PARTITION_FAT_12) ||
+             (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT_16) ||
+             (PartEntry->PartInfo[0].PartitionType == PARTITION_HUGE) ||
+             (PartEntry->PartInfo[0].PartitionType == PARTITION_XINT13))
+           {
+             PartType = "FAT";
+           }
+         else if ((PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32) ||
+                  (PartEntry->PartInfo[0].PartitionType == PARTITION_FAT32_XINT13))
+           {
+             PartType = "FAT32";
+           }
+         else if (PartEntry->PartInfo[0].PartitionType == PARTITION_IFS)
+           {
+             PartType = "NTFS"; /* FIXME: Not quite correct! */
+           }
+       }
 
+#if 0
+      if (PartEntry->PartInfo[0].PartitionLength.QuadPart >= 0x280000000LL) /* 10 GB */
+       {
+         PartSize = (PartEntry->PartInfo[0].PartitionLength.QuadPart + (1 << 29)) >> 30;
+         Unit = "GB";
+       }
+      else
+#endif
+      if (PartEntry->PartInfo[0].PartitionLength.QuadPart >= 0xA00000LL) /* 10 MB */
+       {
+         PartSize = (PartEntry->PartInfo[0].PartitionLength.QuadPart + (1 << 19)) >> 20;
+         Unit = "MB";
+       }
+      else
+       {
+         PartSize = (PartEntry->PartInfo[0].PartitionLength.QuadPart + (1 << 9)) >> 10;
+         Unit = "KB";
+       }
 
-  if (PartEntry->Unpartitioned == TRUE)
-    {
-      sprintf(LineBuffer,
-             "    Unpartitioned space           %I64u %s",
-             PartSize,
-             Unit);
-    }
-  else if (PartEntry->DriveLetter != (CHAR)0)
-    {
       if (PartType == NULL)
        {
-         sprintf(LineBuffer,
-                 "%c:  Type %-3lu                        %I64u %s",
-                 PartEntry->DriveLetter,
-                 PartEntry->PartType,
-                 PartSize,
-                 Unit);
+         sprintf (LineBuffer,
+                  "%c%c  Type %-3u                         %6I64u %s",
+                  (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
+                  (PartEntry->DriveLetter == 0) ? '-' : ':',
+                  PartEntry->PartInfo[0].PartitionType,
+                  PartSize,
+                  Unit);
        }
       else
        {
-         sprintf(LineBuffer,
-                 "%c:  %s                         %I64u %s",
-                 PartEntry->DriveLetter,
-                 PartType,
-                 PartSize,
-                 Unit);
+         sprintf (LineBuffer,
+                  "%c%c  %-24s         %6I64u %s",
+                  (PartEntry->DriveLetter == 0) ? '-' : PartEntry->DriveLetter,
+                  (PartEntry->DriveLetter == 0) ? '-' : ':',
+                  PartType,
+                  PartSize,
+                  Unit);
        }
     }
-  else
-    {
-      sprintf(LineBuffer,
-             "--  %s  Type -3lu   %I64u %s",
-             PartEntry->FileSystemName,
-             PartEntry->PartType,
-             PartSize,
-             Unit);
-    }
 
   Attribute = (List->CurrentDisk == DiskEntry &&
-              List->CurrentPartition == PartIndex) ? 0x71 : 0x17;
-
-  FillConsoleOutputCharacter(' ',
-                            Width,
-                            coPos,
-                            &Written);
+              List->CurrentPartition == PartEntry) ? 0x71 : 0x17;
 
+  if (List->Line >= 0 && List->Line <= Height)
+    {
+      FillConsoleOutputCharacter (' ',
+                                 Width,
+                                 coPos,
+                                 &Written);
+    }
   coPos.X += 4;
   Width -= 8;
-  FillConsoleOutputAttribute(Attribute,
-                            Width,
-                            coPos,
-                            &Written);
-
+  if (List->Line >= 0 && List->Line <= Height)
+    {
+      FillConsoleOutputAttribute (Attribute,
+                                 Width,
+                                 coPos,
+                                 &Written);
+    }
   coPos.X++;
   Width -= 2;
-  WriteConsoleOutputCharacters(LineBuffer,
-                              min(strlen(LineBuffer), Width),
-                              coPos);
-
+  if (List->Line >= 0 && List->Line <= Height)
+    {
+      WriteConsoleOutputCharacters (LineBuffer,
+                                   min (strlen (LineBuffer), Width),
+                                   coPos);
+    }
   List->Line++;
 }
 
 
 static VOID
-PrintDiskData(PPARTLIST List,
-             PDISKENTRY DiskEntry)
+PrintDiskData (PPARTLIST List,
+              PDISKENTRY DiskEntry)
 {
+  PPARTENTRY PartEntry;
   CHAR LineBuffer[128];
   COORD coPos;
   ULONG Written;
@@ -694,13 +1232,10 @@ PrintDiskData(PPARTLIST List,
   USHORT Height;
   ULONGLONG DiskSize;
   PCHAR Unit;
-  SHORT PartIndex;
 
   Width = List->Right - List->Left - 1;
-  Height = List->Bottom - List->Top - 1;
+  Height = List->Bottom - List->Top - 2;
 
-  if (List->Line < 0 || List->Line > Height)
-    return;
 
   coPos.X = List->Left + 1;
   coPos.Y = List->Top + 1 + List->Line;
@@ -722,699 +1257,1280 @@ PrintDiskData(PPARTLIST List,
 
   if (DiskEntry->DriverName.Length > 0)
     {
-      sprintf(LineBuffer,
-             "%I64u %s  Harddisk %lu  (Port=%hu, Bus=%hu, Id=%hu) on %wZ",
-             DiskSize,
-             Unit,
-             DiskEntry->DiskNumber,
-             DiskEntry->Port,
-             DiskEntry->Bus,
-             DiskEntry->Id,
-             &DiskEntry->DriverName);
+      sprintf (LineBuffer,
+              "%6I64u %s  Harddisk %lu  (Port=%hu, Bus=%hu, Id=%hu) on %wZ",
+              DiskSize,
+              Unit,
+              DiskEntry->DiskNumber,
+              DiskEntry->Port,
+              DiskEntry->Bus,
+              DiskEntry->Id,
+              &DiskEntry->DriverName);
     }
   else
     {
-      sprintf(LineBuffer,
-             "%I64u %s  Harddisk %lu  (Port=%hu, Bus=%hu, Id=%hu)",
-             DiskSize,
-             Unit,
-             DiskEntry->DiskNumber,
-             DiskEntry->Port,
-             DiskEntry->Bus,
-             DiskEntry->Id);
+      sprintf (LineBuffer,
+              "%6I64u %s  Harddisk %lu  (Port=%hu, Bus=%hu, Id=%hu)",
+              DiskSize,
+              Unit,
+              DiskEntry->DiskNumber,
+              DiskEntry->Port,
+              DiskEntry->Bus,
+              DiskEntry->Id);
+    }
+  if (List->Line >= 0 && List->Line <= Height)
+    {
+      FillConsoleOutputAttribute (0x17,
+                                 Width,
+                                 coPos,
+                                 &Written);
+
+      FillConsoleOutputCharacter (' ',
+                                 Width,
+                                 coPos,
+                                 &Written);
     }
-
-  FillConsoleOutputAttribute(0x17,
-                            Width,
-                            coPos,
-                            &Written);
-
-  FillConsoleOutputCharacter(' ',
-                            Width,
-                            coPos,
-                            &Written);
 
   coPos.X++;
-  WriteConsoleOutputCharacters(LineBuffer,
-                              min(strlen(LineBuffer), Width - 2),
-                              coPos);
-
+  if (List->Line >= 0 && List->Line <= Height)
+    {
+      WriteConsoleOutputCharacters (LineBuffer,
+                                   min (strlen (LineBuffer), Width - 2),
+                                   coPos);
+    }
   List->Line++;
 
   /* Print separator line */
-  PrintEmptyLine(List);
+  PrintEmptyLine (List);
 
   /* Print partition lines*/
-  for (PartIndex = 0; PartIndex < DiskEntry->PartCount; PartIndex++)
+  LIST_FOR_EACH(PartEntry, &DiskEntry->PartListHead, PARTENTRY, ListEntry)
     {
-      if (!DiskEntry->PartArray[PartIndex].HidePartEntry)
-       {
-         PrintPartitionData(List,
-                            DiskEntry,
-                            PartIndex);
-       }
+      /* Print disk entry */
+      PrintPartitionData (List,
+                         DiskEntry,
+                         PartEntry);
     }
 
   /* Print separator line */
-  PrintEmptyLine(List);
+  PrintEmptyLine (List);
 }
 
 
 VOID
-DrawPartitionList(PPARTLIST List)
+DrawPartitionList (PPARTLIST List)
 {
-  PLIST_ENTRY Entry;
+  PLIST_ENTRY Entry, Entry2;
   PDISKENTRY DiskEntry;
-  CHAR LineBuffer[128];
+  PPARTENTRY PartEntry = NULL;
   COORD coPos;
   ULONG Written;
   SHORT i;
-  SHORT DiskIndex;
+  SHORT CurrentDiskLine;
+  SHORT CurrentPartLine;
+  SHORT LastLine;
+  BOOL CurrentPartLineFound = FALSE;
+  BOOL CurrentDiskLineFound = FALSE;
+
+  /* Calculate the line of the current disk and partition */
+  CurrentDiskLine = 0;
+  CurrentPartLine = 0;
+  LastLine = 0;
+  Entry = List->DiskListHead.Flink;
+  while (Entry != &List->DiskListHead)
+    {
+      DiskEntry = CONTAINING_RECORD (Entry, DISKENTRY, ListEntry);
+      LastLine += 2;
+      if (CurrentPartLineFound == FALSE)
+        {
+          CurrentPartLine += 2;
+       }
+      Entry2 = DiskEntry->PartListHead.Flink;
+      while (Entry2 != &DiskEntry->PartListHead)
+       {
+         PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
+         if (PartEntry == List->CurrentPartition)
+           {
+             CurrentPartLineFound = TRUE;
+           }
+          Entry2 = Entry2->Flink;
+         if (CurrentPartLineFound == FALSE)
+           {
+             CurrentPartLine++;
+           }
+         LastLine++;
+       }
+      if (DiskEntry == List->CurrentDisk)
+        {
+         CurrentDiskLineFound = TRUE;
+       }
+      Entry = Entry->Flink;
+      if (Entry != &List->DiskListHead)
+        {
+         if (CurrentDiskLineFound == FALSE)
+           {
+             CurrentPartLine ++;
+             CurrentDiskLine = CurrentPartLine;
+           }
+         LastLine++;
+       }
+      else
+        {
+         LastLine--;
+       }
+    }
+
+  /* If it possible, make the disk name visible */
+  if (CurrentPartLine < List->Offset)
+    {
+      List->Offset = CurrentPartLine;
+    }
+  else if (CurrentPartLine - List->Offset > List->Bottom - List->Top - 2)
+    {
+      List->Offset = CurrentPartLine - (List->Bottom - List->Top - 2);
+    }
+  if (CurrentDiskLine < List->Offset && CurrentPartLine - CurrentDiskLine < List->Bottom - List->Top - 2)
+    {
+      List->Offset = CurrentDiskLine;
+    }
+
 
   /* draw upper left corner */
   coPos.X = List->Left;
   coPos.Y = List->Top;
-  FillConsoleOutputCharacter(0xDA, // '+',
-                            1,
-                            coPos,
-                            &Written);
+  FillConsoleOutputCharacter (0xDA, // '+',
+                             1,
+                             coPos,
+                             &Written);
 
   /* draw upper edge */
   coPos.X = List->Left + 1;
   coPos.Y = List->Top;
-  FillConsoleOutputCharacter(0xC4, // '-',
-                            List->Right - List->Left - 1,
-                            coPos,
-                            &Written);
+  if (List->Offset == 0)
+    {
+      FillConsoleOutputCharacter (0xC4, // '-',
+                                 List->Right - List->Left - 1,
+                                 coPos,
+                                 &Written);
+    }
+  else
+    {
+      FillConsoleOutputCharacter (0xC4, // '-',
+                                 List->Right - List->Left - 5,
+                                 coPos,
+                                 &Written);
+      coPos.X = List->Right - 5;
+      WriteConsoleOutputCharacters ("(\x18)", // "(up)"
+                                   3,
+                                   coPos);
+      coPos.X = List->Right - 2;
+      FillConsoleOutputCharacter (0xC4, // '-',
+                                 2,
+                                 coPos,
+                                 &Written);
+    }
 
   /* draw upper right corner */
   coPos.X = List->Right;
   coPos.Y = List->Top;
-  FillConsoleOutputCharacter(0xBF, // '+',
-                            1,
-                            coPos,
-                            &Written);
+  FillConsoleOutputCharacter (0xBF, // '+',
+                             1,
+                             coPos,
+                             &Written);
 
   /* draw left and right edge */
   for (i = List->Top + 1; i < List->Bottom; i++)
     {
       coPos.X = List->Left;
       coPos.Y = i;
-      FillConsoleOutputCharacter(0xB3, // '|',
-                                1,
-                                coPos,
-                                &Written);
+      FillConsoleOutputCharacter (0xB3, // '|',
+                                 1,
+                                 coPos,
+                                 &Written);
 
       coPos.X = List->Right;
-      FillConsoleOutputCharacter(0xB3, //'|',
-                                1,
-                                coPos,
-                                &Written);
+      FillConsoleOutputCharacter (0xB3, //'|',
+                                 1,
+                                 coPos,
+                                 &Written);
     }
 
   /* draw lower left corner */
   coPos.X = List->Left;
   coPos.Y = List->Bottom;
-  FillConsoleOutputCharacter(0xC0, // '+',
-                            1,
-                            coPos,
-                            &Written);
+  FillConsoleOutputCharacter (0xC0, // '+',
+                             1,
+                             coPos,
+                             &Written);
 
   /* draw lower edge */
   coPos.X = List->Left + 1;
   coPos.Y = List->Bottom;
-  FillConsoleOutputCharacter(0xC4, // '-',
-                            List->Right - List->Left - 1,
-                            coPos,
-                            &Written);
+  if (LastLine - List->Offset <= List->Bottom - List->Top - 2)
+    {
+      FillConsoleOutputCharacter (0xC4, // '-',
+                                 List->Right - List->Left - 1,
+                                 coPos,
+                                 &Written);
+    }
+  else
+    {
+      FillConsoleOutputCharacter (0xC4, // '-',
+                                 List->Right - List->Left - 5,
+                                 coPos,
+                                 &Written);
+      coPos.X = List->Right - 5;
+      WriteConsoleOutputCharacters ("(\x19)", // "(down)"
+                                   3,
+                                   coPos);
+      coPos.X = List->Right - 2;
+      FillConsoleOutputCharacter (0xC4, // '-',
+                                 2,
+                                 coPos,
+                                 &Written);
+    }
 
   /* draw lower right corner */
   coPos.X = List->Right;
   coPos.Y = List->Bottom;
-  FillConsoleOutputCharacter(0xD9, // '+',
-                            1,
-                            coPos,
-                            &Written);
+  FillConsoleOutputCharacter (0xD9, // '+',
+                             1,
+                             coPos,
+                             &Written);
 
   /* print list entries */
-  List->Line = 0;
+  List->Line = - List->Offset;
 
-  Entry = List->DiskList.Flink;
-  while (Entry != &List->DiskList)
+  LIST_FOR_EACH(DiskEntry, &List->DiskListHead, DISKENTRY, ListEntry)
     {
-      DiskEntry = CONTAINING_RECORD (Entry, DISKENTRY, ListEntry);
-
       /* Print disk entry */
       PrintDiskData (List,
                     DiskEntry);
-
-      Entry = Entry->Flink;
     }
 }
 
 
 VOID
-ScrollDownPartitionList(PPARTLIST List)
+SelectPartition(PPARTLIST List, ULONG DiskNumber, ULONG PartitionNumber)
 {
-  PLIST_ENTRY Entry;
   PDISKENTRY DiskEntry;
+  PPARTENTRY PartEntry;
+  PLIST_ENTRY Entry1;
+  PLIST_ENTRY Entry2;
   ULONG i;
 
   /* Check for empty disks */
-  if (IsListEmpty (&List->DiskList))
+  if (IsListEmpty (&List->DiskListHead))
     return;
 
-  /* check for next usable entry on current disk */
-  for (i = List->CurrentPartition + 1; i < List->CurrentDisk->PartCount; i++)
+  /* Check for first usable entry on next disk */
+  Entry1 = List->CurrentDisk->ListEntry.Flink;
+  while (Entry1 != &List->DiskListHead)
     {
-      if (List->CurrentDisk->PartArray[i].HidePartEntry == FALSE)
+      DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
+
+      if (DiskEntry->DiskNumber == DiskNumber)
+        {
+          Entry2 = DiskEntry->PartListHead.Flink;
+          while (Entry2 != &DiskEntry->PartListHead)
+            {
+              PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
+
+              for (i = 0; i < 4; i++)
+                {
+                  if (PartEntry->PartInfo[i].PartitionNumber == PartitionNumber)
+                   {
+                     List->CurrentDisk = DiskEntry;
+                     List->CurrentPartition = PartEntry;
+                      DrawPartitionList (List);
+                     return;
+                   }
+                }
+              Entry2 = Entry2->Flink;
+            }
+          return;
+        }
+      Entry1 = Entry1->Flink;
+    }
+}
+
+
+VOID
+ScrollDownPartitionList (PPARTLIST List)
+{
+  PDISKENTRY DiskEntry;
+  PPARTENTRY PartEntry;
+  PLIST_ENTRY Entry1;
+  PLIST_ENTRY Entry2;
+
+  /* Check for empty disks */
+  if (IsListEmpty (&List->DiskListHead))
+    return;
+
+  /* Check for next usable entry on current disk */
+  if (List->CurrentPartition != NULL)
+    {
+      Entry2 = List->CurrentPartition->ListEntry.Flink;
+      while (Entry2 != &List->CurrentDisk->PartListHead)
        {
-         List->CurrentPartition = i;
-         DrawPartitionList(List);
-         return;
+         PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
+
+//       if (PartEntry->HidePartEntry == FALSE)
+           {
+             List->CurrentPartition = PartEntry;
+             DrawPartitionList (List);
+             return;
+           }
+         Entry2 = Entry2->Flink;
        }
     }
 
-  /* check for first usable entry on next disk */
-  Entry = List->CurrentDisk->ListEntry.Flink;
-  while (Entry != &List->DiskList)
+  /* Check for first usable entry on next disk */
+  if (List->CurrentDisk != NULL)
     {
-      DiskEntry = CONTAINING_RECORD (Entry, DISKENTRY, ListEntry);
-      for (i = 0; i < DiskEntry->PartCount; i++)
+      Entry1 = List->CurrentDisk->ListEntry.Flink;
+      while (Entry1 != &List->DiskListHead)
        {
-         if (DiskEntry->PartArray[i].HidePartEntry == FALSE)
+         DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
+
+         Entry2 = DiskEntry->PartListHead.Flink;
+         while (Entry2 != &DiskEntry->PartListHead)
            {
-             List->CurrentDisk = DiskEntry;
-             List->CurrentPartition = i;
-             DrawPartitionList(List);
-             return;
+             PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
+
+//           if (PartEntry->HidePartEntry == FALSE)
+               {
+                 List->CurrentDisk = DiskEntry;
+                 List->CurrentPartition = PartEntry;
+                 DrawPartitionList (List);
+                 return;
+               }
+
+             Entry2 = Entry2->Flink;
            }
+
+         Entry1 = Entry1->Flink;
        }
-      Entry = Entry->Flink;
     }
 }
 
 
 VOID
-ScrollUpPartitionList(PPARTLIST List)
+ScrollUpPartitionList (PPARTLIST List)
 {
-  PLIST_ENTRY Entry;
   PDISKENTRY DiskEntry;
-  ULONG i;
+  PPARTENTRY PartEntry;
+  PLIST_ENTRY Entry1;
+  PLIST_ENTRY Entry2;
 
   /* Check for empty disks */
-  if (IsListEmpty (&List->DiskList))
+  if (IsListEmpty (&List->DiskListHead))
     return;
 
   /* check for previous usable entry on current disk */
-  for (i = List->CurrentPartition - 1; i != (ULONG)-1; i--)
+  if (List->CurrentPartition != NULL)
     {
-      if (List->CurrentDisk->PartArray[i].HidePartEntry == FALSE)
+      Entry2 = List->CurrentPartition->ListEntry.Blink;
+      while (Entry2 != &List->CurrentDisk->PartListHead)
        {
-         List->CurrentPartition = i;
-         DrawPartitionList(List);
-         return;
+         PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
+
+//       if (PartEntry->HidePartEntry == FALSE)
+           {
+             List->CurrentPartition = PartEntry;
+             DrawPartitionList (List);
+             return;
+           }
+         Entry2 = Entry2->Blink;
        }
     }
 
+
   /* check for last usable entry on previous disk */
-  Entry = List->CurrentDisk->ListEntry.Blink;
-  while (Entry != &List->DiskList)
+  if (List->CurrentDisk != NULL)
     {
-      DiskEntry = CONTAINING_RECORD (Entry, DISKENTRY, ListEntry);
-      for (i = DiskEntry->PartCount - 1; i != (ULONG)-1; i--)
+      Entry1 = List->CurrentDisk->ListEntry.Blink;
+      while (Entry1 != &List->DiskListHead)
        {
-         if (DiskEntry->PartArray[i].HidePartEntry == FALSE)
+         DiskEntry = CONTAINING_RECORD (Entry1, DISKENTRY, ListEntry);
+
+         Entry2 = DiskEntry->PartListHead.Blink;
+         while (Entry2 != &DiskEntry->PartListHead)
            {
-             List->CurrentDisk = DiskEntry;
-             List->CurrentPartition = i;
-             DrawPartitionList(List);
-             return;
+             PartEntry = CONTAINING_RECORD (Entry2, PARTENTRY, ListEntry);
+
+//           if (PartEntry->HidePartEntry == FALSE)
+               {
+                 List->CurrentDisk = DiskEntry;
+                 List->CurrentPartition = PartEntry;
+                 DrawPartitionList (List);
+                 return;
+               }
+
+             Entry2 = Entry2->Blink;
            }
+
+         Entry1 = Entry1->Blink;
        }
-      Entry = Entry->Blink;
     }
 }
 
 
-BOOLEAN
-GetSelectedPartition(PPARTLIST List,
-                    PPARTDATA Data)
+static PPARTENTRY
+GetPrevPartitionedEntry (PDISKENTRY DiskEntry,
+                        PPARTENTRY CurrentEntry)
 {
-  PDISKENTRY DiskEntry;
-  PPARTENTRY PartEntry;
+  PPARTENTRY PrevEntry;
+  PLIST_ENTRY Entry;
 
-  if (List->CurrentDisk == NULL)
-    return FALSE;
+  if (CurrentEntry->ListEntry.Blink == &DiskEntry->PartListHead)
+    return NULL;
+
+  Entry = CurrentEntry->ListEntry.Blink;
+  while (Entry != &DiskEntry->PartListHead)
+    {
+      PrevEntry = CONTAINING_RECORD (Entry,
+                                    PARTENTRY,
+                                    ListEntry);
+      if (PrevEntry->Unpartitioned == FALSE)
+       return PrevEntry;
+
+      Entry = Entry->Blink;
+    }
+
+  return NULL;
+}
 
-  DiskEntry = List->CurrentDisk;
 
-  if (List->CurrentPartition >= DiskEntry->PartCount)
-    return(FALSE);
+static PPARTENTRY
+GetNextPartitionedEntry (PDISKENTRY DiskEntry,
+                        PPARTENTRY CurrentEntry)
+{
+  PPARTENTRY NextEntry;
+  PLIST_ENTRY Entry;
 
-  PartEntry = &DiskEntry->PartArray[List->CurrentPartition];
+  if (CurrentEntry->ListEntry.Flink == &DiskEntry->PartListHead)
+    return NULL;
 
-  if (PartEntry->Used == FALSE)
+  Entry = CurrentEntry->ListEntry.Flink;
+  while (Entry != &DiskEntry->PartListHead)
     {
-      return(FALSE);
+      NextEntry = CONTAINING_RECORD (Entry,
+                                    PARTENTRY,
+                                    ListEntry);
+      if (NextEntry->Unpartitioned == FALSE)
+       return NextEntry;
+
+      Entry = Entry->Flink;
     }
 
-  /* Copy disk-specific data */
-  Data->DiskSize = DiskEntry->DiskSize;
-  Data->DiskNumber = DiskEntry->DiskNumber;
-  Data->Port = DiskEntry->Port;
-  Data->Bus = DiskEntry->Bus;
-  Data->Id = DiskEntry->Id;
+  return NULL;
+}
+
+
+static PPARTENTRY
+GetPrevUnpartitionedEntry (PDISKENTRY DiskEntry,
+                          PPARTENTRY PartEntry)
+{
+  PPARTENTRY PrevPartEntry;
 
-  /* Copy driver name */
-  RtlInitUnicodeString(&Data->DriverName,
-                      NULL);
-  if (DiskEntry->DriverName.Length != 0)
+  if (PartEntry->ListEntry.Blink != &DiskEntry->PartListHead)
     {
-      Data->DriverName.Buffer = RtlAllocateHeap(ProcessHeap,
-                                               0,
-                                               DiskEntry->DriverName.MaximumLength);
-      if (Data->DriverName.Buffer != NULL)
-       {
-         Data->DriverName.MaximumLength = DiskEntry->DriverName.MaximumLength;
-         Data->DriverName.Length = DiskEntry->DriverName.Length;
-         RtlCopyMemory(Data->DriverName.Buffer,
-                       DiskEntry->DriverName.Buffer,
-                       DiskEntry->DriverName.MaximumLength);
-       }
+      PrevPartEntry = CONTAINING_RECORD (PartEntry->ListEntry.Blink,
+                                        PARTENTRY,
+                                        ListEntry);
+      if (PrevPartEntry->Unpartitioned == TRUE)
+       return PrevPartEntry;
     }
 
-  /* Copy partition-specific data */
-  Data->CreatePartition = FALSE;
-  Data->NewPartSize = 0;
-  Data->PartSize = PartEntry->PartSize;
-  Data->PartNumber = PartEntry->PartNumber;
-  Data->PartType = PartEntry->PartType;
-  Data->DriveLetter = PartEntry->DriveLetter;
+  return NULL;
+}
+
+
+static PPARTENTRY
+GetNextUnpartitionedEntry (PDISKENTRY DiskEntry,
+                          PPARTENTRY PartEntry)
+{
+  PPARTENTRY NextPartEntry;
 
-  return(TRUE);
+  if (PartEntry->ListEntry.Flink != &DiskEntry->PartListHead)
+    {
+      NextPartEntry = CONTAINING_RECORD (PartEntry->ListEntry.Flink,
+                                        PARTENTRY,
+                                        ListEntry);
+      if (NextPartEntry->Unpartitioned == TRUE)
+       return NextPartEntry;
+    }
+
+  return NULL;
 }
 
 
-BOOLEAN
-GetActiveBootPartition(PPARTLIST List,
-                      PPARTDATA Data)
+VOID
+CreateNewPartition (PPARTLIST List,
+                   ULONGLONG PartitionSize,
+                   BOOLEAN AutoCreate)
 {
   PDISKENTRY DiskEntry;
   PPARTENTRY PartEntry;
-  ULONG i;
-
-  if (List->CurrentDisk == NULL)
-    return FALSE;
+  PPARTENTRY PrevPartEntry;
+  PPARTENTRY NextPartEntry;
+  PPARTENTRY NewPartEntry;
+
+  if (List == NULL ||
+      List->CurrentDisk == NULL ||
+      List->CurrentPartition == NULL ||
+      List->CurrentPartition->Unpartitioned == FALSE)
+    {
+      return;
+    }
 
   DiskEntry = List->CurrentDisk;
+  PartEntry = List->CurrentPartition;
 
-  for (i = 0; i < DiskEntry->PartCount; i++)
+  if (AutoCreate == TRUE ||
+      PartitionSize == PartEntry->UnpartitionedLength)
     {
-      if (DiskEntry->PartArray[i].Active)
+      /* Convert current entry to 'new (unformatted)' */
+      PartEntry->FormatState = Unformatted;
+      PartEntry->PartInfo[0].StartingOffset.QuadPart =
+       PartEntry->UnpartitionedOffset + DiskEntry->TrackSize;
+      PartEntry->PartInfo[0].PartitionLength.QuadPart =
+       PartEntry->UnpartitionedLength - DiskEntry->TrackSize;
+      PartEntry->PartInfo[0].PartitionType = PARTITION_ENTRY_UNUSED;
+      PartEntry->PartInfo[0].BootIndicator = FALSE; /* FIXME */
+      PartEntry->PartInfo[0].RewritePartition = TRUE;
+      PartEntry->PartInfo[1].RewritePartition = TRUE;
+      PartEntry->PartInfo[2].RewritePartition = TRUE;
+      PartEntry->PartInfo[3].RewritePartition = TRUE;
+
+      /* Get previous and next partition entries */
+      PrevPartEntry = GetPrevPartitionedEntry (DiskEntry,
+                                              PartEntry);
+      NextPartEntry = GetNextPartitionedEntry (DiskEntry,
+                                              PartEntry);
+
+      if (PrevPartEntry != NULL && NextPartEntry != NULL)
        {
-         PartEntry = &DiskEntry->PartArray[i];
+         /* Current entry is in the middle of the list */
+
+         /* Copy previous container partition data to current entry */
+         RtlCopyMemory (&PartEntry->PartInfo[1],
+                        &PrevPartEntry->PartInfo[1],
+                        sizeof(PARTITION_INFORMATION));
+         PartEntry->PartInfo[1].RewritePartition = TRUE;
 
-         if (PartEntry->Used == FALSE)
+         /* Update previous container partition data */
+
+         PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
+           PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
+
+         if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
            {
-             return(FALSE);
+             /* Special case - previous partition is first partition */
+             PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
+               DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
            }
+         else
+           {
+             PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
+               PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
+           }
+
+         PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
+       }
+      else if (PrevPartEntry == NULL && NextPartEntry != NULL)
+       {
+         /* Current entry is the first entry */
+         return;
+       }
+      else if (PrevPartEntry != NULL && NextPartEntry == NULL)
+       {
+         /* Current entry is the last entry */
 
-         /* Copy disk-specific data */
-         Data->DiskSize = DiskEntry->DiskSize;
-         Data->DiskNumber = DiskEntry->DiskNumber;
-         Data->Port = DiskEntry->Port;
-         Data->Bus = DiskEntry->Bus;
-         Data->Id = DiskEntry->Id;
-
-         /* Copy driver name */
-         RtlInitUnicodeString(&Data->DriverName,
-                              NULL);
-         if (DiskEntry->DriverName.Length != 0)
+         PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
+           PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
+
+         if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
            {
-             Data->DriverName.Buffer = RtlAllocateHeap(ProcessHeap,
-                                                       0,
-                                                       DiskEntry->DriverName.MaximumLength);
-             if (Data->DriverName.Buffer != NULL)
-               {
-                 Data->DriverName.MaximumLength = DiskEntry->DriverName.MaximumLength;
-                 Data->DriverName.Length = DiskEntry->DriverName.Length;
-                 RtlCopyMemory(Data->DriverName.Buffer,
-                               DiskEntry->DriverName.Buffer,
-                               DiskEntry->DriverName.MaximumLength);
-               }
+             /* Special case - previous partition is first partition */
+             PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
+               DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
+           }
+         else
+           {
+             PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
+               PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
+           }
+
+         if ((PartEntry->PartInfo[1].StartingOffset.QuadPart +
+              PartEntry->PartInfo[1].PartitionLength.QuadPart) <
+              (1024LL * 255LL * 63LL * 512LL))
+           {
+             PrevPartEntry->PartInfo[1].PartitionType = PARTITION_EXTENDED;
+           }
+         else
+           {
+             PrevPartEntry->PartInfo[1].PartitionType = PARTITION_XINT13_EXTENDED;
+           }
+
+         PrevPartEntry->PartInfo[1].BootIndicator = FALSE;
+         PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
+       }
+
+      PartEntry->AutoCreate = AutoCreate;
+      PartEntry->New = TRUE;
+      PartEntry->Unpartitioned = FALSE;
+      PartEntry->UnpartitionedOffset = 0ULL;
+      PartEntry->UnpartitionedLength = 0ULL;
+    }
+  else
+    {
+      /* Insert an initialize a new partition entry */
+      NewPartEntry = (PPARTENTRY)RtlAllocateHeap (ProcessHeap,
+                                                 0,
+                                                 sizeof(PARTENTRY));
+      if (NewPartEntry == NULL)
+       return;
+
+      RtlZeroMemory (NewPartEntry,
+                    sizeof(PARTENTRY));
+
+      /* Insert the new entry into the list */
+      InsertTailList (&PartEntry->ListEntry,
+                     &NewPartEntry->ListEntry);
+
+      NewPartEntry->New = TRUE;
+
+      NewPartEntry->FormatState = Unformatted;
+      NewPartEntry->PartInfo[0].StartingOffset.QuadPart =
+       PartEntry->UnpartitionedOffset + DiskEntry->TrackSize;
+      NewPartEntry->PartInfo[0].PartitionLength.QuadPart =
+       PartitionSize - DiskEntry->TrackSize;
+      NewPartEntry->PartInfo[0].PartitionType = PARTITION_ENTRY_UNUSED;
+      NewPartEntry->PartInfo[0].BootIndicator = FALSE; /* FIXME */
+      NewPartEntry->PartInfo[0].RewritePartition = TRUE;
+      NewPartEntry->PartInfo[1].RewritePartition = TRUE;
+      NewPartEntry->PartInfo[2].RewritePartition = TRUE;
+      NewPartEntry->PartInfo[3].RewritePartition = TRUE;
+
+      /* Get previous and next partition entries */
+      PrevPartEntry = GetPrevPartitionedEntry (DiskEntry,
+                                              NewPartEntry);
+      NextPartEntry = GetNextPartitionedEntry (DiskEntry,
+                                              NewPartEntry);
+
+      if (PrevPartEntry != NULL && NextPartEntry != NULL)
+       {
+         /* Current entry is in the middle of the list */
+
+         /* Copy previous container partition data to current entry */
+         RtlCopyMemory (&NewPartEntry->PartInfo[1],
+                        &PrevPartEntry->PartInfo[1],
+                        sizeof(PARTITION_INFORMATION));
+         NewPartEntry->PartInfo[1].RewritePartition = TRUE;
+
+         /* Update previous container partition data */
+
+         PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
+           NewPartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
+
+         if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
+           {
+             /* Special case - previous partition is first partition */
+             PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
+               DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
+           }
+         else
+           {
+             PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
+               NewPartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
            }
 
-         /* Copy partition-specific data */
-         Data->PartSize = PartEntry->PartSize;
-         Data->PartNumber = PartEntry->PartNumber;
-         Data->PartType = PartEntry->PartType;
-         Data->DriveLetter = PartEntry->DriveLetter;
+         PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
+       }
+      else if (PrevPartEntry == NULL && NextPartEntry != NULL)
+       {
+         /* Current entry is the first entry */
+         return;
+       }
+      else if (PrevPartEntry != NULL && NextPartEntry == NULL)
+       {
+         /* Current entry is the last entry */
+
+         PrevPartEntry->PartInfo[1].StartingOffset.QuadPart =
+           NewPartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
 
-         return(TRUE);
+         if (DiskEntry->PartListHead.Flink == &PrevPartEntry->ListEntry)
+           {
+             /* Special case - previous partition is first partition */
+             PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
+               DiskEntry->DiskSize - PrevPartEntry->PartInfo[1].StartingOffset.QuadPart;
+           }
+         else
+           {
+             PrevPartEntry->PartInfo[1].PartitionLength.QuadPart =
+               NewPartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
+           }
+
+         if ((PartEntry->PartInfo[1].StartingOffset.QuadPart +
+              PartEntry->PartInfo[1].PartitionLength.QuadPart) <
+              (1024LL * 255LL * 63LL * 512LL))
+           {
+             PrevPartEntry->PartInfo[1].PartitionType = PARTITION_EXTENDED;
+           }
+         else
+           {
+             PrevPartEntry->PartInfo[1].PartitionType = PARTITION_XINT13_EXTENDED;
+           }
+
+         PrevPartEntry->PartInfo[1].BootIndicator = FALSE;
+         PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
        }
+
+      /* Update offset and size of the remaining unpartitioned disk space */
+      PartEntry->UnpartitionedOffset += PartitionSize;
+      PartEntry->UnpartitionedLength -= PartitionSize;
     }
 
-  return(FALSE);
+  DiskEntry->Modified = TRUE;
+
+  UpdatePartitionNumbers (DiskEntry);
+
+  AssignDriverLetters (List);
 }
 
 
-BOOLEAN
-CreateSelectedPartition(PPARTLIST List,
-  ULONG PartType,
-  ULONGLONG NewPartSize)
+VOID
+DeleteCurrentPartition (PPARTLIST List)
 {
   PDISKENTRY DiskEntry;
   PPARTENTRY PartEntry;
-  ULONG PartEntryNumber;
-  OBJECT_ATTRIBUTES ObjectAttributes;
-  DRIVE_LAYOUT_INFORMATION *LayoutBuffer;
-  IO_STATUS_BLOCK Iosb;
-  NTSTATUS Status;
-  WCHAR Buffer[MAX_PATH];
-  UNICODE_STRING Name;
-  HANDLE FileHandle;
-  LARGE_INTEGER li;
+  PPARTENTRY PrevPartEntry;
+  PPARTENTRY NextPartEntry;
+
+  if (List == NULL ||
+      List->CurrentDisk == NULL ||
+      List->CurrentPartition == NULL ||
+      List->CurrentPartition->Unpartitioned == TRUE)
+    {
+      return;
+    }
 
   DiskEntry = List->CurrentDisk;
-  PartEntry = &DiskEntry->PartArray[List->CurrentPartition];
-  PartEntry->PartType = PartType;
-  PartEntryNumber = List->CurrentPartition;
-
-  DPRINT("NewPartSize %d (%d MB)\n", NewPartSize, NewPartSize / (1024 * 1024));
-  DPRINT("PartEntry->StartingOffset %d\n", PartEntry->StartingOffset);
-  DPRINT("PartEntry->PartSize %d\n", PartEntry->PartSize);
-  DPRINT("PartEntry->PartNumber %d\n", PartEntry->PartNumber);
-  DPRINT("PartEntry->PartType 0x%x\n", PartEntry->PartType);
-  DPRINT("PartEntry->FileSystemName %s\n", PartEntry->FileSystemName);
-
-  swprintf(Buffer,
-    L"\\Device\\Harddisk%d\\Partition0",
-    DiskEntry->DiskNumber);
-  RtlInitUnicodeString(&Name, Buffer);
-
-  InitializeObjectAttributes(&ObjectAttributes,
-    &Name,
-    0,
-    NULL,
-    NULL);
-
-  Status = NtOpenFile(&FileHandle,
-    0x10001,
-    &ObjectAttributes,
-    &Iosb,
-    1,
-    FILE_SYNCHRONOUS_IO_NONALERT);
-  if (NT_SUCCESS(Status))
-    {
-         LayoutBuffer = (DRIVE_LAYOUT_INFORMATION*)RtlAllocateHeap(ProcessHeap, 0, 8192);
-
-         Status = NtDeviceIoControlFile(FileHandle,
-               NULL,
-               NULL,
-               NULL,
-               &Iosb,
-               IOCTL_DISK_GET_DRIVE_LAYOUT,
-               NULL,
-               0,
-               LayoutBuffer,
-               8192);
-         if (!NT_SUCCESS(Status))
-           {
-          DPRINT("IOCTL_DISK_GET_DRIVE_LAYOUT failed() 0x%.08x\n", Status);
-          NtClose(FileHandle);
-          RtlFreeHeap(ProcessHeap, 0, LayoutBuffer);
-          return FALSE;
-        }
+  PartEntry = List->CurrentPartition;
 
-      li.QuadPart = PartEntry->StartingOffset;
-      LayoutBuffer->PartitionEntry[PartEntryNumber].StartingOffset = li;
-      /* FIXME: Adjust PartitionLength so the partition will end on the last sector of a track */
-      li.QuadPart = NewPartSize;
-      LayoutBuffer->PartitionEntry[PartEntryNumber].PartitionLength = li;
-      LayoutBuffer->PartitionEntry[PartEntryNumber].HiddenSectors =
-        PartEntry->StartingOffset / DiskEntry->BytesPerSector;
-      LayoutBuffer->PartitionEntry[PartEntryNumber].PartitionType = PartType;
-      LayoutBuffer->PartitionEntry[PartEntryNumber].RecognizedPartition = TRUE;
-      LayoutBuffer->PartitionEntry[PartEntryNumber].RewritePartition = TRUE;
-
-      Status = NtDeviceIoControlFile(FileHandle,
-        NULL,
-        NULL,
-        NULL,
-        &Iosb,
-        IOCTL_DISK_SET_DRIVE_LAYOUT,
-        LayoutBuffer,
-        8192,
-        NULL,
-        0);
-      if (!NT_SUCCESS(Status))
-        {
-          DPRINT("IOCTL_DISK_SET_DRIVE_LAYOUT failed() 0x%.08x\n", Status);
-          NtClose(FileHandle);
-          RtlFreeHeap(ProcessHeap, 0, LayoutBuffer);
-          return FALSE;
-        }
+  /* Adjust container partition entries */
+
+  /* Get previous and next partition entries */
+  PrevPartEntry = GetPrevPartitionedEntry (DiskEntry,
+                                          PartEntry);
+  NextPartEntry = GetNextPartitionedEntry (DiskEntry,
+                                          PartEntry);
+
+  if (PrevPartEntry != NULL && NextPartEntry != NULL)
+    {
+      /* Current entry is in the middle of the list */
+
+      /*
+       * The first extended partition can not be deleted
+       * as long as other extended partitions are present.
+       */
+      if (PrevPartEntry->ListEntry.Blink == &DiskEntry->PartListHead)
+       return;
+
+      /* Copy previous container partition data to current entry */
+      RtlCopyMemory (&PrevPartEntry->PartInfo[1],
+                    &PartEntry->PartInfo[1],
+                    sizeof(PARTITION_INFORMATION));
+      PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
+    }
+  else if (PrevPartEntry == NULL && NextPartEntry != NULL)
+    {
+      /*
+       * A primary partition can not be deleted as long as
+       * extended partitions are present.
+       */
+      return;
+    }
+  else if (PrevPartEntry != NULL && NextPartEntry == NULL)
+    {
+      /* Current entry is the last entry */
+      RtlZeroMemory (&PrevPartEntry->PartInfo[1],
+                    sizeof(PARTITION_INFORMATION));
+      PrevPartEntry->PartInfo[1].RewritePartition = TRUE;
+    }
+
+
+  /* Adjust unpartitioned disk space entries */
+
+  /* Get pointer to previous and next unpartitioned entries */
+  PrevPartEntry = GetPrevUnpartitionedEntry (DiskEntry,
+                                            PartEntry);
+
+  NextPartEntry = GetNextUnpartitionedEntry (DiskEntry,
+                                            PartEntry);
+
+  if (PrevPartEntry != NULL && NextPartEntry != NULL)
+    {
+      /* Merge previous, current and next unpartitioned entry */
+
+      /* Adjust the previous entries length */
+      PrevPartEntry->UnpartitionedLength +=
+       (PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize +
+        NextPartEntry->UnpartitionedLength);
+
+      /* Remove the current entry */
+      RemoveEntryList (&PartEntry->ListEntry);
+      RtlFreeHeap (ProcessHeap,
+                  0,
+                  PartEntry);
+
+      /* Remove the next entry */
+      RemoveEntryList (&NextPartEntry->ListEntry);
+      RtlFreeHeap (ProcessHeap,
+                  0,
+                  NextPartEntry);
+
+      /* Update current partition */
+      List->CurrentPartition = PrevPartEntry;
+    }
+  else if (PrevPartEntry != NULL && NextPartEntry == NULL)
+    {
+      /* Merge current and previous unpartitioned entry */
+
+      /* Adjust the previous entries length */
+      PrevPartEntry->UnpartitionedLength +=
+       (PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize);
+
+      /* Remove the current entry */
+      RemoveEntryList (&PartEntry->ListEntry);
+      RtlFreeHeap (ProcessHeap,
+                  0,
+                  PartEntry);
+
+      /* Update current partition */
+      List->CurrentPartition = PrevPartEntry;
+    }
+  else if (PrevPartEntry == NULL && NextPartEntry != NULL)
+    {
+      /* Merge current and next unpartitioned entry */
+
+      /* Adjust the next entries offset and length */
+      NextPartEntry->UnpartitionedOffset =
+       PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
+      NextPartEntry->UnpartitionedLength +=
+       (PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize);
+
+      /* Remove the current entry */
+      RemoveEntryList (&PartEntry->ListEntry);
+      RtlFreeHeap (ProcessHeap,
+                  0,
+                  PartEntry);
+
+      /* Update current partition */
+      List->CurrentPartition = NextPartEntry;
     }
   else
     {
-      DPRINT("NtOpenFile failed() 0x%.08x\n", Status);
-      NtClose(FileHandle);
-      RtlFreeHeap(ProcessHeap, 0, LayoutBuffer);
-      return FALSE;
+      /* Nothing to merge but change current entry */
+      PartEntry->New = FALSE;
+      PartEntry->Unpartitioned = TRUE;
+      PartEntry->UnpartitionedOffset =
+       PartEntry->PartInfo[0].StartingOffset.QuadPart - DiskEntry->TrackSize;
+      PartEntry->UnpartitionedLength =
+       PartEntry->PartInfo[0].PartitionLength.QuadPart + DiskEntry->TrackSize;
+
+      /* Wipe the partition table */
+      RtlZeroMemory (&PartEntry->PartInfo,
+                    sizeof(PartEntry->PartInfo));
     }
 
-  NtClose(FileHandle);
-  RtlFreeHeap(ProcessHeap, 0, LayoutBuffer);
+  DiskEntry->Modified = TRUE;
 
-  return TRUE;
+  UpdatePartitionNumbers (DiskEntry);
+
+  AssignDriverLetters (List);
 }
 
 
-BOOLEAN
-DeleteSelectedPartition(PPARTLIST List)
+VOID
+CheckActiveBootPartition (PPARTLIST List)
 {
   PDISKENTRY DiskEntry;
   PPARTENTRY PartEntry;
-  ULONG PartEntryNumber;
-  OBJECT_ATTRIBUTES ObjectAttributes;
-  DRIVE_LAYOUT_INFORMATION *LayoutBuffer;
-  IO_STATUS_BLOCK Iosb;
-  NTSTATUS Status;
-  WCHAR Buffer[MAX_PATH];
-  UNICODE_STRING Name;
-  HANDLE FileHandle;
-  LARGE_INTEGER li;
 
-  DiskEntry = List->CurrentDisk;
-  PartEntry = &DiskEntry->PartArray[List->CurrentPartition];
-  PartEntry->PartType = PARTITION_ENTRY_UNUSED;
-  PartEntryNumber = List->CurrentPartition;
-
-  DPRINT1("DeleteSelectedPartition(PartEntryNumber = %d)\n", PartEntryNumber);
-  DPRINT1("PartEntry->StartingOffset %d\n", PartEntry->StartingOffset);
-  DPRINT1("PartEntry->PartSize %d\n", PartEntry->PartSize);
-  DPRINT1("PartEntry->PartNumber %d\n", PartEntry->PartNumber);
-  DPRINT1("PartEntry->PartType 0x%x\n", PartEntry->PartType);
-  DPRINT1("PartEntry->FileSystemName %s\n", PartEntry->FileSystemName);
-
-  swprintf(Buffer,
-    L"\\Device\\Harddisk%d\\Partition0",
-    DiskEntry->DiskNumber);
-  RtlInitUnicodeString(&Name, Buffer);
-
-  InitializeObjectAttributes(&ObjectAttributes,
-    &Name,
-    0,
-    NULL,
-    NULL);
-
-  Status = NtOpenFile(&FileHandle,
-    0x10001,
-    &ObjectAttributes,
-    &Iosb,
-    1,
-    FILE_SYNCHRONOUS_IO_NONALERT);
-  if (NT_SUCCESS(Status))
-    {
-         LayoutBuffer = (DRIVE_LAYOUT_INFORMATION*)RtlAllocateHeap(ProcessHeap, 0, 8192);
-
-         Status = NtDeviceIoControlFile(FileHandle,
-               NULL,
-               NULL,
-               NULL,
-               &Iosb,
-               IOCTL_DISK_GET_DRIVE_LAYOUT,
-               NULL,
-               0,
-               LayoutBuffer,
-               8192);
-         if (!NT_SUCCESS(Status))
-           {
-          DPRINT("IOCTL_DISK_GET_DRIVE_LAYOUT failed() 0x%.08x\n", Status);
-          NtClose(FileHandle);
-          RtlFreeHeap(ProcessHeap, 0, LayoutBuffer);
-          return FALSE;
-        }
+  /* Check for empty disk list */
+  if (IsListEmpty (&List->DiskListHead))
+    {
+      List->ActiveBootDisk = NULL;
+      List->ActiveBootPartition = NULL;
+      return;
+    }
 
-      li.QuadPart = 0;
-      LayoutBuffer->PartitionEntry[PartEntryNumber].StartingOffset = li;
-      li.QuadPart = 0;
-      LayoutBuffer->PartitionEntry[PartEntryNumber].PartitionLength = li;
-      LayoutBuffer->PartitionEntry[PartEntryNumber].HiddenSectors = 0;
-      LayoutBuffer->PartitionEntry[PartEntryNumber].PartitionType = 0;
-      LayoutBuffer->PartitionEntry[PartEntryNumber].RecognizedPartition = FALSE;
-      LayoutBuffer->PartitionEntry[PartEntryNumber].RewritePartition = TRUE;
-
-      Status = NtDeviceIoControlFile(FileHandle,
-        NULL,
-        NULL,
-        NULL,
-        &Iosb,
-        IOCTL_DISK_SET_DRIVE_LAYOUT,
-        LayoutBuffer,
-        8192,
-        NULL,
-        0);
-      if (!NT_SUCCESS(Status))
-        {
-          DPRINT("IOCTL_DISK_SET_DRIVE_LAYOUT failed() 0x%.08x\n", Status);
-          NtClose(FileHandle);
-          RtlFreeHeap(ProcessHeap, 0, LayoutBuffer);
-          return FALSE;
-        }
+#if 0
+  if (List->ActiveBootDisk != NULL &&
+      List->ActiveBootPartition != NULL)
+    {
+      /* We already have an active boot partition */
+      return;
     }
-  else
+#endif
+
+  DiskEntry = CONTAINING_RECORD (List->DiskListHead.Flink,
+                                DISKENTRY,
+                                ListEntry);
+
+  /* Check for empty partition list */
+  if (IsListEmpty (&DiskEntry->PartListHead))
     {
-      DPRINT("NtOpenFile failed() 0x%.08x\n", Status);
-      NtClose(FileHandle);
-      RtlFreeHeap(ProcessHeap, 0, LayoutBuffer);
-      return FALSE;
+      List->ActiveBootDisk = NULL;
+      List->ActiveBootPartition = NULL;
+      return;
     }
 
-  NtClose(FileHandle);
-  RtlFreeHeap(ProcessHeap, 0, LayoutBuffer);
+  PartEntry = CONTAINING_RECORD (DiskEntry->PartListHead.Flink,
+                                PARTENTRY,
+                                ListEntry);
 
-  return TRUE;
+  /* Set active boot partition */
+  if ((DiskEntry->NewDisk == TRUE) ||
+      (PartEntry->PartInfo[0].BootIndicator == FALSE &&
+       PartEntry->PartInfo[1].BootIndicator == FALSE &&
+       PartEntry->PartInfo[2].BootIndicator == FALSE &&
+       PartEntry->PartInfo[3].BootIndicator == FALSE))
+    {
+      PartEntry->PartInfo[0].BootIndicator = TRUE;
+      PartEntry->PartInfo[0].RewritePartition = TRUE;
+      DiskEntry->Modified = TRUE;
+    }
+
+  /* FIXME: Might be incorrect if partitions were created by Linux FDISK */
+  List->ActiveBootDisk = DiskEntry;
+  List->ActiveBootPartition = PartEntry;
 }
 
-#if 0
+
 BOOLEAN
-MarkPartitionActive (ULONG DiskNumber,
-                    ULONG PartitionNumber,
-                    PPARTDATA ActivePartition)
+CheckForLinuxFdiskPartitions (PPARTLIST List)
 {
-  PPARTLIST List;
+  PDISKENTRY DiskEntry;
   PPARTENTRY PartEntry;
-  ULONG PartEntryNumber;
+  PLIST_ENTRY Entry1;
+  PLIST_ENTRY Entry2;
+  ULONG PartitionCount;
+  ULONG i;
+
+  Entry1 = List->DiskListHead.Flink;
+  while (Entry1 != &List->DiskListHead)
+    {
+      DiskEntry = CONTAINING_RECORD (Entry1,
+                                    DISKENTRY,
+                                    ListEntry);
+
+      Entry2 = DiskEntry->PartListHead.Flink;
+      while (Entry2 != &DiskEntry->PartListHead)
+       {
+         PartEntry = CONTAINING_RECORD (Entry2,
+                                        PARTENTRY,
+                                        ListEntry);
+
+         if (PartEntry->Unpartitioned == FALSE)
+           {
+             PartitionCount = 0;
+
+             for (i = 0; i < 4; i++)
+               {
+                 if (!IsContainerPartition (PartEntry->PartInfo[i].PartitionType) &&
+                     PartEntry->PartInfo[i].PartitionLength.QuadPart != 0ULL)
+                   {
+                     PartitionCount++;
+                   }
+               }
+
+             if (PartitionCount > 1)
+               {
+                 return TRUE;
+               }
+           }
+
+         Entry2 = Entry2->Flink;
+       }
+
+      Entry1 = Entry1->Flink;
+    }
+
+  return FALSE;
+}
+
+
+BOOLEAN
+WritePartitionsToDisk (PPARTLIST List)
+{
+  PDRIVE_LAYOUT_INFORMATION DriveLayout;
   OBJECT_ATTRIBUTES ObjectAttributes;
-  DRIVE_LAYOUT_INFORMATION *LayoutBuffer;
   IO_STATUS_BLOCK Iosb;
-  NTSTATUS Status;
-  WCHAR Buffer[MAX_PATH];
+  WCHAR SrcPath[MAX_PATH];
+  WCHAR DstPath[MAX_PATH];
   UNICODE_STRING Name;
   HANDLE FileHandle;
+  PDISKENTRY DiskEntry1;
+  PDISKENTRY DiskEntry2;
+  PPARTENTRY PartEntry;
+  PLIST_ENTRY Entry1;
+  PLIST_ENTRY Entry2;
+  ULONG PartitionCount;
+  ULONG DriveLayoutSize;
+  ULONG Index;
+  NTSTATUS Status;
 
-  List = InitializePartitionList ();
   if (List == NULL)
     {
-      return(FALSE);
+      return TRUE;
     }
 
-  PartEntry = GetPartitionInformation(List,
-                       DiskNumber,
-                       PartitionNumber,
-                       &PartEntryNumber);
-  if (List == NULL)
+  Entry1 = List->DiskListHead.Flink;
+  while (Entry1 != &List->DiskListHead)
     {
-      DestroyPartitionList(List);
-      return(FALSE);
-    }
-
-
-  swprintf(Buffer,
-    L"\\Device\\Harddisk%d\\Partition0",
-    DiskNumber);
-  RtlInitUnicodeString(&Name, Buffer);
-
-  InitializeObjectAttributes(&ObjectAttributes,
-    &Name,
-    0,
-    NULL,
-    NULL);
-
-  Status = NtOpenFile(&FileHandle,
-    0x10001,
-    &ObjectAttributes,
-    &Iosb,
-    1,
-    FILE_SYNCHRONOUS_IO_NONALERT);
-  if (NT_SUCCESS(Status))
-    {
-         LayoutBuffer = (DRIVE_LAYOUT_INFORMATION*)RtlAllocateHeap(ProcessHeap, 0, 8192);
-
-         Status = NtDeviceIoControlFile(FileHandle,
-               NULL,
-               NULL,
-               NULL,
-               &Iosb,
-               IOCTL_DISK_GET_DRIVE_LAYOUT,
-               NULL,
-               0,
-               LayoutBuffer,
-               8192);
-         if (!NT_SUCCESS(Status))
+      DiskEntry1 = CONTAINING_RECORD (Entry1,
+                                     DISKENTRY,
+                                     ListEntry);
+
+      if (DiskEntry1->Modified == TRUE)
+       {
+         /* Count partitioned entries */
+         PartitionCount = 0;
+         Entry2 = DiskEntry1->PartListHead.Flink;
+         while (Entry2 != &DiskEntry1->PartListHead)
            {
-          NtClose(FileHandle);
-          RtlFreeHeap(ProcessHeap, 0, LayoutBuffer);
-          DestroyPartitionList(List);
-          return FALSE;
-        }
+             PartEntry = CONTAINING_RECORD (Entry2,
+                                            PARTENTRY,
+                                            ListEntry);
+             if (PartEntry->Unpartitioned == FALSE)
+               {
+                 PartitionCount += 4;
+               }
 
+             Entry2 = Entry2->Flink;
+           }
+          if (PartitionCount == 0)
+            {
+              DriveLayoutSize = sizeof (DRIVE_LAYOUT_INFORMATION) +
+               ((4 - 1) * sizeof (PARTITION_INFORMATION));
+            }
+          else
+            {
+             DriveLayoutSize = sizeof (DRIVE_LAYOUT_INFORMATION) +
+               ((PartitionCount - 1) * sizeof (PARTITION_INFORMATION));
+            }
+         DriveLayout = (PDRIVE_LAYOUT_INFORMATION)RtlAllocateHeap (ProcessHeap,
+                                                                   0,
+                                                                    DriveLayoutSize);
+         if (DriveLayout == NULL)
+           {
+             DPRINT1 ("RtlAllocateHeap() failed\n");
+             return FALSE;
+           }
 
-      LayoutBuffer->PartitionEntry[PartEntryNumber].BootIndicator = TRUE;
+         RtlZeroMemory (DriveLayout,
+                        DriveLayoutSize);
+
+          if (PartitionCount == 0)
+            {
+              /* delete all partitions in the mbr */
+              DriveLayout->PartitionCount = 4;
+              for (Index = 0; Index < 4; Index++)
+                {
+                  DriveLayout->PartitionEntry[Index].RewritePartition = TRUE;
+                }
+            }
+          else
+           {
+             DriveLayout->PartitionCount = PartitionCount;
+              
+             Index = 0;
+             Entry2 = DiskEntry1->PartListHead.Flink;
+             while (Entry2 != &DiskEntry1->PartListHead)
+               {
+                 PartEntry = CONTAINING_RECORD (Entry2,
+                                                PARTENTRY,
+                                                ListEntry);
+                 if (PartEntry->Unpartitioned == FALSE)
+                   {
+                     RtlCopyMemory (&DriveLayout->PartitionEntry[Index],
+                                    &PartEntry->PartInfo[0],
+                                    4 * sizeof (PARTITION_INFORMATION));
+                     Index += 4;
+                   }
+
+                 Entry2 = Entry2->Flink;
+               }
+            }
+          if (DiskEntry1->Signature == 0)
+            {
+              LARGE_INTEGER SystemTime;
+              TIME_FIELDS TimeFields;
+              PUCHAR Buffer;
+              Buffer = (PUCHAR)&DiskEntry1->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 (DiskEntry1->Signature == 0)
+                    {
+                      continue;
+                    }
+
+                  /* check if the signature already exist */
+                  /* FIXME:
+                   *   Check also signatures from disks, which are 
+                   *   not visible (bootable) by the bios.
+                   */
+                  Entry2 = List->DiskListHead.Flink;
+                  while (Entry2 != &List->DiskListHead)
+                    {
+                      DiskEntry2 = CONTAINING_RECORD(Entry2, DISKENTRY, ListEntry);
+                      if (DiskEntry1 != DiskEntry2 &&
+                          DiskEntry1->Signature == DiskEntry2->Signature)
+                        {
+                          break;
+                        }
+                      Entry2 = Entry2->Flink;
+                    }
+                  if (Entry2 == &List->DiskListHead)
+                    {
+                      break;
+                    }
+                }
+              
+              /* set one partition entry to dirty, this will update the signature */
+              DriveLayout->PartitionEntry[0].RewritePartition = TRUE;
+
+            }
+
+          DriveLayout->Signature = DiskEntry1->Signature;
+
+
+         swprintf (DstPath,
+                   L"\\Device\\Harddisk%d\\Partition0",
+                   DiskEntry1->DiskNumber);
+         RtlInitUnicodeString (&Name,
+                               DstPath);
+         InitializeObjectAttributes (&ObjectAttributes,
+                                     &Name,
+                                     0,
+                                     NULL,
+                                     NULL);
+
+         Status = NtOpenFile (&FileHandle,
+                              FILE_ALL_ACCESS,
+                               &ObjectAttributes,
+                               &Iosb,
+                               0,                                 
+                               FILE_SYNCHRONOUS_IO_NONALERT);
+
+         if (!NT_SUCCESS (Status))
+           {
+             DPRINT1 ("NtOpenFile() failed (Status %lx)\n", Status);
+             return FALSE;
+           }
 
-      Status = NtDeviceIoControlFile(FileHandle,
-        NULL,
-        NULL,
-        NULL,
-        &Iosb,
-        IOCTL_DISK_SET_DRIVE_LAYOUT,
-        LayoutBuffer,
-        8192,
-        NULL,
-        0);
-      if (!NT_SUCCESS(Status))
-        {
-          NtClose(FileHandle);
-          RtlFreeHeap(ProcessHeap, 0, LayoutBuffer);
-          DestroyPartitionList(List);
-          return FALSE;
-        }
+         Status = NtDeviceIoControlFile (FileHandle,
+                                         NULL,
+                                         NULL,
+                                         NULL,
+                                         &Iosb,
+                                         IOCTL_DISK_SET_DRIVE_LAYOUT,
+                                         DriveLayout,
+                                         DriveLayoutSize,
+                                         NULL,
+                                         0);
+         if (!NT_SUCCESS (Status))
+           {
+             DPRINT1 ("NtDeviceIoControlFile() failed (Status %lx)\n", Status);
+             NtClose (FileHandle);
+             return FALSE;
+           }
+
+         RtlFreeHeap (ProcessHeap,
+                      0,
+                      DriveLayout);
+
+          NtClose (FileHandle);
+
+          /* Install MBR code if the disk is new */
+          if (DiskEntry1->NewDisk == TRUE &&
+              DiskEntry1->BiosDiskNumber == 0)
+           {
+             wcscpy (SrcPath, SourceRootPath.Buffer);
+             wcscat (SrcPath, L"\\loader\\dosmbr.bin");
+
+             DPRINT ("Install MBR bootcode: %S ==> %S\n",
+                      SrcPath, DstPath);
+
+             /* Install MBR bootcode */
+             Status = InstallMbrBootCodeToDisk (SrcPath,
+                                                DstPath);
+             if (!NT_SUCCESS (Status))
+               {
+                 DPRINT1 ("InstallMbrBootCodeToDisk() failed (Status %lx)\n",
+                          Status);
+                 return FALSE;
+               }
+
+             DiskEntry1->NewDisk = FALSE;
+           }
+       }
+
+      Entry1 = Entry1->Flink;
     }
-  else
+
+  return TRUE;
+}
+
+BOOL SetMountedDeviceValues(PPARTLIST List)
+{
+  PLIST_ENTRY Entry1, Entry2;
+  PDISKENTRY DiskEntry;
+  PPARTENTRY PartEntry;
+
+  if (List == NULL)
     {
-      NtClose(FileHandle);
-      RtlFreeHeap(ProcessHeap, 0, LayoutBuffer);
-      DestroyPartitionList(List);
       return FALSE;
     }
 
-  NtClose(FileHandle);
-  RtlFreeHeap(ProcessHeap, 0, LayoutBuffer);
-
-  PartEntry->Active = TRUE;
-  if (!GetActiveBootPartition(List, ActivePartition))
-  {
-    DestroyPartitionList(List);
-    DPRINT("GetActiveBootPartition() failed\n");
-    return FALSE;
-  }
-
-  DestroyPartitionList(List);
+  Entry1 = List->DiskListHead.Flink;
+  while (Entry1 != &List->DiskListHead)
+    {
+      DiskEntry = CONTAINING_RECORD (Entry1,
+                                    DISKENTRY,
+                                    ListEntry);
 
+      Entry2 = DiskEntry->PartListHead.Flink;
+      while (Entry2 != &DiskEntry->PartListHead)
+        {
+          PartEntry = CONTAINING_RECORD(Entry2, PARTENTRY, ListEntry);
+          if (!PartEntry->Unpartitioned && PartEntry->DriveLetter)
+            {
+              if (!SetMountedDeviceValue(PartEntry->DriveLetter, DiskEntry->Signature, PartEntry->PartInfo[0].StartingOffset))
+                {
+                  return FALSE;
+                }
+            }
+          Entry2 = Entry2->Flink;
+        }
+      Entry1 = Entry1->Flink;
+    }
   return TRUE;
 }
-#endif
+
+
 
 /* EOF */