From: "Erich E. Hoover" Subject: [PATCH v3 resend 1/4] server: Allow get_volume_info to issue IRP_MJ_QUERY_VOLUME_INFORMATION. Message-Id: Date: Tue, 8 Sep 2020 14:01:37 -0600 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 From 399b72df5cc2b6ba09ca67286b2bcefb49503aff Mon Sep 17 00:00:00 2001 From: "Erich E. Hoover" 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 --- 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; + + if (!file) return STATUS_INVALID_HANDLE; + + device = IoGetAttachedDevice( file->DeviceObject ); + + TRACE( "volume %x device %p file %p in_size %u out_size %u\n", + 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