Removed outdated email addresses.
[reactos.git] / reactos / ntoskrnl / io / iomgr / arcname.c
index 409e113..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>
-
-static NTSTATUS 
-STDCALL INIT_FUNCTION 
-DiskQueryRoutine(PWSTR ValueName, 
-                 ULONG ValueType, 
-                 PVOID ValueData, 
-                 ULONG ValueLength,
-                 PVOID Context,
-                 PVOID EntryContext);
-
-static VOID INIT_FUNCTION
-IopEnumerateBiosDisks(PLIST_ENTRY ListHead);
-
-static VOID INIT_FUNCTION
-IopEnumerateDisks(PLIST_ENTRY ListHead);
-
-static NTSTATUS INIT_FUNCTION
-IopAssignArcNamesToDisk(PDEVICE_OBJECT DeviceObject, ULONG RDisk, ULONG DiskNumber);
-
-static NTSTATUS INIT_FUNCTION
-IopCheckCdromDevices(PULONG DeviceNumber);
-
-#if defined (ALLOC_PRAGMA)
-#pragma alloc_text(INIT, DiskQueryRoutine)
-#pragma alloc_text(INIT, IopEnumerateBiosDisks)
-#pragma alloc_text(INIT, IopEnumerateDisks)
-#pragma alloc_text(INIT, IopAssignArcNamesToDisk)
-#pragma alloc_text(INIT, IoCreateArcNames)
-#pragma alloc_text(INIT, IopCheckCdromDevices)
-#pragma alloc_text(INIT, IoCreateSystemRootLink)
-#endif
-
+#include <debug.h>
 
-/* MACROS *******************************************************************/
+/* GLOBALS *******************************************************************/
 
-#define FS_VOLUME_BUFFER_SIZE (MAX_PATH + sizeof(FILE_FS_VOLUME_INFORMATION))
+UNICODE_STRING IoArcHalDeviceName, IoArcBootDeviceName;
+PCHAR IoLoaderArcBootDeviceName;
+extern PROS_LOADER_PARAMETER_BLOCK KeRosLoaderBlock;
 
-/* FUNCTIONS ****************************************************************/
+/* FUNCTIONS *****************************************************************/
 
-STATIC 
-NTSTATUS
-STDCALL
+BOOLEAN
 INIT_FUNCTION
-DiskQueryRoutine(PWSTR ValueName,
-                 ULONG ValueType,
-                 PVOID ValueData,
-                 ULONG ValueLength,
-                 PVOID Context,
-                 PVOID EntryContext)
+NTAPI
+IopApplyRosCdromArcHack(IN ULONG i)
 {
-  PLIST_ENTRY ListHead = (PLIST_ENTRY)Context;
-  PULONG GlobalDiskCount = (PULONG)EntryContext;
-  PDISKENTRY DiskEntry;
-  UNICODE_STRING NameU;
-
-  if (ValueType == REG_SZ &&
-      ValueLength == 20 * sizeof(WCHAR))
+    ULONG DeviceNumber = -1;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    ANSI_STRING InstallName;
+    UNICODE_STRING DeviceName;
+    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)
     {
-      DiskEntry = ExAllocatePool(PagedPool, sizeof(DISKENTRY));
-      if (DiskEntry == NULL)
+        /* 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 */
+        InitializeObjectAttributes(&ObjectAttributes,
+                                   &DeviceName,
+                                   0,
+                                   NULL,
+                                   NULL);
+        Status = ZwQueryAttributesFile(&ObjectAttributes, &FileInfo);
+
+        /* Free the string */
+        RtlFreeUnicodeString(&DeviceName);
+
+        /* Check if we found the file */
+        if (NT_SUCCESS(Status))
         {
-          return STATUS_NO_MEMORY;
+            /* We did, save the device number */
+            DeviceNumber = i;
         }
-      DiskEntry->DiskNumber = (*GlobalDiskCount)++;
-
-      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);
-    }
-
-  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))
+        else
         {
-            break;
+            /* 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);
         }
-        
-      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++;
-    }
-}
-
-STATIC VOID INIT_FUNCTION
-IopEnumerateDisks(PLIST_ENTRY ListHead)
-{
-  ULONG i, k;
-  PDISKENTRY DiskEntry;
-  DISK_GEOMETRY DiskGeometry;
-  KEVENT Event;
-  PIRP Irp;
-  IO_STATUS_BLOCK StatusBlock;
-  LARGE_INTEGER PartitionOffset;
-  PULONG Buffer;
-  WCHAR DeviceNameBuffer[80];
-  UNICODE_STRING DeviceName;
-  NTSTATUS Status;
-  PDEVICE_OBJECT DeviceObject;
-  PFILE_OBJECT FileObject;
-  BOOLEAN IsRemovableMedia;
-  PPARTITION_SECTOR PartitionBuffer = NULL;
-  ULONG PartitionBufferSize = 0;
-
-
-  for (i = 0; i < IoGetConfigurationInformation()->DiskCount; i++)
-    {
-
-      swprintf(DeviceNameBuffer,
-              L"\\Device\\Harddisk%lu\\Partition0",
-              i);
-      RtlInitUnicodeString(&DeviceName,
-                          DeviceNameBuffer);
-
 
-      Status = IoGetDeviceObjectPointer(&DeviceName,
-                                       FILE_READ_DATA,
-                                       &FileObject,
-                                       &DeviceObject);
-      if (!NT_SUCCESS(Status))
+        if (!InitIsWinPEMode)
         {
-         continue;
-       }
-      IsRemovableMedia = DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA ? TRUE : FALSE;
-      ObDereferenceObject(FileObject);
-      if (IsRemovableMedia)
-        {
-          ObDereferenceObject(DeviceObject);
-          continue;
-       }
-      DiskEntry = ExAllocatePool(PagedPool, sizeof(DISKENTRY));
-      if (DiskEntry == NULL)
-        {
-          KEBUGCHECK(0);
-        }
-      DiskEntry->DiskNumber = i;
-      DiskEntry->DeviceObject = DeviceObject;
-
-      /* 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 == NULL)
-        {
-          KEBUGCHECK(0);
-        }
+            /* Build the name */
+            sprintf(p, "cdrom(%lu)", DeviceNumber);
 
-      Status = IoCallDriver(DeviceObject, Irp);
-      if (Status == STATUS_PENDING)
-        {
-          KeWaitForSingleObject(&Event,
-                               Executive,
-                               KernelMode,
-                               FALSE,
-                               NULL);
-          Status = StatusBlock.Status;
-        }
-      if (!NT_SUCCESS(Status))
-        {
-          KEBUGCHECK(0);
-        }
-      if (PartitionBuffer != NULL && PartitionBufferSize < DiskGeometry.BytesPerSector)
-        {
-          ExFreePool(PartitionBuffer);
-          PartitionBuffer = NULL;
-        }
-      if (PartitionBuffer == NULL)
-        {
-          PartitionBufferSize = max(DiskGeometry.BytesPerSector, PAGE_SIZE);
-          PartitionBuffer = ExAllocatePool(PagedPool, PartitionBufferSize);
-          if (PartitionBuffer == NULL)
+            /* Adjust original command line */
+            q = strchr(p, ')');
+            if (q)
             {
-              KEBUGCHECK(0);
+                q++;
+                strcpy(Buffer, q);
+                sprintf(p, "cdrom(%lu)", DeviceNumber);
+                strcat(p, Buffer);
             }
         }
+    }
 
