diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c index bf35a47d73890722e46dbad9a9f5720e24639e98..bbb071b786a54fff42cda9b19cd59a10cab3bf8f 100644 --- a/dlls/ntdll/file.c +++ b/dlls/ntdll/file.c @@ -1658,6 +1658,23 @@ NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io, } break; + case FileCompletionInformation: + if (len >= sizeof(FILE_COMPLETION_INFORMATION)) + { + FILE_COMPLETION_INFORMATION *info = (FILE_COMPLETION_INFORMATION *)ptr; + + SERVER_START_REQ( set_completion_info ) + { + req->handle = handle; + req->chandle = info->CompletionPort; + req->ckey = info->CompletionKey; + io->u.Status = wine_server_call( req ); + } + SERVER_END_REQ; + } else + io->u.Status = STATUS_INVALID_PARAMETER_3; + break; + default: FIXME("Unsupported class (%d)\n", class); io->u.Status = STATUS_NOT_IMPLEMENTED; diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index e37f25c8e6194f8b6bd98a92fa98656167c087de..314a3a624ecda58c17b11db794927fbf36dbd70a 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -4156,6 +4156,20 @@ struct query_completion_reply }; + +struct set_completion_info_request +{ + struct request_header __header; + obj_handle_t handle; + obj_handle_t chandle; + unsigned long ckey; +}; +struct set_completion_info_reply +{ + struct reply_header __header; +}; + + enum request { REQ_new_process, @@ -4383,6 +4397,7 @@ enum request REQ_add_completion, REQ_remove_completion, REQ_query_completion, + REQ_set_completion_info, REQ_NB_REQUESTS }; @@ -4615,6 +4630,7 @@ union generic_request struct add_completion_request add_completion_request; struct remove_completion_request remove_completion_request; struct query_completion_request query_completion_request; + struct set_completion_info_request set_completion_info_request; }; union generic_reply { @@ -4845,8 +4861,9 @@ union generic_reply struct add_completion_reply add_completion_reply; struct remove_completion_reply remove_completion_reply; struct query_completion_reply query_completion_reply; + struct set_completion_info_reply set_completion_info_reply; }; -#define SERVER_PROTOCOL_VERSION 314 +#define SERVER_PROTOCOL_VERSION 315 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/completion.c b/server/completion.c index 1282bb47d93b0f7446dd2cec0ed06f4370c9b5e5..13f59395cb8618b9dbbe1b650cea798b16123812 100644 --- a/server/completion.c +++ b/server/completion.c @@ -39,6 +39,7 @@ #include "wine/unicode.h" #include "object.h" +#include "file.h" #include "handle.h" #include "request.h" @@ -124,7 +125,7 @@ static struct completion *create_completion( struct directory *root, const struc return completion; } -static struct completion *get_completion_obj( struct process *process, obj_handle_t handle, unsigned int access ) +struct completion *get_completion_obj( struct process *process, obj_handle_t handle, unsigned int access ) { return (struct completion *) get_handle_obj( process, handle, access, &completion_ops ); } diff --git a/server/fd.c b/server/fd.c index 31e1c9fd6a7afccd4f7297dd5f9ab39a1f51f94c..d671a1cddc665b15f075236878b63124a35f1401 100644 --- a/server/fd.c +++ b/server/fd.c @@ -180,6 +180,8 @@ struct fd struct async_queue *read_q; /* async readers of this fd */ struct async_queue *write_q; /* async writers of this fd */ struct async_queue *wait_q; /* other async waiters of this fd */ + struct completion *completion; /* completion object attached to this fd */ + unsigned long comp_key; /* completion key to set in completion events */ }; static void fd_dump( struct object *obj, int verbose ); @@ -1329,6 +1331,7 @@ static void fd_destroy( struct object *obj ) free_async_queue( fd->write_q ); free_async_queue( fd->wait_q ); + if (fd->completion) release_object( fd->completion ); remove_fd_locks( fd ); list_remove( &fd->inode_entry ); if (fd->poll_index != -1) remove_poll_user( fd, fd->poll_index ); @@ -1406,6 +1409,7 @@ static struct fd *alloc_fd_object(void) fd->read_q = NULL; fd->write_q = NULL; fd->wait_q = NULL; + fd->completion = NULL; list_init( &fd->inode_entry ); list_init( &fd->locks ); @@ -1438,6 +1442,7 @@ struct fd *alloc_pseudo_fd( const struct fd_ops *fd_user_ops, struct object *use fd->read_q = NULL; fd->write_q = NULL; fd->wait_q = NULL; + fd->completion = NULL; fd->no_fd_status = STATUS_BAD_DEVICE_TYPE; list_init( &fd->inode_entry ); list_init( &fd->locks ); @@ -2009,3 +2014,20 @@ DECL_HANDLER(cancel_async) release_object( fd ); } } + +/* attach completion object to a fd */ +DECL_HANDLER(set_completion_info) +{ + struct fd *fd = get_handle_fd_obj( current->process, req->handle, 0 ); + + if (fd) + { + if (!fd->completion) + { + fd->completion = get_completion_obj( current->process, req->chandle, IO_COMPLETION_MODIFY_STATE ); + fd->comp_key = req->ckey; + } + else set_error( STATUS_INVALID_PARAMETER ); + release_object( fd ); + } +} diff --git a/server/file.h b/server/file.h index c84f0b8179b0f68ed10f4f3010215590dd386a4f..d56aad037fe1ec79054aef736eb2c3ed5d7fba49 100644 --- a/server/file.h +++ b/server/file.h @@ -25,6 +25,7 @@ struct fd; struct async_queue; +struct completion; typedef unsigned __int64 file_pos_t; @@ -120,6 +121,10 @@ extern void do_change_notify( int unix_fd ); extern void sigio_callback(void); extern struct object *create_dir_obj( struct fd *fd ); +/* completion */ + +struct completion *get_completion_obj( struct process *process, obj_handle_t handle, unsigned int access ); + /* serial port functions */ extern int is_serial_fd( struct fd *fd ); diff --git a/server/protocol.def b/server/protocol.def index 8eec8a7596c42281e7d3abfca24d88cf750eb7a5..2e83c12ebd585f5708398e9aa80f50c16a267ac9 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2983,3 +2983,11 @@ enum message_type @REPLY unsigned int depth; /* completion queue depth */ @END + + +/* associate object with completion port */ +@REQ(set_completion_info) + obj_handle_t handle; /* object handle */ + obj_handle_t chandle; /* port handle */ + unsigned long ckey; /* completion key */ +@END diff --git a/server/request.h b/server/request.h index 741156596eacd3667bee0124e3e6d11b7c3ae84e..0a013abb3157908da9cb50e033ed14ccb8221c38 100644 --- a/server/request.h +++ b/server/request.h @@ -335,6 +335,7 @@ DECL_HANDLER(open_completion); DECL_HANDLER(add_completion); DECL_HANDLER(remove_completion); DECL_HANDLER(query_completion); +DECL_HANDLER(set_completion_info); #ifdef WANT_REQUEST_HANDLERS @@ -566,6 +567,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_add_completion, (req_handler)req_remove_completion, (req_handler)req_query_completion, + (req_handler)req_set_completion_info, }; #endif /* WANT_REQUEST_HANDLERS */ diff --git a/server/trace.c b/server/trace.c index b43141351378f3388ced373ca3aee832c0ee7131..d1575e1b9ed3fc980b16a9f727e7b663d68f9ff0 100644 --- a/server/trace.c +++ b/server/trace.c @@ -3628,6 +3628,13 @@ static void dump_query_completion_reply( const struct query_completion_reply *re fprintf( stderr, " depth=%08x", req->depth ); } +static void dump_set_completion_info_request( const struct set_completion_info_request *req ) +{ + fprintf( stderr, " handle=%p,", req->handle ); + fprintf( stderr, " chandle=%p,", req->chandle ); + fprintf( stderr, " ckey=%lx", req->ckey ); +} + static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_new_process_request, (dump_func)dump_get_new_process_info_request, @@ -3854,6 +3861,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_add_completion_request, (dump_func)dump_remove_completion_request, (dump_func)dump_query_completion_request, + (dump_func)dump_set_completion_info_request, }; static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { @@ -4082,6 +4090,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)0, (dump_func)dump_remove_completion_reply, (dump_func)dump_query_completion_reply, + (dump_func)0, }; static const char * const req_names[REQ_NB_REQUESTS] = { @@ -4310,6 +4319,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "add_completion", "remove_completion", "query_completion", + "set_completion_info", }; static const struct