Removed outdated email addresses.
[reactos.git] / reactos / ntoskrnl / io / iomgr / arcname.c
index d6f72d1..798219b 100644 (file)
-/* $Id$
- *
- * COPYRIGHT:       See COPYING in the top level directory
- * PROJECT:         ReactOS kernel
- * FILE:            ntoskrnl/io/arcname.c
- * PURPOSE:         Creates ARC names for boot devices
- *
- * PROGRAMMERS:     Eric Kohl (ekohl@rz-online.de)
- */
+/*
+* PROJECT:         ReactOS Kernel
+* LICENSE:         GPL - See COPYING in the top level directory
+* FILE:            ntoskrnl/io/iomgr/arcname.c
+* PURPOSE:         ARC Path Initialization Functions
+* PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
+*                  Eric Kohl
+*/
 
-
-/* INCLUDES *****************************************************************/
+/* INCLUDES ******************************************************************/
 
 #include <ntoskrnl.h>
 #define NDEBUG
-#include <internal/debug.h>
-
-/* MACROS *******************************************************************/
-
-#define FS_VOLUME_BUFFER_SIZE (MAX_PATH + sizeof(FILE_FS_VOLUME_INFORMATION))
-
-/* FUNCTIONS ****************************************************************/
-
-static 
-NTSTATUS
-STDCALL
-INIT_FUNCTION
-DiskQueryRoutine(PWSTR ValueName,
-                 ULONG ValueType,
-                 PVOID ValueData,
-                 ULONG ValueLength,
-                 PVOID Context,
-                 PVOID EntryContext)
-{
-  PLIST_ENTRY ListHead = (PLIST_ENTRY)Context;
-  PULONG GlobalDiskCount = (PULONG)EntryContext;
-  PDISKENTRY DiskEntry;
-  UNICODE_STRING NameU;
+#include <debug.h>
 
-  if (ValueType == REG_SZ &&
-      ValueLength == 20 * sizeof(WCHAR))
-    {
-      DiskEntry = ExAllocatePool(PagedPool, sizeof(DISKENTRY));
-      if (DiskEntry == NULL)
-        {
-          return STATUS_NO_MEMORY;
-        }
-      DiskEntry->DiskNumber = (*GlobalDiskCount)++;
+/* GLOBALS *******************************************************************/
 
-      NameU.Buffer = (PWCHAR)ValueData;
-      NameU.Length = NameU.MaximumLength = 8 * sizeof(WCHAR);
-      RtlUnicodeStringToInteger(&NameU, 16, &DiskEntry->Checksum);
-
-      NameU.Buffer = (PWCHAR)ValueData + 9;
-      RtlUnicodeStringToInteger(&NameU, 16, &DiskEntry->Signature);
-
-      InsertTailList(ListHead, &DiskEntry->ListEntry);
-    }
+UNICODE_STRING IoArcHalDeviceName, IoArcBootDeviceName;
+PCHAR IoLoaderArcBootDeviceName;
+extern PROS_LOADER_PARAMETER_BLOCK KeRosLoaderBlock;
 
-  return STATUS_SUCCESS;
-}
-
-#define ROOT_NAME   L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter"
-
-static VOID INIT_FUNCTION
-IopEnumerateBiosDisks(PLIST_ENTRY ListHead)
-{
-  RTL_QUERY_REGISTRY_TABLE QueryTable[2];
-  WCHAR Name[255];
-  ULONG AdapterCount;
-  ULONG ControllerCount;
-  ULONG DiskCount;
-  NTSTATUS Status;
-  ULONG GlobalDiskCount=0;
-
-  memset(QueryTable, 0, sizeof(QueryTable));
-  QueryTable[0].Name = L"Identifier";
-  QueryTable[0].QueryRoutine = DiskQueryRoutine;
-  QueryTable[0].EntryContext = (PVOID)&GlobalDiskCount;
-
-  AdapterCount = 0;
-  while (1)
-    {
-      swprintf(Name, L"%s\\%lu", ROOT_NAME, AdapterCount);
-      Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
-                                      Name,
-                                      &QueryTable[1],
-                                      NULL,
-                                      NULL);
-      if (!NT_SUCCESS(Status))
-        {
-            break;
-        }
-        
-      swprintf(Name, L"%s\\%lu\\DiskController", ROOT_NAME, AdapterCount);
-      Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
-                                      Name,
-                                      &QueryTable[1],
-                                      NULL,
-                                      NULL);
-      if (NT_SUCCESS(Status))
-        {
-          ControllerCount = 0;
-          while (1)
-            {
-              swprintf(Name, L"%s\\%lu\\DiskController\\%lu", ROOT_NAME, AdapterCount, ControllerCount);
-              Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
-                                              Name,
-                                              &QueryTable[1],
-                                              NULL,
-                                              NULL);
-              if (!NT_SUCCESS(Status))
-                {
-                    break;
-                }
-                
-              swprintf(Name, L"%s\\%lu\\DiskController\\%lu\\DiskPeripheral", ROOT_NAME, AdapterCount, ControllerCount);
-              Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
-                                              Name,
-                                              &QueryTable[1],
-                                              NULL,
-                                              NULL);
-              if (NT_SUCCESS(Status))
-                {
-                  DiskCount = 0;
-                  while (1)
-                    {
-                      swprintf(Name, L"%s\\%lu\\DiskController\\%lu\\DiskPeripheral\\%lu", ROOT_NAME, AdapterCount, ControllerCount, DiskCount);
-                      Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
-                                                      Name,
-                                                      QueryTable,
-                                                      (PVOID)ListHead,
-                                                      NULL);
-                      if (!NT_SUCCESS(Status))
-                        {
-                          break;
-                        }
-                      DiskCount++;
-                    }
-                }
-              ControllerCount++;
-            }
-        }
-      AdapterCount++;
-    }
-}
+/* FUNCTIONS *****************************************************************/
 
 BOOLEAN
 INIT_FUNCTION
