** wip ** setuplib volume drive letters assignment

This commit is contained in:
Hermès Bélusca-Maïto 2024-06-05 22:44:02 +02:00
parent 41380b3b54
commit ba2e90a8c2
No known key found for this signature in database
GPG key ID: 3B2539C65E7B93D0
5 changed files with 605 additions and 28 deletions

View file

@ -1371,7 +1371,8 @@ DoUpdate:
/* Update the mounted devices list */
// FIXME: This should technically be done by mountmgr (if AutoMount is enabled)!
SetMountedDeviceValues(PartitionList);
// SetMountedDeviceValues(PartitionList);
ImportMountedDevices();
}
#ifdef __REACTOS__

View file

@ -257,26 +257,129 @@ GetDriverName(
}
}
#define SET_MAP_LETTER(map, letter) \
do { \
ULONG _i = towupper(letter) - L'A'; \
if (0 <= _i && _i <= L'Z'-L'A') \
(map) |= (1 << _i); \
} while (0)
#define REMOVE_MAP_LETTER(map, letter) \
do { \
ULONG _i = towupper(letter) - L'A'; \
if (0 <= _i && _i <= L'Z'-L'A') \
(map) &= ~(1 << _i); \
} while (0)
static
WCHAR
AssignNextDriveLetter(
_In_ PPARTLIST List,
_Inout_ PVOLENTRY Volume, // PVOLINFO
_In_ BOOLEAN TempAssign)
{
WCHAR Letter = UNICODE_NULL;
if (TempAssign)
{
ULONG i;
/* If the volume already has a drive letter, just return it */
if (Volume->Info.DriveLetter)
return Volume->Info.DriveLetter;
#if 0
/* Browse the existing volumes and flag which letters are taken */
PLIST_ENTRY Entry;
ULONG DriveMap = 0;
for (Entry = List->VolumesList.Flink;
Entry != &List->VolumesList;
Entry = Entry->Flink)
{
PVOLENTRY CurrentVolume = CONTAINING_RECORD(Entry, VOLENTRY, ListEntry);
Letter = CurrentVolume->Info.DriveLetter;
SET_MAP_LETTER(DriveMap, Letter);
}
#endif
/* Scan the drive letters map and find the first free letter.
* Start with the C drive, except on NEC PC-98. */
for (i = (IsNEC_98 ? 0 : 2); i <= L'Z'-L'A'; ++i)
{
if (!(List->DriveMap & (1 << i)))
{
/* Return the letter */
Letter = L'A' + i;
break;
}
}
}
else
{
NTSTATUS Status;
UNICODE_STRING Name;
/* Remove the temporary drive letter from the map */
REMOVE_MAP_LETTER(List->DriveMap, Volume->Info.DriveLetter);
/* Re-assign the drive letter */
RtlInitUnicodeString(&Name, Volume->Info.DeviceName);
Status = GetOrAssignNextVolumeDriveLetter(&Name, &Letter);
DBG_UNREFERENCED_PARAMETER(Status);
}
/* Reserve the letter and set it */
SET_MAP_LETTER(List->DriveMap, Letter);
Volume->Info.DriveLetter = Letter;
return Letter;
}
/**
* @brief
* Assign drive letters to created volumes.
*
* @param[in] List
* Disks/Partitions/Volumes list.
*
* @param[in] TempAssign
* Whether to do a temporary assignment (TRUE: letters are maintained by us
* and are not reported to the system), or to do a permanent assignment
* (FALSE: letters are queried from the MountMgr and assigned to the volumes).
*
* @note
* For the moment, we do it ourselves, by assigning drives to partitions
* that are *only on MBR disks*. We first assign letters to each active
* partition on each disk, then assign letters to each logical partition,
* and finish by assigning letters to the remaining primary partitions.
* (This algorithm is the one that can be observed in the Windows Setup.)
**/
static
VOID
AssignDriveLetters(
IN PPARTLIST List)
_In_ PPARTLIST List,
_In_ BOOLEAN TempAssign)
{
PDISKENTRY DiskEntry;
PPARTENTRY PartEntry;
PLIST_ENTRY Entry1;
PLIST_ENTRY Entry2;
WCHAR Letter;
// WCHAR Letter;
Letter = L'C';
__debugbreak();
/* Assign drive letters to primary partitions */
/* Assign drive letters to volumes on primary partitions */
for (Entry1 = List->DiskListHead.Flink;
Entry1 != &List->DiskListHead;
Entry1 = Entry1->Flink)
{
DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
/* Ignore dynamic disks */
if (DiskEntry->IsDynamic)
continue;
for (Entry2 = DiskEntry->PrimaryPartListHead.Flink;
Entry2 != &DiskEntry->PrimaryPartListHead;
Entry2 = Entry2->Flink)
@ -285,16 +388,17 @@ AssignDriveLetters(
if (!PartEntry->Volume)
continue;
PartEntry->Volume->Info.DriveLetter = UNICODE_NULL;
if (PartEntry->IsPartitioned &&
!IsContainerPartition(PartEntry->PartitionType) &&
(IsRecognizedPartition(PartEntry->PartitionType) ||
PartEntry->SectorCount.QuadPart != 0LL))
if (!(PartEntry->IsPartitioned &&
!IsContainerPartition(PartEntry->PartitionType) &&
(IsRecognizedPartition(PartEntry->PartitionType) ||
PartEntry->SectorCount.QuadPart != 0LL)))
{
if (Letter <= L'Z')
PartEntry->Volume->Info.DriveLetter = Letter++;
// PartEntry->Volume->Info.DriveLetter = UNICODE_NULL;
ASSERT(PartEntry->Volume->Info.DriveLetter == UNICODE_NULL);
continue;
}
AssignNextDriveLetter(List, PartEntry->Volume, TempAssign);
}
}
@ -305,6 +409,10 @@ AssignDriveLetters(
{
DiskEntry = CONTAINING_RECORD(Entry1, DISKENTRY, ListEntry);
/* Ignore dynamic disks */
if (DiskEntry->IsDynamic)
continue;
for (Entry2 = DiskEntry->LogicalPartListHead.Flink;
Entry2 != &DiskEntry->LogicalPartListHead;
Entry2 = Entry2->Flink)
@ -313,19 +421,21 @@ AssignDriveLetters(
if (!PartEntry->Volume)
continue;
PartEntry->Volume->Info.DriveLetter = UNICODE_NULL;
if (PartEntry->IsPartitioned &&
(IsRecognizedPartition(PartEntry->PartitionType) ||
PartEntry->SectorCount.QuadPart != 0LL))
if (!(PartEntry->IsPartitioned &&
(IsRecognizedPartition(PartEntry->PartitionType) ||
PartEntry->SectorCount.QuadPart != 0LL)))
{
if (Letter <= L'Z')
PartEntry->Volume->Info.DriveLetter = Letter++;
// PartEntry->Volume->Info.DriveLetter = UNICODE_NULL;
ASSERT(PartEntry->Volume->Info.DriveLetter == UNICODE_NULL);
continue;
}
AssignNextDriveLetter(List, PartEntry->Volume, TempAssign);
}
}
}
static NTSTATUS
NTAPI
DiskIdentifierQueryRoutine(
@ -2371,6 +2481,10 @@ __debugbreak();
else // !IsUnknown && !IsUnformatted == IsFormatted
Volume->FormatState = Formatted;
/* Set the drive letter in the map */
// AssignNextDriveLetter(List, Volume, FALSE);
SET_MAP_LETTER(List->DriveMap, Volume->Info.DriveLetter);
return STATUS_SUCCESS;
}
@ -2561,6 +2675,46 @@ CreatePartitionList(VOID)
InitializeListHead(&List->VolumesList);
InitializeListHead(&List->PendingUnmountVolumesList);
/* Get the system drive letters map (seen by this process) */
{
PROCESS_DEVICEMAP_INFORMATION DeviceMap;
ULONG i;
Status = NtQueryInformationProcess(NtCurrentProcess(),
ProcessDeviceMap,
&DeviceMap.Query,
sizeof(DeviceMap.Query),
NULL);
/* Zero the map if we failed */
if (!NT_SUCCESS(Status))
RtlZeroMemory(&DeviceMap, sizeof(DeviceMap)); // DeviceMap.Query.DriveMap = 0;
/* Keep only the letters used by other resources (remote drives, CD-ROM,
* RamDisks, ...) that either we or the MountMgr do not maintain */
for (i = 0; i <= 'Z' - 'A'; ++i)
{
/* Skip the drive if it's not in the map */
if (!(DeviceMap.Query.DriveMap & (1 << i)))
continue;
/* Disable unknown drives */
if (!((DeviceMap.Query.DriveType[i] >= DOSDEVICE_DRIVE_REMOVABLE) &&
(DeviceMap.Query.DriveType[i] <= DOSDEVICE_DRIVE_RAMDISK)))
{
DeviceMap.Query.DriveMap &= ~(1 << i);
}
#if 0
/* Disable letters on fixed drives, these should be handled by MountMgr */
if (DeviceMap.Query.DriveType[i] == DOSDEVICE_DRIVE_FIXED)
{
DeviceMap.Query.DriveMap &= ~(1 << i);
}
#endif
}
List->DriveMap = DeviceMap.Query.DriveMap;
}
/*
* Enumerate the disks seen by the BIOS; this will be used later
* to map drives seen by NTOS with their corresponding BIOS names.
@ -2590,7 +2744,6 @@ CreatePartitionList(VOID)
UpdateDiskSignatures(List);
UpdateHwDiskNumbers(List);
AssignDriveLetters(List);
/*
* Retrieve the system partition: the active partition on the system
@ -3499,10 +3652,9 @@ CreatePartition(
* associated with this partition has to be created. */
PartEntry->Volume = InitVolume(DiskEntry->PartList, PartEntry);
ASSERT(PartEntry->Volume);
AssignNextDriveLetter(List, PartEntry->Volume, TRUE);
}
AssignDriveLetters(List);
return TRUE;
}
@ -3548,6 +3700,10 @@ DismountPartition(
/* Dismount the basic volume: link the volume into the list of volumes to unmount */
// return DismountVolume(&Volume->Info, TRUE);
InsertTailList(&List->PendingUnmountVolumesList, &Volume->ListEntry);
/* Remove the drive letter from the map */
REMOVE_MAP_LETTER(List->DriveMap, Volume->Info.DriveLetter);
return STATUS_SUCCESS;
}
@ -3683,7 +3839,7 @@ DeletePartition(
}
UpdateDiskLayout(DiskEntry);
AssignDriveLetters(List);
AssignDriveLetters(List, TRUE);
return TRUE;
}
@ -4380,6 +4536,9 @@ WritePartitionsToDisk(
InitVolumeDeviceName(Volume, NULL);
}
/* Assign persistent drive letters to volumes */
AssignDriveLetters(List, FALSE);
//** Re-dump the list of MountedDevices **//
DumpMountedDevices();
@ -4428,8 +4587,27 @@ typedef struct _REG_DISK_MOUNT_INFO
* @brief
* Assign a "\DosDevices\#:" mount point drive letter to a disk partition or
* volume, specified by a given disk signature and starting partition offset.
*
* @note
* The association is stored in the registry of the **TARGET**
* NT installation, not of the current running one.
*
* We use it to update the mounted devices list
* // FIXME: This should technically be done by mountmgr (if AutoMount is enabled)!
*
* TODO:
* - Make the function more generic for MBR and GPT.
*
* @note
* The stored data actually corresponds to a "unique ID" the partition manager
* gives to the mount manager. In this function below, the format is actually
* the one used for partitions on MBR disks only.
*
* @see
* https://learn.microsoft.com/en-us/windows-hardware/drivers/storage/supporting-mount-manager-requests-in-a-storage-class-driver
* https://winreg-kb.readthedocs.io/en/latest/sources/system-keys/Mounted-devices.html
**/
static BOOLEAN
static NTSTATUS
SetMountedDeviceValue(
_In_ PVOLENTRY Volume)
{
@ -4445,7 +4623,7 @@ SetMountedDeviceValue(
/* Ignore no letter */
if (!Letter)
return TRUE;
return STATUS_SUCCESS;
RtlStringCchPrintfW(Buffer, _countof(Buffer),
L"\\DosDevices\\%c:", Letter);
@ -4473,9 +4651,16 @@ SetMountedDeviceValue(
if (!NT_SUCCESS(Status))
{
DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
return FALSE;
return Status;
}
//
// NOTE: Alternatively, just ask the MountMgr (if we have it)
// for the volume unique ID, via IOCTL_MOUNTDEV_QUERY_UNIQUE_ID !!
//
// _In_ ULONG Signature, // DiskSignature
MountInfo.Signature = PartEntry->DiskEntry->LayoutBuffer->Signature;
MountInfo.StartingOffset = GetPartEntryOffsetInBytes(PartEntry);
Status = NtSetValueKey(KeyHandle,
@ -4488,18 +4673,24 @@ SetMountedDeviceValue(
if (!NT_SUCCESS(Status))
{
DPRINT1("NtSetValueKey() failed (Status %lx)\n", Status);
return FALSE;
return Status;
}
return TRUE;
return STATUS_SUCCESS;
}
/*
* TODO:
* - It may actually make sense to just migrate the volume letters database
* from the current active system to the installation TARGET one.
*/
BOOLEAN
SetMountedDeviceValues(
_In_ PPARTLIST List)
{
PLIST_ENTRY Entry;
PVOLENTRY Volume;
NTSTATUS Status;
if (!List)
return FALSE;
@ -4514,13 +4705,153 @@ SetMountedDeviceValues(
Volume = CONTAINING_RECORD(Entry, VOLENTRY, ListEntry);
/* Assign a "\DosDevices\#:" mount point to this volume */
if (!SetMountedDeviceValue(Volume))
Status = SetMountedDeviceValue(Volume);
if (!NT_SUCCESS(Status))
return FALSE;
}
return TRUE;
}
/**
* @brief
* Imports the \Registry\Machine\SYSTEM\MountedDevices database of the
* current running ReactOS installation to the target ReactOS installation.
*
* Used when both installations are for the same machine.
**/
NTSTATUS
ImportMountedDevices(VOID)
{
NTSTATUS Status;
UNICODE_STRING SrcPath
= RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\MountedDevices");
UNICODE_STRING DstPath
= RTL_CONSTANT_STRING(L"SYSTEM\\MountedDevices");
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE SrcKey = NULL;
HANDLE DstKey = NULL;
PKEY_VALUE_FULL_INFORMATION Buffer;
ULONG BufferSize = sizeof(KEY_VALUE_FULL_INFORMATION) + MAX_PATH * sizeof(WCHAR);
ULONG RequiredSize;
ULONG i = 0;
UNICODE_STRING Name;
/* Open the source key */
InitializeObjectAttributes(&ObjectAttributes,
&SrcPath,
OBJ_CASE_INSENSITIVE,
NULL, NULL);
Status = NtOpenKey(&SrcKey, KEY_QUERY_VALUE, &ObjectAttributes);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtOpenKey() failed with status 0x%08lx\n", Status);
return Status;
}
/* Open the target key */
InitializeObjectAttributes(&ObjectAttributes,
&DstPath,
OBJ_CASE_INSENSITIVE,
GetRootKeyByPredefKey(HKEY_LOCAL_MACHINE, NULL),
NULL);
Status = NtOpenKey(&DstKey, KEY_ALL_ACCESS, &ObjectAttributes);
if (!NT_SUCCESS(Status))
{
Status = NtCreateKey(&DstKey,
KEY_ALL_ACCESS,
&ObjectAttributes,
0,
NULL,
REG_OPTION_NON_VOLATILE,
NULL);
}
if (!NT_SUCCESS(Status))
{
DPRINT1("NtCreateKey() failed (Status %lx)\n", Status);
goto Quit;
}
/*
* Enumerate each value in the source key and copy it into the target key.
*/
Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize);
if (!Buffer)
{
DPRINT1("RtlAllocateHeap() failed\n");
Status = STATUS_NO_MEMORY;
goto Quit;
}
DbgPrint("\n**** Importing HKLM\\SYSTEM\\MountedDevices ****\n");
while (TRUE)
{
Status = NtEnumerateValueKey(SrcKey,
i,
KeyValueFullInformation,
Buffer,
BufferSize,
&RequiredSize);
if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
{
RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
BufferSize = RequiredSize;
Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferSize);
if (!Buffer)
{
DPRINT1("RtlAllocateHeap() failed\n");
// Status = STATUS_NO_MEMORY;
break;
// continue;
}
Status = NtEnumerateValueKey(SrcKey,
i,
KeyValueFullInformation,
Buffer,
BufferSize,
&RequiredSize);
}
if (!NT_SUCCESS(Status))
{
DPRINT("NtEnumerateKey() failed with status 0x%08lx\n", Status);
break;
}
i++;
if (Buffer->Type != REG_BINARY)
{
DPRINT1("Wrong registry type: got 0x%lx, expected 0x%lx (REG_BINARY)\n",
Buffer->Type, REG_BINARY);
}
Name.Length = Name.MaximumLength = Buffer->NameLength;
Name.Buffer = Buffer->Name;
DbgPrint(" '%wZ' =>\n", &Name);
{
PVOID Data = (PVOID)((ULONG_PTR)Buffer + Buffer->DataOffset);
DebugDumpBuffer(Data, Buffer->DataLength);
Status = NtSetValueKey(DstKey,
&Name,
0,
Buffer->Type,
Data,
Buffer->DataLength);
}
DbgPrint("\n");
}
DbgPrint("**** End Importing ****\n");
RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
Quit:
if (DstKey)
NtClose(DstKey);
if (SrcKey)
NtClose(SrcKey);
return Status;
}
/*
* End of SETUP-specific support functions
*****************************************************************************/

View file

@ -193,6 +193,7 @@ typedef struct _PARTLIST
/* (Basic) Volumes management */
LIST_ENTRY VolumesList;
LIST_ENTRY PendingUnmountVolumesList; ///< List of volumes to unmount
ULONG DriveMap; ///< Drive letters map, used by AssignNextDriveLetter()
} PARTLIST, *PPARTLIST;
@ -398,8 +399,12 @@ SetMBRPartitionType(
IN PPARTENTRY PartEntry,
IN UCHAR PartitionType);
BOOLEAN
SetMountedDeviceValues(
_In_ PPARTLIST List);
NTSTATUS
ImportMountedDevices(VOID);
/* EOF */