-      /* read the partition sector */
-      KeInitializeEvent(&Event, NotificationEvent, FALSE);
-      PartitionOffset.QuadPart = 0;
-      Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
-                                        DeviceObject,
-                                        PartitionBuffer,
-                                        DiskGeometry.BytesPerSector,
-                                        &PartitionOffset,
-                                        &Event,
-                                        &StatusBlock);
-      Status = IoCallDriver(DeviceObject, Irp);
-      if (Status == STATUS_PENDING)
-        {
-          KeWaitForSingleObject(&Event,
-                               Executive,
-                               KernelMode,
-                               FALSE,
-                               NULL);
-          Status = StatusBlock.Status;
-        }
-
-      if (!NT_SUCCESS(Status))
-        {
-          KEBUGCHECK(0);
-        }
-
-      /* Calculate the MBR checksum */
-      DiskEntry->Checksum = 0;
-      Buffer = (PULONG)PartitionBuffer;
-      for (k = 0; k < 128; k++)
-        {
-          DiskEntry->Checksum += Buffer[k];
-        }
-      DiskEntry->Checksum = ~DiskEntry->Checksum + 1;
-      DiskEntry->Signature = PartitionBuffer->Signature;
+    /* OK, how many disks are there? */
+    DeviceNumber += ConfigInfo->DiskCount;
 
-      InsertTailList(ListHead, &DiskEntry->ListEntry);
-    }
-  if (PartitionBuffer)
+    /* Return whether this is the CD or not */
+    if ((InitIsWinPEMode) || (ExpInTextModeSetup))
     {
-      ExFreePool(PartitionBuffer);
+        return TRUE;
     }
+
+    /* Failed */
+    return FALSE;
 }
 
-STATIC NTSTATUS INIT_FUNCTION
-IopAssignArcNamesToDisk(PDEVICE_OBJECT DeviceObject, ULONG RDisk, ULONG DiskNumber)
+BOOLEAN
+INIT_FUNCTION
+NTAPI
+IopGetDiskInformation(IN ULONG i,
+                      OUT PULONG CheckSum,
+                      OUT PULONG Signature,
+                      OUT PULONG PartitionCount,
+                      OUT PDEVICE_OBJECT *DiskDeviceObject)
 {
-  WCHAR DeviceNameBuffer[80];
-  WCHAR ArcNameBuffer[80];
-  UNICODE_STRING DeviceName;
-  UNICODE_STRING ArcName;
-  PDRIVE_LAYOUT_INFORMATION LayoutInfo = NULL;
-  NTSTATUS Status;
-  ULONG i;
-  KEVENT Event;
-  PIRP Irp;
-  IO_STATUS_BLOCK StatusBlock;
-  ULONG PartitionNumber;
-
-  swprintf(DeviceNameBuffer,
-          L"\\Device\\Harddisk%lu\\Partition0",
-          DiskNumber);
-  RtlInitUnicodeString(&DeviceName,
-                      DeviceNameBuffer);
-
-  swprintf(ArcNameBuffer,
-          L"\\ArcName\\multi(0)disk(0)rdisk(%lu)",
-          RDisk);
-  RtlInitUnicodeString(&ArcName,
-                      ArcNameBuffer);
-
-  DPRINT("%wZ ==> %wZ\n", &ArcName, &DeviceName);
-
-  Status = IoAssignArcName(&ArcName, &DeviceName);
-  if (!NT_SUCCESS(Status))
+    ULONG j, Checksum;
+    ANSI_STRING TempString;
+    CHAR Buffer[128];
+    UNICODE_STRING DeviceName;
+    NTSTATUS Status;
+    PDEVICE_OBJECT DeviceObject;
+    PFILE_OBJECT FileObject;
+    DISK_GEOMETRY DiskGeometry;
+    PDRIVE_LAYOUT_INFORMATION DriveLayout;
+    KEVENT Event;
+    PIRP Irp;
+    IO_STATUS_BLOCK StatusBlock;
+    LARGE_INTEGER PartitionOffset;
+    PULONG PartitionBuffer;
+
+    /* 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)) return FALSE;
+
+    /* Get the device pointer */
+    Status = IoGetDeviceObjectPointer(&DeviceName,
+                                      FILE_READ_ATTRIBUTES,
+                                      &FileObject,
+                                      &DeviceObject);
+    *DiskDeviceObject = DeviceObject;
+
+    /* Free the string */
+    RtlFreeUnicodeString(&DeviceName);
+
+    /* Move on if we failed */
+    if (!NT_SUCCESS(Status)) return FALSE;
+
+    /* 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)
     {
-      DPRINT1("IoAssignArcName failed, status=%lx\n", Status);
-      return(Status);
+        /* Try again */
+        ObDereferenceObject(FileObject);
+        return FALSE;
     }
 
