[PATCH] ntdll: Add support for FileReplaceCompletionInformation

Andrew Buck mrelectrify at warsaw-revamped.com
Mon May 30 22:09:55 CDT 2022


FileReplaceCompletionInformation is the officially-documented
way of changing or removing completion objects from a file
descriptor.

---
Generally, as long as one has already been created with
CreateIoCompletionPort, the function will succeed. This is used
in some libraries that wrap sockets and use overlapped I/O
upon releasing the native handle.

Signed-off-by: Andrew Buck <mrelectrify at warsaw-revamped.com>
---
 dlls/ntdll/unix/file.c         | 16 ++++++++++++++++
 include/wine/server_protocol.h | 22 +++++++++++++++++++++-
 server/fd.c                    | 22 ++++++++++++++++++++++
 server/protocol.def            | 10 ++++++++++
 server/request.h               |  6 ++++++
 server/trace.c                 | 10 ++++++++++
 6 files changed, 85 insertions(+), 1 deletion(-)

diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index cc8bf0c6e82..ecedf070a05 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -4603,6 +4603,22 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io,
         else status = STATUS_INVALID_PARAMETER_3;
         break;
 
+    case FileReplaceCompletionInformation:
+            if (len >= sizeof(FILE_COMPLETION_INFORMATION))
+            {
+                FILE_COMPLETION_INFORMATION *info = ptr;
+                SERVER_START_REQ( replace_completion_info )
+                {
+                    req->handle   = wine_server_obj_handle( handle );
+                    req->chandle = wine_server_obj_handle( info->CompletionPort );
+                    req->ckey = info->CompletionKey;
+                    status = wine_server_call( req );
+                }
+                SERVER_END_REQ;
+            }
+            else status = STATUS_INVALID_PARAMETER_3;
+            break;
+
     default:
         FIXME("Unsupported class (%d)\n", class);
         status = STATUS_NOT_IMPLEMENTED;
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 868add58abf..f098f6af0c0 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -5066,6 +5066,23 @@ struct set_completion_info_reply
 
 
 
+
+struct replace_completion_info_request
+{
+    struct request_header __header;
+    obj_handle_t  handle;
+    apc_param_t   ckey;
+    obj_handle_t  chandle;
+    char __pad_28[4];
+};
+struct replace_completion_info_reply
+{
+    struct reply_header __header;
+};
+
+
+
+
 struct add_fd_completion_request
 {
     struct request_header __header;
@@ -5697,6 +5714,7 @@ enum request
     REQ_remove_completion,
     REQ_query_completion,
     REQ_set_completion_info,
+    REQ_replace_completion_info,
     REQ_add_fd_completion,
     REQ_set_fd_completion_mode,
     REQ_set_fd_disp_info,
@@ -5979,6 +5997,7 @@ union generic_request
     struct remove_completion_request remove_completion_request;
     struct query_completion_request query_completion_request;
     struct set_completion_info_request set_completion_info_request;
+    struct replace_completion_info_request replace_completion_info_request;
     struct add_fd_completion_request add_fd_completion_request;
     struct set_fd_completion_mode_request set_fd_completion_mode_request;
     struct set_fd_disp_info_request set_fd_disp_info_request;
@@ -6259,6 +6278,7 @@ union generic_reply
     struct remove_completion_reply remove_completion_reply;
     struct query_completion_reply query_completion_reply;
     struct set_completion_info_reply set_completion_info_reply;
+    struct replace_completion_info_reply replace_completion_info_reply;
     struct add_fd_completion_reply add_fd_completion_reply;
     struct set_fd_completion_mode_reply set_fd_completion_mode_reply;
     struct set_fd_disp_info_reply set_fd_disp_info_reply;
@@ -6288,7 +6308,7 @@ union generic_reply
 
 /* ### protocol_version begin ### */
 
-#define SERVER_PROTOCOL_VERSION 751
+#define SERVER_PROTOCOL_VERSION 752
 
 /* ### protocol_version end ### */
 
diff --git a/server/fd.c b/server/fd.c
index 1b4b98b0e76..00314589825 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -2912,6 +2912,28 @@ DECL_HANDLER(set_completion_info)
     }
 }
 