@@ -153,68 +28,112 @@ IopApplyRosCdromArcHack(IN ULONG i)
 {
     ULONG DeviceNumber = -1;
     OBJECT_ATTRIBUTES ObjectAttributes;
+    ANSI_STRING InstallName;
     UNICODE_STRING DeviceName;
-    WCHAR Buffer[MAX_PATH];
-    CHAR AnsiBuffer[MAX_PATH];
+    CHAR Buffer[128], RosSysPath[16];
     FILE_BASIC_INFORMATION FileInfo;
     NTSTATUS Status;
     PCHAR p, q;
+    PCONFIGURATION_INFORMATION ConfigInfo = IoGetConfigurationInformation();
+    extern BOOLEAN InitIsWinPEMode, ExpInTextModeSetup;
+
+    /* Change this if you want ROS to boot properly from another directory */
+    sprintf(RosSysPath, "%s", "reactos");
 
     /* Only ARC Name left - Build full ARC Name */
     p = strstr(KeLoaderBlock->ArcBootDeviceName, "cdrom");
     if (p)
     {
+        /* Build installer name */
+        sprintf(Buffer, "\\Device\\CdRom%lu\\%s\\ntoskrnl.exe", i, RosSysPath);
+        RtlInitAnsiString(&InstallName, Buffer);
+        Status = RtlAnsiStringToUnicodeString(&DeviceName, &InstallName, TRUE);
+        if (!NT_SUCCESS(Status)) return FALSE;
+
         /* Try to find the installer */
-        swprintf(Buffer, L"\\Device\\CdRom%lu\\reactos\\ntoskrnl.exe", i);
-        RtlInitUnicodeString(&DeviceName, Buffer);
         InitializeObjectAttributes(&ObjectAttributes,
                                    &DeviceName,
                                    0,
                                    NULL,
                                    NULL);
         Status = ZwQueryAttributesFile(&ObjectAttributes, &FileInfo);
-        if (NT_SUCCESS(Status)) DeviceNumber = i;
 
-        /* Try to find live CD boot */
-        swprintf(Buffer,
-                 L"\\Device\\CdRom%lu\\reactos\\system32\\ntoskrnl.exe",
-                 i);
-        RtlInitUnicodeString(&DeviceName, Buffer);
-        InitializeObjectAttributes(&ObjectAttributes,
-                                   &DeviceName,
-                                   0,
-                                   NULL,
-                                   NULL);
-        Status = ZwQueryAttributesFile(&ObjectAttributes, &FileInfo);
-        if (NT_SUCCESS(Status)) DeviceNumber = i;
+        /* Free the string */
+        RtlFreeUnicodeString(&DeviceName);
 
-        /* Build the name */
-        sprintf(p, "cdrom(%lu)", DeviceNumber);
+        /* Check if we found the file */
+        if (NT_SUCCESS(Status))
+        {
+            /* We did, save the device number */
+            DeviceNumber = i;
+        }
+        else
+        {
+            /* Build live CD kernel name */
+            sprintf(Buffer,
+                    "\\Device\\CdRom%lu\\%s\\system32\\ntoskrnl.exe",
+                    i, RosSysPath);
+            RtlInitAnsiString(&InstallName, Buffer);
+            Status = RtlAnsiStringToUnicodeString(&DeviceName,
+                                                  &InstallName,
+                                                  TRUE);
+            if (!NT_SUCCESS(Status)) return FALSE;
+
+            /* Try to find it */
+            InitializeObjectAttributes(&ObjectAttributes,
+                                       &DeviceName,
+                                       0,
+                                       NULL,
+                                       NULL);
+            Status = ZwQueryAttributesFile(&ObjectAttributes, &FileInfo);
+            if (NT_SUCCESS(Status)) DeviceNumber = i;
+
+            /* Free the string */
+            RtlFreeUnicodeString(&DeviceName);
+        }
 
-        /* Adjust original command line */
-        q = strchr(p, ')');
-        if (q)
+        if (!InitIsWinPEMode)
         {
-            q++;
-            strcpy(AnsiBuffer, q);
+            /* Build the name */
             sprintf(p, "cdrom(%lu)", DeviceNumber);
-            strcat(p, AnsiBuffer);
+
+            /* Adjust original command line */
+            q = strchr(p, ')');
+            if (q)
+            {
+                q++;
+                strcpy(Buffer, q);
+                sprintf(p, "cdrom(%lu)", DeviceNumber);
+                strcat(p, Buffer);
+            }
         }
     }
 
+    /* OK, how many disks are there? */
+    DeviceNumber += ConfigInfo->DiskCount;
+
     /* Return whether this is the CD or not */
-    if (DeviceNumber != 1) return TRUE;
+    if ((InitIsWinPEMode) || (ExpInTextModeSetup))
+    {
+        return TRUE;
+    }
+
+    /* Failed */
     return FALSE;
 }
 