-  LayoutInfo = ExAllocatePool(PagedPool, 2 * PAGE_SIZE);
-  if (LayoutInfo == NULL)
+    /* Call the driver and check if we have to wait on it */
+    Status = IoCallDriver(DeviceObject, Irp);
+    if (Status == STATUS_PENDING)
     {
-      return STATUS_NO_MEMORY;
+        /* Wait on the driver */
+        KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+        Status = StatusBlock.Status;
     }
-  KeInitializeEvent(&Event, NotificationEvent, FALSE);
-  Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_LAYOUT,
-                                     DeviceObject,
-                                     NULL,
-                                     0,
-                                     LayoutInfo,
-                                     2 * PAGE_SIZE,
-                                     FALSE,
-                                     &Event,
-                                     &StatusBlock);
-  if (Irp == NULL)
+
+    /* Check if we failed */
+    if (!NT_SUCCESS(Status))
     {
-      ExFreePool(LayoutInfo);
-      return STATUS_INSUFFICIENT_RESOURCES;
+        /* Try again */
+        ObDereferenceObject(FileObject);
+        return FALSE;
     }
 
-  Status = IoCallDriver(DeviceObject, Irp);
-  if (Status == STATUS_PENDING)
+    /* Read the partition table */
+    Status = IoReadPartitionTable(DeviceObject,
+                                  DiskGeometry.BytesPerSector,
+                                  TRUE,
+                                  &DriveLayout);
+
+    /* Dereference the file object */
+    ObDereferenceObject(FileObject);
+    if (!NT_SUCCESS(Status)) return FALSE;
+
+    /* Set the offset to 0 */
+    PartitionOffset.QuadPart = 0;
+
+    /* Allocate a buffer for the partition */
+    PartitionBuffer = ExAllocatePoolWithTag(NonPagedPool,
+                                            DiskGeometry.BytesPerSector,
+                                            TAG_IO);
+    if (!PartitionBuffer)
     {
-      KeWaitForSingleObject(&Event,
-                           Executive,
-                           KernelMode,
-                           FALSE,
-                           NULL);
-      Status = StatusBlock.Status;
+        /* Try again */
+        ExFreePoolWithTag(DriveLayout, TAG_FILE_SYSTEM);
+        return FALSE;
     }
-  if (!NT_SUCCESS(Status))
+
+    /* 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)
     {
-      ExFreePool(LayoutInfo);
-      return Status;
+        /* Try again  */
+        ExFreePoolWithTag(PartitionBuffer, TAG_IO);
+        ExFreePoolWithTag(DriveLayout, TAG_FILE_SYSTEM);
+        return FALSE;
     }
 
-  DPRINT("Number of partitions: %u\n", LayoutInfo->PartitionCount);
-  
-  PartitionNumber = 1;
-  for (i = 0; i < LayoutInfo->PartitionCount; i++)
+    /* Call the driver and check if we have to wait */
+    Status = IoCallDriver(DeviceObject, Irp);
+    if (Status == STATUS_PENDING)
     {
-      if (!IsContainerPartition(LayoutInfo->PartitionEntry[i].PartitionType) &&
-          LayoutInfo->PartitionEntry[i].PartitionType != PARTITION_ENTRY_UNUSED)
-        {
-          
-          swprintf(DeviceNameBuffer,
-                  L"\\Device\\Harddisk%lu\\Partition%lu",
-                  DiskNumber,
-                  PartitionNumber);
-          RtlInitUnicodeString(&DeviceName, DeviceNameBuffer);
-
-          swprintf(ArcNameBuffer,
-                  L"\\ArcName\\multi(0)disk(0)rdisk(%lu)partition(%lu)",
-                  RDisk,
-                  PartitionNumber);
-          RtlInitUnicodeString(&ArcName, ArcNameBuffer);
-
-          DPRINT("%wZ ==> %wZ\n", &ArcName, &DeviceName);
-
-          Status = IoAssignArcName(&ArcName, &DeviceName);
-          if (!NT_SUCCESS(Status))
-            {
-              DPRINT1("IoAssignArcName failed, status=%lx\n", Status);
-              ExFreePool(LayoutInfo);
-             return(Status);
-            }
-          PartitionNumber++;
-        }
+        /* Wait for completion */
+        KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+        Status = StatusBlock.Status;
     }