+/* replace completion object for a fd */
+DECL_HANDLER(replace_completion_info)
+{
+    struct fd *fd = get_handle_fd_obj( current->process, req->handle, 0 );
+    struct completion *old_completion;
+
+    if (fd)
+    {
+        if (is_fd_overlapped( fd ) && fd->completion)
+        {
+            old_completion = fd->completion;
+            if (req->chandle)
+                fd->completion = get_completion_obj( current->process, req->chandle, IO_COMPLETION_MODIFY_STATE );
+            else
+                fd->completion = 0;
+            fd->comp_key = req->ckey;
+            release_object( old_completion );
+        }
+        release_object( fd );
+    }
+}
+
 /* push new completion msg into a completion queue attached to the fd */
 DECL_HANDLER(add_fd_completion)
 {
diff --git a/server/protocol.def b/server/protocol.def
index 2be1658fca2..912da634797 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -3530,6 +3530,16 @@ struct handle_info
 @END
 
 
+
+/* associate object with completion port */
+ at REQ(replace_completion_info)
+    obj_handle_t  handle;         /* object handle */
+    apc_param_t   ckey;           /* completion key */
+    obj_handle_t  chandle;        /* port handle */
+ at END
+
+
+
 /* check for associated completion and push msg */
 @REQ(add_fd_completion)
     obj_handle_t   handle;        /* async' object */
diff --git a/server/request.h b/server/request.h
index 7fd63905e0e..64da1c319b1 100644
--- a/server/request.h
+++ b/server/request.h
@@ -369,6 +369,7 @@ DECL_HANDLER(add_completion);
 DECL_HANDLER(remove_completion);
 DECL_HANDLER(query_completion);
 DECL_HANDLER(set_completion_info);
+DECL_HANDLER(replace_completion_info);
 DECL_HANDLER(add_fd_completion);
 DECL_HANDLER(set_fd_completion_mode);
 DECL_HANDLER(set_fd_disp_info);
@@ -650,6 +651,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
     (req_handler)req_remove_completion,
     (req_handler)req_query_completion,
     (req_handler)req_set_completion_info,
+    (req_handler)req_replace_completion_info,
     (req_handler)req_add_fd_completion,
     (req_handler)req_set_fd_completion_mode,
     (req_handler)req_set_fd_disp_info,
@@ -2146,6 +2148,10 @@ C_ASSERT( FIELD_OFFSET(struct set_completion_info_request, handle) == 12 );
 C_ASSERT( FIELD_OFFSET(struct set_completion_info_request, ckey) == 16 );
 C_ASSERT( FIELD_OFFSET(struct set_completion_info_request, chandle) == 24 );
 C_ASSERT( sizeof(struct set_completion_info_request) == 32 );
+C_ASSERT( FIELD_OFFSET(struct replace_completion_info_request, handle) == 12 );
+C_ASSERT( FIELD_OFFSET(struct replace_completion_info_request, ckey) == 16 );
+C_ASSERT( FIELD_OFFSET(struct replace_completion_info_request, chandle) == 24 );
+C_ASSERT( sizeof(struct replace_completion_info_request) == 32 );
 C_ASSERT( FIELD_OFFSET(struct add_fd_completion_request, handle) == 12 );
 C_ASSERT( FIELD_OFFSET(struct add_fd_completion_request, cvalue) == 16 );
 C_ASSERT( FIELD_OFFSET(struct add_fd_completion_request, information) == 24 );
diff --git a/server/trace.c b/server/trace.c
index 15ca4e7d71e..15afd7e3217 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -4263,6 +4263,13 @@ static void dump_set_completion_info_request( const struct set_completion_info_r
     fprintf( stderr, ", chandle=%04x", req->chandle );
 }
 
+static void dump_replace_completion_info_request( const struct replace_completion_info_request *req )
+{
+    fprintf( stderr, " handle=%04x", req->handle );
+    dump_uint64( ", ckey=", &req->ckey );
+    fprintf( stderr, ", chandle=%04x", req->chandle );
+}
+
 static void dump_add_fd_completion_request( const struct add_fd_completion_request *req )
 {
     fprintf( stderr, " handle=%04x", req->handle );
@@ -4737,6 +4744,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
     (dump_func)dump_remove_completion_request,
     (dump_func)dump_query_completion_request,
     (dump_func)dump_set_completion_info_request,
+    (dump_func)dump_replace_completion_info_request,
     (dump_func)dump_add_fd_completion_request,
     (dump_func)dump_set_fd_completion_mode_request,
     (dump_func)dump_set_fd_disp_info_request,
@@ -5020,6 +5028,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
     NULL,
     NULL,
     NULL,
+    NULL,
     (dump_func)dump_get_window_layered_info_reply,
     NULL,
     (dump_func)dump_alloc_user_handle_reply,
@@ -5293,6 +5302,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
     "remove_completion",
     "query_completion",
     "set_completion_info",
+    "replace_completion_info",
     "add_fd_completion",
     "set_fd_completion_mode",
     "set_fd_disp_info",
-- 
2.34.1




More information about the wine-devel mailing list