-VOID
+BOOLEAN
 INIT_FUNCTION
 NTAPI
-IopEnumerateDisks(IN PLIST_ENTRY ListHead)
+IopGetDiskInformation(IN ULONG i,
+                      OUT PULONG CheckSum,
+                      OUT PULONG Signature,
+                      OUT PULONG PartitionCount,
+                      OUT PDEVICE_OBJECT *DiskDeviceObject)
 {
-    ULONG i, j;
+    ULONG j, Checksum;
     ANSI_STRING TempString;
-    CHAR Buffer[256];
+    CHAR Buffer[128];
     UNICODE_STRING DeviceName;
     NTSTATUS Status;
     PDEVICE_OBJECT DeviceObject;
@@ -225,252 +144,147 @@ IopEnumerateDisks(IN PLIST_ENTRY ListHead)
     PIRP Irp;
     IO_STATUS_BLOCK StatusBlock;
     LARGE_INTEGER PartitionOffset;
-    PPARTITION_SECTOR PartitionBuffer;
-    PDISKENTRY DiskEntry;
-
-    /* Loop every detected disk */
-    for (i = 0; i < IoGetConfigurationInformation()->DiskCount; i++)
-    {
-        /* Build the name */
-        sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition0", i);
-
-        /* Convert it to Unicode */
-        RtlInitAnsiString(&TempString, Buffer);
-        Status = RtlAnsiStringToUnicodeString(&DeviceName, &TempString, TRUE);
-        if (!NT_SUCCESS(Status)) continue;
+    PULONG PartitionBuffer;
 
-        /* Get the device pointer */
-        Status = IoGetDeviceObjectPointer(&DeviceName,
-                                          FILE_READ_DATA,
-                                          &FileObject,
-                                          &DeviceObject);
-
-        /* Free the string */
-        RtlFreeUnicodeString(&DeviceName);
+    /* Build the name */
+    sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition0", i);
 
-        /* Move on if we failed */
-        if (!NT_SUCCESS(Status)) continue;
-
-        /* Allocate the ROS disk Entry */
-        DiskEntry = ExAllocatePoolWithTag(PagedPool, sizeof(DISKENTRY), TAG_IO);
-        DiskEntry->DiskNumber = i;
-        DiskEntry->DeviceObject = DeviceObject;
-
-        /* Build an IRP to determine the sector size */
-        KeInitializeEvent(&Event, NotificationEvent, FALSE);
-        Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
-                                            DeviceObject,
-                                            NULL,
-                                            0,
-                                            &DiskGeometry,
-                                            sizeof(DISK_GEOMETRY),
-                                            FALSE,
-                                            &Event,
-                                            &StatusBlock);
-        if (!Irp)
-        {
-            /* Try again */
-            ObDereferenceObject(FileObject);
-            continue;
-        }
+    /* Convert it to Unicode */
+    RtlInitAnsiString(&TempString, Buffer);
+    Status = RtlAnsiStringToUnicodeString(&DeviceName, &TempString, TRUE);
+    if (!NT_SUCCESS(Status)) return FALSE;
 
-        /* Call the driver and check if we have to wait on it */
-        Status = IoCallDriver(DeviceObject, Irp);
-        if (Status == STATUS_PENDING)
-        {
-            /* Wait on the driver */
-            KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
-            Status = StatusBlock.Status;
-        }
+    /* Get the device pointer */
+    Status = IoGetDeviceObjectPointer(&DeviceName,
+                                      FILE_READ_ATTRIBUTES,
+                                      &FileObject,
+                                      &DeviceObject);
+    *DiskDeviceObject = DeviceObject;
 
-        /* Check if we failed */
-        if (!NT_SUCCESS(Status))
-        {
-            /* Try again */
-            ObDereferenceObject(FileObject);
-            continue;
-        }
+    /* Free the string */
+    RtlFreeUnicodeString(&DeviceName);
 
-        /* Read the partition table */
-        Status = IoReadPartitionTable(DeviceObject,
-                                      DiskGeometry.BytesPerSector,
-                                      TRUE,
-                                      &DriveLayout);
+    /* Move on if we failed */
+    if (!NT_SUCCESS(Status)) return FALSE;
 
-        /* Dereference the file object */
+    /* Build an IRP to determine the sector size */
+    KeInitializeEvent(&Event, NotificationEvent, FALSE);
+    Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
+                                        DeviceObject,
+                                        NULL,
+                                        0,
+                                        &DiskGeometry,
+                                        sizeof(DISK_GEOMETRY),
+                                        FALSE,
+                                        &Event,
+                                        &StatusBlock);
+    if (!Irp)
+    {
+        /* Try again */
         ObDereferenceObject(FileObject);
-        if (!NT_SUCCESS(Status)) continue;
-
-        /* Set the offset to 0 */
-        PartitionOffset.QuadPart = 0;
-
-        /* Allocate a buffer for the partition */
-        PartitionBuffer = ExAllocatePoolWithTag(NonPagedPool,
-                                                DiskGeometry.BytesPerSector,
-                                                TAG_IO);
-        if (!PartitionBuffer) continue;
-
-        /* Build an IRP to read the partition sector */
-        KeInitializeEvent(&Event, NotificationEvent, FALSE);
-        Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
-                                           DeviceObject,
-                                           PartitionBuffer,
-                                           DiskGeometry.BytesPerSector,
-                                           &PartitionOffset,
-                                           &Event,
-                                           &StatusBlock);
-
-        /* Call the driver and check if we have to wait */
-        Status = IoCallDriver(DeviceObject, Irp);
-        if (Status == STATUS_PENDING)
-        {
-            /* Wait for completion */
-            KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
-            Status = StatusBlock.Status;
-        }
-
-        /* Check if we failed */
-        if (!NT_SUCCESS(Status))
-        {
-            /* Try again */
-            ExFreePool(PartitionBuffer);
-            ExFreePool(DriveLayout);
-            continue;
-        }
-
-        /* Calculate the MBR checksum */
-        DiskEntry->Checksum = 0;
-        for (j = 0; j < 128; j++)
-        {
-            DiskEntry->Checksum += ((PULONG)PartitionBuffer)[j];
-        }
-
-        /* Save the signature and checksum */
-        DiskEntry->Checksum = ~DiskEntry->Checksum + 1;
-        DiskEntry->Signature = DriveLayout->Signature;
-        DiskEntry->PartitionCount = DriveLayout->PartitionCount;
-
-        /* Insert it into the list */
-        InsertTailList(ListHead, &DiskEntry->ListEntry);
-
-        /* Free the buffer */
-        ExFreePool(PartitionBuffer);
-        ExFreePool(DriveLayout);
+        return FALSE;
     }