-  ExFreePool(LayoutInfo);
-  return STATUS_SUCCESS;
-}
 
-NTSTATUS INIT_FUNCTION
-IoCreateArcNames(VOID)
-{
-  PCONFIGURATION_INFORMATION ConfigInfo;
-  WCHAR DeviceNameBuffer[80];
-  WCHAR ArcNameBuffer[80];
-  UNICODE_STRING DeviceName;
-  UNICODE_STRING ArcName;
-  ULONG i, RDiskNumber;
-  NTSTATUS Status;
-  LIST_ENTRY BiosDiskListHead;
-  LIST_ENTRY DiskListHead;
-  PLIST_ENTRY Entry;
-  PDISKENTRY BiosDiskEntry;
-  PDISKENTRY DiskEntry;
-
-  DPRINT("IoCreateArcNames() called\n");
-
-  ConfigInfo = IoGetConfigurationInformation();
-
-  /* create ARC names for floppy drives */
-  DPRINT("Floppy drives: %lu\n", ConfigInfo->FloppyCount);
-  for (i = 0; i < ConfigInfo->FloppyCount; i++)
+    /* Check if we failed */
+    if (!NT_SUCCESS(Status))
     {
-      swprintf(DeviceNameBuffer,
-              L"\\Device\\Floppy%lu",
-              i);
-      RtlInitUnicodeString(&DeviceName,
-                          DeviceNameBuffer);
-
-      swprintf(ArcNameBuffer,
-              L"\\ArcName\\multi(0)disk(0)fdisk(%lu)",
-              i);
-      RtlInitUnicodeString(&ArcName,
-                          ArcNameBuffer);
-      DPRINT("%wZ ==> %wZ\n",
-            &ArcName,
-            &DeviceName);
-
-      Status = IoAssignArcName(&ArcName,
-                              &DeviceName);
-      if (!NT_SUCCESS(Status))
-       return(Status);
+        /* Try again */
+        ExFreePoolWithTag(PartitionBuffer, TAG_IO);
+        ExFreePoolWithTag(DriveLayout, TAG_FILE_SYSTEM);
+        return FALSE;
     }
 
-  /* create ARC names for hard disk drives */
-  InitializeListHead(&BiosDiskListHead);
-  InitializeListHead(&DiskListHead);
-  IopEnumerateBiosDisks(&BiosDiskListHead);
-  IopEnumerateDisks(&DiskListHead);
+    /* Calculate the MBR checksum */
+    Checksum = 0;
+    for (j = 0; j < 128; j++) Checksum += PartitionBuffer[j];
 
-  RDiskNumber = 0;
-  while (!IsListEmpty(&BiosDiskListHead))
-    {
-      Entry = RemoveHeadList(&BiosDiskListHead);
-      BiosDiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
-      Entry = DiskListHead.Flink;
-      while (Entry != &DiskListHead)
-        {
-          DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
-          if (DiskEntry->Checksum == BiosDiskEntry->Checksum &&
-              DiskEntry->Signature == BiosDiskEntry->Signature)
-            {
+    /* Save the signature and checksum */
+    *CheckSum = ~Checksum + 1;
+    *Signature = DriveLayout->Signature;
+    *PartitionCount = DriveLayout->PartitionCount;
 
-              Status = IopAssignArcNamesToDisk(DiskEntry->DeviceObject, RDiskNumber, DiskEntry->DiskNumber);
+    /* Free the buffer */
+    ExFreePoolWithTag(PartitionBuffer, TAG_IO);
+    ExFreePoolWithTag(DriveLayout, TAG_FILE_SYSTEM);
+    return TRUE;
+}
 
-              RemoveEntryList(&DiskEntry->ListEntry);
-              ExFreePool(DiskEntry);
-              break;
-            }
-          Entry = Entry->Flink;
-        }
-      RDiskNumber++;
-      ExFreePool(BiosDiskEntry);
+BOOLEAN
+INIT_FUNCTION
+NTAPI
+IopAssignArcNamesToCdrom(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
+                         IN PULONG Buffer,
+                         IN ULONG DiskNumber)
+{
+    CHAR ArcBuffer[128];
+    ANSI_STRING TempString;
+    UNICODE_STRING DeviceName, ArcName;
+    NTSTATUS Status;
+    LARGE_INTEGER PartitionOffset;
+    KEVENT Event;
+    IO_STATUS_BLOCK IoStatusBlock;
+    PIRP Irp;
+    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);
+
+    /* Convert it to Unicode */
+    RtlInitAnsiString(&TempString, ArcBuffer);
+    Status = RtlAnsiStringToUnicodeString(&DeviceName, &TempString, TRUE);
+    if (!NT_SUCCESS(Status)) return FALSE;
+
+    /* Get the device for it */
+    Status = IoGetDeviceObjectPointer(&DeviceName,
+                                      FILE_READ_ATTRIBUTES,
+                                      &FileObject,
+                                      &DeviceObject);
+    if (!NT_SUCCESS(Status))
+    {
+        /* Free the string and fail */
+        RtlFreeUnicodeString(&DeviceName);
+        return FALSE;
     }
 
-  while (!IsListEmpty(&DiskListHead))
+    /* Setup the event */
+    KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+    /* Set the offset and build the read IRP */
+    PartitionOffset.QuadPart = 0x8000;
+    Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
+                                       DeviceObject,
+                                       Buffer,
+                                       2048,
+                                       &PartitionOffset,
+                                       &Event,
+                                       &IoStatusBlock);
+    if (!Irp)
     {
-      Entry = RemoveHeadList(&DiskListHead);
-      DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
-      ExFreePool(DiskEntry);
+        /* Free the string and fail */
+        RtlFreeUnicodeString(&DeviceName);
+        return FALSE;
     }
 
