From 5ab1cfc553f11731d9a352f1157084cc1dfd9042 Mon Sep 17 00:00:00 2001 From: Pierre Schweitzer Date: Mon, 21 Oct 2019 18:28:40 +0200 Subject: [PATCH] [NTOSKRNL] Rewrite IoAssignDriveLetters to make NT5 compliant The major change with this rewrite is the support for the mount manager. Fstub will now assume that most of the devices are PnP and that they are already registered to the mount manager. It will thus ask the mount manager to assign the drive letter. Fstub will keep assigning drive letters non mission critical devices such as CDs, floppies and other removable devices. See MountMgr:QueryPoints API test that will now return mount points :-). --- ntoskrnl/fstub/disksup.c | 2027 +++++++++++++++++++++-------------- ntoskrnl/guid.c | 1 + ntoskrnl/include/ntoskrnl.h | 1 + 3 files changed, 1235 insertions(+), 794 deletions(-) diff --git a/ntoskrnl/fstub/disksup.c b/ntoskrnl/fstub/disksup.c index dfdbf0c494c..0b81bc561dd 100644 --- a/ntoskrnl/fstub/disksup.c +++ b/ntoskrnl/fstub/disksup.c @@ -6,6 +6,7 @@ * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) * Eric Kohl * Casper S. Hornstrup (chorns@users.sourceforge.net) +* Pierre Schweitzer */ /* INCLUDES ******************************************************************/ @@ -15,9 +16,6 @@ #include #include -/* DEPRECATED FUNCTIONS ******************************************************/ - -#if 1 const WCHAR DiskMountString[] = L"\\DosDevices\\%C:"; #define AUTO_DRIVE MAXULONG @@ -43,371 +41,870 @@ typedef enum _DISK_MANAGER EZ_Drive } DISK_MANAGER; -static BOOLEAN -HalpAssignDrive(IN PUNICODE_STRING PartitionName, - IN ULONG DriveNumber, - IN UCHAR DriveType, - IN ULONG Signature, - IN LARGE_INTEGER StartingOffset, - IN HANDLE hKey, - IN PUNICODE_STRING BootDevice, - OUT PUCHAR NtSystemPath) +typedef enum _PARTITION_TYPE { - WCHAR DriveNameBuffer[16]; - UNICODE_STRING DriveName; - ULONG i; - NTSTATUS Status; - REG_DISK_MOUNT_INFO DiskMountInfo; - - DPRINT("HalpAssignDrive()\n"); - - if ((DriveNumber != AUTO_DRIVE) && (DriveNumber < 26)) - { - /* Force assignment */ - KeAcquireGuardedMutex(&ObpDeviceMapLock); - if ((ObSystemDeviceMap->DriveMap & (1 << DriveNumber)) != 0) - { - DbgPrint("Drive letter already used!\n"); - KeReleaseGuardedMutex(&ObpDeviceMapLock); - return FALSE; - } - KeReleaseGuardedMutex(&ObpDeviceMapLock); - } - else - { - /* Automatic assignment */ - DriveNumber = AUTO_DRIVE; - KeAcquireGuardedMutex(&ObpDeviceMapLock); - for (i = 2; i < 26; i++) - { - if ((ObSystemDeviceMap->DriveMap & (1 << i)) == 0) - { - DriveNumber = i; - break; - } - } - KeReleaseGuardedMutex(&ObpDeviceMapLock); - - if (DriveNumber == AUTO_DRIVE) - { - DbgPrint("No drive letter available!\n"); - return FALSE; - } - } - - DPRINT("DriveNumber %lu\n", DriveNumber); - - /* Build drive name */ - swprintf(DriveNameBuffer, - L"\\??\\%C:", - 'A' + DriveNumber); - RtlInitUnicodeString(&DriveName, - DriveNameBuffer); - - DPRINT(" %wZ ==> %wZ\n", - &DriveName, - PartitionName); - - /* Create symbolic link */ - Status = IoCreateSymbolicLink(&DriveName, - PartitionName); - - if (hKey && - DriveType == DOSDEVICE_DRIVE_FIXED && - Signature) - { - DiskMountInfo.Signature = Signature; - DiskMountInfo.StartingOffset = StartingOffset; - swprintf(DriveNameBuffer, DiskMountString, L'A' + DriveNumber); - RtlInitUnicodeString(&DriveName, DriveNameBuffer); - - Status = ZwSetValueKey(hKey, - &DriveName, - 0, - REG_BINARY, - &DiskMountInfo, - sizeof(DiskMountInfo)); - if (!NT_SUCCESS(Status)) - { - DPRINT1("ZwCreateValueKey failed for %wZ, status=%x\n", &DriveName, Status); - } - } - - /* Check if this is a boot partition */ - if (RtlCompareUnicodeString(PartitionName, BootDevice, FALSE) == 0) - { - /* Set NtSystemPath to that partition's disk letter */ - *NtSystemPath = (UCHAR)('A' + DriveNumber); - } - - return TRUE; -} - -ULONG -xHalpGetRDiskCount(VOID) -{ - NTSTATUS Status; - UNICODE_STRING ArcName; - PWCHAR ArcNameBuffer; - OBJECT_ATTRIBUTES ObjectAttributes; - HANDLE DirectoryHandle; - POBJECT_DIRECTORY_INFORMATION DirectoryInfo; - ULONG Skip; - ULONG ResultLength; - ULONG CurrentRDisk; - ULONG RDiskCount; - BOOLEAN First = TRUE; - ULONG Count; - - DirectoryInfo = ExAllocatePoolWithTag(PagedPool, 2 * PAGE_SIZE, TAG_FILE_SYSTEM); - if (DirectoryInfo == NULL) - { - return 0; - } - - RtlInitUnicodeString(&ArcName, L"\\ArcName"); - InitializeObjectAttributes(&ObjectAttributes, - &ArcName, - 0, - NULL, - NULL); - - Status = ZwOpenDirectoryObject (&DirectoryHandle, - DIRECTORY_ALL_ACCESS, - &ObjectAttributes); - if (!NT_SUCCESS(Status)) - { - DPRINT1("ZwOpenDirectoryObject for %wZ failed, status=%lx\n", &ArcName, Status); - ExFreePoolWithTag(DirectoryInfo, TAG_FILE_SYSTEM); - return 0; - } - - RDiskCount = 0; - Skip = 0; - while (NT_SUCCESS(Status)) - { - Status = ZwQueryDirectoryObject (DirectoryHandle, - DirectoryInfo, - 2 * PAGE_SIZE, - FALSE, - First, - &Skip, - &ResultLength); - First = FALSE; - if (NT_SUCCESS(Status)) - { - Count = 0; - while (DirectoryInfo[Count].Name.Buffer) - { - DPRINT("Count %x\n", Count); - DirectoryInfo[Count].Name.Buffer[DirectoryInfo[Count].Name.Length / sizeof(WCHAR)] = 0; - ArcNameBuffer = DirectoryInfo[Count].Name.Buffer; - if (DirectoryInfo[Count].Name.Length >= sizeof(L"multi(0)disk(0)rdisk(0)") - sizeof(WCHAR) && - !_wcsnicmp(ArcNameBuffer, L"multi(0)disk(0)rdisk(", (sizeof(L"multi(0)disk(0)rdisk(") - sizeof(WCHAR)) / sizeof(WCHAR))) - { - DPRINT("%S\n", ArcNameBuffer); - ArcNameBuffer += (sizeof(L"multi(0)disk(0)rdisk(") - sizeof(WCHAR)) / sizeof(WCHAR); - CurrentRDisk = 0; - while (iswdigit(*ArcNameBuffer)) - { - CurrentRDisk = CurrentRDisk * 10 + *ArcNameBuffer - L'0'; - ArcNameBuffer++; - } - if (!_wcsicmp(ArcNameBuffer, L")") && - CurrentRDisk >= RDiskCount) - { - RDiskCount = CurrentRDisk + 1; - } - } - Count++; - } - } - } - - ZwClose(DirectoryHandle); - - ExFreePoolWithTag(DirectoryInfo, TAG_FILE_SYSTEM); - return RDiskCount; -} - -NTSTATUS -xHalpGetDiskNumberFromRDisk(ULONG RDisk, PULONG DiskNumber) -{ - WCHAR NameBuffer[80]; - UNICODE_STRING ArcName; - UNICODE_STRING LinkName; - OBJECT_ATTRIBUTES ObjectAttributes; - HANDLE LinkHandle; - NTSTATUS Status; - - swprintf(NameBuffer, - L"\\ArcName\\multi(0)disk(0)rdisk(%lu)", - RDisk); - - RtlInitUnicodeString(&ArcName, NameBuffer); - InitializeObjectAttributes(&ObjectAttributes, - &ArcName, - 0, - NULL, - NULL); - Status = ZwOpenSymbolicLinkObject(&LinkHandle, - SYMBOLIC_LINK_ALL_ACCESS, - &ObjectAttributes); - if (!NT_SUCCESS(Status)) - { - DPRINT1("ZwOpenSymbolicLinkObject failed for %wZ, status=%lx\n", &ArcName, Status); - return Status; - } - - LinkName.Buffer = NameBuffer; - LinkName.Length = 0; - LinkName.MaximumLength = sizeof(NameBuffer); - Status = ZwQuerySymbolicLinkObject(LinkHandle, - &LinkName, - NULL); - ZwClose(LinkHandle); - if (!NT_SUCCESS(Status)) - { - DPRINT1("ZwQuerySymbolicLinkObject failed, status=%lx\n", Status); - return Status; - } - if (LinkName.Length < sizeof(L"\\Device\\Harddisk0\\Partition0") - sizeof(WCHAR) || - LinkName.Length >= sizeof(NameBuffer)) - { - return STATUS_UNSUCCESSFUL; - } - - NameBuffer[LinkName.Length / sizeof(WCHAR)] = 0; - if (_wcsnicmp(NameBuffer, L"\\Device\\Harddisk", (sizeof(L"\\Device\\Harddisk") - sizeof(WCHAR)) / sizeof(WCHAR))) - { - return STATUS_UNSUCCESSFUL; - } - LinkName.Buffer += (sizeof(L"\\Device\\Harddisk") - sizeof(WCHAR)) / sizeof(WCHAR); - - if (!iswdigit(*LinkName.Buffer)) - { - return STATUS_UNSUCCESSFUL; - } - *DiskNumber = 0; - while (iswdigit(*LinkName.Buffer)) - { - *DiskNumber = *DiskNumber * 10 + *LinkName.Buffer - L'0'; - LinkName.Buffer++; - } - if (_wcsicmp(LinkName.Buffer, L"\\Partition0")) - { - return STATUS_UNSUCCESSFUL; - } - return STATUS_SUCCESS; -} + BootablePartition, + PrimaryPartition, + LogicalPartition, + FtPartition, + UnknownPartition, + DataPartition +} PARTITION_TYPE, *PPARTITION_TYPE; NTSTATUS FASTCALL -xHalQueryDriveLayout(IN PUNICODE_STRING DeviceName, +HalpQueryDriveLayout(IN PUNICODE_STRING DeviceName, OUT PDRIVE_LAYOUT_INFORMATION *LayoutInfo) { IO_STATUS_BLOCK StatusBlock; - DISK_GEOMETRY DiskGeometry; PDEVICE_OBJECT DeviceObject = NULL; PFILE_OBJECT FileObject; KEVENT Event; PIRP Irp; NTSTATUS Status; + ULONG BufferSize; + PDRIVE_LAYOUT_INFORMATION Buffer; + PAGED_CODE(); - DPRINT("xHalpQueryDriveLayout %wZ %p\n", - DeviceName, - LayoutInfo); - - /* Get the drives sector size */ + /* Get device pointers */ Status = IoGetDeviceObjectPointer(DeviceName, - FILE_READ_ATTRIBUTES, - &FileObject, - &DeviceObject); + FILE_READ_ATTRIBUTES, + &FileObject, + &DeviceObject); if (!NT_SUCCESS(Status)) { - DPRINT("Status %x\n", Status); - return(Status); + return Status; } - KeInitializeEvent(&Event, - NotificationEvent, - FALSE); + /* Get attached device object */ + DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject); + ObDereferenceObject(FileObject); - Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY, - DeviceObject, - NULL, - 0, - &DiskGeometry, - sizeof(DISK_GEOMETRY), - FALSE, - &Event, - &StatusBlock); + /* Do not handle removable media */ + if (BooleanFlagOn(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) + { + ObDereferenceObject(DeviceObject); + return STATUS_NO_MEDIA; + } + + /* We'll loop until our buffer is big enough */ + Buffer = NULL; + BufferSize = 0x1000; + KeInitializeEvent(&Event, NotificationEvent, FALSE); + do + { + /* If we already had a buffer, it means it's not big + * enough, so free and multiply size by two + */ + if (Buffer != NULL) + { + ExFreePoolWithTag(Buffer, TAG_FSTUB); + BufferSize *= 2; + } + + /* Allocate buffer for output buffer */ + Buffer = ExAllocatePoolWithTag(NonPagedPool, BufferSize, TAG_FSTUB); + if (Buffer == NULL) + { + Status = STATUS_NO_MEMORY; + break; + } + + /* Build the IRP to query drive layout */ + Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_LAYOUT, + DeviceObject, + NULL, + 0, + Buffer, + BufferSize, + FALSE, + &Event, + &StatusBlock); + if (Irp == NULL) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + /* Call the driver and wait if appropriate */ + Status = IoCallDriver(DeviceObject, Irp); + if (Status == STATUS_PENDING) + { + KeWaitForSingleObject(&Event, + Executive, + KernelMode, + FALSE, + NULL); + Status = StatusBlock.Status; + } + /* If buffer is too small, keep looping */ + } while (Status == STATUS_BUFFER_TOO_SMALL); + + /* We're done with the device */ + ObDereferenceObject(DeviceObject); + + /* If querying worked, then return the buffer to the caller */ + if (NT_SUCCESS(Status)) + { + ASSERT(Buffer != NULL); + *LayoutInfo = Buffer; + } + /* Else, release the buffer if still allocated and fail */ + else + { + if (Buffer != NULL) + { + ExFreePoolWithTag(Buffer, TAG_FSTUB); + } + } + + return Status; +} + +NTSTATUS +HalpQueryPartitionType(IN PUNICODE_STRING DeviceName, + IN PDRIVE_LAYOUT_INFORMATION LayoutInfo, + OUT PPARTITION_TYPE PartitionType) +{ + USHORT i; + PIRP Irp; + KEVENT Event; + NTSTATUS Status; + PFILE_OBJECT FileObject; + PDEVICE_OBJECT DeviceObject; + IO_STATUS_BLOCK IoStatusBlock; + PARTITION_INFORMATION_EX PartitionInfo; + + PAGED_CODE(); + + /* Get device pointers */ + Status = IoGetDeviceObjectPointer(DeviceName, + FILE_READ_ATTRIBUTES, + &FileObject, + &DeviceObject); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + /* Get attached device object */ + DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject); + ObDereferenceObject(FileObject); + + /* Assume logical partition for removable devices */ + if (BooleanFlagOn(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA)) + { + ObDereferenceObject(DeviceObject); + *PartitionType = LogicalPartition; + return STATUS_SUCCESS; + } + + /* For the others, query partition info */ + KeInitializeEvent(&Event, NotificationEvent, FALSE); + Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO_EX, + DeviceObject, + NULL, + 0, + &PartitionInfo, + sizeof(PartitionInfo), + FALSE, + &Event, + &IoStatusBlock); if (Irp == NULL) { - ObDereferenceObject(FileObject); - return(STATUS_INSUFFICIENT_RESOURCES); + ObDereferenceObject(DeviceObject); + return STATUS_INSUFFICIENT_RESOURCES; } - Status = IoCallDriver(DeviceObject, - Irp); + Status = IoCallDriver(DeviceObject, Irp); if (Status == STATUS_PENDING) { KeWaitForSingleObject(&Event, - Executive, - KernelMode, - FALSE, - NULL); - Status = StatusBlock.Status; + Executive, + KernelMode, + FALSE, + NULL); + Status = IoStatusBlock.Status; } + + /* We're done with the device */ + ObDereferenceObject(DeviceObject); + + /* If we failed querying partition info, try to return something + * if caller didn't provide a precise layout, assume logical + * partition and fake success. Otherwise, just fail. + */ if (!NT_SUCCESS(Status)) { - if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) + if (LayoutInfo == NULL) { - DiskGeometry.BytesPerSector = 512; - } - else - { - ObDereferenceObject(FileObject); - return(Status); + *PartitionType = LogicalPartition; + return STATUS_SUCCESS; } + + return Status; } - DPRINT("DiskGeometry.BytesPerSector: %lu\n", - DiskGeometry.BytesPerSector); - - if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) + /* First, handle non MBR style (easy cases) */ + if (PartitionInfo.PartitionStyle != PARTITION_STYLE_MBR) { - PDRIVE_LAYOUT_INFORMATION Buffer; - - /* Allocate a partition list for a single entry. */ - Buffer = ExAllocatePoolWithTag(NonPagedPool, - sizeof(DRIVE_LAYOUT_INFORMATION), TAG_FILE_SYSTEM); - if (Buffer != NULL) + /* If not GPT, we don't know what it is */ + if (PartitionInfo.PartitionStyle != PARTITION_STYLE_GPT) { - RtlZeroMemory(Buffer, - sizeof(DRIVE_LAYOUT_INFORMATION)); - Buffer->PartitionCount = 1; - *LayoutInfo = Buffer; - - Status = STATUS_SUCCESS; + *PartitionType = UnknownPartition; + return STATUS_SUCCESS; } - else + + /* Check whether that's data partition */ + if (RtlCompareMemory(&PartitionInfo.Gpt.PartitionType, + &PARTITION_BASIC_DATA_GUID, + sizeof(GUID)) == sizeof(GUID)) { - Status = STATUS_UNSUCCESSFUL; + *PartitionType = DataPartition; + return STATUS_SUCCESS; + } + + /* Otherwise, we don't know */ + *PartitionType = UnknownPartition; + return STATUS_SUCCESS; + } + + /* If we don't recognize partition type, return unknown */ + if (!IsRecognizedPartition(PartitionInfo.Mbr.PartitionType)) + { + *PartitionType = UnknownPartition; + return STATUS_SUCCESS; + } + + /* Check if that's a FT volume */ + if (PartitionInfo.Mbr.PartitionType & PARTITION_NTFT) + { + *PartitionType = FtPartition; + return STATUS_SUCCESS; + } + + /* If the caller didn't provide the complete layout, just return */ + if (LayoutInfo == NULL) + { + *PartitionType = LogicalPartition; + return STATUS_SUCCESS; + } + + /* Now, evaluate the partition to the 4 in the input layout */ + for (i = 0; i < 4; ++i) + { + /* If we find a partition matching */ + if (LayoutInfo->PartitionEntry[i].StartingOffset.QuadPart == PartitionInfo.StartingOffset.QuadPart) + { + /* Return boot if boot flag is set */ + if (PartitionInfo.Mbr.BootIndicator) + { + *PartitionType = BootablePartition; + } + /* Primary otherwise */ + else + { + *PartitionType = PrimaryPartition; + } + + return STATUS_SUCCESS; } } + + /* Otherwise, assume logical */ + *PartitionType = LogicalPartition; + return STATUS_SUCCESS; +} + +PULONG +IopComputeHarddiskDerangements(IN ULONG DiskCount) +{ + PIRP Irp; + KEVENT Event; + ULONG i, j, k; + PULONG Devices; + NTSTATUS Status; + WCHAR Buffer[100]; + UNICODE_STRING ArcName; + PFILE_OBJECT FileObject; + PDEVICE_OBJECT DeviceObject; + IO_STATUS_BLOCK IoStatusBlock; + STORAGE_DEVICE_NUMBER DeviceNumber; + + /* No disks, nothing to do */ + if (DiskCount == 0) + { + return NULL; + } + + /* Allocate a buffer big enough to hold all the disks */ + Devices = ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION, + sizeof(ULONG) * DiskCount, + TAG_FSTUB); + if (Devices == NULL) + { + return NULL; + } + + /* Now, we'll query all the disks */ + for (i = 0; i < DiskCount; ++i) + { + /* Using their ARC name */ + swprintf(Buffer, L"\\ArcName\\multi(0)disk(0)rdisk(%d)", i); + RtlInitUnicodeString(&ArcName, Buffer); + /* Get the attached DeviceObject */ + if (NT_SUCCESS(IoGetDeviceObjectPointer(&ArcName, FILE_READ_ATTRIBUTES, &FileObject, &DeviceObject))) + { + DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject); + ObDereferenceObject(FileObject); + + /* And query it for device number */ + KeInitializeEvent(&Event, NotificationEvent, FALSE); + Irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER, + DeviceObject, + NULL, + 0, + &DeviceNumber, + sizeof(DeviceNumber), + FALSE, + &Event, + &IoStatusBlock); + if (Irp != NULL) + { + Status = IoCallDriver(DeviceObject, Irp); + if (Status == STATUS_PENDING) + { + KeWaitForSingleObject(&Event, + Executive, + KernelMode, + FALSE, + NULL); + Status = IoStatusBlock.Status; + } + + ObDereferenceObject(DeviceObject); + + /* In case of a success remember device number */ + if (NT_SUCCESS(Status)) + { + Devices[i] = DeviceNumber.DeviceNumber; + /* Move on, not to fall into our default case */ + continue; + } + } + else + { + ObDereferenceObject(DeviceObject); + } + + /* Default case, for failures, set -1 */ + Devices[i] = -1; + } + } + + /* Now, we'll check all device numbers */ + for (i = 0; i < DiskCount; ++i) + { + /* First of all, check if we're at the right place */ + for (j = 0; j < DiskCount; ++j) + { + if (Devices[j] == i) + { + break; + } + } + + /* If not, perform the change */ + if (j >= DiskCount) + { + k = 0; + while (Devices[k] != -1) + { + if (++k >= DiskCount) + { + break; + } + } + + if (k < DiskCount) + { + Devices[k] = i; + } + } + } + + /* Return our device derangement map */ + return Devices; +} + +NTSTATUS +HalpNextMountLetter(IN PUNICODE_STRING DeviceName, + OUT PUCHAR DriveLetter) +{ + PIRP Irp; + KEVENT Event; + NTSTATUS Status; + UNICODE_STRING MountMgr; + PFILE_OBJECT FileObject; + PDEVICE_OBJECT DeviceObject; + IO_STATUS_BLOCK IoStatusBlock; + PMOUNTMGR_DRIVE_LETTER_TARGET Target; + MOUNTMGR_DRIVE_LETTER_INFORMATION LetterInfo; + + /* To get next mount letter, we need the MountMgr */ + RtlInitUnicodeString(&MountMgr, L"\\Device\\MountPointManager"); + Status = IoGetDeviceObjectPointer(&MountMgr, + FILE_READ_ATTRIBUTES, + &FileObject, + &DeviceObject); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + /* Allocate our input buffer */ + Target = ExAllocatePoolWithTag(PagedPool, + DeviceName->Length + FIELD_OFFSET(MOUNTMGR_DRIVE_LETTER_TARGET, DeviceName), + TAG_FSTUB); + if (Target == NULL) + { + ObDereferenceObject(FileObject); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* And fill it with the device hat needs a drive letter */ + Target->DeviceNameLength = DeviceName->Length; + RtlCopyMemory(&Target->DeviceName[0], DeviceName->Buffer, DeviceName->Length); + + /* Call the mount manager */ + KeInitializeEvent(&Event, NotificationEvent, FALSE); + Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER, + DeviceObject, + Target, + DeviceName->Length + FIELD_OFFSET(MOUNTMGR_DRIVE_LETTER_TARGET, DeviceName), + &LetterInfo, + sizeof(LetterInfo), + FALSE, + &Event, + &IoStatusBlock); + if (Irp == NULL) + { + ExFreePoolWithTag(Target, TAG_FSTUB); + ObDereferenceObject(FileObject); + return STATUS_INSUFFICIENT_RESOURCES; + } + + Status = IoCallDriver(DeviceObject, Irp); + if (Status == STATUS_PENDING) + { + KeWaitForSingleObject(&Event, + Executive, + KernelMode, + FALSE, + NULL); + Status = IoStatusBlock.Status; + } + + ExFreePoolWithTag(Target, TAG_FSTUB); + ObDereferenceObject(FileObject); + + DPRINT("Done: %d %c\n", LetterInfo.DriveLetterWasAssigned, + LetterInfo.CurrentDriveLetter); + + /* Return the drive letter the MountMgr potentially assigned */ + *DriveLetter = LetterInfo.CurrentDriveLetter; + + /* Also return the success */ + return Status; +} + +NTSTATUS +HalpSetMountLetter(IN PUNICODE_STRING DeviceName, + UCHAR DriveLetter) +{ + PIRP Irp; + KEVENT Event; + NTSTATUS Status; + WCHAR Buffer[30]; + ULONG InputBufferLength; + PFILE_OBJECT FileObject; + PDEVICE_OBJECT DeviceObject; + IO_STATUS_BLOCK IoStatusBlock; + UNICODE_STRING DosDevice, MountMgr; + PMOUNTMGR_CREATE_POINT_INPUT InputBuffer; + + /* Setup the DosDevice name */ + swprintf(Buffer, L"\\DosDevices\\%c:", DriveLetter); + RtlInitUnicodeString(&DosDevice, Buffer); + + /* Allocate the input buffer for the MountMgr */ + InputBufferLength = DosDevice.Length + DeviceName->Length + sizeof(MOUNTMGR_CREATE_POINT_INPUT); + InputBuffer = ExAllocatePoolWithTag(PagedPool, InputBufferLength, TAG_FSTUB); + if (InputBuffer == NULL) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Fill the input buffer */ + InputBuffer->SymbolicLinkNameOffset = sizeof(MOUNTMGR_CREATE_POINT_INPUT); + InputBuffer->SymbolicLinkNameLength = DosDevice.Length; + InputBuffer->DeviceNameOffset = DosDevice.Length + sizeof(MOUNTMGR_CREATE_POINT_INPUT); + InputBuffer->DeviceNameLength = DeviceName->Length; + RtlCopyMemory(&InputBuffer[1], DosDevice.Buffer, DosDevice.Length); + RtlCopyMemory((PVOID)((ULONG_PTR)InputBuffer + InputBuffer->DeviceNameOffset), + DeviceName->Buffer, + DeviceName->Length); + + /* Get the MountMgr device pointer, to send the IOCTL */ + RtlInitUnicodeString(&MountMgr, L"\\Device\\MountPointManager"); + Status = IoGetDeviceObjectPointer(&MountMgr, + FILE_READ_ATTRIBUTES, + &FileObject, + &DeviceObject); + if (!NT_SUCCESS(Status)) + { + ExFreePoolWithTag(InputBuffer, TAG_FSTUB); + return Status; + } + + /* Call the MountMgr */ + KeInitializeEvent(&Event, NotificationEvent, FALSE); + Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_CREATE_POINT, + DeviceObject, + InputBuffer, + InputBufferLength, + NULL, + 0, + FALSE, + &Event, + &IoStatusBlock); + if (Irp == NULL) + { + ObDereferenceObject(FileObject); + ExFreePoolWithTag(InputBuffer, TAG_FSTUB); + return STATUS_INSUFFICIENT_RESOURCES; + } + + Status = IoCallDriver(DeviceObject, Irp); + if (Status == STATUS_PENDING) + { + KeWaitForSingleObject(&Event, + Executive, + KernelMode, + FALSE, + NULL); + Status = IoStatusBlock.Status; + } + + ObDereferenceObject(FileObject); + ExFreePoolWithTag(InputBuffer, TAG_FSTUB); + + /* Return the MountMgr status */ + return Status; +} + +UCHAR +HalpNextDriveLetter(IN PUNICODE_STRING DeviceName, + IN PSTRING NtDeviceName, + OUT PUCHAR NtSystemPath, + BOOLEAN IsRemovable) +{ + UCHAR i; + WCHAR Buffer[40]; + UCHAR DriveLetter; + UNICODE_STRING FloppyString, CdString, NtDeviceNameU, DosDevice; + + /* Quick path, ask directly the mount manager to assign the next + * free drive letter + */ + if (NT_SUCCESS(HalpNextMountLetter(DeviceName, &DriveLetter))) + { + return DriveLetter; + } + + /* We'll allow MountMgr to fail only for non vital path */ + if (NtDeviceName == NULL || NtSystemPath == NULL) + { + return -1; + } + + /* And for removable devices */ + if (!IsRemovable) + { + return 0; + } + + /* Removable might be floppy or cdrom */ + RtlInitUnicodeString(&FloppyString, L"\\Device\\Floppy"); + RtlInitUnicodeString(&CdString, L"\\Device\\CdRom"); + + /* If floppy, start at A */ + if (RtlPrefixUnicodeString(&FloppyString, DeviceName, TRUE)) + { + DriveLetter = 'A'; + } + /* If CD start C */ + else if (RtlPrefixUnicodeString(&CdString, DeviceName, TRUE)) + { + DriveLetter = 'D'; + } + /* For the rest start at C */ else { - /* Read the partition table */ - Status = IoReadPartitionTable(DeviceObject, - DiskGeometry.BytesPerSector, - TRUE, - LayoutInfo); + DriveLetter = 'C'; + } + + /* Now, try to assign a drive letter manually with the MountMgr */ + for (i = DriveLetter; i <= 'Z'; ++i) + { + if (NT_SUCCESS(HalpSetMountLetter(DeviceName, i))) + { + /* If it worked, if we were managing system path, update manually */ + if (NT_SUCCESS(RtlAnsiStringToUnicodeString(&NtDeviceNameU, NtDeviceName, TRUE))) + { + if (RtlEqualUnicodeString(&NtDeviceNameU, DeviceName, TRUE)) + { + *NtSystemPath = i; + } + + RtlFreeUnicodeString(&NtDeviceNameU); + } + + return i; + } + } + + /* Last fall back, we're not on a PnP device... */ + for (i = DriveLetter; i <= 'Z'; ++i) + { + /* We'll link manually, without MountMgr knowing anything about the device */ + swprintf(Buffer, L"\\DosDevices\\%c:", i); + RtlInitUnicodeString(&DosDevice, Buffer); + + /* If linking worked, then the letter was free ;-) */ + if (NT_SUCCESS(IoCreateSymbolicLink(&DosDevice, DeviceName))) + { + /* If it worked, if we were managing system path, update manually */ + if (NT_SUCCESS(RtlAnsiStringToUnicodeString(&NtDeviceNameU, NtDeviceName, TRUE))) + { + if (RtlEqualUnicodeString(&NtDeviceNameU, DeviceName, TRUE)) + { + *NtSystemPath = i; + } + + RtlFreeUnicodeString(&NtDeviceNameU); + } + + return i; + } + } + + /* We're done, nothing happened */ + return 0; +} + +BOOLEAN +HalpIsOldStyleFloppy(PUNICODE_STRING DeviceName) +{ + PIRP Irp; + KEVENT Event; + NTSTATUS Status; + MOUNTDEV_NAME DevName; + PFILE_OBJECT FileObject; + PDEVICE_OBJECT DeviceObject; + IO_STATUS_BLOCK IoStatusBlock; + PAGED_CODE(); + + /* Get the attached device object to our device */ + if (!NT_SUCCESS(IoGetDeviceObjectPointer(DeviceName, + FILE_READ_ATTRIBUTES, + &FileObject, + &DeviceObject))) + { + return FALSE; + } + + DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject); + ObDereferenceObject(FileObject); + + /* Query its device name (ie, check floppy.sys implements MountMgr interface) */ + KeInitializeEvent(&Event, NotificationEvent, FALSE); + Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, + DeviceObject, + NULL, + 0, + &DevName, + sizeof(DevName), + FALSE, + &Event, + &IoStatusBlock); + if (Irp == NULL) + { + ObDereferenceObject(DeviceObject); + return FALSE; + } + + Status = IoCallDriver(DeviceObject, Irp); + if (Status == STATUS_PENDING) + { + KeWaitForSingleObject(&Event, + Executive, + KernelMode, + FALSE, + NULL); + Status = IoStatusBlock.Status; + } + + /* If status is not STATUS_BUFFER_OVERFLOW, it means + * it's pre-mountmgr driver, aka "Old style". + */ + ObDereferenceObject(DeviceObject); + return (Status != STATUS_BUFFER_OVERFLOW); +} + +NTSTATUS +HalpDeleteMountLetter(UCHAR DriveLetter) +{ + PIRP Irp; + KEVENT Event; + NTSTATUS Status; + WCHAR Buffer[30]; + ULONG InputBufferLength; + PFILE_OBJECT FileObject; + PDEVICE_OBJECT DeviceObject; + IO_STATUS_BLOCK IoStatusBlock; + PMOUNTMGR_MOUNT_POINT InputBuffer; + UNICODE_STRING DosDevice, MountMgr; + PMOUNTMGR_MOUNT_POINTS OutputBuffer; + + /* Setup the device name of the letter to delete */ + swprintf(Buffer, L"\\DosDevices\\%c:", DriveLetter); + RtlInitUnicodeString(&DosDevice, Buffer); + + /* Allocate the input buffer for MountMgr */ + InputBufferLength = DosDevice.Length + sizeof(MOUNTMGR_MOUNT_POINT); + InputBuffer = ExAllocatePoolWithTag(PagedPool, InputBufferLength, TAG_FSTUB); + if (InputBuffer == NULL) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Fill it in */ + RtlZeroMemory(InputBuffer, InputBufferLength); + InputBuffer->SymbolicLinkNameOffset = sizeof(MOUNTMGR_MOUNT_POINT); + InputBuffer->SymbolicLinkNameLength = DosDevice.Length; + RtlCopyMemory(&InputBuffer[1], DosDevice.Buffer, DosDevice.Length); + + /* Allocate big enough output buffer (we don't care about the output) */ + OutputBuffer = ExAllocatePoolWithTag(PagedPool, 0x1000, TAG_FSTUB); + if (OutputBuffer == NULL) + { + ExFreePoolWithTag(InputBuffer, TAG_FSTUB); + return STATUS_INSUFFICIENT_RESOURCES; + } + + /* Get the device pointer to the MountMgr */ + RtlInitUnicodeString(&MountMgr, L"\\Device\\MountPointManager"); + Status = IoGetDeviceObjectPointer(&MountMgr, + FILE_READ_ATTRIBUTES, + &FileObject, + &DeviceObject); + if (!NT_SUCCESS(Status)) + { + ExFreePoolWithTag(OutputBuffer, TAG_FSTUB); + ExFreePoolWithTag(InputBuffer, TAG_FSTUB); + return Status; + } + + /* Call the mount manager to delete the drive letter */ + KeInitializeEvent(&Event, NotificationEvent, FALSE); + Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_DELETE_POINTS, + DeviceObject, + InputBuffer, + InputBufferLength, + OutputBuffer, + 0x1000, + FALSE, + &Event, + &IoStatusBlock); + if (Irp == NULL) + { + ObDereferenceObject(FileObject); + ExFreePoolWithTag(OutputBuffer, TAG_FSTUB); + ExFreePoolWithTag(InputBuffer, TAG_FSTUB); + return STATUS_INSUFFICIENT_RESOURCES; + } + + Status = IoCallDriver(DeviceObject, Irp); + if (Status == STATUS_PENDING) + { + KeWaitForSingleObject(&Event, + Executive, + KernelMode, + FALSE, + NULL); + Status = IoStatusBlock.Status; + } + + ObDereferenceObject(FileObject); + ExFreePoolWithTag(OutputBuffer, TAG_FSTUB); + ExFreePoolWithTag(InputBuffer, TAG_FSTUB); + + return Status; +} + +VOID +HalpEnableAutomaticDriveLetterAssignment(VOID) +{ + PIRP Irp; + KEVENT Event; + NTSTATUS Status; + UNICODE_STRING MountMgr; + PFILE_OBJECT FileObject; + PDEVICE_OBJECT DeviceObject; + IO_STATUS_BLOCK IoStatusBlock; + + /* Get the device pointer to the MountMgr */ + RtlInitUnicodeString(&MountMgr, L"\\Device\\MountPointManager"); + Status = IoGetDeviceObjectPointer(&MountMgr, + FILE_READ_ATTRIBUTES, + &FileObject, + &DeviceObject); + if (!NT_SUCCESS(Status)) + { + return; + } + + /* Just send an IOCTL to enable the feature */ + KeInitializeEvent(&Event, NotificationEvent, FALSE); + Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_AUTO_DL_ASSIGNMENTS, + DeviceObject, + NULL, + 0, + NULL, + 0, + FALSE, + &Event, + &IoStatusBlock); + if (Irp == NULL) + { + return; + } + + Status = IoCallDriver(DeviceObject, Irp); + if (Status == STATUS_PENDING) + { + KeWaitForSingleObject(&Event, + Executive, + KernelMode, + FALSE, + NULL); + Status = IoStatusBlock.Status; } ObDereferenceObject(FileObject); - return(Status); + return; } VOID @@ -417,532 +914,474 @@ xHalIoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock, OUT PUCHAR NtSystemPath, OUT PSTRING NtSystemPathString) { - PDRIVE_LAYOUT_INFORMATION *LayoutArray; - PCONFIGURATION_INFORMATION ConfigInfo; - OBJECT_ATTRIBUTES ObjectAttributes; - IO_STATUS_BLOCK StatusBlock; - UNICODE_STRING UnicodeString1; - UNICODE_STRING UnicodeString2; - HANDLE FileHandle; - PWSTR Buffer1; - PWSTR Buffer2; - ULONG i, j, k; - ULONG DiskNumber; - ULONG RDisk; + USHORT i; + PULONG Devices; NTSTATUS Status; - HANDLE hKey; - ULONG Length; - PKEY_VALUE_PARTIAL_INFORMATION PartialInformation; - PREG_DISK_MOUNT_INFO DiskMountInfo; - ULONG RDiskCount; - UNICODE_STRING BootDevice; + WCHAR Buffer[50]; + HANDLE FileHandle; + UCHAR DriveLetter; + BOOLEAN SystemFound; + IO_STATUS_BLOCK StatusBlock; + PARTITION_TYPE PartitionType; + ANSI_STRING StringA1, StringA2; + PSTR Buffer1, Buffer2, LoadOptions; + OBJECT_ATTRIBUTES ObjectAttributes; + PDRIVE_LAYOUT_INFORMATION LayoutInfo; + PCONFIGURATION_INFORMATION ConfigInfo; + UNICODE_STRING StringU1, StringU2, StringU3; + ULONG Increment, DiskCount, RealDiskCount, HarddiskCount, PartitionCount, SystemPartition; - Status = RtlAnsiStringToUnicodeString(&BootDevice, - NtDeviceName, - TRUE); - - DPRINT("xHalIoAssignDriveLetters()\n"); + PAGED_CODE(); + /* Get our disk count */ ConfigInfo = IoGetConfigurationInformation(); + DiskCount = ConfigInfo->DiskCount; + RealDiskCount = 0; - RDiskCount = xHalpGetRDiskCount(); - - DPRINT("RDiskCount %lu\n", RDiskCount); - - Buffer1 = ExAllocatePoolWithTag(PagedPool, - 64 * sizeof(WCHAR), - TAG_FILE_SYSTEM); - if (!Buffer1) return; - - Buffer2 = ExAllocatePoolWithTag(PagedPool, - 32 * sizeof(WCHAR), - TAG_FILE_SYSTEM); - if (!Buffer2) + /* Allocate two generic string buffers we'll use and reuser later on */ + Buffer1 = ExAllocatePoolWithTag(NonPagedPool, 128, TAG_FSTUB); + Buffer2 = ExAllocatePoolWithTag(NonPagedPool, 64, TAG_FSTUB); + if (Buffer1 == NULL || Buffer2 == NULL) { - ExFreePoolWithTag(Buffer1, TAG_FILE_SYSTEM); - return; + KeBugCheck(ASSIGN_DRIVE_LETTERS_FAILED); } - PartialInformation = ExAllocatePoolWithTag(PagedPool, - sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(REG_DISK_MOUNT_INFO), - TAG_FILE_SYSTEM); - if (!PartialInformation) + /* In case of a remote boot, setup system path */ + if (IoRemoteBootClient) { - ExFreePoolWithTag(Buffer2, TAG_FILE_SYSTEM); - ExFreePoolWithTag(Buffer1, TAG_FILE_SYSTEM); - return; - } + PSTR Last, Saved; - DiskMountInfo = (PREG_DISK_MOUNT_INFO) PartialInformation->Data; - - /* Create or open the 'MountedDevices' key */ - RtlInitUnicodeString(&UnicodeString1, L"\\Registry\\Machine\\SYSTEM\\MountedDevices"); - InitializeObjectAttributes(&ObjectAttributes, - &UnicodeString1, - OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, - NULL, - NULL); - Status = ZwCreateKey(&hKey, - KEY_ALL_ACCESS, - &ObjectAttributes, - 0, - NULL, - REG_OPTION_NON_VOLATILE, - NULL); - if (!NT_SUCCESS(Status)) - { - hKey = NULL; - DPRINT("ZwCreateKey failed for %wZ, status=%x\n", &UnicodeString1, Status); - } - - /* Create PhysicalDrive links */ - DPRINT("Physical disk drives: %lu\n", ConfigInfo->DiskCount); - for (i = 0; i < ConfigInfo->DiskCount; i++) - { - swprintf(Buffer1, L"\\Device\\Harddisk%lu\\Partition0", i); - RtlInitUnicodeString(&UnicodeString1, Buffer1); - - InitializeObjectAttributes(&ObjectAttributes, - &UnicodeString1, - 0, - NULL, - NULL); - - Status = ZwOpenFile(&FileHandle, - FILE_READ_DATA | SYNCHRONIZE, - &ObjectAttributes, - &StatusBlock, - FILE_SHARE_READ, - FILE_SYNCHRONOUS_IO_NONALERT); - if (NT_SUCCESS(Status)) + /* Find last \ */ + Last = strrchr(LoaderBlock->NtBootPathName, '\\'); + Saved = NULL; + /* Misformed name, fail */ + if (Last == NULL) { - ZwClose(FileHandle); - - swprintf(Buffer2, L"\\??\\PhysicalDrive%lu", i); - RtlInitUnicodeString(&UnicodeString2, Buffer2); - - DPRINT("Creating link: %S ==> %S\n", - Buffer2, - Buffer1); - - IoCreateSymbolicLink(&UnicodeString2, - &UnicodeString1); + KeBugCheck(ASSIGN_DRIVE_LETTERS_FAILED); } - } - /* Initialize layout array */ - if (ConfigInfo->DiskCount == 0) - goto end_assign_disks; - LayoutArray = ExAllocatePoolWithTag(NonPagedPool, - ConfigInfo->DiskCount * sizeof(PDRIVE_LAYOUT_INFORMATION), TAG_FILE_SYSTEM); - if (!LayoutArray) - { - ExFreePoolWithTag(PartialInformation, TAG_FILE_SYSTEM); - ExFreePoolWithTag(Buffer2, TAG_FILE_SYSTEM); - ExFreePoolWithTag(Buffer1, TAG_FILE_SYSTEM); - if (hKey) ObCloseHandle(hKey, KernelMode); - return; - } - - RtlZeroMemory(LayoutArray, - ConfigInfo->DiskCount * sizeof(PDRIVE_LAYOUT_INFORMATION)); - for (i = 0; i < ConfigInfo->DiskCount; i++) - { - swprintf(Buffer1, L"\\Device\\Harddisk%lu\\Partition0", i); - RtlInitUnicodeString(&UnicodeString1, Buffer1); - - Status = xHalQueryDriveLayout(&UnicodeString1, &LayoutArray[i]); - if (!NT_SUCCESS(Status)) + /* In case the name was terminated by a \... */ + if (Last[1] == ANSI_NULL) { - DbgPrint("xHalQueryDriveLayout() failed (Status = 0x%lx)\n", - Status); - LayoutArray[i] = NULL; - continue; + /* Erase it, save position and find the previous \ */ + *Last = ANSI_NULL; + Saved = Last; + Last = strrchr(LoaderBlock->NtBootPathName, '\\'); + *Saved = '\\'; } - /* We don't use the RewritePartition value while mounting the disks. - * We use this value for marking pre-assigned (registry) partitions. - */ - for (j = 0; j < LayoutArray[i]->PartitionCount; j++) + + /* Misformed name, fail */ + if (Last == NULL) { - LayoutArray[i]->PartitionEntry[j].RewritePartition = FALSE; + KeBugCheck(ASSIGN_DRIVE_LETTERS_FAILED); } + + /* For a remote boot, assign X drive letter */ + NtSystemPath[0] = 'X'; + NtSystemPath[1] = ':'; + /* And copy the end of the boot path */ + strcpy((PSTR)&NtSystemPath[2], Last); + + /* If we had to remove the trailing \, remove it here too */ + if (Saved != NULL) + { + NtSystemPath[strlen((PSTR)NtSystemPath) - 1] = ANSI_NULL; + } + + /* Setup output string */ + RtlInitString(NtSystemPathString, (PSTR)NtSystemPath); } -#ifndef NDEBUG - /* Dump layout array */ - for (i = 0; i < ConfigInfo->DiskCount; i++) + /* For each of our disks, create the physical device DOS device */ + Increment = 0; + if (DiskCount != 0) { - DPRINT("Harddisk %d:\n", - i); - - if (LayoutArray[i] == NULL) - continue; - - DPRINT("Logical partitions: %d\n", - LayoutArray[i]->PartitionCount); - - for (j = 0; j < LayoutArray[i]->PartitionCount; j++) + for (i = 0; i < DiskCount; ++i) { - DPRINT(" %d: nr:%x boot:%x type:%x startblock:%I64u count:%I64u\n", - j, - LayoutArray[i]->PartitionEntry[j].PartitionNumber, - LayoutArray[i]->PartitionEntry[j].BootIndicator, - LayoutArray[i]->PartitionEntry[j].PartitionType, - LayoutArray[i]->PartitionEntry[j].StartingOffset.QuadPart, - LayoutArray[i]->PartitionEntry[j].PartitionLength.QuadPart); - } - } -#endif - - /* Assign pre-assigned (registry) partitions */ - if (hKey) - { - for (k = 2; k < 26; k++) - { - swprintf(Buffer1, DiskMountString, L'A' + k); - RtlInitUnicodeString(&UnicodeString1, Buffer1); - Status = ZwQueryValueKey(hKey, - &UnicodeString1, - KeyValuePartialInformation, - PartialInformation, - sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(REG_DISK_MOUNT_INFO), - &Length); - if (NT_SUCCESS(Status) && - PartialInformation->Type == REG_BINARY && - PartialInformation->DataLength == sizeof(REG_DISK_MOUNT_INFO)) + /* Setup the origin name */ + sprintf(Buffer1, "\\Device\\Harddisk%d\\Partition%d", i, 0); + RtlInitAnsiString(&StringA1, Buffer1); + if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&StringU1, &StringA1, TRUE))) { - DPRINT("%wZ => %08x:%08x%08x\n", &UnicodeString1, DiskMountInfo->Signature, - DiskMountInfo->StartingOffset.u.HighPart, DiskMountInfo->StartingOffset.u.LowPart); - { - BOOLEAN Found = FALSE; - for (i = 0; i < ConfigInfo->DiskCount; i++) - { - DPRINT("%x\n", LayoutArray[i]->Signature); - if (LayoutArray[i] && - LayoutArray[i]->Signature && - LayoutArray[i]->Signature == DiskMountInfo->Signature) - { - for (j = 0; j < LayoutArray[i]->PartitionCount; j++) - { - if (LayoutArray[i]->PartitionEntry[j].StartingOffset.QuadPart == DiskMountInfo->StartingOffset.QuadPart) - { - if (IsRecognizedPartition(LayoutArray[i]->PartitionEntry[j].PartitionType) && - LayoutArray[i]->PartitionEntry[j].RewritePartition == FALSE) - { - swprintf(Buffer2, - L"\\Device\\Harddisk%lu\\Partition%lu", - i, - LayoutArray[i]->PartitionEntry[j].PartitionNumber); - RtlInitUnicodeString(&UnicodeString2, Buffer2); + /* We cannot fail */ + KeBugCheck(ASSIGN_DRIVE_LETTERS_FAILED); + } - /* Assign drive */ - DPRINT(" %wZ\n", &UnicodeString2); - Found = HalpAssignDrive(&UnicodeString2, - k, - DOSDEVICE_DRIVE_FIXED, - DiskMountInfo->Signature, - DiskMountInfo->StartingOffset, - NULL, - &BootDevice, - NtSystemPath); - /* Mark the partition as assigned */ - LayoutArray[i]->PartitionEntry[j].RewritePartition = TRUE; - } - break; - } - } - } - } - if (Found == FALSE) - { - /* We didn't find a partition for this entry, remove them. */ - Status = ZwDeleteValueKey(hKey, &UnicodeString1); - } + /* Open the device */ + InitializeObjectAttributes(&ObjectAttributes, + &StringU1, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + Status = ZwOpenFile(&FileHandle, + SYNCHRONIZE | FILE_READ_DATA, + &ObjectAttributes, + &StatusBlock, + FILE_SHARE_READ, + FILE_SYNCHRONOUS_IO_NONALERT); + if (NT_SUCCESS(Status)) + { + /* If we managed, create the link */ + sprintf(Buffer2, "\\DosDevices\\PhysicalDrive%d", i); + RtlInitAnsiString(&StringA2, Buffer2); + Status = RtlAnsiStringToUnicodeString(&StringU2, &StringA2, TRUE); + if (NT_SUCCESS(Status)) + { + IoCreateSymbolicLink(&StringU2, &StringU1); + RtlFreeUnicodeString(&StringU2); + } + + ZwClose(FileHandle); + + RealDiskCount = i + 1; + } + + RtlFreeUnicodeString(&StringU1); + + if (!NT_SUCCESS(Status)) + { + if (Increment < 50) + { + ++Increment; + ++DiskCount; } } } } - /* Assign bootable partition on first harddisk */ - DPRINT("Assigning bootable primary partition on first harddisk:\n"); - if (RDiskCount > 0) - { - Status = xHalpGetDiskNumberFromRDisk(0, &DiskNumber); - if (NT_SUCCESS(Status) && - DiskNumber < ConfigInfo->DiskCount && - LayoutArray[DiskNumber]) - { - /* Search for bootable partition */ - for (j = 0; j < NUM_PARTITION_TABLE_ENTRIES && j < LayoutArray[DiskNumber]->PartitionCount; j++) - { - if ((LayoutArray[DiskNumber]->PartitionEntry[j].BootIndicator != FALSE) && - IsRecognizedPartition(LayoutArray[DiskNumber]->PartitionEntry[j].PartitionType)) - { - if (LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition == FALSE) - { - swprintf(Buffer2, - L"\\Device\\Harddisk%lu\\Partition%lu", - DiskNumber, - LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber); - RtlInitUnicodeString(&UnicodeString2, Buffer2); + /* We done for our buffers */ + ExFreePoolWithTag(Buffer1, TAG_FSTUB); + ExFreePoolWithTag(Buffer2, TAG_FSTUB); - /* Assign drive */ - DPRINT(" %wZ\n", &UnicodeString2); - HalpAssignDrive(&UnicodeString2, - AUTO_DRIVE, - DOSDEVICE_DRIVE_FIXED, - LayoutArray[DiskNumber]->Signature, - LayoutArray[DiskNumber]->PartitionEntry[j].StartingOffset, - hKey, - &BootDevice, - NtSystemPath); - /* Mark the partition as assigned */ - LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition = TRUE; - } + /* Upcase our load options, if any */ + if (LoaderBlock->LoadOptions != NULL) + { + LoadOptions = _strupr(LoaderBlock->LoadOptions); + } + else + { + LoadOptions = NULL; + } + + /* If we boot with /MININT (system hive as volatile) option, assign X letter to boot device */ + if (LoadOptions != NULL && + strstr(LoadOptions, "MININT") != 0 && + NT_SUCCESS(RtlAnsiStringToUnicodeString(&StringU1, NtDeviceName, TRUE))) + { + if (NT_SUCCESS(HalpSetMountLetter(&StringU1, 'X'))) + { + *NtSystemPath = 'X'; + } + + RtlFreeUnicodeString(&StringU1); + } + + /* Compute our disks derangements */ + DiskCount -= Increment; + if (RealDiskCount > DiskCount) + { + DiskCount = RealDiskCount; + } + Devices = IopComputeHarddiskDerangements(DiskCount); + + /* Now, start browsing all our disks for assigning drive letters + * Here, we'll only handle boot partition and primary partitions + */ + HarddiskCount = 0; + for (i = 0; i < DiskCount; ++i) + { + /* Get device ID according to derangements map */ + if (Devices != NULL) + { + HarddiskCount = Devices[i]; + } + + /* Query disk layout */ + swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition0", HarddiskCount); + RtlInitUnicodeString(&StringU1, Buffer); + if (!NT_SUCCESS(HalpQueryDriveLayout(&StringU1, &LayoutInfo))) + { + LayoutInfo = NULL; + } + + /* Assume we didn't find system */ + SystemFound = FALSE; + swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition%d", HarddiskCount, 1); + RtlInitUnicodeString(&StringU1, Buffer); + /* Query partition info for our disk */ + if (!NT_SUCCESS(HalpQueryPartitionType(&StringU1, LayoutInfo, &PartitionType))) + { + /* It failed, retry for all the partitions */ + for (PartitionCount = 1; ; ++PartitionCount) + { + swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition%d", HarddiskCount, PartitionCount); + RtlInitUnicodeString(&StringU1, Buffer); + if (!NT_SUCCESS(HalpQueryPartitionType(&StringU1, LayoutInfo, &PartitionType))) + { + break; + } + + /* We found a primary partition, assign a drive letter */ + if (PartitionType == PrimaryPartition) + { + HalpNextDriveLetter(&StringU1, NtDeviceName, NtSystemPath, 0); break; } } } + else + { + /* All right */ + for (PartitionCount = 2; ; ++PartitionCount) + { + /* If our partition is bootable (MBR) or data (GPT), that's system partition */ + if (PartitionType == BootablePartition || PartitionType == DataPartition) + { + SystemFound = TRUE; + + /* Assign a drive letter and stop here if MBR */ + HalpNextDriveLetter(&StringU1, NtDeviceName, NtSystemPath, 0); + if (PartitionType == BootablePartition) + { + break; + } + } + + /* Keep looping on all the partitions */ + swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition%d", HarddiskCount, PartitionCount); + RtlInitUnicodeString(&StringU1, Buffer); + if (!NT_SUCCESS(HalpQueryPartitionType(&StringU1, LayoutInfo, &PartitionType))) + { + /* Mount every primary partition if we didn't find system */ + if (!SystemFound) + { + for (PartitionCount = 1; ; ++PartitionCount) + { + swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition%d", HarddiskCount, PartitionCount); + RtlInitUnicodeString(&StringU1, Buffer); + if (!NT_SUCCESS(HalpQueryPartitionType(&StringU1, LayoutInfo, &PartitionType))) + { + break; + } + + if (PartitionType == PrimaryPartition) + { + HalpNextDriveLetter(&StringU1, NtDeviceName, NtSystemPath, 0); + break; + } + } + } + + break; + } + } + } + + /* Free layout, we'll reallocate it for next device */ + if (LayoutInfo != NULL) + { + ExFreePoolWithTag(LayoutInfo, TAG_FSTUB); + } + + HarddiskCount = i + 1; } - /* Assign remaining primary partitions */ - DPRINT("Assigning remaining primary partitions:\n"); - for (RDisk = 0; RDisk < RDiskCount; RDisk++) + /* Now, assign logical partitions */ + for (i = 0; i < DiskCount; ++i) { - Status = xHalpGetDiskNumberFromRDisk(RDisk, &DiskNumber); - if (NT_SUCCESS(Status) && - DiskNumber < ConfigInfo->DiskCount && - LayoutArray[DiskNumber]) + /* Get device ID according to derangements map */ + if (Devices != NULL) { - /* Search for primary partitions */ - for (j = 0; (j < NUM_PARTITION_TABLE_ENTRIES) && (j < LayoutArray[DiskNumber]->PartitionCount); j++) - { - if (LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition == FALSE && - IsRecognizedPartition(LayoutArray[DiskNumber]->PartitionEntry[j].PartitionType)) - { - swprintf(Buffer2, - L"\\Device\\Harddisk%lu\\Partition%lu", - DiskNumber, - LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber); - RtlInitUnicodeString(&UnicodeString2, Buffer2); + HarddiskCount = Devices[i]; + } + else + { + HarddiskCount = i; + } - /* Assign drive */ - DPRINT(" %wZ\n", - &UnicodeString2); - HalpAssignDrive(&UnicodeString2, - AUTO_DRIVE, - DOSDEVICE_DRIVE_FIXED, - LayoutArray[DiskNumber]->Signature, - LayoutArray[DiskNumber]->PartitionEntry[j].StartingOffset, - hKey, - &BootDevice, - NtSystemPath); - /* Mark the partition as assigned */ - LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition = TRUE; + /* Query device layout */ + swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition0", HarddiskCount); + RtlInitUnicodeString(&StringU1, Buffer); + if (!NT_SUCCESS(HalpQueryDriveLayout(&StringU1, &LayoutInfo))) + { + LayoutInfo = NULL; + } + + /* And assign drive letter to logical partitions */ + for (PartitionCount = 1; ; ++PartitionCount) + { + swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition%d", HarddiskCount, PartitionCount); + RtlInitUnicodeString(&StringU1, Buffer); + if (!NT_SUCCESS(HalpQueryPartitionType(&StringU1, LayoutInfo, &PartitionType))) + { + break; + } + + if (PartitionType == LogicalPartition) + { + HalpNextDriveLetter(&StringU1, NtDeviceName, NtSystemPath, 0); + } + } + + /* Free layout, we'll reallocate it for next device */ + if (LayoutInfo != NULL) + { + ExFreePoolWithTag(LayoutInfo, 0); + } + } + + /* Now, assign drive letters to everything else */ + for (i = 0; i < DiskCount; ++i) + { + /* Get device ID according to derangements map */ + if (Devices != NULL) + { + HarddiskCount = Devices[i]; + } + else + { + HarddiskCount = i; + } + + /* Query device layout */ + swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition0", HarddiskCount); + RtlInitUnicodeString(&StringU1, Buffer); + if (!NT_SUCCESS(HalpQueryDriveLayout(&StringU1, &LayoutInfo))) + { + LayoutInfo = NULL; + } + + /* Save system partition if any */ + SystemPartition = 0; + for (PartitionCount = 1; ; ++PartitionCount) + { + swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition%d", HarddiskCount, PartitionCount); + RtlInitUnicodeString(&StringU1, Buffer); + if (!NT_SUCCESS(HalpQueryPartitionType(&StringU1, LayoutInfo, &PartitionType))) + { + break; + } + + if ((PartitionType == BootablePartition || PartitionType == PrimaryPartition) && (SystemPartition == 0)) + { + SystemPartition = PartitionCount; + } + } + + /* And assign drive letter to anything but system partition */ + for (PartitionCount = 1; ; ++PartitionCount) + { + if (PartitionCount != SystemPartition) + { + swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition%d", HarddiskCount, PartitionCount); + RtlInitUnicodeString(&StringU1, Buffer); + if (!NT_SUCCESS(HalpQueryPartitionType(&StringU1, LayoutInfo, &PartitionType))) + { + if (LayoutInfo != NULL) + { + ExFreePoolWithTag(LayoutInfo, 0); + } + + break; + } + + if (PartitionType == PrimaryPartition || PartitionType == FtPartition) + { + HalpNextDriveLetter(&StringU1, NtDeviceName, NtSystemPath, 0); } } } } - /* Assign extended (logical) partitions */ - DPRINT("Assigning extended (logical) partitions:\n"); - for (RDisk = 0; RDisk < RDiskCount; RDisk++) + /* We're done with disks, if we have a device map, free it */ + if (Devices != NULL) { - Status = xHalpGetDiskNumberFromRDisk(RDisk, &DiskNumber); - if (NT_SUCCESS(Status) && - DiskNumber < ConfigInfo->DiskCount && - LayoutArray[DiskNumber]) - { - /* Search for extended partitions */ - for (j = NUM_PARTITION_TABLE_ENTRIES; j < LayoutArray[DiskNumber]->PartitionCount; j++) - { - if (IsRecognizedPartition(LayoutArray[DiskNumber]->PartitionEntry[j].PartitionType) && - LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition == FALSE && - LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber != 0) - { - swprintf(Buffer2, - L"\\Device\\Harddisk%lu\\Partition%lu", - DiskNumber, - LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber); - RtlInitUnicodeString(&UnicodeString2, Buffer2); + ExFreePoolWithTag(Devices, TAG_FSTUB); + } - /* Assign drive */ - DPRINT(" %wZ\n", - &UnicodeString2); - HalpAssignDrive(&UnicodeString2, - AUTO_DRIVE, - DOSDEVICE_DRIVE_FIXED, - LayoutArray[DiskNumber]->Signature, - LayoutArray[DiskNumber]->PartitionEntry[j].StartingOffset, - hKey, - &BootDevice, - NtSystemPath); - /* Mark the partition as assigned */ - LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition = TRUE; + /* Now, assign drive letter to floppy drives */ + for (i = 0; i < ConfigInfo->FloppyCount; ++i) + { + swprintf(Buffer, L"\\Device\\Floppy%d", i); + RtlInitUnicodeString(&StringU1, Buffer); + if (HalpIsOldStyleFloppy(&StringU1)) + { + HalpNextDriveLetter(&StringU1, NtDeviceName, NtSystemPath, TRUE); + } + } + + /* And CD drives */ + for (i = 0; i < ConfigInfo->CdRomCount; ++i) + { + swprintf(Buffer, L"\\Device\\CdRom%d", i); + RtlInitUnicodeString(&StringU1, Buffer); + HalpNextDriveLetter(&StringU1, NtDeviceName, NtSystemPath, TRUE); + } + + /* If not remote boot, handle NtDeviceName */ + if (!IoRemoteBootClient && NT_SUCCESS(RtlAnsiStringToUnicodeString(&StringU1, NtDeviceName, TRUE))) + { + /* Assign it a drive letter */ + DriveLetter = HalpNextDriveLetter(&StringU1, NULL, NULL, TRUE); + if (DriveLetter != 0) + { + if (DriveLetter != 0xFF) + { + *NtSystemPath = DriveLetter; + } + } + /* If it fails through mount manager, retry manually */ + else + { + RtlInitUnicodeString(&StringU2, L"\\Device\\Floppy"); + RtlInitUnicodeString(&StringU3, L"\\Device\\CdRom"); + + if (RtlPrefixUnicodeString(&StringU2, &StringU1, TRUE)) + { + DriveLetter = 'A'; + } + else if (RtlPrefixUnicodeString(&StringU3, &StringU1, TRUE)) + { + DriveLetter = 'D'; + } + else + { + DriveLetter = 'C'; + } + + /* Try any drive letter */ + while (HalpSetMountLetter(&StringU1, DriveLetter) != STATUS_SUCCESS) + { + ++DriveLetter; + + if (DriveLetter > 'Z') + { + break; } } - } - } - /* Assign remaining primary partitions without an arc-name */ - DPRINT("Assigning remaining primary partitions:\n"); - for (DiskNumber = 0; DiskNumber < ConfigInfo->DiskCount; DiskNumber++) - { - if (LayoutArray[DiskNumber]) - { - /* Search for primary partitions */ - for (j = 0; (j < NUM_PARTITION_TABLE_ENTRIES) && (j < LayoutArray[DiskNumber]->PartitionCount); j++) + /* If we're beyond Z (ie, no slot left) */ + if (DriveLetter > 'Z') { - if (LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition == FALSE && - IsRecognizedPartition(LayoutArray[DiskNumber]->PartitionEntry[j].PartitionType)) - { - swprintf(Buffer2, - L"\\Device\\Harddisk%lu\\Partition%lu", - DiskNumber, - LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber); - RtlInitUnicodeString(&UnicodeString2, Buffer2); - - /* Assign drive */ - DPRINT(" %wZ\n", - &UnicodeString2); - HalpAssignDrive(&UnicodeString2, - AUTO_DRIVE, - DOSDEVICE_DRIVE_FIXED, - LayoutArray[DiskNumber]->Signature, - LayoutArray[DiskNumber]->PartitionEntry[j].StartingOffset, - hKey, - &BootDevice, - NtSystemPath); - /* Mark the partition as assigned */ - LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition = TRUE; - } + /* Delete Z, and reuse it for system */ + HalpDeleteMountLetter('Z'); + HalpSetMountLetter(&StringU1, 'Z'); + *NtSystemPath = 'Z'; + } + else + { + /* Return matching drive letter */ + *NtSystemPath = DriveLetter; } } + + RtlFreeUnicodeString(&StringU1); } - /* Assign extended (logical) partitions without an arc-name */ - DPRINT("Assigning extended (logical) partitions:\n"); - for (DiskNumber = 0; DiskNumber < ConfigInfo->DiskCount; DiskNumber++) - { - if (LayoutArray[DiskNumber]) - { - /* Search for extended partitions */ - for (j = NUM_PARTITION_TABLE_ENTRIES; j < LayoutArray[DiskNumber]->PartitionCount; j++) - { - if (IsRecognizedPartition(LayoutArray[DiskNumber]->PartitionEntry[j].PartitionType) && - LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition == FALSE && - LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber != 0) - { - swprintf(Buffer2, - L"\\Device\\Harddisk%lu\\Partition%lu", - DiskNumber, - LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber); - RtlInitUnicodeString(&UnicodeString2, Buffer2); - - /* Assign drive */ - DPRINT(" %wZ\n", - &UnicodeString2); - HalpAssignDrive(&UnicodeString2, - AUTO_DRIVE, - DOSDEVICE_DRIVE_FIXED, - LayoutArray[DiskNumber]->Signature, - LayoutArray[DiskNumber]->PartitionEntry[j].StartingOffset, - hKey, - &BootDevice, - NtSystemPath); - /* Mark the partition as assigned */ - LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition = TRUE; - } - } - } - } - - /* Assign removable disk drives */ - DPRINT("Assigning removable disk drives:\n"); - for (i = 0; i < ConfigInfo->DiskCount; i++) - { - if (LayoutArray[i]) - { - /* Search for virtual partitions */ - if (LayoutArray[i]->PartitionCount == 1 && - LayoutArray[i]->PartitionEntry[0].PartitionType == 0) - { - swprintf(Buffer2, L"\\Device\\Harddisk%lu\\Partition1", i); - RtlInitUnicodeString(&UnicodeString2, Buffer2); - - /* Assign drive */ - DPRINT(" %wZ\n", - &UnicodeString2); - HalpAssignDrive(&UnicodeString2, - AUTO_DRIVE, - DOSDEVICE_DRIVE_REMOVABLE, - 0, - RtlConvertLongToLargeInteger(0), - hKey, - &BootDevice, - NtSystemPath); - } - } - } - - /* Free layout array */ - for (i = 0; i < ConfigInfo->DiskCount; i++) - { - if (LayoutArray[i] != NULL) - ExFreePoolWithTag(LayoutArray[i], TAG_FILE_SYSTEM); - } - ExFreePoolWithTag(LayoutArray, TAG_FILE_SYSTEM); -end_assign_disks: - - /* Assign floppy drives */ - DPRINT("Floppy drives: %lu\n", ConfigInfo->FloppyCount); - for (i = 0; i < ConfigInfo->FloppyCount; i++) - { - swprintf(Buffer1, L"\\Device\\Floppy%lu", i); - RtlInitUnicodeString(&UnicodeString1, Buffer1); - - /* Assign drive letters A: or B: or first free drive letter */ - DPRINT(" %wZ\n", - &UnicodeString1); - HalpAssignDrive(&UnicodeString1, - (i < 2) ? i : AUTO_DRIVE, - DOSDEVICE_DRIVE_REMOVABLE, - 0, - RtlConvertLongToLargeInteger(0), - hKey, - &BootDevice, - NtSystemPath); - } - - /* Assign cdrom drives */ - DPRINT("CD-Rom drives: %lu\n", ConfigInfo->CdRomCount); - for (i = 0; i < ConfigInfo->CdRomCount; i++) - { - swprintf(Buffer1, L"\\Device\\CdRom%lu", i); - RtlInitUnicodeString(&UnicodeString1, Buffer1); - - /* Assign first free drive letter */ - DPRINT(" %wZ\n", &UnicodeString1); - HalpAssignDrive(&UnicodeString1, - AUTO_DRIVE, - DOSDEVICE_DRIVE_CDROM, - 0, - RtlConvertLongToLargeInteger(0), - hKey, - &BootDevice, - NtSystemPath); - } - - /* Anything else to do? */ - - ExFreePoolWithTag(PartialInformation, TAG_FILE_SYSTEM); - ExFreePoolWithTag(Buffer2, TAG_FILE_SYSTEM); - ExFreePoolWithTag(Buffer1, TAG_FILE_SYSTEM); - if (hKey) ObCloseHandle(hKey, KernelMode); + /* Enable auto assignement for mountmgr */ + HalpEnableAutomaticDriveLetterAssignment(); } -#endif - /* PRIVATE FUNCTIONS *********************************************************/ NTSTATUS diff --git a/ntoskrnl/guid.c b/ntoskrnl/guid.c index 31cc46279ab..4e21994c037 100644 --- a/ntoskrnl/guid.c +++ b/ntoskrnl/guid.c @@ -4,5 +4,6 @@ #include #include #include +#include /* NO CODE HERE, THIS IS JUST REQUIRED FOR THE GUID DEFINITIONS */ diff --git a/ntoskrnl/include/ntoskrnl.h b/ntoskrnl/include/ntoskrnl.h index 35a243e2a23..08afcb5e8cc 100644 --- a/ntoskrnl/include/ntoskrnl.h +++ b/ntoskrnl/include/ntoskrnl.h @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #undef NTHALAPI