-}
 
-NTSTATUS
-INIT_FUNCTION
-NTAPI
-IopAssignArcNamesToDisk(IN PDEVICE_OBJECT DeviceObject,
-                        IN ULONG RDisk,
-                        IN ULONG DiskNumber,
-                        IN ULONG PartitionCount,
-                        IN PBOOLEAN FoundHdBoot)
-{
-    CHAR Buffer[256];
-    CHAR ArcBuffer[256];
-    ANSI_STRING TempString, ArcNameString, BootString;
-    ANSI_STRING ArcBootString, ArcSystemString;
-    UNICODE_STRING DeviceName, ArcName, BootPath;
-    ULONG i;
-    NTSTATUS Status;
-
-    /* HACK: Build the ARC name that FreeLDR should've given us */
-    CHAR BootArcName[256]; // should come from FREELDR
-    sprintf(BootArcName, "multi(0)disk(0)rdisk(%lu)", RDisk);
-
-    /* Set default */
-    *FoundHdBoot = FALSE;
-
-    /* Build the boot strings */
-    RtlInitAnsiString(&ArcBootString, KeLoaderBlock->ArcBootDeviceName);
-    RtlInitAnsiString(&ArcSystemString, KeLoaderBlock->ArcHalDeviceName);
-
-    /* Build the NT Device Name */
-    sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition0", DiskNumber);
+    /* Call the driver and check if we have to wait on it */
+    Status = IoCallDriver(DeviceObject, Irp);
+    if (Status == STATUS_PENDING)
+    {
+        /* Wait on the driver */
+        KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+        Status = StatusBlock.Status;
+    }
 
-    /* Convert it to unicode */
-    RtlInitAnsiString(&TempString, Buffer);
-    Status = RtlAnsiStringToUnicodeString(&DeviceName, &TempString, TRUE);
-    if (!NT_SUCCESS(Status)) return Status;
+    /* Check if we failed */
+    if (!NT_SUCCESS(Status))
+    {
+        /* Try again */
+        ObDereferenceObject(FileObject);
+        return FALSE;
+    }
 
-    /* Build the ARC Device Name */
-    sprintf(ArcBuffer, "\\ArcName\\%s", BootArcName);
+    /* Read the partition table */
+    Status = IoReadPartitionTable(DeviceObject,
+                                  DiskGeometry.BytesPerSector,
+                                  TRUE,
+                                  &DriveLayout);
 
-    /* Convert it to Unicode */
-    RtlInitAnsiString(&ArcNameString, ArcBuffer);
-    Status = RtlAnsiStringToUnicodeString(&ArcName, &ArcNameString, TRUE);
-    if (!NT_SUCCESS(Status)) return Status;
+    /* Dereference the file object */
+    ObDereferenceObject(FileObject);
+    if (!NT_SUCCESS(Status)) return FALSE;
 
-    /* Create the symbolic link and free the strings */
-    IoAssignArcName(&ArcName, &DeviceName);
-    RtlFreeUnicodeString(&ArcName);
-    RtlFreeUnicodeString(&DeviceName);
+    /* Set the offset to 0 */
+    PartitionOffset.QuadPart = 0;
 
-    /* Loop all the partitions */
-    for (i = 0; i < PartitionCount; i++)
+    /* Allocate a buffer for the partition */
+    PartitionBuffer = ExAllocatePoolWithTag(NonPagedPool,
+                                            DiskGeometry.BytesPerSector,
+                                            TAG_IO);
+    if (!PartitionBuffer)
     {
-        /* Build the partition device name */
-        sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition%lu", DiskNumber, i+1);
-
-        /* Convert it to Unicode */
-        RtlInitAnsiString(&TempString, Buffer);
-        Status = RtlAnsiStringToUnicodeString(&DeviceName, &TempString, TRUE);
-        if (!NT_SUCCESS(Status)) continue;
-
-        /* Build the partial ARC name for this partition */
-        sprintf(ArcBuffer, "%spartition(%lu)", BootArcName, i + 1);
-        RtlInitAnsiString(&ArcNameString, ArcBuffer);
-
-        /* Check if this is the boot device */
-        if (RtlEqualString(&ArcNameString, &ArcBootString, TRUE))
-        {
-            /* Remember that we found a Hard Disk Boot Device */
-            *FoundHdBoot = TRUE;
-        }
+        /* Try again */
+        ExFreePoolWithTag(DriveLayout, TAG_FILE_SYSTEM);
+        return FALSE;
+    }
 
-        /* Check if it's the system boot partition */
-        if (RtlEqualString(&ArcNameString, &ArcSystemString, TRUE))
-        {
-            /* It is, create a Unicode string for it */
-            RtlInitAnsiString(&BootString, KeLoaderBlock->NtHalPathName);
-            Status = RtlAnsiStringToUnicodeString(&BootPath, &BootString, TRUE);
-            if (NT_SUCCESS(Status))
-            {
-                /* FIXME: Save in registry */
+    /* Build an IRP to read the partition sector */
+    KeInitializeEvent(&Event, NotificationEvent, FALSE);
+    Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
+                                       DeviceObject,
+                                       PartitionBuffer,
+                                       DiskGeometry.BytesPerSector,
+                                       &PartitionOffset,
+                                       &Event,
+                                       &StatusBlock);
+    if (!Irp)
+    {
+        /* Try again  */
+        ExFreePoolWithTag(PartitionBuffer, TAG_IO);
+        ExFreePoolWithTag(DriveLayout, TAG_FILE_SYSTEM);
+        return FALSE;
+    }
 
-                /* Free the string now */
-                RtlFreeUnicodeString(&BootPath);
-            }
-        }
+    /* Call the driver and check if we have to wait */
+    Status = IoCallDriver(DeviceObject, Irp);
+    if (Status == STATUS_PENDING)
+    {
+        /* Wait for completion */
+        KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+        Status = StatusBlock.Status;
+    }
 
