This patch allows the mountmgr to handle the volume information request IRP, allowing volume information to be queried from the mountmgr.
Best, Erich
On 7/15/20 10:08 AM, Erich E. Hoover wrote:
From 2dd03df6e1fc2944d7590cc400059b05a8edbaa1 Mon Sep 17 00:00:00 2001 From: "Erich E. Hoover" erich.e.hoover@gmail.com Date: Fri, 12 Jun 2020 14:48:25 -0600 Subject: mountmgr: Add support for IRP_MJ_QUERY_VOLUME_INFORMATION.
Signed-off-by: Erich E. Hoover erich.e.hoover@gmail.com
dlls/mountmgr.sys/device.c | 137 +++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+)
diff --git a/dlls/mountmgr.sys/device.c b/dlls/mountmgr.sys/device.c index f7a1f1e9b55..439dbc0c7d3 100644 --- a/dlls/mountmgr.sys/device.c +++ b/dlls/mountmgr.sys/device.c @@ -1818,6 +1818,142 @@ static void query_property( struct disk_device *device, IRP *irp ) } }
+/* find a volume that matches the given mount point */ +static struct volume *find_mount_volume( const char *mount_point, enum device_type type ) +{
- struct volume *volume;
- struct disk_device *disk_device;
- LIST_FOR_EACH_ENTRY( volume, &volumes_list, struct volume, entry )
- {
int match = 0;
disk_device = volume->device;
if (disk_device->type != type) continue;
if (mount_point && disk_device->unix_mount)
{
if (strcmp( mount_point, disk_device->unix_mount )) continue;
match++;
}
if (!match) continue;
TRACE( "found matching volume %s for mount %s type %u\n",
debugstr_guid(&volume->guid), debugstr_a(mount_point), type );
return grab_volume( volume );
- }
- return NULL;
+}
This seems less than ideal. I guess maybe a better thing to do is have a union of "struct disk_device" and "struct volume" in the device extension.
We could probably do a better job of properly differentiating drives and volumes anyway, e.g. I think we currently create a "volume" object for all drives, and we create a "disk_device" for drives defined with DEFINE_UNIX_DRIVE and DRIVE_REMOVABLE. It's my understanding that only "volumes" can be mounted, even for removable drives.
+static NTSTATUS WINAPI harddisk_query_volume( DEVICE_OBJECT *device, IRP *irp ) +{
- IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
- int info_class = irpsp->Parameters.QueryVolume.FsInformationClass;
- ULONG length = irpsp->Parameters.QueryVolume.Length;
- struct disk_device *dev = device->DeviceExtension;
- PIO_STATUS_BLOCK io = &irp->IoStatus;
- struct volume *volume;
- TRACE( "volume query %x length %u\n", info_class,
length );
- EnterCriticalSection( &device_section );
- volume = find_mount_volume( dev->unix_mount, DEVICE_HARDDISK_VOL );
- if (!volume)
- {
io->u.Status = STATUS_BAD_DEVICE_TYPE;
goto done;
- }
- switch(info_class)
- {
- case FileFsVolumeInformation:
- {
FILE_FS_VOLUME_INFORMATION *info = irp->UserBuffer;
if (length < sizeof(FILE_FS_VOLUME_INFORMATION))
{
io->u.Status = STATUS_INFO_LENGTH_MISMATCH;
break;
}
info->VolumeCreationTime.QuadPart = 0; /* FIXME */
info->VolumeSerialNumber = volume->serial;
info->VolumeLabelLength = min( strlenW(volume->label) * sizeof(WCHAR),
length - offsetof( FILE_FS_VOLUME_INFORMATION, VolumeLabel ) );
info->SupportsObjects = (get_mountmgr_fs_type(volume->fs_type) == MOUNTMGR_FS_TYPE_NTFS);
memcpy( info->VolumeLabel, volume->label, info->VolumeLabelLength );
io->Information = offsetof( FILE_FS_VOLUME_INFORMATION, VolumeLabel ) + info->VolumeLabelLength;
io->u.Status = STATUS_SUCCESS;
break;
- }
- case FileFsAttributeInformation:
- {
static const WCHAR fatW[] = {'F','A','T'};
static const WCHAR fat32W[] = {'F','A','T','3','2'};
static const WCHAR ntfsW[] = {'N','T','F','S'};
static const WCHAR cdfsW[] = {'C','D','F','S'};
static const WCHAR udfW[] = {'U','D','F'};
FILE_FS_ATTRIBUTE_INFORMATION *info = irp->UserBuffer;
enum mountmgr_fs_type fs_type = get_mountmgr_fs_type(volume->fs_type);
if (length < sizeof(FILE_FS_ATTRIBUTE_INFORMATION))
{
io->u.Status = STATUS_INFO_LENGTH_MISMATCH;
break;
}
switch (fs_type)
{
case MOUNTMGR_FS_TYPE_ISO9660:
info->FileSystemAttributes = FILE_READ_ONLY_VOLUME;
info->MaximumComponentNameLength = 221;
info->FileSystemNameLength = min( sizeof(cdfsW), length - offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) );
memcpy(info->FileSystemName, cdfsW, info->FileSystemNameLength);
break;
case MOUNTMGR_FS_TYPE_UDF:
info->FileSystemAttributes = FILE_READ_ONLY_VOLUME | FILE_UNICODE_ON_DISK | FILE_CASE_SENSITIVE_SEARCH;
info->MaximumComponentNameLength = 255;
info->FileSystemNameLength = min( sizeof(udfW), length - offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) );
memcpy(info->FileSystemName, udfW, info->FileSystemNameLength);
break;
case MOUNTMGR_FS_TYPE_FAT:
info->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES; /* FIXME */
info->MaximumComponentNameLength = 255;
info->FileSystemNameLength = min( sizeof(fatW), length - offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) );
memcpy(info->FileSystemName, fatW, info->FileSystemNameLength);
break;
case MOUNTMGR_FS_TYPE_FAT32:
info->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES; /* FIXME */
info->MaximumComponentNameLength = 255;
info->FileSystemNameLength = min( sizeof(fat32W), length - offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) );
memcpy(info->FileSystemName, fat32W, info->FileSystemNameLength);
break;
default:
info->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES | FILE_PERSISTENT_ACLS;
info->MaximumComponentNameLength = 255;
info->FileSystemNameLength = min( sizeof(ntfsW), length - offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) );
memcpy(info->FileSystemName, ntfsW, info->FileSystemNameLength);
break;
}
io->Information = offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) + info->FileSystemNameLength;
io->u.Status = STATUS_SUCCESS;
break;
- }
- default:
FIXME("Unsupported volume query %x\n", irpsp->Parameters.QueryVolume.FsInformationClass);
io->u.Status = STATUS_NOT_SUPPORTED;
break;
- }
+done:
- LeaveCriticalSection( &device_section );
- IoCompleteRequest( irp, IO_NO_INCREMENT );
- return STATUS_SUCCESS;
+}
/* handler for ioctls on the harddisk device */ static NTSTATUS WINAPI harddisk_ioctl( DEVICE_OBJECT *device, IRP *irp ) { @@ -1915,6 +2051,7 @@ NTSTATUS WINAPI harddisk_driver_entry( DRIVER_OBJECT *driver, UNICODE_STRING *pa
harddisk_driver = driver; driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = harddisk_ioctl;
driver->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = harddisk_query_volume;
/* create a harddisk0 device that isn't assigned to any drive */ create_disk_device( DEVICE_HARDDISK, &device );
-- 2.17.1
On Wed, Jul 15, 2020 at 9:35 AM Zebediah Figura z.figura12@gmail.com wrote:
. .. This seems less than ideal. I guess maybe a better thing to do is have a union of "struct disk_device" and "struct volume" in the device extension. ...
Thanks Zeb! At least the way we're currently doing things, it looks to me like that would be problematic. Right now we create a disk_device for every volume (this is fine), but that we can also change the device type of a volume at any time (this looks problematic). That's not unsolvable though, I can see a couple choices: 1) if we call set_volume_info with (type != disk_device->type) then we could store the volume info, delete the device (and volume), and then recreate it again 2) we could add an optional volume entry to disk_device on creation, making the reverse lookup simple (even if the device type changes)
I've attached an example of the second option, since that seems simpler, and would appreciate your thoughts.
Best, Erich
We could probably do a better job of properly differentiating drives and volumes anyway, e.g. I think we currently create a "volume" object for all drives, and we create a "disk_device" for drives defined with DEFINE_UNIX_DRIVE and DRIVE_REMOVABLE. It's my understanding that only "volumes" can be mounted, even for removable drives.
+static NTSTATUS WINAPI harddisk_query_volume( DEVICE_OBJECT *device, IRP *irp ) +{
- IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
- int info_class = irpsp->Parameters.QueryVolume.FsInformationClass;
- ULONG length = irpsp->Parameters.QueryVolume.Length;
- struct disk_device *dev = device->DeviceExtension;
- PIO_STATUS_BLOCK io = &irp->IoStatus;
- struct volume *volume;
- TRACE( "volume query %x length %u\n", info_class,
length );
- EnterCriticalSection( &device_section );
- volume = find_mount_volume( dev->unix_mount, DEVICE_HARDDISK_VOL );
- if (!volume)
- {
io->u.Status = STATUS_BAD_DEVICE_TYPE;
goto done;
- }
- switch(info_class)
- {
- case FileFsVolumeInformation:
- {
FILE_FS_VOLUME_INFORMATION *info = irp->UserBuffer;
if (length < sizeof(FILE_FS_VOLUME_INFORMATION))
{
io->u.Status = STATUS_INFO_LENGTH_MISMATCH;
break;
}
info->VolumeCreationTime.QuadPart = 0; /* FIXME */
info->VolumeSerialNumber = volume->serial;
info->VolumeLabelLength = min( strlenW(volume->label) * sizeof(WCHAR),
length - offsetof( FILE_FS_VOLUME_INFORMATION, VolumeLabel ) );
info->SupportsObjects = (get_mountmgr_fs_type(volume->fs_type) == MOUNTMGR_FS_TYPE_NTFS);
memcpy( info->VolumeLabel, volume->label, info->VolumeLabelLength );
io->Information = offsetof( FILE_FS_VOLUME_INFORMATION, VolumeLabel ) + info->VolumeLabelLength;
io->u.Status = STATUS_SUCCESS;
break;
- }
- case FileFsAttributeInformation:
- {
static const WCHAR fatW[] = {'F','A','T'};
static const WCHAR fat32W[] = {'F','A','T','3','2'};
static const WCHAR ntfsW[] = {'N','T','F','S'};
static const WCHAR cdfsW[] = {'C','D','F','S'};
static const WCHAR udfW[] = {'U','D','F'};
FILE_FS_ATTRIBUTE_INFORMATION *info = irp->UserBuffer;
enum mountmgr_fs_type fs_type = get_mountmgr_fs_type(volume->fs_type);
if (length < sizeof(FILE_FS_ATTRIBUTE_INFORMATION))
{
io->u.Status = STATUS_INFO_LENGTH_MISMATCH;
break;
}
switch (fs_type)
{
case MOUNTMGR_FS_TYPE_ISO9660:
info->FileSystemAttributes = FILE_READ_ONLY_VOLUME;
info->MaximumComponentNameLength = 221;
info->FileSystemNameLength = min( sizeof(cdfsW), length - offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) );
memcpy(info->FileSystemName, cdfsW, info->FileSystemNameLength);
break;
case MOUNTMGR_FS_TYPE_UDF:
info->FileSystemAttributes = FILE_READ_ONLY_VOLUME | FILE_UNICODE_ON_DISK | FILE_CASE_SENSITIVE_SEARCH;
info->MaximumComponentNameLength = 255;
info->FileSystemNameLength = min( sizeof(udfW), length - offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) );
memcpy(info->FileSystemName, udfW, info->FileSystemNameLength);
break;
case MOUNTMGR_FS_TYPE_FAT:
info->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES; /* FIXME */
info->MaximumComponentNameLength = 255;
info->FileSystemNameLength = min( sizeof(fatW), length - offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) );
memcpy(info->FileSystemName, fatW, info->FileSystemNameLength);
break;
case MOUNTMGR_FS_TYPE_FAT32:
info->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES; /* FIXME */
info->MaximumComponentNameLength = 255;
info->FileSystemNameLength = min( sizeof(fat32W), length - offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) );
memcpy(info->FileSystemName, fat32W, info->FileSystemNameLength);
break;
default:
info->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES | FILE_PERSISTENT_ACLS;
info->MaximumComponentNameLength = 255;
info->FileSystemNameLength = min( sizeof(ntfsW), length - offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) );
memcpy(info->FileSystemName, ntfsW, info->FileSystemNameLength);
break;
}
io->Information = offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) + info->FileSystemNameLength;
io->u.Status = STATUS_SUCCESS;
break;
- }
- default:
FIXME("Unsupported volume query %x\n", irpsp->Parameters.QueryVolume.FsInformationClass);
io->u.Status = STATUS_NOT_SUPPORTED;
break;
- }
+done:
- LeaveCriticalSection( &device_section );
- IoCompleteRequest( irp, IO_NO_INCREMENT );
- return STATUS_SUCCESS;
+}
/* handler for ioctls on the harddisk device */ static NTSTATUS WINAPI harddisk_ioctl( DEVICE_OBJECT *device, IRP *irp ) { @@ -1915,6 +2051,7 @@ NTSTATUS WINAPI harddisk_driver_entry( DRIVER_OBJECT *driver, UNICODE_STRING *pa
harddisk_driver = driver; driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = harddisk_ioctl;
driver->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = harddisk_query_volume;
/* create a harddisk0 device that isn't assigned to any drive */ create_disk_device( DEVICE_HARDDISK, &device );
-- 2.17.1
On 7/15/20 8:58 PM, Erich E. Hoover wrote:
On Wed, Jul 15, 2020 at 9:35 AM Zebediah Figura z.figura12@gmail.com wrote:
. .. This seems less than ideal. I guess maybe a better thing to do is have a union of "struct disk_device" and "struct volume" in the device extension. ...
Thanks Zeb! At least the way we're currently doing things, it looks to me like that would be problematic. Right now we create a disk_device for every volume (this is fine), but that we can also change the device type of a volume at any time (this looks problematic). That's not unsolvable though, I can see a couple choices:
Right, I guess my point is that we probably shouldn't be treating disks and volumes as interchangeable. If someone were to map a Unix path, I think that should be a "volume" regardless of whether it's removable or not, and that any "volume" should have an implicit "drive" attached, but not the reverse. At least, that's my understanding of how it works on Windows, but of course I could be wrong about that.
- if we call set_volume_info with (type != disk_device->type) then we
could store the volume info, delete the device (and volume), and then recreate it again 2) we could add an optional volume entry to disk_device on creation, making the reverse lookup simple (even if the device type changes)
I've attached an example of the second option, since that seems simpler, and would appreciate your thoughts.
I would agree that for now this seems like a reasonable solution. We should fix drives and volumes, but that's somewhat orthogonal to this patch series...
Best, Erich
We could probably do a better job of properly differentiating drives and volumes anyway, e.g. I think we currently create a "volume" object for all drives, and we create a "disk_device" for drives defined with DEFINE_UNIX_DRIVE and DRIVE_REMOVABLE. It's my understanding that only "volumes" can be mounted, even for removable drives.
+static NTSTATUS WINAPI harddisk_query_volume( DEVICE_OBJECT *device, IRP *irp ) +{
- IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
- int info_class = irpsp->Parameters.QueryVolume.FsInformationClass;
- ULONG length = irpsp->Parameters.QueryVolume.Length;
- struct disk_device *dev = device->DeviceExtension;
- PIO_STATUS_BLOCK io = &irp->IoStatus;
- struct volume *volume;
- TRACE( "volume query %x length %u\n", info_class,
length );
- EnterCriticalSection( &device_section );
- volume = find_mount_volume( dev->unix_mount, DEVICE_HARDDISK_VOL );
- if (!volume)
- {
io->u.Status = STATUS_BAD_DEVICE_TYPE;
goto done;
- }
- switch(info_class)
- {
- case FileFsVolumeInformation:
- {
FILE_FS_VOLUME_INFORMATION *info = irp->UserBuffer;
if (length < sizeof(FILE_FS_VOLUME_INFORMATION))
{
io->u.Status = STATUS_INFO_LENGTH_MISMATCH;
break;
}
info->VolumeCreationTime.QuadPart = 0; /* FIXME */
info->VolumeSerialNumber = volume->serial;
info->VolumeLabelLength = min( strlenW(volume->label) * sizeof(WCHAR),
length - offsetof( FILE_FS_VOLUME_INFORMATION, VolumeLabel ) );
info->SupportsObjects = (get_mountmgr_fs_type(volume->fs_type) == MOUNTMGR_FS_TYPE_NTFS);
memcpy( info->VolumeLabel, volume->label, info->VolumeLabelLength );
io->Information = offsetof( FILE_FS_VOLUME_INFORMATION, VolumeLabel ) + info->VolumeLabelLength;
io->u.Status = STATUS_SUCCESS;
break;
- }
- case FileFsAttributeInformation:
- {
static const WCHAR fatW[] = {'F','A','T'};
static const WCHAR fat32W[] = {'F','A','T','3','2'};
static const WCHAR ntfsW[] = {'N','T','F','S'};
static const WCHAR cdfsW[] = {'C','D','F','S'};
static const WCHAR udfW[] = {'U','D','F'};
FILE_FS_ATTRIBUTE_INFORMATION *info = irp->UserBuffer;
enum mountmgr_fs_type fs_type = get_mountmgr_fs_type(volume->fs_type);
if (length < sizeof(FILE_FS_ATTRIBUTE_INFORMATION))
{
io->u.Status = STATUS_INFO_LENGTH_MISMATCH;
break;
}
switch (fs_type)
{
case MOUNTMGR_FS_TYPE_ISO9660:
info->FileSystemAttributes = FILE_READ_ONLY_VOLUME;
info->MaximumComponentNameLength = 221;
info->FileSystemNameLength = min( sizeof(cdfsW), length - offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) );
memcpy(info->FileSystemName, cdfsW, info->FileSystemNameLength);
break;
case MOUNTMGR_FS_TYPE_UDF:
info->FileSystemAttributes = FILE_READ_ONLY_VOLUME | FILE_UNICODE_ON_DISK | FILE_CASE_SENSITIVE_SEARCH;
info->MaximumComponentNameLength = 255;
info->FileSystemNameLength = min( sizeof(udfW), length - offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) );
memcpy(info->FileSystemName, udfW, info->FileSystemNameLength);
break;
case MOUNTMGR_FS_TYPE_FAT:
info->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES; /* FIXME */
info->MaximumComponentNameLength = 255;
info->FileSystemNameLength = min( sizeof(fatW), length - offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) );
memcpy(info->FileSystemName, fatW, info->FileSystemNameLength);
break;
case MOUNTMGR_FS_TYPE_FAT32:
info->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES; /* FIXME */
info->MaximumComponentNameLength = 255;
info->FileSystemNameLength = min( sizeof(fat32W), length - offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) );
memcpy(info->FileSystemName, fat32W, info->FileSystemNameLength);
break;
default:
info->FileSystemAttributes = FILE_CASE_PRESERVED_NAMES | FILE_PERSISTENT_ACLS;
info->MaximumComponentNameLength = 255;
info->FileSystemNameLength = min( sizeof(ntfsW), length - offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) );
memcpy(info->FileSystemName, ntfsW, info->FileSystemNameLength);
break;
}
io->Information = offsetof( FILE_FS_ATTRIBUTE_INFORMATION, FileSystemName ) + info->FileSystemNameLength;
io->u.Status = STATUS_SUCCESS;
break;
- }
- default:
FIXME("Unsupported volume query %x\n", irpsp->Parameters.QueryVolume.FsInformationClass);
io->u.Status = STATUS_NOT_SUPPORTED;
break;
- }
+done:
- LeaveCriticalSection( &device_section );
- IoCompleteRequest( irp, IO_NO_INCREMENT );
- return STATUS_SUCCESS;
+}
/* handler for ioctls on the harddisk device */ static NTSTATUS WINAPI harddisk_ioctl( DEVICE_OBJECT *device, IRP *irp ) { @@ -1915,6 +2051,7 @@ NTSTATUS WINAPI harddisk_driver_entry( DRIVER_OBJECT *driver, UNICODE_STRING *pa
harddisk_driver = driver; driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = harddisk_ioctl;
driver->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = harddisk_query_volume;
/* create a harddisk0 device that isn't assigned to any drive */ create_disk_device( DEVICE_HARDDISK, &device );
-- 2.17.1