From 635714397fc25b92d0f8bda1ca9af65bd060ff00 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Mon, 16 Apr 2007 14:45:03 +0200 Subject: [PATCH] server: Add infrastructure for ioctl server request. --- dlls/ntdll/file.c | 68 +++++++++++++++++++++++++++------- include/wine/server_protocol.h | 21 ++++++++++- server/change.c | 2 + server/fd.c | 20 ++++++++++ server/file.c | 1 + server/file.h | 5 +++ server/mailslot.c | 3 ++ server/named_pipe.c | 3 ++ server/process.c | 1 + server/protocol.def | 11 ++++++ server/queue.c | 1 + server/request.c | 1 + server/request.h | 2 + server/serial.c | 1 + server/signal.c | 1 + server/sock.c | 1 + server/thread.c | 1 + server/trace.c | 21 +++++++++++ 18 files changed, 150 insertions(+), 14 deletions(-) diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c index b218b8323e..b29bb1370a 100644 --- a/dlls/ntdll/file.c +++ b/dlls/ntdll/file.c @@ -913,6 +913,48 @@ done: return status; } + +/* callback for ioctl async I/O completion */ +static NTSTATUS ioctl_completion( void *arg, IO_STATUS_BLOCK *io, NTSTATUS status ) +{ + io->u.Status = status; + return status; +} + +/* do a ioctl call through the server */ +static NTSTATUS server_ioctl_file( HANDLE handle, HANDLE event, + PIO_APC_ROUTINE apc, PVOID apc_context, + IO_STATUS_BLOCK *io, ULONG code, + PVOID in_buffer, ULONG in_size, + PVOID out_buffer, ULONG out_size ) +{ + NTSTATUS status; + + SERVER_START_REQ( ioctl ) + { + req->handle = handle; + req->code = code; + req->async.callback = ioctl_completion; + req->async.iosb = io; + req->async.arg = NULL; + req->async.apc = apc; + req->async.apc_arg = apc_context; + req->async.event = event; + wine_server_add_data( req, in_buffer, in_size ); + wine_server_set_reply( req, out_buffer, out_size ); + if (!(status = wine_server_call( req ))) + io->Information = wine_server_reply_size( reply ); + } + SERVER_END_REQ; + + if (status == STATUS_NOT_SUPPORTED) + FIXME("Unsupported ioctl %x (device=%x access=%x func=%x method=%x)\n", + code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3); + + return status; +} + + /************************************************************************** * NtDeviceIoControlFile [NTDLL.@] * ZwDeviceIoControlFile [NTDLL.@] @@ -942,6 +984,7 @@ NTSTATUS WINAPI NtDeviceIoControlFile(HANDLE handle, HANDLE event, PVOID out_buffer, ULONG out_size) { ULONG device = (code >> 16); + NTSTATUS status; TRACE("(%p,%p,%p,%p,%p,0x%08x,%p,0x%08x,%p,0x%08x)\n", handle, event, apc, apc_context, io, code, @@ -954,24 +997,24 @@ NTSTATUS WINAPI NtDeviceIoControlFile(HANDLE handle, HANDLE event, case FILE_DEVICE_DVD: case FILE_DEVICE_CONTROLLER: case FILE_DEVICE_MASS_STORAGE: - io->u.Status = CDROM_DeviceIoControl(handle, event, apc, apc_context, io, code, - in_buffer, in_size, out_buffer, out_size); + status = CDROM_DeviceIoControl(handle, event, apc, apc_context, io, code, + in_buffer, in_size, out_buffer, out_size); break; case FILE_DEVICE_SERIAL_PORT: - io->u.Status = COMM_DeviceIoControl(handle, event, apc, apc_context, io, code, - in_buffer, in_size, out_buffer, out_size); + status = COMM_DeviceIoControl(handle, event, apc, apc_context, io, code, + in_buffer, in_size, out_buffer, out_size); break; case FILE_DEVICE_TAPE: - io->u.Status = TAPE_DeviceIoControl(handle, event, apc, apc_context, io, code, - in_buffer, in_size, out_buffer, out_size); + status = TAPE_DeviceIoControl(handle, event, apc, apc_context, io, code, + in_buffer, in_size, out_buffer, out_size); break; default: - FIXME("Unsupported ioctl %x (device=%x access=%x func=%x method=%x)\n", - code, device, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3); - io->u.Status = STATUS_NOT_SUPPORTED; + status = server_ioctl_file( handle, event, apc, apc_context, io, code, + in_buffer, in_size, out_buffer, out_size ); break; } - return io->u.Status; + if (status != STATUS_PENDING) io->u.Status = status; + return status; } /*********************************************************************** @@ -1170,9 +1213,8 @@ NTSTATUS WINAPI NtFsControlFile(HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc break; default: - FIXME("Unsupported fsctl %x (device=%x access=%x func=%x method=%x)\n", - code, code >> 16, (code >> 14) & 3, (code >> 2) & 0xfff, code & 3); - status = STATUS_NOT_SUPPORTED; + status = server_ioctl_file( handle, event, apc, apc_context, io, code, + in_buffer, in_size, out_buffer, out_size ); break; } diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index fe0f7da815..a4ee09188d 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -2679,6 +2679,22 @@ struct cancel_async_reply +struct ioctl_request +{ + struct request_header __header; + obj_handle_t handle; + unsigned int code; + async_data_t async; + /* VARARG(in_data,bytes); */ +}; +struct ioctl_reply +{ + struct reply_header __header; + /* VARARG(out_data,bytes); */ +}; + + + struct create_named_pipe_request { struct request_header __header; @@ -4141,6 +4157,7 @@ enum request REQ_set_serial_info, REQ_register_async, REQ_cancel_async, + REQ_ioctl, REQ_create_named_pipe, REQ_connect_named_pipe, REQ_wait_named_pipe, @@ -4365,6 +4382,7 @@ union generic_request struct set_serial_info_request set_serial_info_request; struct register_async_request register_async_request; struct cancel_async_request cancel_async_request; + struct ioctl_request ioctl_request; struct create_named_pipe_request create_named_pipe_request; struct connect_named_pipe_request connect_named_pipe_request; struct wait_named_pipe_request wait_named_pipe_request; @@ -4587,6 +4605,7 @@ union generic_reply struct set_serial_info_reply set_serial_info_reply; struct register_async_reply register_async_reply; struct cancel_async_reply cancel_async_reply; + struct ioctl_reply ioctl_reply; struct create_named_pipe_reply create_named_pipe_reply; struct connect_named_pipe_reply connect_named_pipe_reply; struct wait_named_pipe_reply wait_named_pipe_reply; @@ -4671,6 +4690,6 @@ union generic_reply struct allocate_locally_unique_id_reply allocate_locally_unique_id_reply; }; -#define SERVER_PROTOCOL_VERSION 292 +#define SERVER_PROTOCOL_VERSION 293 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/change.c b/server/change.c index c7d5823b7a..e996d4999e 100644 --- a/server/change.c +++ b/server/change.c @@ -187,6 +187,7 @@ static const struct fd_ops dir_fd_ops = default_poll_event, /* poll_event */ no_flush, /* flush */ dir_get_fd_type, /* get_fd_type */ + default_fd_ioctl, /* ioctl */ default_fd_queue_async, /* queue_async */ default_fd_reselect_async, /* reselect_async */ default_fd_cancel_async /* cancel_async */ @@ -520,6 +521,7 @@ static const struct fd_ops inotify_fd_ops = inotify_poll_event, /* poll_event */ NULL, /* flush */ NULL, /* get_fd_type */ + NULL, /* ioctl */ NULL, /* queue_async */ NULL, /* reselect_async */ NULL, /* cancel_async */ diff --git a/server/fd.c b/server/fd.c index 88fa6a4464..37ddefb781 100644 --- a/server/fd.c +++ b/server/fd.c @@ -1686,6 +1686,13 @@ void default_poll_event( struct fd *fd, int event ) else if (!fd->inode) set_fd_events( fd, fd->fd_ops->get_poll_events( fd ) ); } +/* default ioctl() routine */ +void default_fd_ioctl( struct fd *fd, unsigned int code, const async_data_t *async, + const void *data, data_size_t size ) +{ + set_error( STATUS_NOT_SUPPORTED ); +} + struct async *fd_queue_async( struct fd *fd, const async_data_t *data, int type, int count ) { struct async_queue *queue; @@ -1918,6 +1925,19 @@ DECL_HANDLER(unmount_device) } } +/* perform an ioctl on a file */ +DECL_HANDLER(ioctl) +{ + unsigned int access = (req->code >> 14) & (FILE_READ_DATA|FILE_WRITE_DATA); + struct fd *fd = get_handle_fd_obj( current->process, req->handle, access ); + + if (fd) + { + fd->fd_ops->ioctl( fd, req->code, &req->async, get_req_data(), get_req_data_size() ); + release_object( fd ); + } +} + /* create / reschedule an async I/O */ DECL_HANDLER(register_async) { diff --git a/server/file.c b/server/file.c index 8e10847550..a45c340d36 100644 --- a/server/file.c +++ b/server/file.c @@ -94,6 +94,7 @@ static const struct fd_ops file_fd_ops = default_poll_event, /* poll_event */ file_flush, /* flush */ file_get_fd_type, /* get_fd_type */ + default_fd_ioctl, /* ioctl */ default_fd_queue_async, /* queue_async */ default_fd_reselect_async, /* reselect_async */ default_fd_cancel_async /* cancel_async */ diff --git a/server/file.h b/server/file.h index 5e2e5f01d1..2c54e4d798 100644 --- a/server/file.h +++ b/server/file.h @@ -39,6 +39,9 @@ struct fd_ops void (*flush)(struct fd *, struct event **); /* get file information */ enum server_fd_type (*get_fd_type)(struct fd *fd); + /* perform an ioctl on the file */ + void (*ioctl)(struct fd *fd, unsigned int code, const async_data_t *async, + const void *data, data_size_t size); /* queue an async operation */ void (*queue_async)(struct fd *, const async_data_t *data, int type, int count); /* selected events for async i/o need an update */ @@ -74,6 +77,8 @@ extern void default_poll_event( struct fd *fd, int event ); extern struct async *fd_queue_async( struct fd *fd, const async_data_t *data, int type, int count ); extern void fd_async_wake_up( struct fd *fd, int type, unsigned int status ); extern void fd_reselect_async( struct fd *fd, struct async_queue *queue ); +extern void default_fd_ioctl( struct fd *fd, unsigned int code, const async_data_t *async, + const void *data, data_size_t size ); extern void default_fd_queue_async( struct fd *fd, const async_data_t *data, int type, int count ); extern void default_fd_reselect_async( struct fd *fd, struct async_queue *queue ); extern void default_fd_cancel_async( struct fd *fd ); diff --git a/server/mailslot.c b/server/mailslot.c index 8872742f2b..94f7f340a0 100644 --- a/server/mailslot.c +++ b/server/mailslot.c @@ -96,6 +96,7 @@ static const struct fd_ops mailslot_fd_ops = default_poll_event, /* poll_event */ no_flush, /* flush */ mailslot_get_fd_type, /* get_fd_type */ + default_fd_ioctl, /* ioctl */ mailslot_queue_async, /* queue_async */ default_fd_reselect_async, /* reselect_async */ default_fd_cancel_async /* cancel_async */ @@ -142,6 +143,7 @@ static const struct fd_ops mail_writer_fd_ops = default_poll_event, /* poll_event */ no_flush, /* flush */ mail_writer_get_fd_type, /* get_fd_type */ + default_fd_ioctl, /* ioctl */ default_fd_queue_async, /* queue_async */ default_fd_reselect_async, /* reselect_async */ default_fd_cancel_async /* cancel_async */ @@ -187,6 +189,7 @@ static const struct fd_ops mailslot_device_fd_ops = default_poll_event, /* poll_event */ no_flush, /* flush */ mailslot_device_get_fd_type, /* get_fd_type */ + default_fd_ioctl, /* ioctl */ default_fd_queue_async, /* queue_async */ default_fd_reselect_async, /* reselect_async */ default_fd_cancel_async /* cancel_async */ diff --git a/server/named_pipe.c b/server/named_pipe.c index d5b88a2710..62c30c4aab 100644 --- a/server/named_pipe.c +++ b/server/named_pipe.c @@ -162,6 +162,7 @@ static const struct fd_ops pipe_server_fd_ops = default_poll_event, /* poll_event */ pipe_server_flush, /* flush */ pipe_server_get_fd_type, /* get_fd_type */ + default_fd_ioctl, /* ioctl */ default_fd_queue_async, /* queue_async */ default_fd_reselect_async, /* reselect_async */ default_fd_cancel_async, /* cancel_async */ @@ -197,6 +198,7 @@ static const struct fd_ops pipe_client_fd_ops = default_poll_event, /* poll_event */ pipe_client_flush, /* flush */ pipe_client_get_fd_type, /* get_fd_type */ + default_fd_ioctl, /* ioctl */ default_fd_queue_async, /* queue_async */ default_fd_reselect_async, /* reselect_async */ default_fd_cancel_async /* cancel_async */ @@ -234,6 +236,7 @@ static const struct fd_ops named_pipe_device_fd_ops = default_poll_event, /* poll_event */ no_flush, /* flush */ named_pipe_device_get_fd_type, /* get_fd_type */ + default_fd_ioctl, /* ioctl */ default_fd_queue_async, /* queue_async */ default_fd_reselect_async, /* reselect_async */ default_fd_cancel_async /* cancel_async */ diff --git a/server/process.c b/server/process.c index 2e9fd59489..fffae5171b 100644 --- a/server/process.c +++ b/server/process.c @@ -86,6 +86,7 @@ static const struct fd_ops process_fd_ops = process_poll_event, /* poll_event */ NULL, /* flush */ NULL, /* get_fd_type */ + NULL, /* ioctl */ NULL, /* queue_async */ NULL, /* reselect_async */ NULL /* cancel async */ diff --git a/server/protocol.def b/server/protocol.def index 3396d4a0cd..3ca7241270 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1972,6 +1972,17 @@ enum message_type @END +/* Perform an ioctl on a file */ +@REQ(ioctl) + obj_handle_t handle; /* handle to the device */ + unsigned int code; /* ioctl code */ + async_data_t async; /* async I/O parameters */ + VARARG(in_data,bytes); /* ioctl input data */ +@REPLY + VARARG(out_data,bytes); /* ioctl output data */ +@END + + /* Create a named pipe */ @REQ(create_named_pipe) unsigned int access; diff --git a/server/queue.c b/server/queue.c index fa80d62903..85e08568e3 100644 --- a/server/queue.c +++ b/server/queue.c @@ -168,6 +168,7 @@ static const struct fd_ops msg_queue_fd_ops = msg_queue_poll_event, /* poll_event */ NULL, /* flush */ NULL, /* get_fd_type */ + NULL, /* ioctl */ NULL, /* queue_async */ NULL, /* reselect_async */ NULL /* cancel async */ diff --git a/server/request.c b/server/request.c index 404dda0477..4c4036a0a1 100644 --- a/server/request.c +++ b/server/request.c @@ -108,6 +108,7 @@ static const struct fd_ops master_socket_fd_ops = master_socket_poll_event, /* poll_event */ NULL, /* flush */ NULL, /* get_fd_type */ + NULL, /* ioctl */ NULL, /* queue_async */ NULL, /* reselect_async */ NULL /* cancel_async */ diff --git a/server/request.h b/server/request.h index 5b28a7f077..3424fb3fb1 100644 --- a/server/request.h +++ b/server/request.h @@ -245,6 +245,7 @@ DECL_HANDLER(get_serial_info); DECL_HANDLER(set_serial_info); DECL_HANDLER(register_async); DECL_HANDLER(cancel_async); +DECL_HANDLER(ioctl); DECL_HANDLER(create_named_pipe); DECL_HANDLER(connect_named_pipe); DECL_HANDLER(wait_named_pipe); @@ -468,6 +469,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_set_serial_info, (req_handler)req_register_async, (req_handler)req_cancel_async, + (req_handler)req_ioctl, (req_handler)req_create_named_pipe, (req_handler)req_connect_named_pipe, (req_handler)req_wait_named_pipe, diff --git a/server/serial.c b/server/serial.c index 4d1853cd36..d677d171e8 100644 --- a/server/serial.c +++ b/server/serial.c @@ -107,6 +107,7 @@ static const struct fd_ops serial_fd_ops = default_poll_event, /* poll_event */ serial_flush, /* flush */ serial_get_fd_type, /* get_file_info */ + default_fd_ioctl, /* ioctl */ serial_queue_async, /* queue_async */ default_fd_reselect_async, /* reselect_async */ default_fd_cancel_async /* cancel_async */ diff --git a/server/signal.c b/server/signal.c index 11a0179976..fb16c2fbdd 100644 --- a/server/signal.c +++ b/server/signal.c @@ -84,6 +84,7 @@ static const struct fd_ops handler_fd_ops = handler_poll_event, /* poll_event */ NULL, /* flush */ NULL, /* get_fd_type */ + NULL, /* ioctl */ NULL, /* queue_async */ NULL, /* reselect_async */ NULL /* cancel_async */ diff --git a/server/sock.c b/server/sock.c index 817c6bd2c3..29b685e32e 100644 --- a/server/sock.c +++ b/server/sock.c @@ -126,6 +126,7 @@ static const struct fd_ops sock_fd_ops = sock_poll_event, /* poll_event */ no_flush, /* flush */ sock_get_fd_type, /* get_file_info */ + default_fd_ioctl, /* ioctl */ sock_queue_async, /* queue_async */ sock_reselect_async, /* reselect_async */ sock_cancel_async /* cancel_async */ diff --git a/server/thread.c b/server/thread.c index 2bf031e54e..8e63e8b238 100644 --- a/server/thread.c +++ b/server/thread.c @@ -131,6 +131,7 @@ static const struct fd_ops thread_fd_ops = thread_poll_event, /* poll_event */ NULL, /* flush */ NULL, /* get_fd_type */ + NULL, /* ioctl */ NULL, /* queue_async */ NULL, /* reselect_async */ NULL /* cancel_async */ diff --git a/server/trace.c b/server/trace.c index 2b42a90808..84c409e7bd 100644 --- a/server/trace.c +++ b/server/trace.c @@ -2401,6 +2401,23 @@ static void dump_cancel_async_request( const struct cancel_async_request *req ) fprintf( stderr, " handle=%p", req->handle ); } +static void dump_ioctl_request( const struct ioctl_request *req ) +{ + fprintf( stderr, " handle=%p,", req->handle ); + fprintf( stderr, " code=%08x,", req->code ); + fprintf( stderr, " async=" ); + dump_async_data( &req->async ); + fprintf( stderr, "," ); + fprintf( stderr, " in_data=" ); + dump_varargs_bytes( cur_size ); +} + +static void dump_ioctl_reply( const struct ioctl_reply *req ) +{ + fprintf( stderr, " out_data=" ); + dump_varargs_bytes( cur_size ); +} + static void dump_create_named_pipe_request( const struct create_named_pipe_request *req ) { fprintf( stderr, " access=%08x,", req->access ); @@ -3590,6 +3607,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_set_serial_info_request, (dump_func)dump_register_async_request, (dump_func)dump_cancel_async_request, + (dump_func)dump_ioctl_request, (dump_func)dump_create_named_pipe_request, (dump_func)dump_connect_named_pipe_request, (dump_func)dump_wait_named_pipe_request, @@ -3810,6 +3828,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)0, (dump_func)0, (dump_func)0, + (dump_func)dump_ioctl_reply, (dump_func)dump_create_named_pipe_reply, (dump_func)0, (dump_func)0, @@ -4030,6 +4049,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "set_serial_info", "register_async", "cancel_async", + "ioctl", "create_named_pipe", "connect_named_pipe", "wait_named_pipe", @@ -4166,6 +4186,7 @@ static const struct { "NOT_A_DIRECTORY", STATUS_NOT_A_DIRECTORY }, { "NOT_IMPLEMENTED", STATUS_NOT_IMPLEMENTED }, { "NOT_REGISTRY_FILE", STATUS_NOT_REGISTRY_FILE }, + { "NOT_SUPPORTED", STATUS_NOT_SUPPORTED }, { "NO_DATA_DETECTED", STATUS_NO_DATA_DETECTED }, { "NO_IMPERSONATION_TOKEN", STATUS_NO_IMPERSONATION_TOKEN }, { "NO_MEMORY", STATUS_NO_MEMORY }, -- 2.32.0.93.g670b81a890