[NTOS:FSTUB] Fix bugs in the drive-letters assignment algorithm

Addendum to commit 5ab1cfc553.

- Fix the drive letters assignment ordering for hard disks.

  * Fix the loop that assigns letters to MBR boot and primary partitions;
  * Fix the condition that finds the boot partition (or defaults to the
    first primary partition) to be skipped when assigning letters to all
    remaining hard-disk partitions -- after letters have been assigned
    to the specific boot, primary, logical, etc. partitions.

  NOTE: The drive-letter assignment algorithm is as follows:

  1. For each hard disk, assign a letter to the first encountered boot
     (MBR "active") partition; or if GPT disk, to all data partitions.
     If no boot partition has been found on this disk, assign a letter
     to all of its primary partitions.

  2. Assign a letter to all (MBR) logical partitions for each hard disk.

  3. Assign a letter to all remaining partitions with recognized IDs on
     all disks.

  ****
  We observe that the algorithm 1-3 is tailored for MBR-partitioned disks,
  as it is inherited from the way MS-DOS did it. In addition, partitions
  on GPT disks acquire their drive letters early one, during step 1.
  ****

  4. Assign letters to floppy disks (see below), then to CD-ROMs.

  5. Finally, verify that the OS boot volume has got a drive letter; if
     not, get a free one (or delete the 'Z' drive letter and reassign it
     to the boot volume).

  (See also "Inside Storage Management, Part 1", Mark Russinovich,
   https://www.digiater.nl/openvms/decus/vmslt00b/nt/storage-mgt-nt_2.htm
   about the `IoAssignDriveLetters` function.)

- When assigning drive letters to floppy drives, first assign letters to
  legacy (non-MountMgr-aware) devices, and then to MountMgr-aware devices.