-        /* Build the full ARC name */
-        sprintf(Buffer, "\\ArcName\\%spartition(%lu)", BootArcName, i + 1);
+    /* Check if we failed */
+    if (!NT_SUCCESS(Status))
+    {
+        /* Try again */
+        ExFreePoolWithTag(PartitionBuffer, TAG_IO);
+        ExFreePoolWithTag(DriveLayout, TAG_FILE_SYSTEM);
+        return FALSE;
+    }
 
-        /* Convert it to Unicode */
-        RtlInitAnsiString(&ArcNameString, Buffer);
-        Status = RtlAnsiStringToUnicodeString(&ArcName, &ArcNameString, TRUE);
-        if (!NT_SUCCESS(Status)) continue;
+    /* Calculate the MBR checksum */
+    Checksum = 0;
+    for (j = 0; j < 128; j++) Checksum += PartitionBuffer[j];
 
-        /* Create the symbolic link and free the strings */
-        IoAssignArcName(&ArcName, &DeviceName);
-        RtlFreeUnicodeString(&ArcName);
-        RtlFreeUnicodeString(&DeviceName);
-    }
+    /* Save the signature and checksum */
+    *CheckSum = ~Checksum + 1;
+    *Signature = DriveLayout->Signature;
+    *PartitionCount = DriveLayout->PartitionCount;
 
