This fixes various corner cases.
This is not motivated by any particular application. However, the server-side code seems at least as simple as the existing client-side code, is more accurate, and removes a potential source of complication from any future work involving asyncs.
-- v4: server: Reimplement mailslots using server-side I/O. ntdll: Respect the "options" argument to NtCreateMailslotFile.
From: Elizabeth Figura zfigura@codeweavers.com
Named pipes are now implemented entirely on the server side, and there is no code that warrants a separate FD type. --- server/named_pipe.c | 2 +- server/protocol.def | 1 - 2 files changed, 1 insertion(+), 2 deletions(-)
diff --git a/server/named_pipe.c b/server/named_pipe.c index f3404a33c3b..dd8c14b30a9 100644 --- a/server/named_pipe.c +++ b/server/named_pipe.c @@ -1016,7 +1016,7 @@ static void pipe_end_reselect_async( struct fd *fd, struct async_queue *queue )
static enum server_fd_type pipe_end_get_fd_type( struct fd *fd ) { - return FD_TYPE_PIPE; + return FD_TYPE_DEVICE; }
static void pipe_end_peek( struct pipe_end *pipe_end ) diff --git a/server/protocol.def b/server/protocol.def index 91257fce3a1..3c6596aebe2 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1500,7 +1500,6 @@ enum server_fd_type FD_TYPE_DIR, /* directory */ FD_TYPE_SOCKET, /* socket */ FD_TYPE_SERIAL, /* serial port */ - FD_TYPE_PIPE, /* named pipe */ FD_TYPE_MAILSLOT, /* mailslot */ FD_TYPE_CHAR, /* unspecified char device */ FD_TYPE_DEVICE, /* Windows device file */
From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/kernel32/tests/mailslot.c | 106 ++++++++++++++++++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-)
diff --git a/dlls/kernel32/tests/mailslot.c b/dlls/kernel32/tests/mailslot.c index a23aad96995..f21d3a3076f 100644 --- a/dlls/kernel32/tests/mailslot.c +++ b/dlls/kernel32/tests/mailslot.c @@ -22,18 +22,24 @@ #include <stdlib.h> #include <stdio.h>
+#include <ntstatus.h> +#define WIN32_NO_STATUS #include <windef.h> #include <winbase.h> - +#include <winternl.h> #include "wine/test.h"
static const char szmspath[] = "\\.\mailslot\wine_mailslot_test";
static int mailslot_test(void) { + UNICODE_STRING nt_path = RTL_CONSTANT_STRING( L"\??\MAILSLOT\wine_mailslot_test" ); HANDLE hSlot, hSlot2, hWriter, hWriter2; unsigned char buffer[16]; DWORD count, dwMax, dwNext, dwMsgCount, dwTimeout; + FILE_MAILSLOT_QUERY_INFORMATION info; + OBJECT_ATTRIBUTES attr; + IO_STATUS_BLOCK io; BOOL ret;
/* sanity check on GetMailslotInfo */ @@ -102,6 +108,20 @@ static int mailslot_test(void) "slot write\n"); ok( GetLastError() == ERROR_ACCESS_DENIED, "wrong error %lu\n", GetLastError() );
+ io.Status = 0xdeadbeef; + io.Information = 0xdeadbeef; + ret = NtReadFile( hSlot, NULL, NULL, NULL, &io, buffer, sizeof(buffer), NULL, NULL ); + ok( ret == STATUS_IO_TIMEOUT, "got %#x\n", ret ); + ok( io.Status == 0xdeadbeef, "got status %#lx\n", io.Status ); + ok( io.Information == 0xdeadbeef, "got size %Iu\n", io.Information ); + + io.Status = 0xdeadbeef; + io.Information = 0xdeadbeef; + ret = NtWriteFile( hSlot, NULL, NULL, NULL, &io, buffer, sizeof(buffer), NULL, NULL ); + ok( ret == STATUS_ACCESS_DENIED, "got %#x\n", ret ); + ok( io.Status == 0xdeadbeef, "got status %#lx\n", io.Status ); + ok( io.Information == 0xdeadbeef, "got size %Iu\n", io.Information ); + /* now try and open the client, but with the wrong sharing mode */ hWriter = CreateFileA(szmspath, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); @@ -141,6 +161,13 @@ static int mailslot_test(void) ok( GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_ACCESS_DENIED, "wrong error %lu\n", GetLastError() );
+ io.Status = 0xdeadbeef; + io.Information = 0xdeadbeef; + ret = NtReadFile( hWriter, NULL, NULL, NULL, &io, buffer, sizeof(buffer), NULL, NULL ); + todo_wine ok( ret == STATUS_INVALID_PARAMETER, "got %#x\n", ret ); + ok( io.Status == 0xdeadbeef, "got status %#lx\n", io.Status ); + ok( io.Information == 0xdeadbeef, "got size %Iu\n", io.Information ); + /* * seeing as there's something in the slot, * we should be able to read it once @@ -310,6 +337,48 @@ static int mailslot_test(void) if (!ret) ok( GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %lu\n", GetLastError() ); else ok( count == 0, "wrong count %lu\n", count );
+ /* Try to perform a partial read. */ + count = 0; + ret = WriteFile( hWriter, buffer, 2, &count, NULL ); + ok( ret, "got %d\n", ret ); + ok( count == 2, "got count %lu\n", count ); + + io.Status = 0xdeadbeef; + io.Information = 0xdeadbeef; + ret = NtReadFile( hSlot, NULL, NULL, NULL, &io, buffer, 1, NULL, NULL ); + todo_wine ok( ret == STATUS_BUFFER_TOO_SMALL, "got %#x\n", ret ); + todo_wine ok( io.Status == 0xdeadbeef, "got status %#lx\n", io.Status ); + todo_wine ok( io.Information == 0xdeadbeef, "got size %Iu\n", io.Information ); + + io.Status = 0xdeadbeef; + io.Information = 0xdeadbeef; + memset( &info, 0xcc, sizeof(info) ); + ret = NtQueryInformationFile( hSlot, &io, &info, sizeof(info), FileMailslotQueryInformation ); + ok( ret == STATUS_SUCCESS, "got %#x\n", ret ); + ok( io.Status == STATUS_SUCCESS, "got status %#lx\n", io.Status ); + ok( io.Information == sizeof(info), "got size %Iu\n", io.Information ); + ok( !info.MaximumMessageSize, "got maximum size %lu\n", info.MaximumMessageSize ); + ok( !info.MailslotQuota, "got quota %lu\n", info.MailslotQuota ); + todo_wine ok( info.NextMessageSize == 2, "got next size %lu\n", info.NextMessageSize ); + todo_wine ok( info.MessagesAvailable == 1, "got message count %lu\n", info.MessagesAvailable ); + ok( !info.ReadTimeout.QuadPart, "got timeout %I64u\n", info.ReadTimeout.QuadPart ); + + io.Status = 0xdeadbeef; + io.Information = 0xdeadbeef; + memset( &info, 0xcc, sizeof(info) ); + ret = NtQueryInformationFile( hWriter, &io, &info, sizeof(info), FileMailslotQueryInformation ); + todo_wine ok( ret == STATUS_SUCCESS || ret == STATUS_INVALID_PARAMETER /* Win < 8 */, "got %#x\n", ret ); + if (ret == STATUS_SUCCESS) + { + ok( io.Status == STATUS_SUCCESS, "got status %#lx\n", io.Status ); + ok( io.Information == sizeof(info), "got size %Iu\n", io.Information ); + ok( !info.MaximumMessageSize, "got maximum size %lu\n", info.MaximumMessageSize ); + ok( !info.MailslotQuota, "got quota %lu\n", info.MailslotQuota ); + ok( info.NextMessageSize == 2, "got next size %lu\n", info.NextMessageSize ); + ok( info.MessagesAvailable == 1, "got message count %lu\n", info.MessagesAvailable ); + ok( !info.ReadTimeout.QuadPart, "got timeout %I64u\n", info.ReadTimeout.QuadPart ); + } + /* finally close the mailslot and its client */ ok( CloseHandle( hWriter2 ), "closing 2nd client\n"); ok( CloseHandle( hWriter ), "closing the client\n"); @@ -327,6 +396,41 @@ static int mailslot_test(void) ok( dwTimeout >= 900, "timeout too short %lu\n", dwTimeout ); ok( CloseHandle( hSlot ), "closing the mailslot\n");
+ InitializeObjectAttributes( &attr, &nt_path, 0, NULL, NULL ); + ret = NtCreateMailslotFile( &hSlot, GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, &attr, &io, 0, 0, 0, NULL ); + ok( !ret, "got %#x\n", ret ); + + io.Status = 0xdeadbeef; + io.Information = 0xdeadbeef; + ret = NtWriteFile( hSlot, NULL, NULL, NULL, &io, buffer, sizeof(buffer), NULL, NULL ); + todo_wine ok( ret == STATUS_INVALID_PARAMETER, "got %#x\n", ret ); + ok( io.Status == 0xdeadbeef, "got status %#lx\n", io.Status ); + ok( io.Information == 0xdeadbeef, "got size %Iu\n", io.Information ); + + io.Status = 0xdeadbeef; + io.Information = 0xdeadbeef; + ret = NtReadFile( hSlot, NULL, NULL, NULL, &io, buffer, sizeof(buffer), NULL, NULL ); + todo_wine ok( ret == STATUS_PENDING, "got %#x\n", ret ); + ok( io.Status == 0xdeadbeef, "got status %#lx\n", io.Status ); + ok( io.Information == 0xdeadbeef, "got size %Iu\n", io.Information ); + + ret = WaitForSingleObject( hSlot, 0 ); + todo_wine ok( ret == WAIT_TIMEOUT, "got %d\n", ret ); + + hWriter = CreateFileA( szmspath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL ); + ok( hWriter != INVALID_HANDLE_VALUE, "got err %lu\n", GetLastError() ); + + ret = WriteFile( hWriter, "data", 4, &count, NULL ); + ok( ret == TRUE, "got error %lu\n", GetLastError() ); + + ret = WaitForSingleObject( hSlot, 1000 ); + ok( !ret, "got %d\n", ret ); + todo_wine ok( !io.Status, "got status %#lx\n", io.Status ); + todo_wine ok( io.Information == 4, "got size %Iu\n", io.Information ); + + CloseHandle( hWriter ); + CloseHandle( hSlot ); + return 0; }
From: Elizabeth Figura zfigura@codeweavers.com
That is, don't fill the IOSB or signal completion (unless the async was explicitly marked as pending, with set_async_pending().
This is for convenience. --- server/async.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/server/async.c b/server/async.c index 80129ac0ac3..3c9b9588c6e 100644 --- a/server/async.c +++ b/server/async.c @@ -368,16 +368,6 @@ obj_handle_t async_handoff( struct async *async, data_size_t *result, int force_
async->initial_status = get_error();
- if (!async->pending && NT_ERROR( get_error() )) - { - async->iosb->status = get_error(); - async_call_completion_callback( async ); - - close_handle( async->thread->process, async->wait_handle ); - async->wait_handle = 0; - return 0; - } - if (get_error() != STATUS_PENDING) { /* status and data are already set and returned */ @@ -393,6 +383,16 @@ obj_handle_t async_handoff( struct async *async, data_size_t *result, int force_ } }
+ if (!async->pending && NT_ERROR( async->iosb->status )) + { + async_call_completion_callback( async ); + + close_handle( async->thread->process, async->wait_handle ); + async->wait_handle = 0; + set_error( async->iosb->status ); + return 0; + } + if (async->iosb->status != STATUS_PENDING) { if (result) *result = async->iosb->result;
From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/kernel32/sync.c | 4 ++-- dlls/kernel32/tests/mailslot.c | 4 ++-- dlls/ntdll/unix/file.c | 1 + server/mailslot.c | 7 +++---- server/protocol.def | 1 + 5 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/dlls/kernel32/sync.c b/dlls/kernel32/sync.c index 53419cd4618..44fd01002d4 100644 --- a/dlls/kernel32/sync.c +++ b/dlls/kernel32/sync.c @@ -692,8 +692,8 @@ HANDLE WINAPI CreateMailslotW( LPCWSTR lpName, DWORD nMaxMessageSize, else timeout.QuadPart = ((LONGLONG)0x7fffffff << 32) | 0xffffffff;
- if (!set_ntstatus( NtCreateMailslotFile( &handle, GENERIC_READ | SYNCHRONIZE, &attr, - &iosb, 0, 0, nMaxMessageSize, &timeout ))) + if (!set_ntstatus( NtCreateMailslotFile( &handle, GENERIC_READ | SYNCHRONIZE, &attr, &iosb, + FILE_SYNCHRONOUS_IO_NONALERT, 0, nMaxMessageSize, &timeout ))) handle = INVALID_HANDLE_VALUE;
RtlFreeUnicodeString( &nameW ); diff --git a/dlls/kernel32/tests/mailslot.c b/dlls/kernel32/tests/mailslot.c index f21d3a3076f..c27401e01c5 100644 --- a/dlls/kernel32/tests/mailslot.c +++ b/dlls/kernel32/tests/mailslot.c @@ -410,12 +410,12 @@ static int mailslot_test(void) io.Status = 0xdeadbeef; io.Information = 0xdeadbeef; ret = NtReadFile( hSlot, NULL, NULL, NULL, &io, buffer, sizeof(buffer), NULL, NULL ); - todo_wine ok( ret == STATUS_PENDING, "got %#x\n", ret ); + ok( ret == STATUS_PENDING, "got %#x\n", ret ); ok( io.Status == 0xdeadbeef, "got status %#lx\n", io.Status ); ok( io.Information == 0xdeadbeef, "got size %Iu\n", io.Information );
ret = WaitForSingleObject( hSlot, 0 ); - todo_wine ok( ret == WAIT_TIMEOUT, "got %d\n", ret ); + ok( ret == WAIT_TIMEOUT, "got %d\n", ret );
hWriter = CreateFileA( szmspath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL ); ok( hWriter != INVALID_HANDLE_VALUE, "got err %lu\n", GetLastError() ); diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 15fdf2cb021..f0bcf72f108 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -4175,6 +4175,7 @@ NTSTATUS WINAPI NtCreateMailslotFile( HANDLE *handle, ULONG access, OBJECT_ATTRI SERVER_START_REQ( create_mailslot ) { req->access = access; + req->options = options; req->max_msgsize = msg_size; req->read_timeout = timeout ? timeout->QuadPart : -1; wine_server_add_data( req, objattr, len ); diff --git a/server/mailslot.c b/server/mailslot.c index 2d8697ec9bd..b8a48c66bed 100644 --- a/server/mailslot.c +++ b/server/mailslot.c @@ -474,7 +474,7 @@ static enum server_fd_type mailslot_device_file_get_fd_type( struct fd *fd )
static struct mailslot *create_mailslot( struct object *root, const struct unicode_str *name, unsigned int attr, - int max_msgsize, timeout_t read_timeout, + unsigned int options, int max_msgsize, timeout_t read_timeout, const struct security_descriptor *sd ) { struct mailslot *mailslot; @@ -494,8 +494,7 @@ static struct mailslot *create_mailslot( struct object *root, fcntl( fds[1], F_SETFL, O_NONBLOCK ); shutdown( fds[0], SHUT_RD ); mailslot->write_fd = fds[0]; - if ((mailslot->fd = create_anonymous_fd( &mailslot_fd_ops, fds[1], &mailslot->obj, - FILE_SYNCHRONOUS_IO_NONALERT ))) + if ((mailslot->fd = create_anonymous_fd( &mailslot_fd_ops, fds[1], &mailslot->obj, options ))) { allow_fd_caching( mailslot->fd ); return mailslot; @@ -566,7 +565,7 @@ DECL_HANDLER(create_mailslot) if (!(root = get_directory_obj( current->process, objattr->rootdir ))) return; }
- if ((mailslot = create_mailslot( root, &name, objattr->attributes, req->max_msgsize, + if ((mailslot = create_mailslot( root, &name, objattr->attributes, req->options, req->max_msgsize, req->read_timeout, sd ))) { reply->handle = alloc_handle( current->process, mailslot, req->access, objattr->attributes ); diff --git a/server/protocol.def b/server/protocol.def index 3c6596aebe2..97cf762a467 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -3431,6 +3431,7 @@ struct handle_info /* Create a mailslot */ @REQ(create_mailslot) unsigned int access; /* wanted access rights */ + unsigned int options; timeout_t read_timeout; unsigned int max_msgsize; VARARG(objattr,object_attributes); /* object attributes */
From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/kernel32/tests/mailslot.c | 30 ++---- dlls/ntdll/unix/file.c | 66 +----------- include/wine/server_protocol.h | 8 +- server/mailslot.c | 191 ++++++++++++++++++++++++--------- server/protocol.def | 1 - server/request.h | 7 +- server/trace.c | 1 + 7 files changed, 163 insertions(+), 141 deletions(-)
diff --git a/dlls/kernel32/tests/mailslot.c b/dlls/kernel32/tests/mailslot.c index c27401e01c5..30805edc48e 100644 --- a/dlls/kernel32/tests/mailslot.c +++ b/dlls/kernel32/tests/mailslot.c @@ -94,7 +94,6 @@ static int mailslot_test(void) SetLastError(0xdeadbeef); ret = ReadFile(hSlot, buffer, 0, &count, NULL); ok(!ret, "ReadFile should fail\n"); - todo_wine ok(GetLastError() == ERROR_SEM_TIMEOUT, "wrong error %lu\n", GetLastError()); ok(count == 0, "expected 0, got %lu\n", count);
@@ -264,9 +263,7 @@ static int mailslot_test(void) ok( GetMailslotInfo( hSlot, NULL, &dwNext, &dwMsgCount, NULL ), "getmailslotinfo failed\n"); ok( dwNext == 1, "dwNext incorrect\n"); - todo_wine { ok( dwMsgCount == 2, "dwMsgCount incorrect\n"); - }
/* write a 3rd message with zero size */ ok( WriteFile( hWriter2, buffer, 0, &count, NULL), "3rd write failed\n"); @@ -276,8 +273,7 @@ static int mailslot_test(void) ok( GetMailslotInfo( hSlot, NULL, &dwNext, &dwMsgCount, NULL ), "getmailslotinfo failed\n"); ok( dwNext == 1, "dwNext incorrect\n"); - todo_wine - ok( dwMsgCount == 3, "dwMsgCount incorrect %lu\n", dwMsgCount); + ok( dwMsgCount == 3, "dwMsgCount incorrect %lu\n", dwMsgCount);
buffer[0]=buffer[1]=0;
@@ -295,9 +291,7 @@ static int mailslot_test(void) ok( GetMailslotInfo( hSlot, NULL, &dwNext, &dwMsgCount, NULL ), "getmailslotinfo failed\n"); ok( dwNext == 2, "dwNext incorrect\n"); - todo_wine { - ok( dwMsgCount == 2, "dwMsgCount incorrect %lu\n", dwMsgCount); - } + ok( dwMsgCount == 2, "dwMsgCount incorrect %lu\n", dwMsgCount);
/* read the second message */ ok( ReadFile( hSlot, buffer, sizeof buffer, &count, NULL), @@ -310,15 +304,11 @@ static int mailslot_test(void) ok( GetMailslotInfo( hSlot, NULL, &dwNext, &dwMsgCount, NULL ), "getmailslotinfo failed\n"); ok( dwNext == 0, "dwNext incorrect %lu\n", dwNext); - todo_wine { - ok( dwMsgCount == 1, "dwMsgCount incorrect %lu\n", dwMsgCount); - } + ok( dwMsgCount == 1, "dwMsgCount incorrect %lu\n", dwMsgCount);
/* read the 3rd (zero length) message */ - todo_wine { ok( ReadFile( hSlot, buffer, sizeof buffer, &count, NULL), "3rd slot read failed\n"); - } ok( count == 0, "failed to get 3rd message\n");
/* @@ -346,9 +336,9 @@ static int mailslot_test(void) io.Status = 0xdeadbeef; io.Information = 0xdeadbeef; ret = NtReadFile( hSlot, NULL, NULL, NULL, &io, buffer, 1, NULL, NULL ); - todo_wine ok( ret == STATUS_BUFFER_TOO_SMALL, "got %#x\n", ret ); - todo_wine ok( io.Status == 0xdeadbeef, "got status %#lx\n", io.Status ); - todo_wine ok( io.Information == 0xdeadbeef, "got size %Iu\n", io.Information ); + ok( ret == STATUS_BUFFER_TOO_SMALL, "got %#x\n", ret ); + ok( io.Status == 0xdeadbeef, "got status %#lx\n", io.Status ); + ok( io.Information == 0xdeadbeef, "got size %Iu\n", io.Information );
io.Status = 0xdeadbeef; io.Information = 0xdeadbeef; @@ -359,8 +349,8 @@ static int mailslot_test(void) ok( io.Information == sizeof(info), "got size %Iu\n", io.Information ); ok( !info.MaximumMessageSize, "got maximum size %lu\n", info.MaximumMessageSize ); ok( !info.MailslotQuota, "got quota %lu\n", info.MailslotQuota ); - todo_wine ok( info.NextMessageSize == 2, "got next size %lu\n", info.NextMessageSize ); - todo_wine ok( info.MessagesAvailable == 1, "got message count %lu\n", info.MessagesAvailable ); + ok( info.NextMessageSize == 2, "got next size %lu\n", info.NextMessageSize ); + ok( info.MessagesAvailable == 1, "got message count %lu\n", info.MessagesAvailable ); ok( !info.ReadTimeout.QuadPart, "got timeout %I64u\n", info.ReadTimeout.QuadPart );
io.Status = 0xdeadbeef; @@ -425,8 +415,8 @@ static int mailslot_test(void)
ret = WaitForSingleObject( hSlot, 1000 ); ok( !ret, "got %d\n", ret ); - todo_wine ok( !io.Status, "got status %#lx\n", io.Status ); - todo_wine ok( io.Information == 4, "got size %Iu\n", io.Information ); + ok( !io.Status, "got status %#lx\n", io.Status ); + ok( io.Information == 4, "got size %Iu\n", io.Information );
CloseHandle( hWriter ); CloseHandle( hSlot ); diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index f0bcf72f108..ca95dd347eb 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -4522,44 +4522,6 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, } } break; - case FileMailslotQueryInformation: - { - FILE_MAILSLOT_QUERY_INFORMATION *info = ptr; - - SERVER_START_REQ( set_mailslot_info ) - { - req->handle = wine_server_obj_handle( handle ); - req->flags = 0; - status = wine_server_call( req ); - if (status == STATUS_SUCCESS) - { - info->MaximumMessageSize = reply->max_msgsize; - info->MailslotQuota = 0; - info->NextMessageSize = 0; - info->MessagesAvailable = 0; - info->ReadTimeout.QuadPart = reply->read_timeout; - } - } - SERVER_END_REQ; - if (!status) - { - char *tmpbuf; - ULONG size = info->MaximumMessageSize ? info->MaximumMessageSize : 0x10000; - if (size > 0x10000) size = 0x10000; - if ((tmpbuf = malloc( size ))) - { - if (needs_close) close( fd ); - if (!server_get_unix_fd( handle, FILE_READ_DATA, &fd, &needs_close, NULL, NULL )) - { - int res = recv( fd, tmpbuf, size, MSG_PEEK ); - info->MessagesAvailable = (res > 0); - info->NextMessageSize = (res >= 0) ? res : MAILSLOT_NO_MESSAGE; - } - free( tmpbuf ); - } - } - } - break; case FileNameInformation: { FILE_NAME_INFORMATION *info = ptr; @@ -5156,10 +5118,7 @@ static BOOL async_write_proc( void *user, ULONG_PTR *info, unsigned int *status &needs_close, &type, NULL ))) break;
- if (!fileio->count && type == FD_TYPE_MAILSLOT) - result = send( fd, fileio->buffer, 0, 0 ); - else - result = write( fd, &fileio->buffer[fileio->already], fileio->count - fileio->already ); + result = write( fd, &fileio->buffer[fileio->already], fileio->count - fileio->already );
if (needs_close) close( fd );
@@ -5364,20 +5323,6 @@ static unsigned int get_io_timeouts( HANDLE handle, enum server_fd_type type, UL } break; } - case FD_TYPE_MAILSLOT: - if (is_read) - { - timeouts->interval = 0; /* return as soon as we got something */ - SERVER_START_REQ( set_mailslot_info ) - { - req->handle = wine_server_obj_handle( handle ); - req->flags = 0; - if (!wine_server_call( req ) && reply->read_timeout != TIMEOUT_INFINITE) - timeouts->total = reply->read_timeout / -10000; - } - SERVER_END_REQ; - } - break; case FD_TYPE_SOCKET: case FD_TYPE_CHAR: if (is_read) timeouts->interval = 0; /* return as soon as we got something */ @@ -5428,7 +5373,6 @@ static NTSTATUS get_io_avail_mode( HANDLE handle, enum server_fd_type type, BOOL } break; } - case FD_TYPE_MAILSLOT: case FD_TYPE_SOCKET: case FD_TYPE_CHAR: *avail_mode = TRUE; @@ -5703,7 +5647,7 @@ NTSTATUS WINAPI NtReadFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, vo if (total) /* return with what we got so far */ status = STATUS_SUCCESS; else - status = (type == FD_TYPE_MAILSLOT) ? STATUS_IO_TIMEOUT : STATUS_TIMEOUT; + status = STATUS_TIMEOUT; goto done; } if (ret == -1 && errno != EINTR) @@ -5934,11 +5878,7 @@ NTSTATUS WINAPI NtWriteFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, v
for (;;) { - /* zero-length writes on sockets may not work with plain write(2) */ - if (!length && type == FD_TYPE_MAILSLOT) - result = send( unix_handle, buffer, 0, 0 ); - else - result = write( unix_handle, (const char *)buffer + total, length - total ); + result = write( unix_handle, (const char *)buffer + total, length - total );
if (result >= 0) { diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 411ced944a3..cc83b66ea1f 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -1775,8 +1775,6 @@ enum server_fd_type FD_TYPE_DIR, FD_TYPE_SOCKET, FD_TYPE_SERIAL, - FD_TYPE_PIPE, - FD_TYPE_MAILSLOT, FD_TYPE_CHAR, FD_TYPE_DEVICE, FD_TYPE_NB_TYPES @@ -4847,10 +4845,12 @@ struct create_mailslot_request { struct request_header __header; unsigned int access; + unsigned int options; + char __pad_20[4]; timeout_t read_timeout; unsigned int max_msgsize; /* VARARG(objattr,object_attributes); */ - char __pad_28[4]; + char __pad_36[4]; }; struct create_mailslot_reply { @@ -6597,7 +6597,7 @@ union generic_reply
/* ### protocol_version begin ### */
-#define SERVER_PROTOCOL_VERSION 830 +#define SERVER_PROTOCOL_VERSION 831
/* ### protocol_version end ### */
diff --git a/server/mailslot.c b/server/mailslot.c index b8a48c66bed..7defbccdb44 100644 --- a/server/mailslot.c +++ b/server/mailslot.c @@ -47,14 +47,21 @@ #include "thread.h" #include "request.h"
+struct mailslot_message +{ + struct list entry; + struct iosb *iosb; +}; + struct mailslot { struct object obj; struct fd *fd; - int write_fd; unsigned int max_msgsize; timeout_t read_timeout; struct list writers; + struct list messages; + struct async_queue read_q; };
/* mailslot functions */ @@ -91,21 +98,23 @@ static const struct object_ops mailslot_ops = };
static enum server_fd_type mailslot_get_fd_type( struct fd *fd ); -static void mailslot_queue_async( struct fd *fd, struct async *async, int type, int count ); +static void mailslot_read( struct fd *fd, struct async *async, file_pos_t pos ); +static void mailslot_write( struct fd *fd, struct async *async, file_pos_t pos ); +static void mailslot_get_file_info( struct fd *fd, obj_handle_t handle, unsigned int info_class );
static const struct fd_ops mailslot_fd_ops = { default_fd_get_poll_events, /* get_poll_events */ default_poll_event, /* poll_event */ mailslot_get_fd_type, /* get_fd_type */ - no_fd_read, /* read */ - no_fd_write, /* write */ + mailslot_read, /* read */ + mailslot_write, /* write */ no_fd_flush, /* flush */ - default_fd_get_file_info, /* get_file_info */ + mailslot_get_file_info, /* get_file_info */ no_fd_get_volume_info, /* get_volume_info */ default_fd_ioctl, /* ioctl */ default_fd_cancel_async, /* cancel_async */ - mailslot_queue_async, /* queue_async */ + no_fd_queue_async, /* queue_async */ default_fd_reselect_async /* reselect_async */ };
@@ -150,14 +159,16 @@ static const struct object_ops mail_writer_ops = };
static enum server_fd_type mail_writer_get_fd_type( struct fd *fd ); +static void mail_writer_read( struct fd *fd, struct async *async, file_pos_t pos ); +static void mail_writer_write( struct fd *fd, struct async *async, file_pos_t pos );
static const struct fd_ops mail_writer_fd_ops = { default_fd_get_poll_events, /* get_poll_events */ default_poll_event, /* poll_event */ mail_writer_get_fd_type, /* get_fd_type */ - no_fd_read, /* read */ - no_fd_write, /* write */ + mail_writer_read, /* read */ + mail_writer_write, /* write */ no_fd_flush, /* flush */ default_fd_get_file_info, /* get_file_info */ no_fd_get_volume_info, /* get_volume_info */ @@ -258,17 +269,29 @@ static const struct fd_ops mailslot_device_fd_ops = default_fd_reselect_async /* reselect_async */ };
+static struct mailslot_message *get_first_message( struct mailslot *mailslot ) +{ + if (list_empty( &mailslot->messages )) + return NULL; + + return LIST_ENTRY( list_head( &mailslot->messages ), struct mailslot_message, entry ); +} + static void mailslot_destroy( struct object *obj) { struct mailslot *mailslot = (struct mailslot *) obj; + struct mailslot_message *message;
- assert( mailslot->fd ); - - if (mailslot->write_fd != -1) + while ((message = get_first_message( mailslot ))) { - shutdown( mailslot->write_fd, SHUT_RDWR ); - close( mailslot->write_fd ); + list_remove( &message->entry ); + release_object( message->iosb ); + free( message ); } + + free_async_queue( &mailslot->read_q ); + + assert( mailslot->fd ); release_object( mailslot->fd ); }
@@ -283,7 +306,85 @@ static void mailslot_dump( struct object *obj, int verbose )
static enum server_fd_type mailslot_get_fd_type( struct fd *fd ) { - return FD_TYPE_MAILSLOT; + return FD_TYPE_DEVICE; +} + +static void reselect_mailslot( struct mailslot *mailslot ) +{ + struct mailslot_message *message; + struct async *async; + + while ((message = get_first_message( mailslot )) && (async = find_pending_async( &mailslot->read_q ))) + { + struct iosb *read_iosb = async_get_iosb( async ); + + if (read_iosb->out_size < message->iosb->in_size) + { + async_request_complete( async, STATUS_BUFFER_TOO_SMALL, 0, 0, NULL ); + } + else + { + async_request_complete( async, STATUS_SUCCESS, message->iosb->in_size, + message->iosb->in_size, message->iosb->in_data ); + message->iosb->in_data = NULL; + list_remove( &message->entry ); + release_object( message->iosb ); + free( message ); + } + + release_object( async ); + release_object( read_iosb ); + } +} + +static void mailslot_read( struct fd *fd, struct async *async, file_pos_t pos ) +{ + struct mailslot *mailslot = get_fd_user( fd ); + + if (mailslot->read_timeout != (timeout_t)-1) + async_set_timeout( async, mailslot->read_timeout ? mailslot->read_timeout : -1, STATUS_IO_TIMEOUT ); + queue_async( &mailslot->read_q, async ); + reselect_mailslot( mailslot ); + set_error( STATUS_PENDING ); +} + +static void mailslot_write( struct fd *fd, struct async *async, file_pos_t pos ) +{ + set_error( STATUS_INVALID_PARAMETER ); +} + +static void mailslot_get_file_info( struct fd *fd, obj_handle_t handle, unsigned int info_class ) +{ + struct mailslot *mailslot = get_fd_user( fd ); + + switch (info_class) + { + case FileMailslotQueryInformation: + { + FILE_MAILSLOT_QUERY_INFORMATION *info; + struct mailslot_message *message; + + if (get_reply_max_size() < sizeof(*info)) + { + set_error( STATUS_INFO_LENGTH_MISMATCH ); + return; + } + + if (!(info = set_reply_data_size( sizeof(*info) ))) return; + info->MaximumMessageSize = mailslot->max_msgsize; + info->MailslotQuota = 0; + info->MessagesAvailable = list_count( &mailslot->messages ); + if ((message = get_first_message( mailslot ))) + info->NextMessageSize = message->iosb->in_size; + else + info->NextMessageSize = MAILSLOT_NO_MESSAGE; + info->ReadTimeout.QuadPart = mailslot->read_timeout; + break; + } + + default: + default_fd_get_file_info( fd, handle, info_class ); + } }
static struct fd *mailslot_get_fd( struct object *obj ) @@ -318,7 +419,6 @@ static struct object *mailslot_open_file( struct object *obj, unsigned int acces { struct mailslot *mailslot = (struct mailslot *)obj; struct mail_writer *writer; - int unix_fd;
if (!(sharing & FILE_SHARE_READ)) { @@ -341,23 +441,15 @@ static struct object *mailslot_open_file( struct object *obj, unsigned int acces } }
- if ((unix_fd = dup( mailslot->write_fd )) == -1) - { - file_set_error(); - return NULL; - } if (!(writer = alloc_object( &mail_writer_ops ))) - { - close( unix_fd ); return NULL; - } grab_object( mailslot ); writer->mailslot = mailslot; writer->access = mail_writer_map_access( &writer->obj, access ); writer->sharing = sharing; list_add_head( &mailslot->writers, &writer->entry );
- if (!(writer->fd = create_anonymous_fd( &mail_writer_fd_ops, unix_fd, &writer->obj, options ))) + if (!(writer->fd = alloc_pseudo_fd( &mail_writer_fd_ops, &writer->obj, options ))) { release_object( writer ); return NULL; @@ -366,18 +458,6 @@ static struct object *mailslot_open_file( struct object *obj, unsigned int acces return &writer->obj; }
-static void mailslot_queue_async( struct fd *fd, struct async *async, int type, int count ) -{ - struct mailslot *mailslot = get_fd_user( fd ); - - assert(mailslot->obj.ops == &mailslot_ops); - - fd_queue_async( fd, async, type ); - async_set_timeout( async, mailslot->read_timeout ? mailslot->read_timeout : -1, - STATUS_IO_TIMEOUT ); - set_error( STATUS_PENDING ); -} - static void mailslot_device_dump( struct object *obj, int verbose ) { fputs( "Mailslot device\n", stderr ); @@ -478,29 +558,21 @@ static struct mailslot *create_mailslot( struct object *root, const struct security_descriptor *sd ) { struct mailslot *mailslot; - int fds[2];
if (!(mailslot = create_named_object( root, &mailslot_ops, name, attr, sd ))) return NULL;
mailslot->fd = NULL; - mailslot->write_fd = -1; mailslot->max_msgsize = max_msgsize; mailslot->read_timeout = read_timeout; list_init( &mailslot->writers ); + list_init( &mailslot->messages ); + init_async_queue( &mailslot->read_q );
- if (!socketpair( PF_UNIX, SOCK_DGRAM, 0, fds )) + if ((mailslot->fd = alloc_pseudo_fd( &mailslot_fd_ops, &mailslot->obj, options ))) { - fcntl( fds[0], F_SETFL, O_NONBLOCK ); - fcntl( fds[1], F_SETFL, O_NONBLOCK ); - shutdown( fds[0], SHUT_RD ); - mailslot->write_fd = fds[0]; - if ((mailslot->fd = create_anonymous_fd( &mailslot_fd_ops, fds[1], &mailslot->obj, options ))) - { - allow_fd_caching( mailslot->fd ); - return mailslot; - } + allow_fd_caching( mailslot->fd ); + return mailslot; } - else file_set_error();
release_object( mailslot ); return NULL; @@ -522,7 +594,26 @@ static void mail_writer_destroy( struct object *obj)
static enum server_fd_type mail_writer_get_fd_type( struct fd *fd ) { - return FD_TYPE_MAILSLOT; + return FD_TYPE_DEVICE; +} + +static void mail_writer_read( struct fd *fd, struct async *async, file_pos_t pos ) +{ + set_error( STATUS_INVALID_PARAMETER ); +} + +static void mail_writer_write( struct fd *fd, struct async *async, file_pos_t pos ) +{ + struct mail_writer *writer = get_fd_user( fd ); + struct mailslot_message *message; + data_size_t size; + + if (!(message = mem_alloc( sizeof(*message) ))) return; + message->iosb = async_get_iosb( async ); + size = message->iosb->in_size; + list_add_tail( &writer->mailslot->messages, &message->entry ); + reselect_mailslot( writer->mailslot ); + async_request_complete( async, STATUS_SUCCESS, size, 0, NULL ); }
static struct fd *mail_writer_get_fd( struct object *obj ) diff --git a/server/protocol.def b/server/protocol.def index 97cf762a467..d684fbe89d6 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1500,7 +1500,6 @@ enum server_fd_type FD_TYPE_DIR, /* directory */ FD_TYPE_SOCKET, /* socket */ FD_TYPE_SERIAL, /* serial port */ - FD_TYPE_MAILSLOT, /* mailslot */ FD_TYPE_CHAR, /* unspecified char device */ FD_TYPE_DEVICE, /* Windows device file */ FD_TYPE_NB_TYPES diff --git a/server/request.h b/server/request.h index 572ef89987f..6158aefdb78 100644 --- a/server/request.h +++ b/server/request.h @@ -2068,9 +2068,10 @@ C_ASSERT( sizeof(struct get_system_handles_request) == 16 ); C_ASSERT( FIELD_OFFSET(struct get_system_handles_reply, count) == 8 ); C_ASSERT( sizeof(struct get_system_handles_reply) == 16 ); C_ASSERT( FIELD_OFFSET(struct create_mailslot_request, access) == 12 ); -C_ASSERT( FIELD_OFFSET(struct create_mailslot_request, read_timeout) == 16 ); -C_ASSERT( FIELD_OFFSET(struct create_mailslot_request, max_msgsize) == 24 ); -C_ASSERT( sizeof(struct create_mailslot_request) == 32 ); +C_ASSERT( FIELD_OFFSET(struct create_mailslot_request, options) == 16 ); +C_ASSERT( FIELD_OFFSET(struct create_mailslot_request, read_timeout) == 24 ); +C_ASSERT( FIELD_OFFSET(struct create_mailslot_request, max_msgsize) == 32 ); +C_ASSERT( sizeof(struct create_mailslot_request) == 40 ); C_ASSERT( FIELD_OFFSET(struct create_mailslot_reply, handle) == 8 ); C_ASSERT( sizeof(struct create_mailslot_reply) == 16 ); C_ASSERT( FIELD_OFFSET(struct set_mailslot_info_request, handle) == 12 ); diff --git a/server/trace.c b/server/trace.c index be81af3d55f..0a20adbbd91 100644 --- a/server/trace.c +++ b/server/trace.c @@ -4077,6 +4077,7 @@ static void dump_get_system_handles_reply( const struct get_system_handles_reply static void dump_create_mailslot_request( const struct create_mailslot_request *req ) { fprintf( stderr, " access=%08x", req->access ); + fprintf( stderr, ", options=%08x", req->options ); dump_timeout( ", read_timeout=", &req->read_timeout ); fprintf( stderr, ", max_msgsize=%08x", req->max_msgsize ); dump_varargs_object_attributes( ", objattr=", cur_size );
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=147267
Your paranoid android.
=== build (build log) ===
error: patch failed: include/wine/server_protocol.h:6597 Task: Patch failed to apply
=== debian11 (build log) ===
error: patch failed: include/wine/server_protocol.h:6597 Task: Patch failed to apply
=== debian11b (build log) ===
error: patch failed: include/wine/server_protocol.h:6597 Task: Patch failed to apply