-  /* create ARC names for cdrom drives */
-  DPRINT("CD-ROM drives: %lu\n", ConfigInfo->CdRomCount);
-  for (i = 0; i < ConfigInfo->CdRomCount; i++)
+    /* Call the driver and check if we have to wait on it */
+    Status = IoCallDriver(DeviceObject, Irp);
+    if (Status == STATUS_PENDING)
     {
-      swprintf(DeviceNameBuffer,
-              L"\\Device\\CdRom%lu",
-              i);
-      RtlInitUnicodeString(&DeviceName,
-                          DeviceNameBuffer);
-
-      swprintf(ArcNameBuffer,
-              L"\\ArcName\\multi(0)disk(0)cdrom(%lu)",
-              i);
-      RtlInitUnicodeString(&ArcName,
-                          ArcNameBuffer);
-      DPRINT("%wZ ==> %wZ\n",
-            &ArcName,
-            &DeviceName);
-
-      Status = IoAssignArcName(&ArcName,
-                              &DeviceName);
-      if (!NT_SUCCESS(Status))
-       return(Status);
+        /* Wait for completion */
+        KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+        Status = IoStatusBlock.Status;
     }
 
-  DPRINT("IoCreateArcNames() done\n");
+    /* Dereference the file object */
+    ObDereferenceObject(FileObject);
+    if (!NT_SUCCESS(Status)) return FALSE;
 
-  return(STATUS_SUCCESS);
-}
+    /* Now calculate the checksum */
+    for (i = 0; i < 2048 / sizeof(ULONG); i++) CheckSum += Buffer[i];
 
+    if (KeRosLoaderBlock) goto freeldrhack;
 
