Per AJ's request for splitting, this patch allows the get_volume_info request to issue an IRP to request the volume information from the mountmgr. Sorry it's taken me awhile to get to this :/
Note that patch 1 and 2 can be applied in opposite order, if desired.
Best, Erich2
On 9/8/20 3:01 PM, Erich E. Hoover wrote:
From 399b72df5cc2b6ba09ca67286b2bcefb49503aff Mon Sep 17 00:00:00 2001 From: "Erich E. Hoover" erich.e.hoover@gmail.com Date: Sat, 23 May 2020 21:39:41 -0600 Subject: server: Allow get_volume_info to issue IRP_MJ_QUERY_VOLUME_INFORMATION.
Signed-off-by: Erich E. Hoover erich.e.hoover@gmail.com
dlls/ntoskrnl.exe/ntoskrnl.c | 64 ++++++++++++++++++++++++++++++++++++ server/device.c | 18 +++++++++- server/fd.c | 15 ++++++--- server/file.h | 4 +-- server/named_pipe.c | 5 +-- server/protocol.def | 11 +++++++ 6 files changed, 107 insertions(+), 10 deletions(-)
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c index e94feabc826..5ce7702a06b 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/ntoskrnl.c @@ -760,6 +760,69 @@ static NTSTATUS dispatch_ioctl( struct dispatch_context *context ) return STATUS_SUCCESS; }
+/* process a volume information request for a given device */ +static NTSTATUS dispatch_volume( struct dispatch_context *context ) +{
- IO_STACK_LOCATION *irpsp;
- IRP *irp;
- void *out_buff = NULL;
- void *to_free = NULL;
- DEVICE_OBJECT *device;
- FILE_OBJECT *file = wine_server_get_ptr( context->params.ioctl.file );
- ULONG out_size = context->params.ioctl.out_size;
There seem to be a couple of copy-paste errors here.
- if (!file) return STATUS_INVALID_HANDLE;
- device = IoGetAttachedDevice( file->DeviceObject );
- TRACE( "volume %x device %p file %p in_size %u out_size %u\n",
Maybe "class" instead of "volume" is a bit clearer? I also am a big fan of marking hex numbers as hex...
context->params.volume.info_class, device, file, context->in_size, out_size );
- if (out_size)
- {
if (out_size > context->in_size)
{
if (!(out_buff = HeapAlloc( GetProcessHeap(), 0, out_size ))) return STATUS_NO_MEMORY;
memcpy( out_buff, context->in_buff, context->in_size );
to_free = context->in_buff;
context->in_buff = out_buff;
}
else
out_buff = context->in_buff;
- }
- irp = IoAllocateIrp( device->StackSize, FALSE );
- if (!irp)
- {
HeapFree( GetProcessHeap(), 0, out_buff );
return STATUS_NO_MEMORY;
- }
- irpsp = IoGetNextIrpStackLocation( irp );
- irpsp->MajorFunction = IRP_MJ_QUERY_VOLUME_INFORMATION;
- irpsp->Parameters.QueryVolume.FsInformationClass = context->params.volume.info_class;
- irpsp->Parameters.QueryVolume.Length = out_size;
- irpsp->DeviceObject = NULL;
- irpsp->CompletionRoutine = NULL;
- irpsp->FileObject = file;
- irp->AssociatedIrp.SystemBuffer = context->in_buff;
- irp->RequestorMode = KernelMode;
- irp->UserBuffer = out_buff;
- irp->UserIosb = NULL;
- irp->UserEvent = NULL;
- irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
- irp->Tail.Overlay.OriginalFileObject = file;
- irp->RequestorMode = UserMode;
- context->in_buff = NULL;
- irp->Flags |= IRP_DEALLOCATE_BUFFER; /* deallocate in_buff */
- dispatch_irp( device, irp, context );
- HeapFree( GetProcessHeap(), 0, to_free );
- return STATUS_SUCCESS;
+}
static NTSTATUS dispatch_free( struct dispatch_context *context ) { void *obj = wine_server_get_ptr( context->params.free.obj ); @@ -791,6 +854,7 @@ static const dispatch_func dispatch_funcs[] = dispatch_write, /* IRP_CALL_WRITE */ dispatch_flush, /* IRP_CALL_FLUSH */ dispatch_ioctl, /* IRP_CALL_IOCTL */
- dispatch_volume, /* IRP_CALL_VOLUME */ dispatch_free, /* IRP_CALL_FREE */ dispatch_cancel /* IRP_CALL_CANCEL */
}; diff --git a/server/device.c b/server/device.c index 01e08f295f7..6bacb859187 100644 --- a/server/device.c +++ b/server/device.c @@ -190,6 +190,7 @@ static int device_file_write( struct fd *fd, struct async *async, file_pos_t pos static int device_file_flush( struct fd *fd, struct async *async ); static int device_file_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ); static void device_file_reselect_async( struct fd *fd, struct async_queue *queue ); +static int device_file_get_volume_info( struct fd *fd, struct async *async, unsigned int info_class );
static const struct object_ops device_file_ops = { @@ -223,7 +224,7 @@ static const struct fd_ops device_file_fd_ops = device_file_write, /* write */ device_file_flush, /* flush */ default_fd_get_file_info, /* get_file_info */
- no_fd_get_volume_info, /* get_volume_info */
- device_file_get_volume_info, /* get_volume_info */ device_file_ioctl, /* ioctl */ default_fd_queue_async, /* queue_async */ device_file_reselect_async /* reselect_async */
@@ -575,6 +576,10 @@ static int fill_irp_params( struct device_manager *manager, struct irp_call *irp irp->params.ioctl.file = get_kernel_object_ptr( manager, &irp->file->obj ); irp->params.ioctl.out_size = irp->iosb->out_size; break;
case IRP_CALL_VOLUME:
irp->params.volume.file = get_kernel_object_ptr( manager, &irp->file->obj );
irp->params.volume.out_size = irp->iosb->out_size;
break;
}
*params = irp->params;
@@ -612,6 +617,17 @@ static enum server_fd_type device_file_get_fd_type( struct fd *fd ) return FD_TYPE_DEVICE; }
+static int device_file_get_volume_info( struct fd *fd, struct async *async, unsigned int info_class ) +{
- struct device_file *file = get_fd_user( fd );
- irp_params_t params;
- memset( ¶ms, 0, sizeof(params) );
- params.volume.type = IRP_CALL_VOLUME;
- params.volume.info_class = info_class;
- return queue_irp( file, ¶ms, async );
+}
static int device_file_read( struct fd *fd, struct async *async, file_pos_t pos ) { struct device_file *file = get_fd_user( fd ); diff --git a/server/fd.c b/server/fd.c index 7ea8ac273e5..29f36d801c5 100644 --- a/server/fd.c +++ b/server/fd.c @@ -2324,9 +2324,10 @@ void default_fd_get_file_info( struct fd *fd, obj_handle_t handle, unsigned int }
/* default get_volume_info() routine */ -void no_fd_get_volume_info( struct fd *fd, unsigned int info_class ) +int no_fd_get_volume_info( struct fd *fd, struct async *async, unsigned int info_class ) { set_error( STATUS_OBJECT_TYPE_MISMATCH );
- return 0;
}
/* default ioctl() routine */ @@ -2618,13 +2619,17 @@ DECL_HANDLER(get_file_info) /* query volume info */ DECL_HANDLER(get_volume_info) {
- struct fd *fd = get_handle_fd_obj( current->process, req->handle, 0 );
- struct fd *fd = get_handle_fd_obj( current->process, req->async.handle, 0 );
- struct async *async;
- if (fd)
- if (!fd) return;
- if ((async = create_request_async( fd, fd->comp_flags, &req->async ))) {
fd->fd_ops->get_volume_info( fd, req->info_class );
release_object( fd );
reply->wait = async_handoff( async, fd->fd_ops->get_volume_info( fd, async, req->info_class ), NULL, 0 );
}release_object( async );
- release_object( fd );
}
/* open a file object */ diff --git a/server/file.h b/server/file.h index e8ace7f49e4..53c03c006bc 100644 --- a/server/file.h +++ b/server/file.h @@ -65,7 +65,7 @@ struct fd_ops /* query file info */ void (*get_file_info)( struct fd *, obj_handle_t, unsigned int ); /* query volume info */
- void (*get_volume_info)( struct fd *, unsigned int );
- int (*get_volume_info)( struct fd *, struct async *, unsigned int ); /* perform an ioctl on the file */ int (*ioctl)(struct fd *fd, ioctl_code_t code, struct async *async ); /* queue an async operation */
@@ -114,7 +114,7 @@ extern int no_fd_write( struct fd *fd, struct async *async, file_pos_t pos ); extern int no_fd_flush( struct fd *fd, struct async *async ); extern void no_fd_get_file_info( struct fd *fd, obj_handle_t handle, unsigned int info_class ); extern void default_fd_get_file_info( struct fd *fd, obj_handle_t handle, unsigned int info_class ); -extern void no_fd_get_volume_info( struct fd *fd, unsigned int info_class ); +extern int no_fd_get_volume_info( struct fd *fd, struct async *async, unsigned int info_class ); extern int no_fd_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ); extern int default_fd_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ); extern void no_fd_queue_async( struct fd *fd, struct async *async, int type, int count ); diff --git a/server/named_pipe.c b/server/named_pipe.c index e7e5436c0e5..c57e7891953 100644 --- a/server/named_pipe.c +++ b/server/named_pipe.c @@ -143,7 +143,7 @@ static int pipe_end_set_sd( struct object *obj, const struct security_descriptor static int pipe_end_read( struct fd *fd, struct async *async, file_pos_t pos ); static int pipe_end_write( struct fd *fd, struct async *async_data, file_pos_t pos ); static int pipe_end_flush( struct fd *fd, struct async *async ); -static void pipe_end_get_volume_info( struct fd *fd, unsigned int info_class ); +static int pipe_end_get_volume_info( struct fd *fd, struct async *async, unsigned int info_class ); static void pipe_end_reselect_async( struct fd *fd, struct async_queue *queue ); static void pipe_end_get_file_info( struct fd *fd, obj_handle_t handle, unsigned int info_class );
@@ -699,7 +699,7 @@ static int pipe_end_set_sd( struct object *obj, const struct security_descriptor return 0; }
-static void pipe_end_get_volume_info( struct fd *fd, unsigned int info_class ) +static int pipe_end_get_volume_info( struct fd *fd, struct async *async, unsigned int info_class ) { switch (info_class) { @@ -719,6 +719,7 @@ static void pipe_end_get_volume_info( struct fd *fd, unsigned int info_class ) default: set_error( STATUS_NOT_IMPLEMENTED ); }
- return 0;
}
static void message_queue_read( struct pipe_end *pipe_end, struct iosb *iosb ) diff --git a/server/protocol.def b/server/protocol.def index 92290af701c..86f27f7aebd 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -675,6 +675,7 @@ enum irp_type IRP_CALL_WRITE, IRP_CALL_FLUSH, IRP_CALL_IOCTL,
- IRP_CALL_VOLUME, IRP_CALL_FREE, IRP_CALL_CANCEL
}; @@ -728,6 +729,14 @@ typedef union client_ptr_t file; /* opaque ptr for the file object */ } ioctl; struct
- {
enum irp_type type; /* IRP_CALL_VOLUME */
unsigned int info_class;/* information class */
data_size_t out_size; /* needed output size */
int __pad;
client_ptr_t file; /* opaque ptr for the file object */
- } volume;
- struct { enum irp_type type; /* IRP_CALL_FREE */ int __pad;
@@ -1353,9 +1362,11 @@ enum server_fd_type
/* Query volume information */ @REQ(get_volume_info)
- async_data_t async; /* async I/O parameters */ obj_handle_t handle; /* handle to the file */ unsigned int info_class; /* queried information class */
@REPLY
- obj_handle_t wait; /* handle to wait on for blocking read */ VARARG(data,bytes); /* volume info data */
@END
-- 2.17.1