-    /* Return success */
-    return STATUS_SUCCESS;
+    /* Free the buffer */
+    ExFreePoolWithTag(PartitionBuffer, TAG_IO);
+    ExFreePoolWithTag(DriveLayout, TAG_FILE_SYSTEM);
+    return TRUE;
 }
 
 BOOLEAN
 INIT_FUNCTION
 NTAPI
-IopAssignArcNamesToCdrom(IN PULONG Buffer,
+IopAssignArcNamesToCdrom(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
+                         IN PULONG Buffer,
                          IN ULONG DiskNumber)
 {
-    CHAR ArcBuffer[256];
-    ANSI_STRING TempString, ArcNameString;
+    CHAR ArcBuffer[128];
+    ANSI_STRING TempString;
     UNICODE_STRING DeviceName, ArcName;
     NTSTATUS Status;
     LARGE_INTEGER PartitionOffset;
@@ -480,6 +294,10 @@ IopAssignArcNamesToCdrom(IN PULONG Buffer,
     ULONG i, CheckSum = 0;
     PDEVICE_OBJECT DeviceObject;
     PFILE_OBJECT FileObject;
+    PARC_DISK_INFORMATION ArcDiskInfo = LoaderBlock->ArcDiskInformation;
+    PLIST_ENTRY NextEntry;
+    PARC_DISK_SIGNATURE ArcDiskEntry;
+    BOOLEAN IsBootCdRom = FALSE;
 
     /* Build the device name */
     sprintf(ArcBuffer, "\\Device\\CdRom%lu", DiskNumber);
@@ -536,6 +354,28 @@ IopAssignArcNamesToCdrom(IN PULONG Buffer,
     /* Now calculate the checksum */
     for (i = 0; i < 2048 / sizeof(ULONG); i++) CheckSum += Buffer[i];
 
+    if (KeRosLoaderBlock) goto freeldrhack;
+
+    /* Search if this device is the actual boot CD */
+    for (NextEntry = ArcDiskInfo->DiskSignatureListHead.Flink;
+         NextEntry != &ArcDiskInfo->DiskSignatureListHead;
+         NextEntry = NextEntry->Flink)
+    {
+        /* Get the current ARC disk signature entry */
+        ArcDiskEntry = CONTAINING_RECORD(NextEntry,
+                                         ARC_DISK_SIGNATURE,
+                                         ListEntry);
+        /* And check if checksums and arc names match */
+        if (CheckSum == ArcDiskEntry->CheckSum &&
+            strcmp(KeLoaderBlock->ArcBootDeviceName, ArcDiskEntry->ArcName) == 0)
+        {
+            IsBootCdRom = TRUE;
+            break;
+        }
+    }
+    goto checkbootcd;
+
+freeldrhack:
     /*
      * FIXME: In normal conditions, NTLDR/FreeLdr sends the *proper* CDROM
      * ARC Path name, and what happens here is a comparision of both checksums
@@ -551,14 +391,17 @@ IopAssignArcNamesToCdrom(IN PULONG Buffer,
      * The signature code stays however, because eventually FreeLDR will work
      * like NTLDR, and, conversly, we do want to be able to be booted by NTLDR.
      */
-    if (IopApplyRosCdromArcHack(DiskNumber))
+    IsBootCdRom = IopApplyRosCdromArcHack(DiskNumber);
+
+checkbootcd:
+    if (IsBootCdRom)
     {
         /* This is the boot CD-ROM, build the ARC name */
         sprintf(ArcBuffer, "\\ArcName\\%s", KeLoaderBlock->ArcBootDeviceName);
 
         /* Convert it to Unicode */
-        RtlInitAnsiString(&ArcNameString, ArcBuffer);
-        Status = RtlAnsiStringToUnicodeString(&ArcName, &ArcNameString, TRUE);
+        RtlInitAnsiString(&TempString, ArcBuffer);
+        Status = RtlAnsiStringToUnicodeString(&ArcName, &TempString, TRUE);
         if (!NT_SUCCESS(Status)) return FALSE;
 
         /* Create the symbolic link and free the strings */
@@ -574,80 +417,208 @@ IopAssignArcNamesToCdrom(IN PULONG Buffer,
     return FALSE;
 }
 
-NTSTATUS INIT_FUNCTION
-IoCreateArcNames(VOID)
+NTSTATUS
+INIT_FUNCTION
+NTAPI
+IopCreateArcNames(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
 {
-    PCONFIGURATION_INFORMATION ConfigInfo;
-    ULONG i, RDiskNumber;
+    PCONFIGURATION_INFORMATION ConfigInfo = IoGetConfigurationInformation();
+    PARC_DISK_INFORMATION ArcDiskInfo = LoaderBlock->ArcDiskInformation;
+    CHAR Buffer[128];
+    ANSI_STRING ArcBootString, ArcSystemString, ArcString;
+    UNICODE_STRING ArcName, BootPath, DeviceName;
+    BOOLEAN SingleDisk;
+    ULONG i, j, Length;
+    PDEVICE_OBJECT DeviceObject;
+    ULONG Signature, Checksum, PartitionCount;
+    PLIST_ENTRY NextEntry;
+    PARC_DISK_SIGNATURE ArcDiskEntry;
     NTSTATUS Status;
-    LIST_ENTRY BiosDiskListHead;
-    LIST_ENTRY DiskListHead;
-    PLIST_ENTRY Entry;
-    PDISKENTRY BiosDiskEntry;
-    PDISKENTRY DiskEntry;
-    BOOLEAN FoundBoot;
-    PULONG Buffer;
-
-    ConfigInfo = IoGetConfigurationInformation();
-
-    /* create ARC names for hard disk drives */
-    InitializeListHead(&BiosDiskListHead);
-    InitializeListHead(&DiskListHead);
-    IopEnumerateBiosDisks(&BiosDiskListHead);
-    IopEnumerateDisks(&DiskListHead);
-
-    RDiskNumber = 0;
-    while (!IsListEmpty(&BiosDiskListHead))
+    BOOLEAN FoundBoot = FALSE;
+    PULONG PartitionBuffer;
+
+    /* Check if we only have one disk on the machine */
+    SingleDisk = ArcDiskInfo->DiskSignatureListHead.Flink->Flink ==
+                 (&ArcDiskInfo->DiskSignatureListHead);
+
+    /* Create the global HAL partition name */
+    sprintf(Buffer, "\\ArcName\\%s", LoaderBlock->ArcHalDeviceName);
+    RtlInitAnsiString(&ArcString, Buffer);
+    RtlAnsiStringToUnicodeString(&IoArcHalDeviceName, &ArcString, TRUE);
+
+    /* Create the global system partition name */
+    sprintf(Buffer, "\\ArcName\\%s", LoaderBlock->ArcBootDeviceName);
+    RtlInitAnsiString(&ArcString, Buffer);
+    RtlAnsiStringToUnicodeString(&IoArcBootDeviceName, &ArcString, TRUE);
+
+    /* Allocate memory for the string */
+    Length = strlen(LoaderBlock->ArcBootDeviceName) + sizeof(ANSI_NULL);
+    IoLoaderArcBootDeviceName = ExAllocatePoolWithTag(PagedPool,
+                                                      Length,
+                                                      TAG_IO);
+    if (IoLoaderArcBootDeviceName)
+    {
+        /* Copy the name */
+        RtlCopyMemory(IoLoaderArcBootDeviceName,
+                      LoaderBlock->ArcBootDeviceName,
+                      Length);
+    }
+
+    /* Check if we only found a disk, but we're booting from CD-ROM */
+    if ((SingleDisk) && strstr(LoaderBlock->ArcBootDeviceName, "cdrom"))
     {
-        Entry = RemoveHeadList(&BiosDiskListHead);
-        BiosDiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
-        Entry = DiskListHead.Flink;
-        while (Entry != &DiskListHead)
+        /* Then disable single-disk mode, since there's a CD drive out there */
+        SingleDisk = FALSE;
+    }
+
+    /* Build the boot strings */
+    RtlInitAnsiString(&ArcBootString, LoaderBlock->ArcBootDeviceName);
+    RtlInitAnsiString(&ArcSystemString, LoaderBlock->ArcHalDeviceName);
+
+    /* Loop every detected disk */
+    for (i = 0; i < ConfigInfo->DiskCount; i++)
+    {
+        /* Get information about the disk */
+        if (!IopGetDiskInformation(i,
+                                   &Checksum,
+                                   &Signature,
+                                   &PartitionCount,
+                                   &DeviceObject))
+        {
+            /* Skip this disk */
+            continue;
+        }
+
+        /* Loop ARC disks */
+        for (NextEntry = ArcDiskInfo->DiskSignatureListHead.Flink;
+             NextEntry != &ArcDiskInfo->DiskSignatureListHead;
+             NextEntry = NextEntry->Flink)
         {
-            DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
-            if (DiskEntry->Checksum == BiosDiskEntry->Checksum &&
-                DiskEntry->Signature == BiosDiskEntry->Signature)
+            /* Get the current ARC disk signature entry */
+            ArcDiskEntry = CONTAINING_RECORD(NextEntry,
+                                             ARC_DISK_SIGNATURE,
+                                             ListEntry);
+
+            /*
+             * Now check if the signature and checksum match, unless this is
+             * the only disk that was in the ARC list, and also in the device
+             * tree, in which case the check is bypassed and we accept the disk
+             */
+            if (((SingleDisk) && (ConfigInfo->DiskCount == 1)) ||
+                ((Checksum == ArcDiskEntry->CheckSum) &&
+                 (Signature == ArcDiskEntry->Signature)))
             {
+                /* Build the NT Device Name */
+                sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition0", i);
+
+                /* Convert it to Unicode */
+                RtlInitAnsiString(&ArcString, Buffer);
+                Status = RtlAnsiStringToUnicodeString(&DeviceName,
+                                                      &ArcString,
+                                                      TRUE);
+                if (!NT_SUCCESS(Status)) continue;
+
+                /* Build the ARC Device Name */
+                sprintf(Buffer, "\\ArcName\\%s", ArcDiskEntry->ArcName);
+
+                /* Convert it to Unicode */
+                RtlInitAnsiString(&ArcString, Buffer);
+                Status = RtlAnsiStringToUnicodeString(&ArcName,
+                                                      &ArcString,
+                                                      TRUE);
+                if (!NT_SUCCESS(Status)) continue;
+
+                /* Create the symbolic link and free the strings */
+                IoAssignArcName(&ArcName, &DeviceName);
+                RtlFreeUnicodeString(&ArcName);
+                RtlFreeUnicodeString(&DeviceName);
+
+                /* Loop all the partitions */
+                for (j = 0; j < PartitionCount; j++)
+                {
+                    /* Build the partition device name */
+                    sprintf(Buffer,
+                            "\\Device\\Harddisk%lu\\Partition%lu",
+                            i,
+                            j + 1);
+
+                    /* Convert it to Unicode */
+                    RtlInitAnsiString(&ArcString, Buffer);
+                    Status = RtlAnsiStringToUnicodeString(&DeviceName,
+                                                          &ArcString,
+                                                          TRUE);
+                    if (!NT_SUCCESS(Status)) continue;
+
+                    /* Build the partial ARC name for this partition */
+                    sprintf(Buffer,
+                            "%spartition(%lu)",
+                            ArcDiskEntry->ArcName,
+                            j + 1);
+                    RtlInitAnsiString(&ArcString, Buffer);
+
+                    /* Check if this is the boot device */
+                    if (RtlEqualString(&ArcString, &ArcBootString, TRUE))
+                    {
+                        /* Remember that we found a Hard Disk Boot Device */
+                        FoundBoot = TRUE;
+                    }
 
-                Status = IopAssignArcNamesToDisk(DiskEntry->DeviceObject,
-                                                 RDiskNumber,
-                                                 DiskEntry->DiskNumber,
-                                                 DiskEntry->PartitionCount,
-                                                 &FoundBoot);
+                    /* Check if it's the system boot partition */
+                    if (RtlEqualString(&ArcString, &ArcSystemString, TRUE))
+                    {
+                        /* It is, create a Unicode string for it */
+                        RtlInitAnsiString(&ArcString,
+                                          LoaderBlock->NtHalPathName);
+                        Status = RtlAnsiStringToUnicodeString(&BootPath,
+                                                              &ArcString,
+                                                              TRUE);
+                        if (NT_SUCCESS(Status))
+                        {
+                            /* FIXME: Save in registry */
 
-                RemoveEntryList(&DiskEntry->ListEntry);
-                ExFreePool(DiskEntry);
-                break;
+                            /* Free the string now */
+                            RtlFreeUnicodeString(&BootPath);
+                        }
+                    }
+
+                    /* Build the full ARC name */
+                    sprintf(Buffer,
+                            "\\ArcName\\%spartition(%lu)",
+                            ArcDiskEntry->ArcName,
+                            j + 1);
+
+                    /* Convert it to Unicode */
+                    RtlInitAnsiString(&ArcString, Buffer);
+                    Status = RtlAnsiStringToUnicodeString(&ArcName,
+                                                          &ArcString,
+                                                          TRUE);
+                    if (!NT_SUCCESS(Status)) continue;
+
+                    /* Create the symbolic link and free the strings */
+                    IoAssignArcName(&ArcName, &DeviceName);
+                    RtlFreeUnicodeString(&ArcName);
+                    RtlFreeUnicodeString(&DeviceName);
+                }
             }
-            Entry = Entry->Flink;
         }
-        RDiskNumber++;
-        ExFreePool(BiosDiskEntry);
-    }
-
-    while (!IsListEmpty(&DiskListHead))
-    {
-        Entry = RemoveHeadList(&DiskListHead);
-        DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
-        ExFreePool(DiskEntry);
     }
 
     /* Check if we didn't find the boot disk */
     if (!FoundBoot)
     {
         /* Allocate a buffer for the CD-ROM MBR */
-        Buffer = ExAllocatePoolWithTag(NonPagedPool, 2048, TAG_IO);
-        if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES;
+        PartitionBuffer = ExAllocatePoolWithTag(NonPagedPool, 2048, TAG_IO);
+        if (!PartitionBuffer) return STATUS_INSUFFICIENT_RESOURCES;
 
         /* Loop every CD-ROM */
         for (i = 0; i < ConfigInfo->CdRomCount; i++)
         {
             /* Give it an ARC name */
-            if (IopAssignArcNamesToCdrom(Buffer, i)) break;
+            if (IopAssignArcNamesToCdrom(LoaderBlock, PartitionBuffer, i)) break;
         }
 
         /* Free the buffer */
-        ExFreePool(Buffer);
+        ExFreePoolWithTag(PartitionBuffer, TAG_IO);
     }
 
     /* Return success */