-static NTSTATUS INIT_FUNCTION
-IopCheckCdromDevices(PULONG DeviceNumber)
-{
-  PCONFIGURATION_INFORMATION ConfigInfo;
-  OBJECT_ATTRIBUTES ObjectAttributes;
-  UNICODE_STRING DeviceName;
-  WCHAR DeviceNameBuffer[MAX_PATH];
-  HANDLE Handle;
-  ULONG i;
-  NTSTATUS Status;
-  IO_STATUS_BLOCK IoStatusBlock;
-#if 0
-  PFILE_FS_VOLUME_INFORMATION FileFsVolume;
-  USHORT Buffer[FS_VOLUME_BUFFER_SIZE];
-
-  FileFsVolume = (PFILE_FS_VOLUME_INFORMATION)Buffer;
-#endif
-
-  ConfigInfo = IoGetConfigurationInformation();
-  for (i = 0; i < ConfigInfo->CdRomCount; i++)
+    /* Search if this device is the actual boot CD */
+    for (NextEntry = ArcDiskInfo->DiskSignatureListHead.Flink;
+         NextEntry != &ArcDiskInfo->DiskSignatureListHead;
+         NextEntry = NextEntry->Flink)
     {
-#if 0
-      swprintf(DeviceNameBuffer,
-              L"\\Device\\CdRom%lu\\",
-              i);
-      RtlInitUnicodeString(&DeviceName,
-                          DeviceNameBuffer);
-
-      InitializeObjectAttributes(&ObjectAttributes,
-                                &DeviceName,
-                                0,
-                                NULL,
-                                NULL);
-
-      Status = ZwOpenFile(&Handle,
-                         FILE_ALL_ACCESS,
-                         &ObjectAttributes,
-                         &IoStatusBlock,
-                         0,
-                         0);
-      DPRINT("ZwOpenFile()  DeviceNumber %lu  Status %lx\n", i, Status);
-      if (NT_SUCCESS(Status))
-       {
-         Status = ZwQueryVolumeInformationFile(Handle,
-                                               &IoStatusBlock,
-                                               FileFsVolume,
-                                               FS_VOLUME_BUFFER_SIZE,
-                                               FileFsVolumeInformation);
-         DPRINT("ZwQueryVolumeInformationFile()  Status %lx\n", Status);
-         if (NT_SUCCESS(Status))
-           {
-             DPRINT("VolumeLabel: '%S'\n", FileFsVolume->VolumeLabel);
-             if (_wcsicmp(FileFsVolume->VolumeLabel, L"REACTOS") == 0)
-               {
-                 ZwClose(Handle);
-                 *DeviceNumber = i;
-                 return(STATUS_SUCCESS);
-               }
-           }
-         ZwClose(Handle);
-       }
-#endif
-
-      /*
-       * Check for 'reactos/ntoskrnl.exe' first...
-       */
-
-      swprintf(DeviceNameBuffer,
-              L"\\Device\\CdRom%lu\\reactos\\ntoskrnl.exe",
-              i);
-      RtlInitUnicodeString(&DeviceName,
-                          DeviceNameBuffer);
-
-      InitializeObjectAttributes(&ObjectAttributes,
-                                &DeviceName,
-                                0,
-                                NULL,
-                                NULL);
-
-      Status = ZwOpenFile(&Handle,
-                         FILE_ALL_ACCESS,
-                         &ObjectAttributes,
-                         &IoStatusBlock,
-                         0,
-                         0);
-      DPRINT("ZwOpenFile()  DeviceNumber %lu  Status %lx\n", i, Status);
-      if (NT_SUCCESS(Status))
-       {
-         DPRINT("Found ntoskrnl.exe on Cdrom%lu\n", i);
-         ZwClose(Handle);
-         *DeviceNumber = i;
-         return(STATUS_SUCCESS);
-       }
-
-      /*
-       * ...and for 'reactos/system32/ntoskrnl.exe' also.
-       */
-
-      swprintf(DeviceNameBuffer,
-              L"\\Device\\CdRom%lu\\reactos\\system32\\ntoskrnl.exe",
-              i);
-      RtlInitUnicodeString(&DeviceName,
-                          DeviceNameBuffer);
-
-      InitializeObjectAttributes(&ObjectAttributes,
-                                &DeviceName,
-                                0,
-                                NULL,
-                                NULL);
-
-      Status = ZwOpenFile(&Handle,
-                         FILE_ALL_ACCESS,
-                         &ObjectAttributes,
-                         &IoStatusBlock,
-                         0,
-                         0);
-      DPRINT("ZwOpenFile()  DeviceNumber %lu  Status %lx\n", i, Status);
-      if (NT_SUCCESS(Status))
-       {
-         DPRINT("Found ntoskrnl.exe on Cdrom%lu\n", i);
-         ZwClose(Handle);
-         *DeviceNumber = i;
-         return(STATUS_SUCCESS);
-       }
+        /* 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
+     * in order to see if this is the actual boot CD.
+     *
+     * In ReactOS this doesn't currently happen, instead we have a hack on top
+     * of this file which scans the CD for the ntoskrnl.exe file, then modifies
+     * the LoaderBlock's ARC Path with the right CDROM path. Consequently, we
+     * get the same state as if NTLDR had properly booted us, except that we do
+     * not actually need to check the signature, since the hack already did the
+     * check for ntoskrnl.exe, which is just as good.
+     *
+     * 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.
+     */
+    IsBootCdRom = IopApplyRosCdromArcHack(DiskNumber);
+
+checkbootcd:
+    if (IsBootCdRom)
+    {
+        /* This is the boot CD-ROM, build the ARC name */
+        sprintf(ArcBuffer, "\\ArcName\\%s", KeLoaderBlock->ArcBootDeviceName);
 
-  DPRINT("Could not find ntoskrnl.exe\n");
-  *DeviceNumber = (ULONG)-1;
+        /* Convert it to Unicode */
+        RtlInitAnsiString(&TempString, ArcBuffer);
+        Status = RtlAnsiStringToUnicodeString(&ArcName, &TempString, TRUE);
+        if (!NT_SUCCESS(Status)) return FALSE;
 
-  return(STATUS_UNSUCCESSFUL);
-}
+        /* Create the symbolic link and free the strings */
+        IoAssignArcName(&ArcName, &DeviceName);
+        RtlFreeUnicodeString(&ArcName);
+        RtlFreeUnicodeString(&DeviceName);
 
+        /* Let caller know that we've found the boot CD */
+        return TRUE;
+    }
+
+    /* No boot CD found */
+    return FALSE;
+}
 