View file

@ -8,6 +8,7 @@
/* INCLUDES ******************************************************************/
#include "precomp.h"
#include <mountdev.h>
#include "volutil.h"
#include "fsrec.h"
@ -19,12 +20,238 @@
/* FUNCTIONS *****************************************************************/
/**
* @brief
* Requests the MountMgr to retrieve the drive letter,
* if any, associated to the given volume.
*
* @param[in] VolumeName
* Device name of the volume.
*
* @param[out] DriveLetter
* Pointer to a WCHAR buffer receiving the corresponding drive letter,
* or UNICODE_NULL if none has been assigned.
*
* @return A status code.
**/
NTSTATUS
GetVolumeDriveLetter(
_In_ PCUNICODE_STRING VolumeName,
_Out_ PWCHAR DriveLetter)
{
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
HANDLE Handle;
UNICODE_STRING MountMgrDevice;
ULONG Length;
MOUNTMGR_MOUNT_POINTS MountPoints;
PMOUNTMGR_MOUNT_POINTS MountPointsPtr;
/*
* This variable is used to store the device name
* for the input buffer to IOCTL_MOUNTMGR_QUERY_POINTS.
* It's based on MOUNTMGR_MOUNT_POINT (mountmgr.h).
* Doing it this way prevents memory allocation.
* The device name won't be longer.
*/
struct
{
MOUNTMGR_MOUNT_POINT;
WCHAR DeviceName[256];
} DeviceName;
/* Default to no letter */
*DriveLetter = UNICODE_NULL;
/* First, retrieve the corresponding device name */
DeviceName.SymbolicLinkNameOffset = DeviceName.UniqueIdOffset = 0;
DeviceName.SymbolicLinkNameLength = DeviceName.UniqueIdLength = 0;
DeviceName.DeviceNameOffset = (ULONG_PTR)&DeviceName.DeviceName - (ULONG_PTR)&DeviceName;
DeviceName.DeviceNameLength = VolumeName->Length;
RtlCopyMemory(&DeviceName.DeviceName, VolumeName->Buffer, VolumeName->Length);
/* Now, query the MountMgr for the DOS path */
RtlInitUnicodeString(&MountMgrDevice, MOUNTMGR_DEVICE_NAME);
InitializeObjectAttributes(&ObjectAttributes,
&MountMgrDevice,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtOpenFile(&Handle,
FILE_READ_ATTRIBUTES | SYNCHRONIZE, // FILE_READ_DATA
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_NONALERT);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtOpenFile() failed, Status 0x%08lx\n", Status);
return Status;
}
MountPointsPtr = NULL;
Status = NtDeviceIoControlFile(Handle,
NULL, NULL, NULL,
&IoStatusBlock,
IOCTL_MOUNTMGR_QUERY_POINTS,
&DeviceName, sizeof(DeviceName),
&MountPoints, sizeof(MountPoints));
/* Only tolerated failure here is buffer too small, which is expected */
if (!NT_SUCCESS(Status) && (Status != STATUS_BUFFER_OVERFLOW))
{
goto Quit;
}
/* Compute the needed size to store the mount points list */
Length = MountPoints.Size;
/* Reallocate the memory, even in case of success, because
* that's the buffer that will be returned to the caller */
MountPointsPtr = RtlAllocateHeap(ProcessHeap, HEAP_ZERO_MEMORY, Length);
if (!MountPointsPtr)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto Quit;
}
/* Re-query the mount points list with proper size */
Status = NtDeviceIoControlFile(Handle,
NULL, NULL, NULL,
&IoStatusBlock,
IOCTL_MOUNTMGR_QUERY_POINTS,
&DeviceName, sizeof(DeviceName),
MountPointsPtr, Length);
if (!NT_SUCCESS(Status))
goto Quit;
/* Find the drive letter amongst the mount points */
for (MountPointsPtr->Size = 0; // Reuse the Size field to store the current index.
MountPointsPtr->Size < MountPointsPtr->NumberOfMountPoints;
MountPointsPtr->Size++)
{
UNICODE_STRING SymLink;
SymLink.Length = SymLink.MaximumLength = MountPointsPtr->MountPoints[MountPointsPtr->Size].SymbolicLinkNameLength;
SymLink.Buffer = (PWCHAR)((ULONG_PTR)MountPointsPtr + MountPointsPtr->MountPoints[MountPointsPtr->Size].SymbolicLinkNameOffset);
if (MOUNTMGR_IS_DRIVE_LETTER(&SymLink))
{
/* Return the drive letter, ensuring it's uppercased */
*DriveLetter = towupper(SymLink.Buffer[12]);
break;
}
}
/* We are done, return success */
Status = STATUS_SUCCESS;
Quit:
if (MountPointsPtr)
RtlFreeHeap(ProcessHeap, 0, MountPointsPtr);
NtClose(Handle);
return Status;
}
/**
* @brief
* Requests the MountMgr to either assign the next available drive letter
* to the given volume, if none already exists, or to retrieve its existing
* associated drive letter.
*
* @param[in] VolumeName
* Device name of the volume.
*
* @param[out] DriveLetter
* Pointer to a WCHAR buffer receiving the corresponding drive letter,
* or UNICODE_NULL if none has been assigned.
*
* @return A status code.
**/
NTSTATUS
GetOrAssignNextVolumeDriveLetter(
_In_ PCUNICODE_STRING VolumeName,
_Out_ PWCHAR DriveLetter)
{
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
HANDLE Handle;
UNICODE_STRING MountMgrDevice;
MOUNTMGR_DRIVE_LETTER_INFORMATION LetterInfo;
/*
* This variable is used to store the device name
* for the input buffer to IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER.
* It's based on MOUNTMGR_DRIVE_LETTER_TARGET (mountmgr.h).
* Doing it this way prevents memory allocation.
* The device name won't be longer.
*/
struct
{
USHORT DeviceNameLength;
WCHAR DeviceName[256];
} DeviceName;
/* Default to no letter */
*DriveLetter = UNICODE_NULL;
/* First, retrieve the corresponding device name */
DeviceName.DeviceNameLength = VolumeName->Length;
RtlCopyMemory(&DeviceName.DeviceName, VolumeName->Buffer, VolumeName->Length);
/* Now, query the MountMgr for the DOS path */
RtlInitUnicodeString(&MountMgrDevice, MOUNTMGR_DEVICE_NAME);
InitializeObjectAttributes(&ObjectAttributes,
&MountMgrDevice,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Status = NtOpenFile(&Handle,
FILE_READ_ATTRIBUTES | SYNCHRONIZE, // FILE_READ_DATA
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_NONALERT);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtOpenFile() failed, Status 0x%08lx\n", Status);
return Status;
}
Status = NtDeviceIoControlFile(Handle,
NULL, NULL, NULL,
&IoStatusBlock,
IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER,
&DeviceName, sizeof(DeviceName),
&LetterInfo, sizeof(LetterInfo));
if (!NT_SUCCESS(Status))
goto Quit;
DPRINT1("DriveLetterWasAssigned = %s, CurrentDriveLetter = %c\n",
LetterInfo.DriveLetterWasAssigned ? "TRUE" : "FALSE",
LetterInfo.CurrentDriveLetter ? LetterInfo.CurrentDriveLetter : '-');
/* Return the drive letter the MountMgr potentially assigned,
* ensuring it's uppercased */
*DriveLetter = towupper(LetterInfo.CurrentDriveLetter);
Quit:
NtClose(Handle);
return Status;
}
/**
* @brief
* Attempts to mount the designated volume, and retrieve and cache
* some of its properties (file system, volume label, ...).
**/
NTSTATUS
MountVolume(
_Inout_ PVOLINFO Volume,
_In_opt_ UCHAR MbrPartitionType)
{
NTSTATUS Status;
UNICODE_STRING Name;
HANDLE VolumeHandle;
/* If the volume is already mounted, just return success */
@ -128,6 +355,12 @@ MountVolume(
}
}
/* Get the volume drive letter */
__debugbreak();
RtlInitUnicodeString(&Name, Volume->DeviceName);
Status = GetVolumeDriveLetter(&Name, &Volume->DriveLetter);
UNREFERENCED_PARAMETER(Status);
/* Close the volume */
if (VolumeHandle)
NtClose(VolumeHandle);
@ -215,6 +448,7 @@ DismountVolume(
/* Reset some data only if dismount succeeded */
if (NT_SUCCESS(Status))
{
// TODO: Should we notify MountMgr to delete the drive letter?
Volume->DriveLetter = UNICODE_NULL;
Volume->VolumeLabel[0] = UNICODE_NULL;
Volume->FileSystem[0] = UNICODE_NULL;

View file

@ -37,6 +37,12 @@ typedef struct _VOLINFO
(!IsUnknown(VolInfo) && !IsUnformatted(VolInfo))
NTSTATUS
GetOrAssignNextVolumeDriveLetter(
_In_ PCUNICODE_STRING VolumeName,
_Out_ PWCHAR DriveLetter);
// DetectFileSystem()
NTSTATUS
MountVolume(
_Inout_ PVOLINFO Volume,