This commit is contained in:
Hermès Bélusca-Maïto
2026-04-11 18:16:27 +02:00
parent 750e463fb1
commit 278234259d
+66 -105
View File
@@ -1041,39 +1041,54 @@ xHalIoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
/* Now, start browsing all the disks for assigning drive letters.
* Here, we'll only handle the bootable and primary partitions. */
HarddiskCount = 0;
for (i = 0; i < DiskCount; ++i)
{
/* Get the device ID from the derangements map */
if (Devices != NULL)
{
HarddiskCount = Devices[i];
}
HarddiskCount = (Devices ? Devices[i] : i);
/* Query the disk layout */
swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition0", HarddiskCount);
RtlInitUnicodeString(&DeviceName, Buffer);
if (!NT_SUCCESS(HalpQueryDriveLayout(&DeviceName, &LayoutInfo)))
{
Status = HalpQueryDriveLayout(&DeviceName, &LayoutInfo);
if (!NT_SUCCESS(Status))
LayoutInfo = NULL;
}
/* Assume we didn't find a bootable partition */
BootableFound = FALSE;
swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition%d", HarddiskCount, 1);
RtlInitUnicodeString(&DeviceName, Buffer);
/* Query partition info for our disk */
if (!NT_SUCCESS(HalpQueryPartitionType(&DeviceName, LayoutInfo, &PartitionType)))
for (PartitionCount = 1; ; ++PartitionCount)
{
swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition%d", HarddiskCount, PartitionCount);
RtlInitUnicodeString(&DeviceName, Buffer);
Status = HalpQueryPartitionType(&DeviceName, LayoutInfo, &PartitionType);
if (!NT_SUCCESS(Status))
{
/* It failed, retry for all the partitions */
break;
}
/* If the partition is bootable (MBR) or data (GPT), we've found it */
if (PartitionType == BootablePartition || PartitionType == DataPartition)
{
BootableFound = TRUE;
/* Assign a drive letter and stop here if MBR */
HalpNextDriveLetter(&DeviceName, NtDeviceName, NtSystemPath, FALSE);
if (PartitionType == BootablePartition)
break;
}
/* Keep looping on all the partitions */
}
/* Mount every primary partition if we didn't find a bootable partition */
if (!BootableFound)
{
/* It failed, retry for all the partitions */
for (PartitionCount = 1; ; ++PartitionCount)
{
swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition%d", HarddiskCount, PartitionCount);
RtlInitUnicodeString(&DeviceName, Buffer);
if (!NT_SUCCESS(HalpQueryPartitionType(&DeviceName, LayoutInfo, &PartitionType)))
{
Status = HalpQueryPartitionType(&DeviceName, LayoutInfo, &PartitionType);
if (!NT_SUCCESS(Status))
break;
}
/* We found a primary partition, assign a drive letter */
if (PartitionType == PrimaryPartition)
@@ -1083,59 +1098,10 @@ xHalIoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
}
}
}
else
{
/* All right */
for (PartitionCount = 2; ; ++PartitionCount)
{
/* If the partition is bootable (MBR) or data (GPT), we've found it */
if (PartitionType == BootablePartition || PartitionType == DataPartition)
{
BootableFound = TRUE;
/* Assign a drive letter and stop here if MBR */
HalpNextDriveLetter(&DeviceName, NtDeviceName, NtSystemPath, FALSE);
if (PartitionType == BootablePartition)
break;
}
/* Keep looping on all the partitions */
swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition%d", HarddiskCount, PartitionCount);
RtlInitUnicodeString(&DeviceName, Buffer);
if (!NT_SUCCESS(HalpQueryPartitionType(&DeviceName, LayoutInfo, &PartitionType)))
{
/* Mount every primary partition if we didn't find a bootable partition */
if (!BootableFound)
{
for (PartitionCount = 1; ; ++PartitionCount)
{
swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition%d", HarddiskCount, PartitionCount);
RtlInitUnicodeString(&DeviceName, Buffer);
if (!NT_SUCCESS(HalpQueryPartitionType(&DeviceName, LayoutInfo, &PartitionType)))
{
break;
}
if (PartitionType == PrimaryPartition)
{
HalpNextDriveLetter(&DeviceName, NtDeviceName, NtSystemPath, FALSE);
break;
}
}
}
break;
}
}
}
/* Free the layout, we'll reallocate it for the next disk */
if (LayoutInfo != NULL)
{
ExFreePoolWithTag(LayoutInfo, TAG_FSTUB);
}
HarddiskCount = i + 1;
}
/* Now, assign drive letters to logical partitions */
@@ -1147,20 +1113,18 @@ xHalIoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
/* Query the disk layout */
swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition0", HarddiskCount);
RtlInitUnicodeString(&DeviceName, Buffer);
if (!NT_SUCCESS(HalpQueryDriveLayout(&DeviceName, &LayoutInfo)))
{
Status = HalpQueryDriveLayout(&DeviceName, &LayoutInfo);
if (!NT_SUCCESS(Status))
LayoutInfo = NULL;
}
/* And assign drive letters to logical partitions */
for (PartitionCount = 1; ; ++PartitionCount)
{
swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition%d", HarddiskCount, PartitionCount);
RtlInitUnicodeString(&DeviceName, Buffer);
if (!NT_SUCCESS(HalpQueryPartitionType(&DeviceName, LayoutInfo, &PartitionType)))
{
Status = HalpQueryPartitionType(&DeviceName, LayoutInfo, &PartitionType);
if (!NT_SUCCESS(Status))
break;
}
if (PartitionType == LogicalPartition)
{
@@ -1170,9 +1134,7 @@ xHalIoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
/* Free the layout, we'll reallocate it for the next disk */
if (LayoutInfo != NULL)
{
ExFreePoolWithTag(LayoutInfo, 0);
}
ExFreePoolWithTag(LayoutInfo, TAG_FSTUB);
}
/* Now, assign drive letters to everything else */
@@ -1184,10 +1146,9 @@ xHalIoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
/* Query the disk layout */
swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition0", HarddiskCount);
RtlInitUnicodeString(&DeviceName, Buffer);
if (!NT_SUCCESS(HalpQueryDriveLayout(&DeviceName, &LayoutInfo)))
{
Status = HalpQueryDriveLayout(&DeviceName, &LayoutInfo);
if (!NT_SUCCESS(Status))
LayoutInfo = NULL;
}
/* Save the bootable or first primary (MBR) partition, if any */
SkipPartition = 0;
@@ -1195,12 +1156,12 @@ xHalIoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
{
swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition%d", HarddiskCount, PartitionCount);
RtlInitUnicodeString(&DeviceName, Buffer);
if (!NT_SUCCESS(HalpQueryPartitionType(&DeviceName, LayoutInfo, &PartitionType)))
{
Status = HalpQueryPartitionType(&DeviceName, LayoutInfo, &PartitionType);
if (!NT_SUCCESS(Status))
break;
}
if ((PartitionType == BootablePartition || PartitionType == PrimaryPartition) && (SkipPartition == 0))
if ((PartitionType == BootablePartition) ||
((PartitionType == PrimaryPartition) && (SkipPartition == 0)))
{
SkipPartition = PartitionCount;
}
@@ -1214,38 +1175,40 @@ xHalIoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition%d", HarddiskCount, PartitionCount);
RtlInitUnicodeString(&DeviceName, Buffer);
if (!NT_SUCCESS(HalpQueryPartitionType(&DeviceName, LayoutInfo, &PartitionType)))
{
if (LayoutInfo != NULL)
{
ExFreePoolWithTag(LayoutInfo, 0);
}
Status = HalpQueryPartitionType(&DeviceName, LayoutInfo, &PartitionType);
if (!NT_SUCCESS(Status))
break;
}
if (PartitionType == PrimaryPartition || PartitionType == FtPartition)
{
HalpNextDriveLetter(&DeviceName, NtDeviceName, NtSystemPath, FALSE);
}
}
/* Free the layout, we'll reallocate it for the next disk */
if (LayoutInfo != NULL)
ExFreePoolWithTag(LayoutInfo, TAG_FSTUB);
}
/* We're done with the disks; free the derangements map */
if (Devices != NULL)
{
ExFreePoolWithTag(Devices, TAG_FSTUB);
}
/* Now, assign drive letter to floppy drives */
/* Now, assign drive letters to floppy devices:
* first for legacy, then for MountMgr-aware ones. */
for (i = 0; i < ConfigInfo->FloppyCount; ++i)
{
swprintf(Buffer, L"\\Device\\Floppy%d", i);
RtlInitUnicodeString(&DeviceName, Buffer);
if (HalpIsOldStyleFloppy(&DeviceName))
{
if (HalpIsOldStyleFloppy(&DeviceName)) // Legacy device
HalpNextDriveLetter(&DeviceName, NtDeviceName, NtSystemPath, TRUE);
}
for (i = 0; i < ConfigInfo->FloppyCount; ++i)
{
swprintf(Buffer, L"\\Device\\Floppy%d", i);
RtlInitUnicodeString(&DeviceName, Buffer);
if (!HalpIsOldStyleFloppy(&DeviceName)) // MountMgr-aware device
HalpNextDriveLetter(&DeviceName, NtDeviceName, NtSystemPath, TRUE);
}
}
/* And CD-ROM drives */
@@ -1284,19 +1247,17 @@ xHalIoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
break;
}
/* If we're beyond Z (ie, no slot left) */
/* If we're beyond Z (no letter left), delete Z and
* reuse it for the OS boot volume (SystemRoot) */
if (DriveLetter > 'Z')
{
/* Delete Z, and reuse it for system */
HalpDeleteMountLetter('Z');
HalpSetMountLetter(&DeviceName, 'Z');
*NtSystemPath = 'Z';
}
else
{
/* Return matching drive letter */
*NtSystemPath = DriveLetter;
DriveLetter = 'Z';
HalpDeleteMountLetter(DriveLetter);
HalpSetMountLetter(&DeviceName, DriveLetter);
}
/* Return the matching drive letter */
*NtSystemPath = DriveLetter;
}
RtlFreeUnicodeString(&DeviceName);