-NTSTATUS INIT_FUNCTION
-IoCreateSystemRootLink(PCHAR ParameterLine)
+NTSTATUS
+INIT_FUNCTION
+NTAPI
+IopCreateArcNames(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
 {
-  OBJECT_ATTRIBUTES ObjectAttributes;
-  IO_STATUS_BLOCK IoStatusBlock;
-  UNICODE_STRING LinkName = RTL_CONSTANT_STRING(L"\\SystemRoot");
-  UNICODE_STRING DeviceName;
-  UNICODE_STRING ArcName;
-  UNICODE_STRING BootPath;
-  PCHAR ParamBuffer;
-  PWCHAR ArcNameBuffer;
-  PCHAR p;
-  NTSTATUS Status;
-  ULONG Length;
-  HANDLE Handle;
-
-  /* Create local parameter line copy */
-  ParamBuffer = ExAllocatePool(PagedPool, 256);
-  strcpy(ParamBuffer, (char *)ParameterLine);
-
-  DPRINT("%s\n", ParamBuffer);
-  /* Format: <arc_name>\<path> [options...] */
-
-  /* cut options off */
-  p = strchr(ParamBuffer, ' ');
-  if (p)
-    *p = 0;
-  DPRINT("%s\n", ParamBuffer);
-
-  /* extract path */
-  p = strchr(ParamBuffer, '\\');
-  if (p)
-    {
-      DPRINT("Boot path: %s\n", p);
-      RtlCreateUnicodeStringFromAsciiz(&BootPath, p);
-      *p = 0;
-    }
-  else
+    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;
+    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)
     {
-      DPRINT("Boot path: %s\n", "\\");
-      RtlCreateUnicodeStringFromAsciiz(&BootPath, "\\");
+        /* Copy the name */
+        RtlCopyMemory(IoLoaderArcBootDeviceName,
+                      LoaderBlock->ArcBootDeviceName,
+                      Length);
     }
-  DPRINT("ARC name: %s\n", ParamBuffer);
 
-  p = strstr(ParamBuffer, "cdrom");
-  if (p != NULL)
+    /* Check if we only found a disk, but we're booting from CD-ROM */
+    if ((SingleDisk) && strstr(LoaderBlock->ArcBootDeviceName, "cdrom"))
     {
-      ULONG DeviceNumber;
-
-      DPRINT("Booting from CD-ROM!\n");
-      Status = IopCheckCdromDevices(&DeviceNumber);
-      if (!NT_SUCCESS(Status))
-       {
-         CPRINT("Failed to find setup disk!\n");
-         return(Status);
-       }
-
-      sprintf(p, "cdrom(%lu)", DeviceNumber);
-
-      DPRINT("New ARC name: %s\n", ParamBuffer);
-
-      /* Adjust original command line */
-      p = strstr(ParameterLine, "cdrom");
-      if (p != NULL);
-       {
-         char temp[256];
-         char *q;
-
-         q = strchr(p, ')');
-         if (q != NULL)
-           {
-
-             q++;
-             strcpy(temp, q);
-             sprintf(p, "cdrom(%lu)", DeviceNumber);
-             strcat(p, temp);
-           }
-       }
+        /* Then disable single-disk mode, since there's a CD drive out there */
+        SingleDisk = FALSE;
     }
 
-  /* Only arc name left - build full arc name */
-  ArcNameBuffer = ExAllocatePool(PagedPool, 256 * sizeof(WCHAR));
-  swprintf(ArcNameBuffer,
-          L"\\ArcName\\%S", ParamBuffer);
-  RtlInitUnicodeString(&ArcName, ArcNameBuffer);
-  DPRINT("Arc name: %wZ\n", &ArcName);
-
-  /* free ParamBuffer */
-  ExFreePool(ParamBuffer);
-
-  /* allocate device name string */
-  DeviceName.Length = 0;
-  DeviceName.MaximumLength = 256 * sizeof(WCHAR);
-  DeviceName.Buffer = ExAllocatePool(PagedPool, 256 * sizeof(WCHAR));
-
-  InitializeObjectAttributes(&ObjectAttributes,
-                            &ArcName,
-                            OBJ_OPENLINK,
-                            NULL,
-                            NULL);
-
-  Status = ZwOpenSymbolicLinkObject(&Handle,
-                                   SYMBOLIC_LINK_ALL_ACCESS,
-                                   &ObjectAttributes);
-  if (!NT_SUCCESS(Status))
-    {
-      RtlFreeUnicodeString(&BootPath);
-      ExFreePool(DeviceName.Buffer);
-      CPRINT("ZwOpenSymbolicLinkObject() '%wZ' failed (Status %x)\n",
-            &ArcName,
-            Status);
-      ExFreePool(ArcName.Buffer);
-
-      return(Status);
-    }
-  ExFreePool(ArcName.Buffer);
+    /* Build the boot strings */
+    RtlInitAnsiString(&ArcBootString, LoaderBlock->ArcBootDeviceName);
+    RtlInitAnsiString(&ArcSystemString, LoaderBlock->ArcHalDeviceName);
 
-  Status = ZwQuerySymbolicLinkObject(Handle,
-                                    &DeviceName,
-                                    &Length);
-  ZwClose (Handle);
-  if (!NT_SUCCESS(Status))
+    /* Loop every detected disk */
+    for (i = 0; i < ConfigInfo->DiskCount; i++)
     {
-      RtlFreeUnicodeString(&BootPath);
-      ExFreePool(DeviceName.Buffer);
-      CPRINT("ZwQuerySymbolicObject() failed (Status %x)\n",
-            Status);
+        /* Get information about the disk */
+        if (!IopGetDiskInformation(i,
+                                   &Checksum,
+                                   &Signature,
+                                   &PartitionCount,
+                                   &DeviceObject))
+        {
+            /* Skip this disk */
+            continue;
+        }
 
-      return(Status);
-    }
-  DPRINT("Length: %lu DeviceName: %wZ\n", Length, &DeviceName);
+        /* Loop ARC disks */
+        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);
+
+            /*
+             * 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;
+                    }
 
-  RtlAppendUnicodeStringToString(&DeviceName,
-                                &BootPath);
+                    /* 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 */
 
-  RtlFreeUnicodeString(&BootPath);
-  DPRINT("DeviceName: %wZ\n", &DeviceName);
+                            /* 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);
+                }
+            }
+        }
+    }
 
-  /* create the '\SystemRoot' link */
-  Status = IoCreateSymbolicLink(&LinkName,
-                               &DeviceName);
-  ExFreePool(DeviceName.Buffer);
-  if (!NT_SUCCESS(Status))
+    /* Check if we didn't find the boot disk */
+    if (!FoundBoot)
     {
-      CPRINT("IoCreateSymbolicLink() failed (Status %x)\n",
-            Status);
+        /* Allocate a buffer for the CD-ROM MBR */
+        PartitionBuffer = ExAllocatePoolWithTag(NonPagedPool, 2048, TAG_IO);
+        if (!PartitionBuffer) return STATUS_INSUFFICIENT_RESOURCES;
 
-      return(Status);
+        /* Loop every CD-ROM */
+        for (i = 0; i < ConfigInfo->CdRomCount; i++)
+        {
+            /* Give it an ARC name */
+            if (IopAssignArcNamesToCdrom(LoaderBlock, PartitionBuffer, i)) break;
+        }
+
+        /* Free the buffer */
+        ExFreePoolWithTag(PartitionBuffer, TAG_IO);
     }
 
-  /* Check whether '\SystemRoot'(LinkName) can be opened */
-  InitializeObjectAttributes(&ObjectAttributes,
-                            &LinkName,
-                            0,
-                            NULL,
-                            NULL);
-
-  Status = ZwOpenFile(&Handle,
-                     FILE_ALL_ACCESS,
-                     &ObjectAttributes,
-                     &IoStatusBlock,
-                     0,
-                     0);
-  if (!NT_SUCCESS(Status))
+    /* Return success */
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+IopReassignSystemRoot(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
+                      OUT PANSI_STRING NtBootPath)
+{
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    NTSTATUS Status;
+    CHAR Buffer[256], AnsiBuffer[256];
+    WCHAR ArcNameBuffer[64];
+    ANSI_STRING TargetString, ArcString, TempString;
+    UNICODE_STRING LinkName, TargetName, ArcName;
+    HANDLE LinkHandle;
+
+    /* Create the Unicode name for the current ARC boot device */
+    sprintf(Buffer, "\\ArcName\\%s", LoaderBlock->ArcBootDeviceName);
+    RtlInitAnsiString(&TargetString, Buffer);
+    Status = RtlAnsiStringToUnicodeString(&TargetName, &TargetString, TRUE);
+    if (!NT_SUCCESS(Status)) return FALSE;
+
+    /* Initialize the attributes and open the link */
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &TargetName,
+                               OBJ_CASE_INSENSITIVE,
+                               NULL,
+                               NULL);
+    Status = NtOpenSymbolicLinkObject(&LinkHandle,
+                                      SYMBOLIC_LINK_ALL_ACCESS,
+                                      &ObjectAttributes);
+    if (!NT_SUCCESS(Status))
     {
-      CPRINT("ZwOpenFile() failed to open '\\SystemRoot' (Status %x)\n",
-            Status);
-      return(Status);
+        /* We failed, free the string */
+        RtlFreeUnicodeString(&TargetName);
+        return FALSE;
     }
 
-  ZwClose(Handle);
+    /* Query the current \\SystemRoot */
+    ArcName.Buffer = ArcNameBuffer;
+    ArcName.Length = 0;
+    ArcName.MaximumLength = sizeof(ArcNameBuffer);
+    Status = NtQuerySymbolicLinkObject(LinkHandle, &ArcName, NULL);
+    if (!NT_SUCCESS(Status))
+    {
+        /* We failed, free the string */
+        RtlFreeUnicodeString(&TargetName);
+        return FALSE;
+    }
 
-  return(STATUS_SUCCESS);
+    /* Convert it to Ansi */
+    ArcString.Buffer = AnsiBuffer;
+    ArcString.Length = 0;
+    ArcString.MaximumLength = sizeof(AnsiBuffer);
+    Status = RtlUnicodeStringToAnsiString(&ArcString, &ArcName, FALSE);
+    AnsiBuffer[ArcString.Length] = ANSI_NULL;
+
+    /* Close the link handle and free the name */
+    ObCloseHandle(LinkHandle, KernelMode);
+    RtlFreeUnicodeString(&TargetName);
+
+    /* Setup the system root name again */
+    RtlInitAnsiString(&TempString, "\\SystemRoot");
+    Status = RtlAnsiStringToUnicodeString(&LinkName, &TempString, TRUE);
+    if (!NT_SUCCESS(Status)) return FALSE;
+
+    /* Open the symbolic link for it */
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &LinkName,
+                               OBJ_CASE_INSENSITIVE,
+                               NULL,
+                               NULL);
+    Status = NtOpenSymbolicLinkObject(&LinkHandle,
+                                      SYMBOLIC_LINK_ALL_ACCESS,
+                                      &ObjectAttributes);
+    if (!NT_SUCCESS(Status)) return FALSE;
+
+    /* Destroy it */
+    NtMakeTemporaryObject(LinkHandle);
+    ObCloseHandle(LinkHandle, KernelMode);
+
+    /* Now create the new name for it */
+    sprintf(Buffer, "%s%s", ArcString.Buffer, LoaderBlock->NtBootPathName);
+
+    /* Copy it into the passed parameter and null-terminate it */
+    RtlCopyString(NtBootPath, &ArcString);
+    Buffer[strlen(Buffer) - 1] = ANSI_NULL;
+
+    /* Setup the Unicode-name for the new symbolic link value */
+    RtlInitAnsiString(&TargetString, Buffer);
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &LinkName,
+                               OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
+                               NULL,
+                               NULL);
+    Status = RtlAnsiStringToUnicodeString(&ArcName, &TargetString, TRUE);
+    if (!NT_SUCCESS(Status)) return FALSE;
+
+    /* Create it */
+    Status = NtCreateSymbolicLinkObject(&LinkHandle,
+                                        SYMBOLIC_LINK_ALL_ACCESS,
+                                        &ObjectAttributes,
+                                        &ArcName);
+
+    /* Free all the strings and close the handle and return success */
+    RtlFreeUnicodeString(&ArcName);
+    RtlFreeUnicodeString(&LinkName);
+    ObCloseHandle(LinkHandle, KernelMode);
+    return TRUE;
 }
 
 /* EOF */