From 9c6e895b0b3df2146027f0af9a51cc4d2253e005 Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Sat, 27 Dec 2014 17:33:55 +0100 Subject: [PATCH] Added patch to add support for named pipe message mode. --- README.md | 3 +- debian/changelog | 1 + patches/Makefile | 36 +- ...dd-tests-for-PeekNamedPipe-with-part.patch | 280 +++++++++ ...dd-tests-for-sending-and-receiving-l.patch | 168 ++++++ ...ts-Add-tests-for-closing-named-pipes.patch | 127 ++++ ...ing-if-message-mode-is-not-supported.patch | 89 +++ ...lar-code-in-NtReadFile-and-FILE_Asyn.patch | 169 ++++++ ...-to-check-for-broken-pipe-into-a-sep.patch | 107 ++++ ...lar-code-in-NtWriteFile-and-FILE_Asy.patch | 130 +++++ ...SEQPACKET-socket-in-combination-with.patch | 542 ++++++++++++++++++ ...ng-for-partially-received-messages-i.patch | 321 +++++++++++ ...dd-more-tests-with-overlapped-IO-and.patch | 188 ++++++ ...e-tests-for-overlapped-partial-reads.patch | 85 +++ ...est-sending-peeking-and-receiving-an.patch | 384 +++++++++++++ ...ll-Add-support-for-nonblocking-pipes.patch | 52 ++ ...dd-tests-for-PIPE_NOWAIT-in-message-.patch | 126 ++++ ...o-set-PIPE_NOWAIT-on-byte-mode-pipes.patch | 112 ++++ ...dd-additional-tests-for-PIPE_NOWAIT-.patch | 333 +++++++++++ patches/kernel32-Named_Pipe/definition | 1 + ...rt-for-TF_DISCONNECT-and-TF_REUSE_SO.patch | 51 +- 21 files changed, 3277 insertions(+), 28 deletions(-) create mode 100644 patches/kernel32-Named_Pipe/0002-kernel32-tests-Add-tests-for-PeekNamedPipe-with-part.patch create mode 100644 patches/kernel32-Named_Pipe/0003-kernel32-tests-Add-tests-for-sending-and-receiving-l.patch create mode 100644 patches/kernel32-Named_Pipe/0004-kernel32-tests-Add-tests-for-closing-named-pipes.patch create mode 100644 patches/kernel32-Named_Pipe/0005-server-Show-warning-if-message-mode-is-not-supported.patch create mode 100644 patches/kernel32-Named_Pipe/0006-ntdll-Unify-similar-code-in-NtReadFile-and-FILE_Asyn.patch create mode 100644 patches/kernel32-Named_Pipe/0007-ntdll-Move-logic-to-check-for-broken-pipe-into-a-sep.patch create mode 100644 patches/kernel32-Named_Pipe/0008-ntdll-Unify-similar-code-in-NtWriteFile-and-FILE_Asy.patch create mode 100644 patches/kernel32-Named_Pipe/0009-server-Use-SOCK_SEQPACKET-socket-in-combination-with.patch create mode 100644 patches/kernel32-Named_Pipe/0010-ntdll-Add-handling-for-partially-received-messages-i.patch create mode 100644 patches/kernel32-Named_Pipe/0011-kernel32-tests-Add-more-tests-with-overlapped-IO-and.patch create mode 100644 patches/kernel32-Named_Pipe/0012-ntdll-Fix-some-tests-for-overlapped-partial-reads.patch create mode 100644 patches/kernel32-Named_Pipe/0013-kernel32-tests-Test-sending-peeking-and-receiving-an.patch create mode 100644 patches/kernel32-Named_Pipe/0014-ntdll-Add-support-for-nonblocking-pipes.patch create mode 100644 patches/kernel32-Named_Pipe/0015-kernel32-tests-Add-tests-for-PIPE_NOWAIT-in-message-.patch create mode 100644 patches/kernel32-Named_Pipe/0016-ntdll-Allow-to-set-PIPE_NOWAIT-on-byte-mode-pipes.patch create mode 100644 patches/kernel32-Named_Pipe/0017-kernel32-tests-Add-additional-tests-for-PIPE_NOWAIT-.patch diff --git a/README.md b/README.md index c6832e28..23164d04 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Wine. All those differences are also documented on the Included bug fixes and improvements =================================== -**Bugfixes and features included in the next upcoming release [11]:** +**Bugfixes and features included in the next upcoming release [12]:** * Add stub for D3DXComputeTangentFrameEx ([Wine Bug #31984](https://bugs.winehq.org/show_bug.cgi?id=31984)) * Add stub for D3DXIntersect @@ -48,6 +48,7 @@ Included bug fixes and improvements * Implement ID3DXEffect::FindNextValidTechnique ([Wine Bug #34101](https://bugs.winehq.org/show_bug.cgi?id=34101)) * Implement IDXGIOutput::GetDesc * Support for SLGetWindowsInformationDWORD ([Wine Bug #36709](https://bugs.winehq.org/show_bug.cgi?id=36709)) +* Support for named pipe message mode ([Wine Bug #17195](https://bugs.winehq.org/show_bug.cgi?id=17195)) * Try harder to get the host name address in getaddrinfo() ([Wine Bug #29609](https://bugs.winehq.org/show_bug.cgi?id=29609)) * Use actual program name if available to describe PulseAudio streams diff --git a/debian/changelog b/debian/changelog index e2361040..d4995539 100644 --- a/debian/changelog +++ b/debian/changelog @@ -18,6 +18,7 @@ wine-staging (1.7.34) UNRELEASED; urgency=low * Added patch to use actual program name if available to describe PulseAudio streams. * Added patch to try harder to get the host name address in getaddrinfo(). * Added patch to fix invalid usage of RegOpenKeyExW in msdmo. + * Added patch to add support for named pipe message mode. * Removed patch to implement combase HSTRING objects (accepted upstream). * Removed patch to add fake ProductId to registry (accepted upstream). * Removed patch to implement stubs for MFStartup and MFShutdown (accepted upstream). diff --git a/patches/Makefile b/patches/Makefile index 1f5798fe..56a23e6c 100644 --- a/patches/Makefile +++ b/patches/Makefile @@ -761,15 +761,49 @@ kernel32-GetVolumePathName.ok: # | # | This patchset fixes the following Wine bugs: # | * [#16550] Fix for ConnectNamedPort return value in overlapped mode +# | * [#17195] Support for named pipe message mode # | # | Modified files: -# | * dlls/kernel32/sync.c +# | * dlls/kernel32/file.c, dlls/kernel32/sync.c, dlls/kernel32/tests/pipe.c, dlls/ntdll/file.c, server/named_pipe.c, +# | server/protocol.def, server/sock.c, server/sock.h # | .INTERMEDIATE: kernel32-Named_Pipe.ok kernel32-Named_Pipe.ok: $(call APPLY_FILE,kernel32-Named_Pipe/0001-kernel32-ConnectNamedPort-should-return-FALSE-and-se.patch) + $(call APPLY_FILE,kernel32-Named_Pipe/0002-kernel32-tests-Add-tests-for-PeekNamedPipe-with-part.patch) + $(call APPLY_FILE,kernel32-Named_Pipe/0003-kernel32-tests-Add-tests-for-sending-and-receiving-l.patch) + $(call APPLY_FILE,kernel32-Named_Pipe/0004-kernel32-tests-Add-tests-for-closing-named-pipes.patch) + $(call APPLY_FILE,kernel32-Named_Pipe/0005-server-Show-warning-if-message-mode-is-not-supported.patch) + $(call APPLY_FILE,kernel32-Named_Pipe/0006-ntdll-Unify-similar-code-in-NtReadFile-and-FILE_Asyn.patch) + $(call APPLY_FILE,kernel32-Named_Pipe/0007-ntdll-Move-logic-to-check-for-broken-pipe-into-a-sep.patch) + $(call APPLY_FILE,kernel32-Named_Pipe/0008-ntdll-Unify-similar-code-in-NtWriteFile-and-FILE_Asy.patch) + $(call APPLY_FILE,kernel32-Named_Pipe/0009-server-Use-SOCK_SEQPACKET-socket-in-combination-with.patch) + $(call APPLY_FILE,kernel32-Named_Pipe/0010-ntdll-Add-handling-for-partially-received-messages-i.patch) + $(call APPLY_FILE,kernel32-Named_Pipe/0011-kernel32-tests-Add-more-tests-with-overlapped-IO-and.patch) + $(call APPLY_FILE,kernel32-Named_Pipe/0012-ntdll-Fix-some-tests-for-overlapped-partial-reads.patch) + $(call APPLY_FILE,kernel32-Named_Pipe/0013-kernel32-tests-Test-sending-peeking-and-receiving-an.patch) + $(call APPLY_FILE,kernel32-Named_Pipe/0014-ntdll-Add-support-for-nonblocking-pipes.patch) + $(call APPLY_FILE,kernel32-Named_Pipe/0015-kernel32-tests-Add-tests-for-PIPE_NOWAIT-in-message-.patch) + $(call APPLY_FILE,kernel32-Named_Pipe/0016-ntdll-Allow-to-set-PIPE_NOWAIT-on-byte-mode-pipes.patch) + $(call APPLY_FILE,kernel32-Named_Pipe/0017-kernel32-tests-Add-additional-tests-for-PIPE_NOWAIT-.patch) @( \ echo '+ { "Dan Kegel", "kernel32: ConnectNamedPort should return FALSE and set ERROR_PIPE_CONNECTED on success in overlapped mode.", 1 },'; \ + echo '+ { "Sebastian Lackner", "kernel32/tests: Add tests for PeekNamedPipe with partial received messages.", 1 },'; \ + echo '+ { "Sebastian Lackner", "kernel32/tests: Add tests for sending and receiving large messages.", 1 },'; \ + echo '+ { "Adam Martinson", "kernel32/tests: Add tests for closing named pipes.", 1 },'; \ + echo '+ { "Sebastian Lackner", "server: Show warning if message mode is not supported.", 1 },'; \ + echo '+ { "Sebastian Lackner", "ntdll: Unify similar code in NtReadFile and FILE_AsyncReadService.", 1 },'; \ + echo '+ { "Sebastian Lackner", "ntdll: Move logic to check for broken pipe into a separate function.", 1 },'; \ + echo '+ { "Sebastian Lackner", "ntdll: Unify similar code in NtWriteFile and FILE_AsyncWriteService.", 1 },'; \ + echo '+ { "Sebastian Lackner", "server: Use SOCK_SEQPACKET socket in combination with SO_PEEK_OFF to implement message mode on Unix.", 1 },'; \ + echo '+ { "Sebastian Lackner", "ntdll: Add handling for partially received messages in NtReadFile.", 1 },'; \ + echo '+ { "Sebastian Lackner", "kernel32/tests: Add more tests with overlapped IO and partial reads from named pipes.", 1 },'; \ + echo '+ { "Sebastian Lackner", "ntdll: Fix some tests for overlapped partial reads.", 1 },'; \ + echo '+ { "Sebastian Lackner", "kernel32/tests: Test sending, peeking and receiving an empty message.", 1 },'; \ + echo '+ { "Sebastian Lackner", "ntdll: Add support for nonblocking pipes.", 1 },'; \ + echo '+ { "Sebastian Lackner", "kernel32/tests: Add tests for PIPE_NOWAIT in message mode.", 1 },'; \ + echo '+ { "Sebastian Lackner", "ntdll: Allow to set PIPE_NOWAIT on byte-mode pipes.", 1 },'; \ + echo '+ { "Sebastian Lackner", "kernel32/tests: Add additional tests for PIPE_NOWAIT in overlapped mode.", 1 },'; \ ) > kernel32-Named_Pipe.ok # Patchset kernel32-Profile diff --git a/patches/kernel32-Named_Pipe/0002-kernel32-tests-Add-tests-for-PeekNamedPipe-with-part.patch b/patches/kernel32-Named_Pipe/0002-kernel32-tests-Add-tests-for-PeekNamedPipe-with-part.patch new file mode 100644 index 00000000..6d7a4143 --- /dev/null +++ b/patches/kernel32-Named_Pipe/0002-kernel32-tests-Add-tests-for-PeekNamedPipe-with-part.patch @@ -0,0 +1,280 @@ +From a08cd0cbb65ca0c53857c35e40f6d3d910119b22 Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Thu, 31 Jul 2014 00:28:59 +0200 +Subject: kernel32/tests: Add tests for PeekNamedPipe with partial received + messages. + +This patch adds a couple more tests to ensure that PeekNamedPipe correctly +returns the number of remaining bytes which are part of the same message. +Moreover we have to be sure, that PeekNamedPipe also returns the same +information from all threads. + +Changes in v2: + * Also add tests for reverse direction. + +Changes in v3: + * Fix compiler warning on x86_64. +--- + dlls/kernel32/tests/pipe.c | 142 ++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 140 insertions(+), 2 deletions(-) + +diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c +index 056f95b..a252bc8 100644 +--- a/dlls/kernel32/tests/pipe.c ++++ b/dlls/kernel32/tests/pipe.c +@@ -46,7 +46,8 @@ static void CALLBACK user_apc(ULONG_PTR param) + + enum rpcThreadOp + { +- RPC_READFILE ++ RPC_READFILE, ++ RPC_PEEKNAMEDPIPE + }; + + struct rpcThreadArgs +@@ -54,7 +55,7 @@ struct rpcThreadArgs + ULONG_PTR returnValue; + DWORD lastError; + enum rpcThreadOp op; +- ULONG_PTR args[5]; ++ ULONG_PTR args[6]; + }; + + static DWORD CALLBACK rpcThreadMain(LPVOID arg) +@@ -73,6 +74,15 @@ static DWORD CALLBACK rpcThreadMain(LPVOID arg) + (LPOVERLAPPED)rpcargs->args[4] ); /* overlapped */ + break; + ++ case RPC_PEEKNAMEDPIPE: ++ rpcargs->returnValue = (ULONG_PTR)PeekNamedPipe( (HANDLE)rpcargs->args[0], /* hPipe */ ++ (LPVOID)rpcargs->args[1], /* lpvBuffer */ ++ (DWORD)rpcargs->args[2], /* cbBuffer */ ++ (LPDWORD)rpcargs->args[3], /* lpcbRead */ ++ (LPDWORD)rpcargs->args[4], /* lpcbAvail */ ++ (LPDWORD)rpcargs->args[5] ); /* lpcbMessage */ ++ break; ++ + default: + SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); + rpcargs->returnValue = 0; +@@ -109,6 +119,33 @@ static BOOL RpcReadFile(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, LPDWORD + return (BOOL)rpcargs.returnValue; + } + ++/* Runs PeekNamedPipe(...) from a different thread */ ++static BOOL RpcPeekNamedPipe(HANDLE hPipe, LPVOID lpvBuffer, DWORD cbBuffer, ++ LPDWORD lpcbRead, LPDWORD lpcbAvail, LPDWORD lpcbMessage) ++{ ++ struct rpcThreadArgs rpcargs; ++ HANDLE thread; ++ DWORD threadId; ++ ++ rpcargs.returnValue = 0; ++ rpcargs.lastError = GetLastError(); ++ rpcargs.op = RPC_PEEKNAMEDPIPE; ++ rpcargs.args[0] = (ULONG_PTR)hPipe; ++ rpcargs.args[1] = (ULONG_PTR)lpvBuffer; ++ rpcargs.args[2] = (ULONG_PTR)cbBuffer; ++ rpcargs.args[3] = (ULONG_PTR)lpcbRead; ++ rpcargs.args[4] = (ULONG_PTR)lpcbAvail; ++ rpcargs.args[5] = (ULONG_PTR)lpcbMessage; ++ ++ thread = CreateThread(NULL, 0, rpcThreadMain, (void *)&rpcargs, 0, &threadId); ++ ok(thread != NULL, "CreateThread failed. %d\n", GetLastError()); ++ ok(WaitForSingleObject(thread, INFINITE) == WAIT_OBJECT_0,"WaitForSingleObject failed with %d.\n", GetLastError()); ++ CloseHandle(thread); ++ ++ SetLastError(rpcargs.lastError); ++ return (BOOL)rpcargs.returnValue; ++} ++ + static void test_CreateNamedPipe(int pipemode) + { + HANDLE hnp; +@@ -118,6 +155,7 @@ static void test_CreateNamedPipe(int pipemode) + char ibuf[32], *pbuf; + DWORD written; + DWORD readden; ++ DWORD leftmsg; + DWORD avail; + DWORD lpmode; + BOOL ret; +@@ -232,9 +270,21 @@ static void test_CreateNamedPipe(int pipemode) + ok(written == sizeof(obuf2), "write file len\n"); + ok(ReadFile(hFile, ibuf, 4, &readden, NULL), "ReadFile\n"); + ok(readden == 4, "read got %d bytes\n", readden); ++ readden = leftmsg = -1; ++ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe\n"); ++ ok(readden == sizeof(obuf2) - 4, "peek got %d bytes total\n", readden); ++ if (pipemode == PIPE_TYPE_BYTE) ++ ok(leftmsg == 0, "peek got %d bytes left in message\n", leftmsg); ++ else ++ todo_wine ++ ok(leftmsg == sizeof(obuf2) - 4, "peek got %d bytes left in message\n", leftmsg); + ok(ReadFile(hFile, ibuf + 4, sizeof(ibuf) - 4, &readden, NULL), "ReadFile\n"); + ok(readden == sizeof(obuf2) - 4, "read got %d bytes\n", readden); + ok(memcmp(obuf2, ibuf, written) == 0, "content check\n"); ++ readden = leftmsg = -1; ++ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe\n"); ++ ok(readden == 0, "peek got %d bytes total\n", readden); ++ ok(leftmsg == 0, "peek got %d bytes left in message\n", leftmsg); + + memset(ibuf, 0, sizeof(ibuf)); + ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile\n"); +@@ -447,6 +497,16 @@ static void test_CreateNamedPipe(int pipemode) + ok(written == sizeof(obuf), "write file len 9\n"); + ok(WriteFile(hnp, obuf2, sizeof(obuf2), &written, NULL), "WriteFile 9\n"); + ok(written == sizeof(obuf2), "write file len 9\n"); ++ readden = leftmsg = -1; ++ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 9\n"); ++ ok(readden == sizeof(obuf) + sizeof(obuf2), "peek got %d bytes total 9\n", readden); ++ todo_wine ++ ok(leftmsg == sizeof(obuf), "peek got %d bytes left in message 9\n", leftmsg); ++ readden = leftmsg = -1; ++ ok(RpcPeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 9\n"); ++ ok(readden == sizeof(obuf) + sizeof(obuf2), "peek got %d bytes total 9\n", readden); ++ todo_wine ++ ok(leftmsg == sizeof(obuf), "peek got %d bytes left in message 9\n", leftmsg); + SetLastError(0xdeadbeef); + todo_wine + ok(!ReadFile(hFile, ibuf, 4, &readden, NULL), "ReadFile 9\n"); +@@ -460,6 +520,16 @@ static void test_CreateNamedPipe(int pipemode) + todo_wine + ok(GetLastError() == ERROR_MORE_DATA, "wrong error 9\n"); + ok(readden == 4, "read got %d bytes 9\n", readden); ++ readden = leftmsg = -1; ++ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 9\n"); ++ ok(readden == sizeof(obuf) - 8 + sizeof(obuf2), "peek got %d bytes total 9\n", readden); ++ todo_wine ++ ok(leftmsg == sizeof(obuf) - 8, "peek got %d bytes left in message 9\n", leftmsg); ++ readden = leftmsg = -1; ++ ok(RpcPeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 9\n"); ++ ok(readden == sizeof(obuf) - 8 + sizeof(obuf2), "peek got %d bytes total 9\n", readden); ++ todo_wine ++ ok(leftmsg == sizeof(obuf) - 8, "peek got %d bytes left in message 9\n", leftmsg); + ret = RpcReadFile(hFile, ibuf + 8, sizeof(ibuf), &readden, NULL); + ok(ret, "RpcReadFile 9\n"); + todo_wine +@@ -468,6 +538,14 @@ static void test_CreateNamedPipe(int pipemode) + if (readden <= sizeof(obuf) - 8) /* blocks forever if second part was already received */ + { + memset(ibuf, 0, sizeof(ibuf)); ++ readden = leftmsg = -1; ++ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 9\n"); ++ ok(readden == sizeof(obuf2), "peek got %d bytes total 9\n", readden); ++ ok(leftmsg == sizeof(obuf2), "peek got %d bytes left in message 9\n", leftmsg); ++ readden = leftmsg = -1; ++ ok(RpcPeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 9\n"); ++ ok(readden == sizeof(obuf2), "peek got %d bytes total 9\n", readden); ++ ok(leftmsg == sizeof(obuf2), "peek got %d bytes left in message 9\n", leftmsg); + SetLastError(0xdeadbeef); + ret = RpcReadFile(hFile, ibuf, 4, &readden, NULL); + ok(!ret, "RpcReadFile 9\n"); +@@ -480,11 +558,27 @@ static void test_CreateNamedPipe(int pipemode) + todo_wine + ok(GetLastError() == ERROR_MORE_DATA, "wrong error 9\n"); + ok(readden == 4, "read got %d bytes 9\n", readden); ++ readden = leftmsg = -1; ++ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 9\n"); ++ ok(readden == sizeof(obuf2) - 8, "peek got %d bytes total 9\n", readden); ++ ok(leftmsg == sizeof(obuf2) - 8, "peek got %d bytes left in message 9\n", leftmsg); ++ readden = leftmsg = -1; ++ ok(RpcPeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 9\n"); ++ ok(readden == sizeof(obuf2) - 8, "peek got %d bytes total 9\n", readden); ++ ok(leftmsg == sizeof(obuf2) - 8, "peek got %d bytes left in message 9\n", leftmsg); + ret = RpcReadFile(hFile, ibuf + 8, sizeof(ibuf), &readden, NULL); + ok(ret, "RpcReadFile 9\n"); + ok(readden == sizeof(obuf2) - 8, "read got %d bytes 9\n", readden); + ok(memcmp(obuf2, ibuf, sizeof(obuf2)) == 0, "content check 9\n"); + } ++ readden = leftmsg = -1; ++ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 9\n"); ++ ok(readden == 0, "peek got %d bytes total 9\n", readden); ++ ok(leftmsg == 0, "peek got %d bytes left in message 9\n", leftmsg); ++ readden = leftmsg = -1; ++ ok(RpcPeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 9\n"); ++ ok(readden == 0, "peek got %d bytes total 9\n", readden); ++ ok(leftmsg == 0, "peek got %d bytes left in message 9\n", leftmsg); + + /* Now the reverse direction */ + memset(ibuf, 0, sizeof(ibuf)); +@@ -492,6 +586,16 @@ static void test_CreateNamedPipe(int pipemode) + ok(written == sizeof(obuf2), "write file len 10\n"); + ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile 10\n"); + ok(written == sizeof(obuf), "write file len 10\n"); ++ readden = leftmsg = -1; ++ ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 10\n"); ++ ok(readden == sizeof(obuf) + sizeof(obuf2), "peek got %d bytes total 10\n", readden); ++ todo_wine ++ ok(leftmsg == sizeof(obuf2), "peek got %d bytes left in message 10\n", leftmsg); ++ readden = leftmsg = -1; ++ ok(RpcPeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 10\n"); ++ ok(readden == sizeof(obuf) + sizeof(obuf2), "peek got %d bytes total 10\n", readden); ++ todo_wine ++ ok(leftmsg == sizeof(obuf2), "peek got %d bytes left in message 10\n", leftmsg); + SetLastError(0xdeadbeef); + todo_wine + ok(!ReadFile(hnp, ibuf, 4, &readden, NULL), "ReadFile 10\n"); +@@ -505,6 +609,16 @@ static void test_CreateNamedPipe(int pipemode) + todo_wine + ok(GetLastError() == ERROR_MORE_DATA, "wrong error 10\n"); + ok(readden == 4, "read got %d bytes 10\n", readden); ++ readden = leftmsg = -1; ++ ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 10\n"); ++ ok(readden == sizeof(obuf2) - 8 + sizeof(obuf), "peek got %d bytes total 10\n", readden); ++ todo_wine ++ ok(leftmsg == sizeof(obuf2) - 8, "peek got %d bytes left in message 10\n", leftmsg); ++ readden = leftmsg = -1; ++ ok(RpcPeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 10\n"); ++ ok(readden == sizeof(obuf2) - 8 + sizeof(obuf), "peek got %d bytes total 10\n", readden); ++ todo_wine ++ ok(leftmsg == sizeof(obuf2) - 8, "peek got %d bytes left in message 10\n", leftmsg); + ret = RpcReadFile(hnp, ibuf + 8, sizeof(ibuf), &readden, NULL); + ok(ret, "RpcReadFile 10\n"); + todo_wine +@@ -513,6 +627,14 @@ static void test_CreateNamedPipe(int pipemode) + if (readden <= sizeof(obuf2) - 8) /* blocks forever if second part was already received */ + { + memset(ibuf, 0, sizeof(ibuf)); ++ readden = leftmsg = -1; ++ ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 10\n"); ++ ok(readden == sizeof(obuf), "peek got %d bytes total 10\n", readden); ++ ok(leftmsg == sizeof(obuf), "peek got %d bytes left in message 10\n", leftmsg); ++ readden = leftmsg = -1; ++ ok(RpcPeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 10\n"); ++ ok(readden == sizeof(obuf), "peek got %d bytes total 10\n", readden); ++ ok(leftmsg == sizeof(obuf), "peek got %d bytes left in message 10\n", leftmsg); + SetLastError(0xdeadbeef); + ret = RpcReadFile(hnp, ibuf, 4, &readden, NULL); + ok(!ret, "RpcReadFile 10\n"); +@@ -525,11 +647,27 @@ static void test_CreateNamedPipe(int pipemode) + todo_wine + ok(GetLastError() == ERROR_MORE_DATA, "wrong error 10\n"); + ok(readden == 4, "read got %d bytes 10\n", readden); ++ readden = leftmsg = -1; ++ ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 10\n"); ++ ok(readden == sizeof(obuf) - 8, "peek got %d bytes total 10\n", readden); ++ ok(leftmsg == sizeof(obuf) - 8, "peek got %d bytes left in message 10\n", leftmsg); ++ readden = leftmsg = -1; ++ ok(RpcPeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 10\n"); ++ ok(readden == sizeof(obuf) - 8, "peek got %d bytes total 10\n", readden); ++ ok(leftmsg == sizeof(obuf) - 8, "peek got %d bytes left in message 10\n", leftmsg); + ret = RpcReadFile(hnp, ibuf + 8, sizeof(ibuf), &readden, NULL); + ok(ret, "RpcReadFile 10\n"); + ok(readden == sizeof(obuf) - 8, "read got %d bytes 10\n", readden); + ok(memcmp(obuf, ibuf, sizeof(obuf)) == 0, "content check 10\n"); + } ++ readden = leftmsg = -1; ++ ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 10\n"); ++ ok(readden == 0, "peek got %d bytes total 10\n", readden); ++ ok(leftmsg == 0, "peek got %d bytes left in message 10\n", leftmsg); ++ readden = leftmsg = -1; ++ ok(RpcPeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 10\n"); ++ ok(readden == 0, "peek got %d bytes total 10\n", readden); ++ ok(leftmsg == 0, "peek got %d bytes left in message 10\n", leftmsg); + + } + +-- +2.1.3 + diff --git a/patches/kernel32-Named_Pipe/0003-kernel32-tests-Add-tests-for-sending-and-receiving-l.patch b/patches/kernel32-Named_Pipe/0003-kernel32-tests-Add-tests-for-sending-and-receiving-l.patch new file mode 100644 index 00000000..bf51f43c --- /dev/null +++ b/patches/kernel32-Named_Pipe/0003-kernel32-tests-Add-tests-for-sending-and-receiving-l.patch @@ -0,0 +1,168 @@ +From 695d78fbb48472fce38f103fba76f56c36a4cb5d Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Sun, 3 Aug 2014 23:14:35 +0200 +Subject: kernel32/tests: Add tests for sending and receiving large messages. + +This set of tests seems to confirm that on Windows, there is no upper size +limit where messages are splitted. The kernel seems to temporarily allocate +additional buffers (or use existing buffers very efficient), so WriteFile() +can never fail because of size limitations. + +Changes in v2: + * Avoid compilation warning on x86_64. +--- + dlls/kernel32/tests/pipe.c | 124 +++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 124 insertions(+) + +diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c +index a252bc8..246ee30 100644 +--- a/dlls/kernel32/tests/pipe.c ++++ b/dlls/kernel32/tests/pipe.c +@@ -47,6 +47,7 @@ static void CALLBACK user_apc(ULONG_PTR param) + enum rpcThreadOp + { + RPC_READFILE, ++ RPC_WRITEFILE, + RPC_PEEKNAMEDPIPE + }; + +@@ -74,6 +75,14 @@ static DWORD CALLBACK rpcThreadMain(LPVOID arg) + (LPOVERLAPPED)rpcargs->args[4] ); /* overlapped */ + break; + ++ case RPC_WRITEFILE: ++ rpcargs->returnValue = (ULONG_PTR)WriteFile( (HANDLE)rpcargs->args[0], /* hFile */ ++ (LPCVOID)rpcargs->args[1], /* buffer */ ++ (DWORD)rpcargs->args[2], /* bytesToWrite */ ++ (LPDWORD)rpcargs->args[3], /* bytesWritten */ ++ (LPOVERLAPPED)rpcargs->args[4] ); /* overlapped */ ++ break; ++ + case RPC_PEEKNAMEDPIPE: + rpcargs->returnValue = (ULONG_PTR)PeekNamedPipe( (HANDLE)rpcargs->args[0], /* hPipe */ + (LPVOID)rpcargs->args[1], /* lpvBuffer */ +@@ -671,6 +680,121 @@ static void test_CreateNamedPipe(int pipemode) + + } + ++ /* Test behaviour for very huge messages (which don't fit completely in the buffer) */ ++ { ++ static char big_obuf[512 * 1024]; ++ static char big_ibuf[512 * 1024]; ++ struct rpcThreadArgs rpcargs; ++ HANDLE thread; ++ DWORD threadId; ++ memset(big_obuf, 0xAA, sizeof(big_obuf)); ++ ++ /* Ensure that both pipes are empty before we continue with the next test */ ++ while (PeekNamedPipe(hFile, NULL, 0, NULL, &readden, NULL) && readden > 0) ++ ok(ReadFile(hFile, big_ibuf, sizeof(big_ibuf), &readden, NULL) || ++ GetLastError() == ERROR_MORE_DATA, "ReadFile\n"); ++ ++ while (PeekNamedPipe(hnp, NULL, 0, NULL, &readden, NULL) && readden > 0) ++ ok(ReadFile(hnp, big_ibuf, sizeof(big_ibuf), &readden, NULL) || ++ GetLastError() == ERROR_MORE_DATA, "ReadFile\n"); ++ ++ readden = leftmsg = -1; ++ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe\n"); ++ ok(readden == 0, "peek got %d bytes total\n", readden); ++ ok(leftmsg == 0, "peek got %d bytes left in message\n", leftmsg); ++ ++ /* transmit big message, receive with buffer of equal size */ ++ memset(big_ibuf, 0, sizeof(big_ibuf)); ++ rpcargs.returnValue = 0; ++ rpcargs.lastError = GetLastError(); ++ rpcargs.op = RPC_WRITEFILE; ++ rpcargs.args[0] = (ULONG_PTR)hnp; ++ rpcargs.args[1] = (ULONG_PTR)big_obuf; ++ rpcargs.args[2] = (ULONG_PTR)sizeof(big_obuf); ++ rpcargs.args[3] = (ULONG_PTR)&written; ++ rpcargs.args[4] = (ULONG_PTR)NULL; ++ ++ thread = CreateThread(NULL, 0, rpcThreadMain, (void *)&rpcargs, 0, &threadId); ++ ok(thread != NULL, "CreateThread failed. %d\n", GetLastError()); ++ ret = WaitForSingleObject(thread, 200); ++ ok(ret == WAIT_TIMEOUT, "WaitForSingleObject returned %d instead of %d.\n", ret, WAIT_TIMEOUT); ++ ok(ReadFile(hFile, big_ibuf, sizeof(big_ibuf), &readden, NULL), "ReadFile\n"); ++ todo_wine ++ ok(readden == sizeof(big_obuf), "read got %d bytes\n", readden); ++ todo_wine ++ ok(memcmp(big_ibuf, big_obuf, sizeof(big_obuf)) == 0, "content check\n"); ++ do ++ { ++ ret = WaitForSingleObject(thread, 1); ++ while (PeekNamedPipe(hFile, NULL, 0, NULL, &readden, NULL) && readden > 0) ++ ok(ReadFile(hFile, big_ibuf, sizeof(big_ibuf), &readden, NULL) || ++ GetLastError() == ERROR_MORE_DATA, "ReadFile\n"); ++ } ++ while (ret == WAIT_TIMEOUT); ++ ok(WaitForSingleObject(thread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed with %d.\n", GetLastError()); ++ ok((BOOL)rpcargs.returnValue, "WriteFile\n"); ++ ok(written == sizeof(big_obuf), "write file len\n"); ++ CloseHandle(thread); ++ ++ readden = leftmsg = -1; ++ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe\n"); ++ ok(readden == 0, "peek got %d bytes total\n", readden); ++ ok(leftmsg == 0, "peek got %d bytes left in message\n", leftmsg); ++ ++ /* same as above, but receive as multiple parts */ ++ memset(big_ibuf, 0, sizeof(big_ibuf)); ++ rpcargs.returnValue = 0; ++ rpcargs.lastError = GetLastError(); ++ ++ thread = CreateThread(NULL, 0, rpcThreadMain, (void *)&rpcargs, 0, &threadId); ++ ok(thread != NULL, "CreateThread failed. %d\n", GetLastError()); ++ ret = WaitForSingleObject(thread, 200); ++ ok(ret == WAIT_TIMEOUT, "WaitForSingleObject returned %d instead of %d.\n", ret, WAIT_TIMEOUT); ++ if (pipemode == PIPE_TYPE_BYTE) ++ { ++ ok(ReadFile(hFile, big_ibuf, 32, &readden, NULL), "ReadFile\n"); ++ ok(readden == 32, "read got %d bytes\n", readden); ++ ok(ReadFile(hFile, big_ibuf + 32, 32, &readden, NULL), "ReadFile\n"); ++ } ++ else ++ { ++ SetLastError(0xdeadbeef); ++ todo_wine ++ ok(!ReadFile(hFile, big_ibuf, 32, &readden, NULL), "ReadFile\n"); ++ todo_wine ++ ok(GetLastError() == ERROR_MORE_DATA, "wrong error\n"); ++ ok(readden == 32, "read got %d bytes\n", readden); ++ SetLastError(0xdeadbeef); ++ todo_wine ++ ok(!ReadFile(hFile, big_ibuf + 32, 32, &readden, NULL), "ReadFile\n"); ++ todo_wine ++ ok(GetLastError() == ERROR_MORE_DATA, "wrong error\n"); ++ } ++ ok(readden == 32, "read got %d bytes\n", readden); ++ ok(ReadFile(hFile, big_ibuf + 64, sizeof(big_ibuf) - 64, &readden, NULL), "ReadFile\n"); ++ todo_wine ++ ok(readden == sizeof(big_obuf) - 64, "read got %d bytes\n", readden); ++ todo_wine ++ ok(memcmp(big_ibuf, big_obuf, sizeof(big_obuf)) == 0, "content check\n"); ++ do ++ { ++ ret = WaitForSingleObject(thread, 1); ++ while (PeekNamedPipe(hFile, NULL, 0, NULL, &readden, NULL) && readden > 0) ++ ok(ReadFile(hFile, big_ibuf, sizeof(big_ibuf), &readden, NULL) || ++ GetLastError() == ERROR_MORE_DATA, "ReadFile\n"); ++ } ++ while (ret == WAIT_TIMEOUT); ++ ok(WaitForSingleObject(thread, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject failed with %d.\n", GetLastError()); ++ ok((BOOL)rpcargs.returnValue, "WriteFile\n"); ++ ok(written == sizeof(big_obuf), "write file len\n"); ++ CloseHandle(thread); ++ ++ readden = leftmsg = -1; ++ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe\n"); ++ ok(readden == 0, "peek got %d bytes total\n", readden); ++ ok(leftmsg == 0, "peek got %d bytes left in message\n", leftmsg); ++ } ++ + /* Picky conformance tests */ + + /* Verify that you can't connect to pipe again +-- +2.1.3 + diff --git a/patches/kernel32-Named_Pipe/0004-kernel32-tests-Add-tests-for-closing-named-pipes.patch b/patches/kernel32-Named_Pipe/0004-kernel32-tests-Add-tests-for-closing-named-pipes.patch new file mode 100644 index 00000000..b91170a7 --- /dev/null +++ b/patches/kernel32-Named_Pipe/0004-kernel32-tests-Add-tests-for-closing-named-pipes.patch @@ -0,0 +1,127 @@ +From ce6c2fe58743667cec2ce798bbcd938f44d71b80 Mon Sep 17 00:00:00 2001 +From: Adam Martinson +Date: Tue, 18 Dec 2012 15:52:57 -0600 +Subject: kernel32/tests: Add tests for closing named pipes. + +Changes in v2: + * Add SetLastError(). +--- + dlls/kernel32/tests/pipe.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 95 insertions(+) + +diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c +index 246ee30..f42fe5c 100644 +--- a/dlls/kernel32/tests/pipe.c ++++ b/dlls/kernel32/tests/pipe.c +@@ -923,6 +923,100 @@ static void test_CreateNamedPipe_instances_must_match(void) + ok(CloseHandle(hnp2), "CloseHandle\n"); + } + ++static void test_CloseNamedPipe(void) ++{ ++ HANDLE hnp; ++ HANDLE hFile; ++ static const char obuf[] = "Bit Bucket"; ++ char ibuf[32]; ++ DWORD written; ++ DWORD readden; ++ ++ hnp = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX, ++ PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, ++ /* nMaxInstances */ 1, ++ /* nOutBufSize */ 1024, ++ /* nInBufSize */ 1024, ++ /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT, ++ /* lpSecurityAttrib */ NULL); ++ ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n"); ++ ++ hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); ++ ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed (%d)\n", GetLastError()); ++ ++ /* don't try to do i/o if one side couldn't be opened, as it hangs */ ++ if (hFile != INVALID_HANDLE_VALUE) ++ { ++ /* Make sure we can read and write a few bytes in both directions */ ++ memset(ibuf, 0, sizeof(ibuf)); ++ ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile\n"); ++ ok(written == sizeof(obuf), "write file len 1\n"); ++ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, NULL), "Peek\n"); ++ ok(readden == sizeof(obuf), "got %d bytes\n", readden); ++ ++ /* close server end without disconnecting */ ++ ok(CloseHandle(hnp), "CloseHandle() failed: %08x\n", GetLastError()); ++ ++ todo_wine ++ ok(ReadFile(hFile, ibuf, 0, &readden, NULL), "ReadFile() failed: %08x\n", GetLastError()); ++ ok(readden == 0, "got %d bytes\n", readden); ++ ++ memset(ibuf, 0, sizeof(ibuf)); ++ ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() failed: %08x\n", GetLastError()); ++ ok(readden == sizeof(obuf), "got %d bytes\n", readden); ++ /* pipe is empty now */ ++ ++ SetLastError(0xdeadbeef); ++ ok(!ReadFile(hFile, ibuf, 0, &readden, NULL), "ReadFile() succeeded\n"); ++ ok(GetLastError() == ERROR_BROKEN_PIPE, "GetLastError() returned %08x, expected ERROR_BROKEN_PIPE\n", GetLastError()); ++ SetLastError(0); ++ ++ CloseHandle(hFile); ++ } ++ ++ hnp = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX, ++ PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, ++ /* nMaxInstances */ 1, ++ /* nOutBufSize */ 1024, ++ /* nInBufSize */ 1024, ++ /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT, ++ /* lpSecurityAttrib */ NULL); ++ ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n"); ++ ++ hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); ++ ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed (%d)\n", GetLastError()); ++ ++ if (hFile != INVALID_HANDLE_VALUE) ++ { ++ /* Make sure we can read and write a few bytes in both directions */ ++ memset(ibuf, 0, sizeof(ibuf)); ++ ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile\n"); ++ ok(written == sizeof(obuf), "write file len 1\n"); ++ ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, NULL), "Peek\n"); ++ ok(readden == sizeof(obuf), "got %d bytes\n", readden); ++ ++ /* close client end without disconnecting */ ++ ok(CloseHandle(hFile), "CloseHandle() failed: %08x\n", GetLastError()); ++ ++ /* you'd think ERROR_MORE_DATA, but no */ ++ todo_wine ++ ok(ReadFile(hnp, ibuf, 0, &readden, NULL), "ReadFile() failed: %08x\n", GetLastError()); ++ ok(readden == 0, "got %d bytes\n", readden); ++ ++ memset(ibuf, 0, sizeof(ibuf)); ++ ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() failed: %08x\n", GetLastError()); ++ ok(readden == sizeof(obuf), "got %d bytes\n", readden); ++ /* pipe is empty now */ ++ ++ SetLastError(0xdeadbeef); ++ ok(!ReadFile(hnp, ibuf, 0, &readden, NULL), "ReadFile() succeeded\n"); ++ ok(GetLastError() == ERROR_BROKEN_PIPE, "GetLastError() returned %08x, expected ERROR_BROKEN_PIPE\n", GetLastError()); ++ SetLastError(0); ++ ++ CloseHandle(hnp); ++ } ++} ++ + /** implementation of alarm() */ + static DWORD CALLBACK alarmThreadMain(LPVOID arg) + { +@@ -2425,6 +2519,7 @@ START_TEST(pipe) + test_NamedPipe_2(); + test_CreateNamedPipe(PIPE_TYPE_BYTE); + test_CreateNamedPipe(PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE); ++ test_CloseNamedPipe(); + test_CreatePipe(); + test_impersonation(); + test_overlapped(); +-- +2.1.3 + diff --git a/patches/kernel32-Named_Pipe/0005-server-Show-warning-if-message-mode-is-not-supported.patch b/patches/kernel32-Named_Pipe/0005-server-Show-warning-if-message-mode-is-not-supported.patch new file mode 100644 index 00000000..3bfb1fd6 --- /dev/null +++ b/patches/kernel32-Named_Pipe/0005-server-Show-warning-if-message-mode-is-not-supported.patch @@ -0,0 +1,89 @@ +From db0a81d0a3513d169335286471969b1fb9c38be1 Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Mon, 4 Aug 2014 00:29:26 +0200 +Subject: server: Show warning if message mode is not supported. + +This patch changes the create_named_pipe wineserver call to return +which flags were supported. This allows to show a FIXME in ntdll for +missing message mode support. +--- + dlls/ntdll/file.c | 14 ++++++++++---- + server/named_pipe.c | 1 + + server/protocol.def | 1 + + 3 files changed, 12 insertions(+), 4 deletions(-) + +diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c +index 5232027..01cef2c 100644 +--- a/dlls/ntdll/file.c ++++ b/dlls/ntdll/file.c +@@ -3091,6 +3091,7 @@ NTSTATUS WINAPI NtCreateNamedPipeFile( PHANDLE handle, ULONG access, + { + struct security_descriptor *sd = NULL; + struct object_attributes objattr; ++ unsigned int flags; + NTSTATUS status; + + TRACE("(%p %x %s %p %x %d %x %d %d %d %d %d %d %p)\n", +@@ -3109,16 +3110,17 @@ NTSTATUS WINAPI NtCreateNamedPipeFile( PHANDLE handle, ULONG access, + status = NTDLL_create_struct_sd( attr->SecurityDescriptor, &sd, &objattr.sd_len ); + if (status != STATUS_SUCCESS) return status; + ++ flags = (pipe_type ? NAMED_PIPE_MESSAGE_STREAM_WRITE : 0) | ++ (read_mode ? NAMED_PIPE_MESSAGE_STREAM_READ : 0) | ++ (completion_mode ? NAMED_PIPE_NONBLOCKING_MODE : 0); ++ + SERVER_START_REQ( create_named_pipe ) + { + req->access = access; + req->attributes = attr->Attributes; + req->options = options; + req->sharing = sharing; +- req->flags = +- (pipe_type ? NAMED_PIPE_MESSAGE_STREAM_WRITE : 0) | +- (read_mode ? NAMED_PIPE_MESSAGE_STREAM_READ : 0) | +- (completion_mode ? NAMED_PIPE_NONBLOCKING_MODE : 0); ++ req->flags = flags; + req->maxinstances = max_inst; + req->outsize = outbound_quota; + req->insize = inbound_quota; +@@ -3128,9 +3130,13 @@ NTSTATUS WINAPI NtCreateNamedPipeFile( PHANDLE handle, ULONG access, + wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length ); + status = wine_server_call( req ); + if (!status) *handle = wine_server_ptr_handle( reply->handle ); ++ flags &= ~reply->flags; /* contains now all unsupported flags */ + } + SERVER_END_REQ; + ++ if (!status && (flags & (NAMED_PIPE_MESSAGE_STREAM_WRITE | NAMED_PIPE_MESSAGE_STREAM_READ))) ++ FIXME("Message mode not supported, falling back to byte mode.\n"); ++ + NTDLL_free_struct_sd( sd ); + return status; + } +diff --git a/server/named_pipe.c b/server/named_pipe.c +index 047b62c..81741de 100644 +--- a/server/named_pipe.c ++++ b/server/named_pipe.c +@@ -965,6 +965,7 @@ DECL_HANDLER(create_named_pipe) + return; + } + ++ reply->flags = req->flags & ~(NAMED_PIPE_MESSAGE_STREAM_WRITE | NAMED_PIPE_MESSAGE_STREAM_READ); + reply->handle = 0; + + if (!objattr_is_valid( objattr, get_req_data_size() )) +diff --git a/server/protocol.def b/server/protocol.def +index fc6bec5..503b02f 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -2283,6 +2283,7 @@ enum message_type + unsigned int flags; + VARARG(objattr,object_attributes); /* object attributes */ + @REPLY ++ unsigned int flags; + obj_handle_t handle; /* handle to the pipe */ + @END + +-- +2.1.3 + diff --git a/patches/kernel32-Named_Pipe/0006-ntdll-Unify-similar-code-in-NtReadFile-and-FILE_Asyn.patch b/patches/kernel32-Named_Pipe/0006-ntdll-Unify-similar-code-in-NtReadFile-and-FILE_Asyn.patch new file mode 100644 index 00000000..7256b543 --- /dev/null +++ b/patches/kernel32-Named_Pipe/0006-ntdll-Unify-similar-code-in-NtReadFile-and-FILE_Asyn.patch @@ -0,0 +1,169 @@ +From a1d2578281a218b32b84d4be18c75680439f60c9 Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Fri, 15 Aug 2014 22:23:08 +0200 +Subject: ntdll: Unify similar code in NtReadFile and FILE_AsyncReadService. + +Please note that besides merging the functions (which makes the code much +more readable) this also fixes some inconsistencies. Basically the code +from a unix fd should do the same in both cases, but it didn't... + +Changes in FILE_AsyncReadService: + * Immediately retry on EINTR, chances are very good that it will + succeed in a second attempt, and its not worth to use different code + because of this small difference. + * When read(...) == 0 the result code was always STATUS_PIPE_BROKEN, + whereas NtReadFile uses different behaviour based on the fd type. + Now both implementations match, and behave the same way. +--- + dlls/ntdll/file.c | 106 +++++++++++++++++++++++------------------------------- + 1 file changed, 45 insertions(+), 61 deletions(-) + +diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c +index 01cef2c..a20c3e8 100644 +--- a/dlls/ntdll/file.c ++++ b/dlls/ntdll/file.c +@@ -411,50 +411,63 @@ NTSTATUS FILE_GetNtStatus(void) + } + } + ++/* helper function for NtReadFile and FILE_AsyncReadService */ ++static NTSTATUS read_unix_fd(int fd, char *buf, ULONG *total, ULONG length, ++ enum server_fd_type type, BOOL avail_mode) ++{ ++ int result; ++ for(;;) ++ { ++ result = read( fd, buf + *total, length - *total ); ++ if (result >= 0) ++ { ++ *total += result; ++ if (!result || *total >= length || avail_mode) ++ { ++ if (*total) ++ return STATUS_SUCCESS; ++ switch (type) ++ { ++ case FD_TYPE_FILE: ++ case FD_TYPE_CHAR: ++ return length ? STATUS_END_OF_FILE : STATUS_SUCCESS; ++ case FD_TYPE_SERIAL: ++ return STATUS_PENDING; ++ default: ++ return STATUS_PIPE_BROKEN; ++ } ++ } ++ else if (type != FD_TYPE_FILE) /* no async I/O on regular files */ ++ return STATUS_PENDING; ++ } ++ else if (errno != EINTR) ++ { ++ if (errno == EAGAIN) break; ++ return FILE_GetNtStatus(); ++ } ++ } ++ return STATUS_PENDING; ++} ++ + /*********************************************************************** + * FILE_AsyncReadService (INTERNAL) + */ + static NTSTATUS FILE_AsyncReadService(void *user, PIO_STATUS_BLOCK iosb, NTSTATUS status, void **apc) + { + async_fileio_read *fileio = user; +- int fd, needs_close, result; ++ int fd, needs_close; ++ enum server_fd_type type; + + switch (status) + { + case STATUS_ALERTED: /* got some new data */ + /* check to see if the data is ready (non-blocking) */ + if ((status = server_get_unix_fd( fileio->io.handle, FILE_READ_DATA, &fd, +- &needs_close, NULL, NULL ))) ++ &needs_close, &type, NULL ))) + break; +- +- result = read(fd, &fileio->buffer[fileio->already], fileio->count - fileio->already); ++ status = read_unix_fd( fd, fileio->buffer, &fileio->already, fileio->count, ++ type, fileio->avail_mode ); + if (needs_close) close( fd ); +- +- if (result < 0) +- { +- if (errno == EAGAIN || errno == EINTR) +- status = STATUS_PENDING; +- else /* check to see if the transfer is complete */ +- status = FILE_GetNtStatus(); +- } +- else if (result == 0) +- { +- status = fileio->already ? STATUS_SUCCESS : STATUS_PIPE_BROKEN; +- } +- else +- { +- fileio->already += result; +- if (fileio->already >= fileio->count || fileio->avail_mode) +- status = STATUS_SUCCESS; +- else +- { +- /* if we only have to read the available data, and none is available, +- * simply cancel the request. If data was available, it has been read +- * while in by previous call (NtDelayExecution) +- */ +- status = (fileio->avail_mode) ? STATUS_SUCCESS : STATUS_PENDING; +- } +- } + break; + + case STATUS_TIMEOUT: +@@ -603,7 +616,6 @@ static NTSTATUS get_io_avail_mode( HANDLE handle, enum server_fd_type type, BOOL + return status; + } + +- + /****************************************************************************** + * NtReadFile [NTDLL.@] + * ZwReadFile [NTDLL.@] +@@ -696,37 +708,9 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent, + + for (;;) + { +- if ((result = read( unix_handle, (char *)buffer + total, length - total )) >= 0) +- { +- total += result; +- if (!result || total == length) +- { +- if (total) +- { +- status = STATUS_SUCCESS; +- goto done; +- } +- switch (type) +- { +- case FD_TYPE_FILE: +- case FD_TYPE_CHAR: +- status = length ? STATUS_END_OF_FILE : STATUS_SUCCESS; +- goto done; +- case FD_TYPE_SERIAL: +- break; +- default: +- status = STATUS_PIPE_BROKEN; +- goto done; +- } +- } +- else if (type == FD_TYPE_FILE) continue; /* no async I/O on regular files */ +- } +- else if (errno != EAGAIN) +- { +- if (errno == EINTR) continue; +- if (!total) status = FILE_GetNtStatus(); ++ status = read_unix_fd( unix_handle, buffer, &total, length, type, FALSE ); ++ if (status != STATUS_PENDING) + goto done; +- } + + if (async_read) + { +-- +2.1.3 + diff --git a/patches/kernel32-Named_Pipe/0007-ntdll-Move-logic-to-check-for-broken-pipe-into-a-sep.patch b/patches/kernel32-Named_Pipe/0007-ntdll-Move-logic-to-check-for-broken-pipe-into-a-sep.patch new file mode 100644 index 00000000..d66aa2be --- /dev/null +++ b/patches/kernel32-Named_Pipe/0007-ntdll-Move-logic-to-check-for-broken-pipe-into-a-sep.patch @@ -0,0 +1,107 @@ +From 32d3c69ae680a7b6f71e203ca33f882eb0b69c47 Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Fri, 15 Aug 2014 23:06:06 +0200 +Subject: ntdll: Move logic to check for broken pipe into a separate function. + +--- + dlls/ntdll/file.c | 75 +++++++++++++++++++++++++++++-------------------------- + 1 file changed, 39 insertions(+), 36 deletions(-) + +diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c +index a20c3e8..8de4b98 100644 +--- a/dlls/ntdll/file.c ++++ b/dlls/ntdll/file.c +@@ -411,6 +411,31 @@ NTSTATUS FILE_GetNtStatus(void) + } + } + ++/* helper function for FSCTL_PIPE_PEEK */ ++static NTSTATUS unix_fd_avail(int fd, int *avail) ++{ ++ struct pollfd pollfd; ++ int ret; ++ *avail = 0; ++ ++#ifdef FIONREAD ++ if (ioctl( fd, FIONREAD, avail ) != 0) ++ { ++ TRACE("FIONREAD failed reason: %s\n", strerror(errno)); ++ return FILE_GetNtStatus(); ++ } ++ if (*avail) ++ return STATUS_SUCCESS; ++#endif ++ ++ pollfd.fd = fd; ++ pollfd.events = POLLIN; ++ pollfd.revents = 0; ++ ret = poll( &pollfd, 1, 0 ); ++ return (ret == -1 || (ret == 1 && (pollfd.revents & (POLLHUP|POLLERR)))) ? ++ STATUS_PIPE_BROKEN : STATUS_SUCCESS; ++} ++ + /* helper function for NtReadFile and FILE_AsyncReadService */ + static NTSTATUS read_unix_fd(int fd, char *buf, ULONG *total, ULONG length, + enum server_fd_type type, BOOL avail_mode) +@@ -1557,44 +1582,22 @@ NTSTATUS WINAPI NtFsControlFile(HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc + if ((status = server_get_unix_fd( handle, FILE_READ_DATA, &fd, &needs_close, NULL, NULL ))) + break; + +-#ifdef FIONREAD +- if (ioctl( fd, FIONREAD, &avail ) != 0) +- { +- TRACE("FIONREAD failed reason: %s\n",strerror(errno)); +- if (needs_close) close( fd ); +- status = FILE_GetNtStatus(); +- break; +- } +-#endif +- if (!avail) /* check for closed pipe */ +- { +- struct pollfd pollfd; +- int ret; +- +- pollfd.fd = fd; +- pollfd.events = POLLIN; +- pollfd.revents = 0; +- ret = poll( &pollfd, 1, 0 ); +- if (ret == -1 || (ret == 1 && (pollfd.revents & (POLLHUP|POLLERR)))) +- { +- if (needs_close) close( fd ); +- status = STATUS_PIPE_BROKEN; +- break; +- } +- } +- buffer->NamedPipeState = 0; /* FIXME */ +- buffer->ReadDataAvailable = avail; +- buffer->NumberOfMessages = 0; /* FIXME */ +- buffer->MessageLength = 0; /* FIXME */ +- io->Information = FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data ); +- status = STATUS_SUCCESS; +- if (avail) ++ status = unix_fd_avail( fd, &avail ); ++ if (!status) + { +- ULONG data_size = out_size - FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data ); +- if (data_size) ++ buffer->NamedPipeState = 0; /* FIXME */ ++ buffer->ReadDataAvailable = avail; ++ buffer->NumberOfMessages = 0; /* FIXME */ ++ buffer->MessageLength = 0; /* FIXME */ ++ io->Information = FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data ); ++ if (avail) + { +- int res = recv( fd, buffer->Data, data_size, MSG_PEEK ); +- if (res >= 0) io->Information += res; ++ ULONG data_size = out_size - FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data ); ++ if (data_size) ++ { ++ int res = recv( fd, buffer->Data, data_size, MSG_PEEK ); ++ if (res >= 0) io->Information += res; ++ } + } + } + if (needs_close) close( fd ); +-- +2.1.3 + diff --git a/patches/kernel32-Named_Pipe/0008-ntdll-Unify-similar-code-in-NtWriteFile-and-FILE_Asy.patch b/patches/kernel32-Named_Pipe/0008-ntdll-Unify-similar-code-in-NtWriteFile-and-FILE_Asy.patch new file mode 100644 index 00000000..7b8e583b --- /dev/null +++ b/patches/kernel32-Named_Pipe/0008-ntdll-Unify-similar-code-in-NtWriteFile-and-FILE_Asy.patch @@ -0,0 +1,130 @@ +From cbfe442e44c7297e524c1e3b6ae077b2c84d4ab5 Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Mon, 18 Aug 2014 01:48:17 +0200 +Subject: ntdll: Unify similar code in NtWriteFile and FILE_AsyncWriteService. + +Changes in FILE_AsyncWriteService: + * Immediately retry on EINTR, chances are very good that it will + succeed in a second attempt, and its not worth to use different code + because of this small difference. + * Why is it STATUS_SUCCESS when we have a partial sync write, but + an error for async? Lets assume its always success... +--- + dlls/ntdll/file.c | 78 +++++++++++++++++++++++++------------------------------ + 1 file changed, 35 insertions(+), 43 deletions(-) + +diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c +index 8de4b98..e8a1066 100644 +--- a/dlls/ntdll/file.c ++++ b/dlls/ntdll/file.c +@@ -926,6 +926,37 @@ NTSTATUS WINAPI NtReadFileScatter( HANDLE file, HANDLE event, PIO_APC_ROUTINE ap + return status; + } + ++/* helper function for NtWriteFile and FILE_AsyncWriteService */ ++static NTSTATUS write_unix_fd(int fd, const char *buf, ULONG *total, ULONG length, enum server_fd_type type) ++{ ++ int result; ++ for(;;) ++ { ++ if (!length && (type == FD_TYPE_MAILSLOT || type == FD_TYPE_PIPE || type == FD_TYPE_SOCKET)) ++ result = send( fd, buf, 0, 0 ); ++ else ++ result = write( fd, buf + *total, length - *total ); ++ if (result >= 0) ++ { ++ *total += result; ++ if (*total >= length) ++ return STATUS_SUCCESS; ++ else if (type != FD_TYPE_FILE) /* no async I/O on regular files */ ++ return STATUS_PENDING; ++ } ++ else if (errno != EINTR) ++ { ++ if (errno == EAGAIN) ++ break; ++ else if (*total) ++ return STATUS_SUCCESS; ++ else if (errno == EFAULT) ++ return STATUS_INVALID_USER_BUFFER; ++ return FILE_GetNtStatus(); ++ } ++ } ++ return STATUS_PENDING; ++} + + /*********************************************************************** + * FILE_AsyncWriteService (INTERNAL) +@@ -933,7 +964,7 @@ NTSTATUS WINAPI NtReadFileScatter( HANDLE file, HANDLE event, PIO_APC_ROUTINE ap + static NTSTATUS FILE_AsyncWriteService(void *user, IO_STATUS_BLOCK *iosb, NTSTATUS status, void **apc) + { + async_fileio_write *fileio = user; +- int result, fd, needs_close; ++ int fd, needs_close; + enum server_fd_type type; + + switch (status) +@@ -943,24 +974,8 @@ static NTSTATUS FILE_AsyncWriteService(void *user, IO_STATUS_BLOCK *iosb, NTSTAT + if ((status = server_get_unix_fd( fileio->io.handle, FILE_WRITE_DATA, &fd, + &needs_close, &type, NULL ))) + break; +- +- if (!fileio->count && (type == FD_TYPE_MAILSLOT || type == FD_TYPE_PIPE || type == FD_TYPE_SOCKET)) +- result = send( fd, fileio->buffer, 0, 0 ); +- else +- result = write( fd, &fileio->buffer[fileio->already], fileio->count - fileio->already ); +- ++ status = write_unix_fd( fd, fileio->buffer, &fileio->already, fileio->count, type ); + if (needs_close) close( fd ); +- +- if (result < 0) +- { +- if (errno == EAGAIN || errno == EINTR) status = STATUS_PENDING; +- else status = FILE_GetNtStatus(); +- } +- else +- { +- fileio->already += result; +- status = (fileio->already < fileio->count) ? STATUS_PENDING : STATUS_SUCCESS; +- } + break; + + case STATUS_TIMEOUT: +@@ -1120,32 +1135,9 @@ NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent, + + for (;;) + { +- /* zero-length writes on sockets may not work with plain write(2) */ +- if (!length && (type == FD_TYPE_MAILSLOT || type == FD_TYPE_PIPE || type == FD_TYPE_SOCKET)) +- result = send( unix_handle, buffer, 0, 0 ); +- else +- result = write( unix_handle, (const char *)buffer + total, length - total ); +- +- if (result >= 0) +- { +- total += result; +- if (total == length) +- { +- status = STATUS_SUCCESS; +- goto done; +- } +- if (type == FD_TYPE_FILE) continue; /* no async I/O on regular files */ +- } +- else if (errno != EAGAIN) +- { +- if (errno == EINTR) continue; +- if (!total) +- { +- if (errno == EFAULT) status = STATUS_INVALID_USER_BUFFER; +- else status = FILE_GetNtStatus(); +- } ++ status = write_unix_fd( unix_handle, buffer, &total, length, type ); ++ if (status != STATUS_PENDING) + goto done; +- } + + if (async_write) + { +-- +2.1.3 + diff --git a/patches/kernel32-Named_Pipe/0009-server-Use-SOCK_SEQPACKET-socket-in-combination-with.patch b/patches/kernel32-Named_Pipe/0009-server-Use-SOCK_SEQPACKET-socket-in-combination-with.patch new file mode 100644 index 00000000..1986fe1b --- /dev/null +++ b/patches/kernel32-Named_Pipe/0009-server-Use-SOCK_SEQPACKET-socket-in-combination-with.patch @@ -0,0 +1,542 @@ +From b52ac9f6c1d7391d350e9b7cefbcbb0ac2b62516 Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Mon, 4 Aug 2014 05:01:11 +0200 +Subject: server: Use SOCK_SEQPACKET socket in combination with SO_PEEK_OFF to + implement message mode on Unix. + +Based on ideas by Erich E. Hoover. + +Similar to Windows, when a pipe has been created with message mode flags, then all +sending operations always behave in "message mode". Currently the read mode isn't +handled yet, and the default is byte mode, to stay backwards compatible. + +Changes in v2: + * Show FIXME when message is too big and was splitted + * Simplify logic for FSCTL_PIPE_PEEK + +Changes in v3: + * Avoid changes in later patches, directly store pipe mode in signal attributes. + +Changes in v4: + * Moved changes into read_unix_fd function to make them available for async reads. + +Changes in v5: + * Rebased, merged with following patch. +--- + dlls/kernel32/sync.c | 2 +- + dlls/kernel32/tests/pipe.c | 9 ---- + dlls/ntdll/file.c | 106 ++++++++++++++++++++++++++++++++++++------- + server/named_pipe.c | 109 ++++++++++++++++++++++++++++++++++++--------- + server/sock.c | 4 +- + server/sock.h | 26 +++++++++++ + 6 files changed, 207 insertions(+), 49 deletions(-) + create mode 100644 server/sock.h + +diff --git a/dlls/kernel32/sync.c b/dlls/kernel32/sync.c +index 12887ff..5be278e 100644 +--- a/dlls/kernel32/sync.c ++++ b/dlls/kernel32/sync.c +@@ -1472,7 +1472,7 @@ BOOL WINAPI PeekNamedPipe( HANDLE hPipe, LPVOID lpvBuffer, DWORD cbBuffer, + ULONG read_size = io.Information - FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data ); + if (lpcbAvail) *lpcbAvail = buffer->ReadDataAvailable; + if (lpcbRead) *lpcbRead = read_size; +- if (lpcbMessage) *lpcbMessage = 0; /* FIXME */ ++ if (lpcbMessage) *lpcbMessage = buffer->MessageLength; + if (lpvBuffer) memcpy( lpvBuffer, buffer->Data, read_size ); + } + else SetLastError( RtlNtStatusToDosError(status) ); +diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c +index f42fe5c..743144e 100644 +--- a/dlls/kernel32/tests/pipe.c ++++ b/dlls/kernel32/tests/pipe.c +@@ -285,7 +285,6 @@ static void test_CreateNamedPipe(int pipemode) + if (pipemode == PIPE_TYPE_BYTE) + ok(leftmsg == 0, "peek got %d bytes left in message\n", leftmsg); + else +- todo_wine + ok(leftmsg == sizeof(obuf2) - 4, "peek got %d bytes left in message\n", leftmsg); + ok(ReadFile(hFile, ibuf + 4, sizeof(ibuf) - 4, &readden, NULL), "ReadFile\n"); + ok(readden == sizeof(obuf2) - 4, "read got %d bytes\n", readden); +@@ -509,12 +508,10 @@ static void test_CreateNamedPipe(int pipemode) + readden = leftmsg = -1; + ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 9\n"); + ok(readden == sizeof(obuf) + sizeof(obuf2), "peek got %d bytes total 9\n", readden); +- todo_wine + ok(leftmsg == sizeof(obuf), "peek got %d bytes left in message 9\n", leftmsg); + readden = leftmsg = -1; + ok(RpcPeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 9\n"); + ok(readden == sizeof(obuf) + sizeof(obuf2), "peek got %d bytes total 9\n", readden); +- todo_wine + ok(leftmsg == sizeof(obuf), "peek got %d bytes left in message 9\n", leftmsg); + SetLastError(0xdeadbeef); + todo_wine +@@ -532,12 +529,10 @@ static void test_CreateNamedPipe(int pipemode) + readden = leftmsg = -1; + ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 9\n"); + ok(readden == sizeof(obuf) - 8 + sizeof(obuf2), "peek got %d bytes total 9\n", readden); +- todo_wine + ok(leftmsg == sizeof(obuf) - 8, "peek got %d bytes left in message 9\n", leftmsg); + readden = leftmsg = -1; + ok(RpcPeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 9\n"); + ok(readden == sizeof(obuf) - 8 + sizeof(obuf2), "peek got %d bytes total 9\n", readden); +- todo_wine + ok(leftmsg == sizeof(obuf) - 8, "peek got %d bytes left in message 9\n", leftmsg); + ret = RpcReadFile(hFile, ibuf + 8, sizeof(ibuf), &readden, NULL); + ok(ret, "RpcReadFile 9\n"); +@@ -598,12 +593,10 @@ static void test_CreateNamedPipe(int pipemode) + readden = leftmsg = -1; + ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 10\n"); + ok(readden == sizeof(obuf) + sizeof(obuf2), "peek got %d bytes total 10\n", readden); +- todo_wine + ok(leftmsg == sizeof(obuf2), "peek got %d bytes left in message 10\n", leftmsg); + readden = leftmsg = -1; + ok(RpcPeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 10\n"); + ok(readden == sizeof(obuf) + sizeof(obuf2), "peek got %d bytes total 10\n", readden); +- todo_wine + ok(leftmsg == sizeof(obuf2), "peek got %d bytes left in message 10\n", leftmsg); + SetLastError(0xdeadbeef); + todo_wine +@@ -621,12 +614,10 @@ static void test_CreateNamedPipe(int pipemode) + readden = leftmsg = -1; + ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "PeekNamedPipe 10\n"); + ok(readden == sizeof(obuf2) - 8 + sizeof(obuf), "peek got %d bytes total 10\n", readden); +- todo_wine + ok(leftmsg == sizeof(obuf2) - 8, "peek got %d bytes left in message 10\n", leftmsg); + readden = leftmsg = -1; + ok(RpcPeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "RpcPeekNamedPipe 10\n"); + ok(readden == sizeof(obuf2) - 8 + sizeof(obuf), "peek got %d bytes total 10\n", readden); +- todo_wine + ok(leftmsg == sizeof(obuf2) - 8, "peek got %d bytes left in message 10\n", leftmsg); + ret = RpcReadFile(hnp, ibuf + 8, sizeof(ibuf), &readden, NULL); + ok(ret, "RpcReadFile 10\n"); +diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c +index e8a1066..5cbfa40 100644 +--- a/dlls/ntdll/file.c ++++ b/dlls/ntdll/file.c +@@ -76,6 +76,10 @@ + # include + #endif + ++#ifndef SO_PEEK_OFF ++#define SO_PEEK_OFF 42 ++#endif ++ + #define NONAMELESSUNION + #define NONAMELESSSTRUCT + #include "ntstatus.h" +@@ -436,18 +440,57 @@ static NTSTATUS unix_fd_avail(int fd, int *avail) + STATUS_PIPE_BROKEN : STATUS_SUCCESS; + } + ++/* returns the pipe flags for a file descriptor */ ++static inline int get_pipe_flags(int fd) ++{ ++#ifdef __linux__ ++ return fcntl( fd, F_GETSIG ); ++#else ++ return 0; ++#endif ++} ++ + /* helper function for NtReadFile and FILE_AsyncReadService */ + static NTSTATUS read_unix_fd(int fd, char *buf, ULONG *total, ULONG length, + enum server_fd_type type, BOOL avail_mode) + { +- int result; ++ struct msghdr msg; ++ struct iovec iov; ++ int pipe_flags = 0, result; ++ ++ if (type == FD_TYPE_PIPE) ++ pipe_flags = get_pipe_flags( fd ); ++ + for(;;) + { +- result = read( fd, buf + *total, length - *total ); ++ if (pipe_flags & NAMED_PIPE_MESSAGE_STREAM_WRITE) ++ { ++ msg.msg_name = NULL; ++ msg.msg_namelen = 0; ++ msg.msg_iov = &iov; ++ msg.msg_iovlen = 1; ++ msg.msg_control = NULL; ++ msg.msg_controllen = 0; ++ msg.msg_flags = 0; ++ ++ iov.iov_base = buf + *total; ++ iov.iov_len = length - *total; ++ ++ result = recvmsg( fd, &msg, MSG_PEEK | (*total ? MSG_DONTWAIT : 0) ); ++ if (result >= 0 && !(msg.msg_flags & MSG_TRUNC)) ++ { ++ int ret; ++ while (!(ret = recv( fd, NULL, 0, MSG_TRUNC)) && result > 0); ++ if (ret < 0) ERR("dequeue message failed reason: %s\n", strerror(errno)); ++ } ++ } ++ else ++ result = read( fd, buf + *total, length - *total ); ++ + if (result >= 0) + { + *total += result; +- if (!result || *total >= length || avail_mode) ++ if (!result || *total >= length || (avail_mode && !(pipe_flags & NAMED_PIPE_MESSAGE_STREAM_WRITE))) + { + if (*total) + return STATUS_SUCCESS; +@@ -462,16 +505,17 @@ static NTSTATUS read_unix_fd(int fd, char *buf, ULONG *total, ULONG length, + return STATUS_PIPE_BROKEN; + } + } ++ else if (pipe_flags & NAMED_PIPE_MESSAGE_STREAM_WRITE) ++ continue; + else if (type != FD_TYPE_FILE) /* no async I/O on regular files */ + return STATUS_PENDING; + } ++ else if (errno == EAGAIN) ++ return (avail_mode && *total) ? STATUS_SUCCESS : STATUS_PENDING; + else if (errno != EINTR) +- { +- if (errno == EAGAIN) break; + return FILE_GetNtStatus(); +- } + } +- return STATUS_PENDING; ++ return STATUS_UNSUCCESSFUL; /* never reached */ + } + + /*********************************************************************** +@@ -929,13 +973,14 @@ NTSTATUS WINAPI NtReadFileScatter( HANDLE file, HANDLE event, PIO_APC_ROUTINE ap + /* helper function for NtWriteFile and FILE_AsyncWriteService */ + static NTSTATUS write_unix_fd(int fd, const char *buf, ULONG *total, ULONG length, enum server_fd_type type) + { ++ ULONG msgsize = (ULONG)-1; + int result; + for(;;) + { + if (!length && (type == FD_TYPE_MAILSLOT || type == FD_TYPE_PIPE || type == FD_TYPE_SOCKET)) + result = send( fd, buf, 0, 0 ); + else +- result = write( fd, buf + *total, length - *total ); ++ result = write( fd, buf + *total, min(length - *total, msgsize) ); + if (result >= 0) + { + *total += result; +@@ -944,6 +989,17 @@ static NTSTATUS write_unix_fd(int fd, const char *buf, ULONG *total, ULONG lengt + else if (type != FD_TYPE_FILE) /* no async I/O on regular files */ + return STATUS_PENDING; + } ++ else if (errno == EMSGSIZE && type == FD_TYPE_PIPE && msgsize > 4096) ++ { ++ static ULONG warn_msgsize; ++ if (msgsize == (ULONG)-1) msgsize = (length + 32 + 4095) & ~4095; ++ if (msgsize > warn_msgsize) ++ { ++ FIXME("Message is too big, try to increase /proc/sys/net/core/wmem_default to at least %d\n", msgsize); ++ warn_msgsize = msgsize; ++ } ++ msgsize -= 4096; /* FIXME: use more intelligent algorithm to discover msgsize */ ++ } + else if (errno != EINTR) + { + if (errno == EAGAIN) +@@ -1577,20 +1633,40 @@ NTSTATUS WINAPI NtFsControlFile(HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc + status = unix_fd_avail( fd, &avail ); + if (!status) + { ++ ULONG data_size = out_size - FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data ); ++ int pipe_flags = get_pipe_flags( fd ); ++ + buffer->NamedPipeState = 0; /* FIXME */ + buffer->ReadDataAvailable = avail; +- buffer->NumberOfMessages = 0; /* FIXME */ +- buffer->MessageLength = 0; /* FIXME */ ++ buffer->NumberOfMessages = 0; ++ buffer->MessageLength = 0; + io->Information = FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data ); +- if (avail) ++ ++ if (pipe_flags & NAMED_PIPE_MESSAGE_STREAM_WRITE) + { +- ULONG data_size = out_size - FIELD_OFFSET( FILE_PIPE_PEEK_BUFFER, Data ); +- if (data_size) ++ int peek_offset; ++ socklen_t sock_opt_len = sizeof(peek_offset); ++ if (getsockopt( fd, SOL_SOCKET, SO_PEEK_OFF, &peek_offset, &sock_opt_len )) ++ ERR("getsockopt(SO_PEEK_OFF) failed reason: %s\n", strerror(errno)); ++ else + { +- int res = recv( fd, buffer->Data, data_size, MSG_PEEK ); +- if (res >= 0) io->Information += res; ++ char *data = data_size ? buffer->Data : NULL; ++ int res = recv( fd, data, data_size, MSG_PEEK | MSG_TRUNC | MSG_DONTWAIT ); ++ if (res >= 0) io->Information += min(res, data_size); ++ ++ if (setsockopt( fd, SOL_SOCKET, SO_PEEK_OFF, &peek_offset, sizeof(peek_offset) )) ++ ERR("setsockopt(SO_PEEK_OFF) failed reason: %s\n", strerror(errno)); ++ ++ buffer->ReadDataAvailable = avail - peek_offset; ++ buffer->NumberOfMessages = avail > peek_offset; /* FIXME */ ++ buffer->MessageLength = max(0, res); + } + } ++ else if (avail && data_size) ++ { ++ int res = recv( fd, buffer->Data, data_size, MSG_PEEK | MSG_DONTWAIT ); ++ if (res >= 0) io->Information += res; ++ } + } + if (needs_close) close( fd ); + } +diff --git a/server/named_pipe.c b/server/named_pipe.c +index 81741de..0631159 100644 +--- a/server/named_pipe.c ++++ b/server/named_pipe.c +@@ -42,6 +42,10 @@ + #include + #endif + ++#ifndef SO_PEEK_OFF ++#define SO_PEEK_OFF 42 ++#endif ++ + #include "ntstatus.h" + #define WIN32_NO_STATUS + #include "windef.h" +@@ -49,6 +53,7 @@ + #include "winioctl.h" + + #include "file.h" ++#include "sock.h" + #include "handle.h" + #include "thread.h" + #include "request.h" +@@ -804,14 +809,36 @@ static struct pipe_server *find_available_server( struct named_pipe *pipe ) + return NULL; + } + ++/* check if message mode named pipes are supported */ ++static int check_messagemode(void) ++{ ++#ifdef __linux__ ++ static const int zero = 0; ++ static int messagemode = -1; ++ int fd; ++ ++ if (messagemode < 0) ++ { ++ fd = socket( PF_UNIX, SOCK_SEQPACKET, 0 ); ++ messagemode = (fd != -1) && (setsockopt( fd, SOL_SOCKET, SO_PEEK_OFF, &zero, sizeof(zero) ) != -1); ++ if (fd != -1) close( fd ); ++ } ++ ++ return messagemode; ++#else ++ return 0; ++#endif ++} ++ + static struct object *named_pipe_open_file( struct object *obj, unsigned int access, + unsigned int sharing, unsigned int options ) + { ++ static const int zero = 0; + struct named_pipe *pipe = (struct named_pipe *)obj; + struct pipe_server *server; + struct pipe_client *client; + unsigned int pipe_sharing; +- int fds[2]; ++ int fds[2], type; + + if (!(server = find_available_server( pipe ))) + { +@@ -830,7 +857,10 @@ static struct object *named_pipe_open_file( struct object *obj, unsigned int acc + + if ((client = create_pipe_client( options, pipe->flags ))) + { +- if (!socketpair( PF_UNIX, SOCK_STREAM, 0, fds )) ++ type = ((pipe->flags & NAMED_PIPE_MESSAGE_STREAM_WRITE) && check_messagemode()) ? ++ SOCK_SEQPACKET : SOCK_STREAM; ++ ++ if (!socketpair( PF_UNIX, type, 0, fds )) + { + assert( !server->fd ); + +@@ -840,32 +870,53 @@ static struct object *named_pipe_open_file( struct object *obj, unsigned int acc + if (is_overlapped( options )) fcntl( fds[1], F_SETFL, O_NONBLOCK ); + if (is_overlapped( server->options )) fcntl( fds[0], F_SETFL, O_NONBLOCK ); + +- if (pipe->insize) +- { +- setsockopt( fds[0], SOL_SOCKET, SO_RCVBUF, &pipe->insize, sizeof(pipe->insize) ); +- setsockopt( fds[1], SOL_SOCKET, SO_RCVBUF, &pipe->insize, sizeof(pipe->insize) ); +- } +- if (pipe->outsize) ++ /* FIXME: For message mode we don't pay attention to the provided buffer size. ++ * Linux pipes cannot dynamically adjust size, so we leave the size to the system ++ * instead of using the application provided value. Please note that this will ++ * have the effect that the application doesn't block when sending very large ++ * messages. */ ++ if (type != SOCK_SEQPACKET) + { +- setsockopt( fds[0], SOL_SOCKET, SO_SNDBUF, &pipe->outsize, sizeof(pipe->outsize) ); +- setsockopt( fds[1], SOL_SOCKET, SO_SNDBUF, &pipe->outsize, sizeof(pipe->outsize) ); ++ if (pipe->insize) ++ { ++ setsockopt( fds[0], SOL_SOCKET, SO_RCVBUF, &pipe->insize, sizeof(pipe->insize) ); ++ setsockopt( fds[1], SOL_SOCKET, SO_RCVBUF, &pipe->insize, sizeof(pipe->insize) ); ++ } ++ if (pipe->outsize) ++ { ++ setsockopt( fds[0], SOL_SOCKET, SO_SNDBUF, &pipe->outsize, sizeof(pipe->outsize) ); ++ setsockopt( fds[1], SOL_SOCKET, SO_SNDBUF, &pipe->outsize, sizeof(pipe->outsize) ); ++ } + } + +- client->fd = create_anonymous_fd( &pipe_client_fd_ops, fds[1], &client->obj, options ); +- server->fd = create_anonymous_fd( &pipe_server_fd_ops, fds[0], &server->obj, server->options ); +- if (client->fd && server->fd) ++ if (type != SOCK_SEQPACKET || (setsockopt( fds[0], SOL_SOCKET, SO_PEEK_OFF, &zero, sizeof(zero) ) != -1 && ++ setsockopt( fds[1], SOL_SOCKET, SO_PEEK_OFF, &zero, sizeof(zero) ) != -1)) + { +- allow_fd_caching( client->fd ); +- allow_fd_caching( server->fd ); +- fd_copy_completion( server->ioctl_fd, server->fd ); +- if (server->state == ps_wait_open) +- fd_async_wake_up( server->ioctl_fd, ASYNC_TYPE_WAIT, STATUS_SUCCESS ); +- set_server_state( server, ps_connected_server ); +- server->client = client; +- client->server = server; ++ fcntl( fds[0], F_SETSIG, server->pipe_flags ); ++ fcntl( fds[1], F_SETSIG, client->pipe_flags ); ++ ++ client->fd = create_anonymous_fd( &pipe_client_fd_ops, fds[1], &client->obj, options ); ++ server->fd = create_anonymous_fd( &pipe_server_fd_ops, fds[0], &server->obj, server->options ); ++ if (client->fd && server->fd) ++ { ++ allow_fd_caching( client->fd ); ++ allow_fd_caching( server->fd ); ++ fd_copy_completion( server->ioctl_fd, server->fd ); ++ if (server->state == ps_wait_open) ++ fd_async_wake_up( server->ioctl_fd, ASYNC_TYPE_WAIT, STATUS_SUCCESS ); ++ set_server_state( server, ps_connected_server ); ++ server->client = client; ++ client->server = server; ++ } ++ else ++ { ++ release_object( client ); ++ client = NULL; ++ } + } + else + { ++ sock_set_error(); + release_object( client ); + client = NULL; + } +@@ -965,7 +1016,10 @@ DECL_HANDLER(create_named_pipe) + return; + } + +- reply->flags = req->flags & ~(NAMED_PIPE_MESSAGE_STREAM_WRITE | NAMED_PIPE_MESSAGE_STREAM_READ); ++ reply->flags = req->flags; ++ if (!check_messagemode()) ++ reply->flags &= ~(NAMED_PIPE_MESSAGE_STREAM_WRITE | NAMED_PIPE_MESSAGE_STREAM_READ); ++ + reply->handle = 0; + + if (!objattr_is_valid( objattr, get_req_data_size() )) +@@ -1065,6 +1119,7 @@ DECL_HANDLER(set_named_pipe_info) + { + struct pipe_server *server; + struct pipe_client *client = NULL; ++ int unix_fd; + + server = get_pipe_server_obj( current->process, req->handle, FILE_WRITE_ATTRIBUTES ); + if (!server) +@@ -1087,10 +1142,20 @@ DECL_HANDLER(set_named_pipe_info) + else if (client) + { + client->pipe_flags = server->pipe->flags | req->flags; ++ #ifdef __linux__ ++ if (client->fd && (unix_fd = get_unix_fd( client->fd )) != -1) ++ fcntl( unix_fd, F_SETSIG, client->pipe_flags ); ++ clear_error(); ++ #endif + } + else + { + server->pipe_flags = server->pipe->flags | req->flags; ++ #ifdef __linux__ ++ if (server->fd && (unix_fd = get_unix_fd( server->fd )) != -1) ++ fcntl( unix_fd, F_SETSIG, server->pipe_flags ); ++ clear_error(); ++ #endif + } + + if (client) +diff --git a/server/sock.c b/server/sock.c +index 7c0212e..73a2549 100644 +--- a/server/sock.c ++++ b/server/sock.c +@@ -55,6 +55,7 @@ + + #include "process.h" + #include "file.h" ++#include "sock.h" + #include "handle.h" + #include "thread.h" + #include "request.h" +@@ -127,7 +128,6 @@ static void sock_cancel_async( struct fd *fd, struct process *process, struct th + + static int sock_get_ntstatus( int err ); + static int sock_get_error( int err ); +-static void sock_set_error(void); + + static const struct object_ops sock_ops = + { +@@ -910,7 +910,7 @@ static int sock_get_ntstatus( int err ) + } + + /* set the last error depending on errno */ +-static void sock_set_error(void) ++void sock_set_error(void) + { + set_error( sock_get_ntstatus( errno ) ); + } +diff --git a/server/sock.h b/server/sock.h +new file mode 100644 +index 0000000..21551b4 +--- /dev/null ++++ b/server/sock.h +@@ -0,0 +1,26 @@ ++/* ++ * Server-side socket definitions ++ * ++ * Copyright (C) 2014 Sebastian Lackner ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2.1 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA ++ */ ++ ++#ifndef __WINE_SERVER_SOCK_H ++#define __WINE_SERVER_SOCK_H ++ ++extern void sock_set_error(void); ++ ++#endif /* __WINE_SERVER_SOCK_H */ +-- +2.1.3 + diff --git a/patches/kernel32-Named_Pipe/0010-ntdll-Add-handling-for-partially-received-messages-i.patch b/patches/kernel32-Named_Pipe/0010-ntdll-Add-handling-for-partially-received-messages-i.patch new file mode 100644 index 00000000..1c1708dd --- /dev/null +++ b/patches/kernel32-Named_Pipe/0010-ntdll-Add-handling-for-partially-received-messages-i.patch @@ -0,0 +1,321 @@ +From 8d70c149974dafbdabc76cf2fb9daf9108a853f2 Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Mon, 11 Aug 2014 18:20:52 +0200 +Subject: ntdll: Add handling for partially received messages in NtReadFile. + +Changes in v2: + * Merged with final version of error code handling. + * Poll for broken pipe to distinguish between zero-byte messages and errors. + +Changes in v3: + * Rebased. Simplified check for broken pipe. + +Changes in v4: + * Include changes from later patch. +--- + dlls/kernel32/tests/pipe.c | 53 +++++----------------------------------------- + dlls/ntdll/file.c | 28 ++++++++++++++++++------ + 2 files changed, 27 insertions(+), 54 deletions(-) + +diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c +index 743144e..6a27826 100644 +--- a/dlls/kernel32/tests/pipe.c ++++ b/dlls/kernel32/tests/pipe.c +@@ -304,9 +304,7 @@ static void test_CreateNamedPipe(int pipemode) + else + { + SetLastError(0xdeadbeef); +- todo_wine + ok(!ReadFile(hnp, ibuf, 4, &readden, NULL), "ReadFile\n"); +- todo_wine + ok(GetLastError() == ERROR_MORE_DATA, "wrong error\n"); + } + ok(readden == 4, "read got %d bytes\n", readden); +@@ -327,15 +325,11 @@ static void test_CreateNamedPipe(int pipemode) + else + { + SetLastError(0xdeadbeef); +- todo_wine + ok(!ReadFile(hnp, ibuf, 4, &readden, NULL), "ReadFile\n"); +- todo_wine + ok(GetLastError() == ERROR_MORE_DATA, "wrong error\n"); + ok(readden == 4, "read got %d bytes\n", readden); + SetLastError(0xdeadbeef); +- todo_wine + ok(!ReadFile(hnp, ibuf + 4, 4, &readden, NULL), "ReadFile\n"); +- todo_wine + ok(GetLastError() == ERROR_MORE_DATA, "wrong error\n"); + } + ok(readden == 4, "read got %d bytes\n", readden); +@@ -397,9 +391,7 @@ static void test_CreateNamedPipe(int pipemode) + ok(readden == sizeof(obuf) + sizeof(obuf2), "read 4 got %d bytes\n", readden); + } + else { +- todo_wine { +- ok(readden == sizeof(obuf), "read 4 got %d bytes\n", readden); +- } ++ ok(readden == sizeof(obuf), "read 4 got %d bytes\n", readden); + } + pbuf = ibuf; + ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 4a check\n"); +@@ -429,9 +421,7 @@ static void test_CreateNamedPipe(int pipemode) + pbuf = ibuf; + ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 5a check\n"); + ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n"); +- todo_wine { +- ok(readden == sizeof(obuf), "read 5 got %d bytes\n", readden); +- } ++ ok(readden == sizeof(obuf), "read 5 got %d bytes\n", readden); + pbuf = ibuf; + ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 5a check\n"); + if (readden <= sizeof(obuf)) +@@ -440,10 +430,8 @@ static void test_CreateNamedPipe(int pipemode) + /* Multiple writes in the reverse direction */ + /* the write of obuf2 from write4 should still be in the buffer */ + ok(PeekNamedPipe(hnp, ibuf, sizeof(ibuf), &readden, &avail, NULL), "Peek6a\n"); +- todo_wine { +- ok(readden == sizeof(obuf2), "peek6a got %d bytes\n", readden); +- ok(avail == sizeof(obuf2), "peek6a got %d bytes available\n", avail); +- } ++ ok(readden == sizeof(obuf2), "peek6a got %d bytes\n", readden); ++ ok(avail == sizeof(obuf2), "peek6a got %d bytes available\n", avail); + if (avail > 0) { + ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n"); + ok(readden == sizeof(obuf2), "read 6a got %d bytes\n", readden); +@@ -461,9 +449,7 @@ static void test_CreateNamedPipe(int pipemode) + pbuf = ibuf; + ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 6a check\n"); + ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n"); +- todo_wine { +- ok(readden == sizeof(obuf), "read 6b got %d bytes\n", readden); +- } ++ ok(readden == sizeof(obuf), "read 6b got %d bytes\n", readden); + pbuf = ibuf; + ok(memcmp(obuf, pbuf, sizeof(obuf)) == 0, "content 6a check\n"); + if (readden <= sizeof(obuf)) +@@ -474,9 +460,7 @@ static void test_CreateNamedPipe(int pipemode) + ok(WriteFile(hnp, obuf2, sizeof(obuf2), &written, NULL), "WriteFile 7\n"); + ok(written == sizeof(obuf2), "write file len 7\n"); + SetLastError(0xdeadbeef); +- todo_wine + ok(!ReadFile(hFile, ibuf, 4, &readden, NULL), "ReadFile 7\n"); +- todo_wine + ok(GetLastError() == ERROR_MORE_DATA, "wrong error 7\n"); + ok(readden == 4, "read got %d bytes 7\n", readden); + ok(ReadFile(hFile, ibuf + 4, sizeof(ibuf) - 4, &readden, NULL), "ReadFile 7\n"); +@@ -487,9 +471,7 @@ static void test_CreateNamedPipe(int pipemode) + ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile 8\n"); + ok(written == sizeof(obuf), "write file len 8\n"); + SetLastError(0xdeadbeef); +- todo_wine + ok(!ReadFile(hnp, ibuf, 4, &readden, NULL), "ReadFile 8\n"); +- todo_wine + ok(GetLastError() == ERROR_MORE_DATA, "wrong error 8\n"); + ok(readden == 4, "read got %d bytes 8\n", readden); + ok(ReadFile(hnp, ibuf + 4, sizeof(ibuf) - 4, &readden, NULL), "ReadFile 8\n"); +@@ -514,16 +496,12 @@ static void test_CreateNamedPipe(int pipemode) + ok(readden == sizeof(obuf) + sizeof(obuf2), "peek got %d bytes total 9\n", readden); + ok(leftmsg == sizeof(obuf), "peek got %d bytes left in message 9\n", leftmsg); + SetLastError(0xdeadbeef); +- todo_wine + ok(!ReadFile(hFile, ibuf, 4, &readden, NULL), "ReadFile 9\n"); +- todo_wine + ok(GetLastError() == ERROR_MORE_DATA, "wrong error 9\n"); + ok(readden == 4, "read got %d bytes 9\n", readden); + SetLastError(0xdeadbeef); + ret = RpcReadFile(hFile, ibuf + 4, 4, &readden, NULL); +- todo_wine + ok(!ret, "RpcReadFile 9\n"); +- todo_wine + ok(GetLastError() == ERROR_MORE_DATA, "wrong error 9\n"); + ok(readden == 4, "read got %d bytes 9\n", readden); + readden = leftmsg = -1; +@@ -536,7 +514,6 @@ static void test_CreateNamedPipe(int pipemode) + ok(leftmsg == sizeof(obuf) - 8, "peek got %d bytes left in message 9\n", leftmsg); + ret = RpcReadFile(hFile, ibuf + 8, sizeof(ibuf), &readden, NULL); + ok(ret, "RpcReadFile 9\n"); +- todo_wine + ok(readden == sizeof(obuf) - 8, "read got %d bytes 9\n", readden); + ok(memcmp(obuf, ibuf, sizeof(obuf)) == 0, "content check 9\n"); + if (readden <= sizeof(obuf) - 8) /* blocks forever if second part was already received */ +@@ -553,13 +530,10 @@ static void test_CreateNamedPipe(int pipemode) + SetLastError(0xdeadbeef); + ret = RpcReadFile(hFile, ibuf, 4, &readden, NULL); + ok(!ret, "RpcReadFile 9\n"); +- todo_wine + ok(GetLastError() == ERROR_MORE_DATA, "wrong error 9\n"); + ok(readden == 4, "read got %d bytes 9\n", readden); + SetLastError(0xdeadbeef); +- todo_wine + ok(!ReadFile(hFile, ibuf + 4, 4, &readden, NULL), "ReadFile 9\n"); +- todo_wine + ok(GetLastError() == ERROR_MORE_DATA, "wrong error 9\n"); + ok(readden == 4, "read got %d bytes 9\n", readden); + readden = leftmsg = -1; +@@ -599,16 +573,12 @@ static void test_CreateNamedPipe(int pipemode) + ok(readden == sizeof(obuf) + sizeof(obuf2), "peek got %d bytes total 10\n", readden); + ok(leftmsg == sizeof(obuf2), "peek got %d bytes left in message 10\n", leftmsg); + SetLastError(0xdeadbeef); +- todo_wine + ok(!ReadFile(hnp, ibuf, 4, &readden, NULL), "ReadFile 10\n"); +- todo_wine + ok(GetLastError() == ERROR_MORE_DATA, "wrong error 10\n"); + ok(readden == 4, "read got %d bytes 10\n", readden); + SetLastError(0xdeadbeef); + ret = RpcReadFile(hnp, ibuf + 4, 4, &readden, NULL); +- todo_wine + ok(!ret, "RpcReadFile 10\n"); +- todo_wine + ok(GetLastError() == ERROR_MORE_DATA, "wrong error 10\n"); + ok(readden == 4, "read got %d bytes 10\n", readden); + readden = leftmsg = -1; +@@ -621,7 +591,6 @@ static void test_CreateNamedPipe(int pipemode) + ok(leftmsg == sizeof(obuf2) - 8, "peek got %d bytes left in message 10\n", leftmsg); + ret = RpcReadFile(hnp, ibuf + 8, sizeof(ibuf), &readden, NULL); + ok(ret, "RpcReadFile 10\n"); +- todo_wine + ok(readden == sizeof(obuf2) - 8, "read got %d bytes 10\n", readden); + ok(memcmp(obuf2, ibuf, sizeof(obuf2)) == 0, "content check 10\n"); + if (readden <= sizeof(obuf2) - 8) /* blocks forever if second part was already received */ +@@ -638,13 +607,10 @@ static void test_CreateNamedPipe(int pipemode) + SetLastError(0xdeadbeef); + ret = RpcReadFile(hnp, ibuf, 4, &readden, NULL); + ok(!ret, "RpcReadFile 10\n"); +- todo_wine + ok(GetLastError() == ERROR_MORE_DATA, "wrong error 10\n"); + ok(readden == 4, "read got %d bytes 10\n", readden); + SetLastError(0xdeadbeef); +- todo_wine + ok(!ReadFile(hnp, ibuf + 4, 4, &readden, NULL), "ReadFile 10\n"); +- todo_wine + ok(GetLastError() == ERROR_MORE_DATA, "wrong error 10\n"); + ok(readden == 4, "read got %d bytes 10\n", readden); + readden = leftmsg = -1; +@@ -750,15 +716,11 @@ static void test_CreateNamedPipe(int pipemode) + else + { + SetLastError(0xdeadbeef); +- todo_wine + ok(!ReadFile(hFile, big_ibuf, 32, &readden, NULL), "ReadFile\n"); +- todo_wine + ok(GetLastError() == ERROR_MORE_DATA, "wrong error\n"); + ok(readden == 32, "read got %d bytes\n", readden); + SetLastError(0xdeadbeef); +- todo_wine + ok(!ReadFile(hFile, big_ibuf + 32, 32, &readden, NULL), "ReadFile\n"); +- todo_wine + ok(GetLastError() == ERROR_MORE_DATA, "wrong error\n"); + } + ok(readden == 32, "read got %d bytes\n", readden); +@@ -948,7 +910,6 @@ static void test_CloseNamedPipe(void) + /* close server end without disconnecting */ + ok(CloseHandle(hnp), "CloseHandle() failed: %08x\n", GetLastError()); + +- todo_wine + ok(ReadFile(hFile, ibuf, 0, &readden, NULL), "ReadFile() failed: %08x\n", GetLastError()); + ok(readden == 0, "got %d bytes\n", readden); + +@@ -990,7 +951,6 @@ static void test_CloseNamedPipe(void) + ok(CloseHandle(hFile), "CloseHandle() failed: %08x\n", GetLastError()); + + /* you'd think ERROR_MORE_DATA, but no */ +- todo_wine + ok(ReadFile(hnp, ibuf, 0, &readden, NULL), "ReadFile() failed: %08x\n", GetLastError()); + ok(readden == 0, "got %d bytes\n", readden); + +@@ -2460,7 +2420,6 @@ static void test_readfileex_pending(void) + num_bytes = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = ReadFile(server, read_buf, 0, &num_bytes, &overlapped); +-todo_wine + ok(GetLastError() == ERROR_IO_PENDING, "expected ERROR_IO_PENDING, got %d\n", GetLastError()); + ok(num_bytes == 0, "bytes %u\n", num_bytes); + ok((NTSTATUS)overlapped.Internal == STATUS_PENDING, "expected STATUS_PENDING, got %#lx\n", overlapped.Internal); +@@ -2476,11 +2435,9 @@ todo_wine + ok(num_bytes == 1, "bytes %u\n", num_bytes); + + wait = WaitForSingleObject(event, 100); +-todo_wine + ok(wait == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", wait); + + ok(num_bytes == 1, "bytes %u\n", num_bytes); +-todo_wine + ok((NTSTATUS)overlapped.Internal == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#lx\n", overlapped.Internal); + ok(overlapped.InternalHigh == 0, "expected 0, got %lu\n", overlapped.InternalHigh); + +diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c +index 5cbfa40..81f941d 100644 +--- a/dlls/ntdll/file.c ++++ b/dlls/ntdll/file.c +@@ -415,7 +415,7 @@ NTSTATUS FILE_GetNtStatus(void) + } + } + +-/* helper function for FSCTL_PIPE_PEEK */ ++/* helper function for FSCTL_PIPE_PEEK and read_unix_fd */ + static NTSTATUS unix_fd_avail(int fd, int *avail) + { + struct pollfd pollfd; +@@ -444,7 +444,14 @@ static NTSTATUS unix_fd_avail(int fd, int *avail) + static inline int get_pipe_flags(int fd) + { + #ifdef __linux__ +- return fcntl( fd, F_GETSIG ); ++ int flags = fcntl( fd, F_GETSIG ); ++ ++ /* NAMED_PIPE_MESSAGE_STREAM_READ only allowed in ++ * combination with NAMED_PIPE_MESSAGE_STREAM_WRITE. */ ++ if (!(flags & NAMED_PIPE_MESSAGE_STREAM_WRITE)) ++ flags &= ~NAMED_PIPE_MESSAGE_STREAM_READ; ++ ++ return flags; + #else + return 0; + #endif +@@ -490,10 +497,12 @@ static NTSTATUS read_unix_fd(int fd, char *buf, ULONG *total, ULONG length, + if (result >= 0) + { + *total += result; +- if (!result || *total >= length || (avail_mode && !(pipe_flags & NAMED_PIPE_MESSAGE_STREAM_WRITE))) ++ if (!result || *total >= length || (avail_mode && !(pipe_flags & NAMED_PIPE_MESSAGE_STREAM_WRITE)) || ++ ((pipe_flags & NAMED_PIPE_MESSAGE_STREAM_READ) && !(msg.msg_flags & MSG_TRUNC))) + { + if (*total) +- return STATUS_SUCCESS; ++ return ((pipe_flags & NAMED_PIPE_MESSAGE_STREAM_READ) && (msg.msg_flags & MSG_TRUNC)) ? ++ STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS; + switch (type) + { + case FD_TYPE_FILE: +@@ -501,11 +510,18 @@ static NTSTATUS read_unix_fd(int fd, char *buf, ULONG *total, ULONG length, + return length ? STATUS_END_OF_FILE : STATUS_SUCCESS; + case FD_TYPE_SERIAL: + return STATUS_PENDING; ++ case FD_TYPE_PIPE: ++ { ++ NTSTATUS status = unix_fd_avail( fd, &result ); ++ if (!status && !result && !length) status = STATUS_PENDING; ++ return status; ++ } + default: + return STATUS_PIPE_BROKEN; + } + } +- else if (pipe_flags & NAMED_PIPE_MESSAGE_STREAM_WRITE) ++ else if ((pipe_flags & (NAMED_PIPE_MESSAGE_STREAM_WRITE | NAMED_PIPE_MESSAGE_STREAM_READ)) == ++ NAMED_PIPE_MESSAGE_STREAM_WRITE) + continue; + else if (type != FD_TYPE_FILE) /* no async I/O on regular files */ + return STATUS_PENDING; +@@ -863,7 +879,7 @@ done: + + err: + if (needs_close) close( unix_handle ); +- if (status == STATUS_SUCCESS || (status == STATUS_END_OF_FILE && !async_read)) ++ if (status == STATUS_SUCCESS || status == STATUS_BUFFER_OVERFLOW || (status == STATUS_END_OF_FILE && !async_read)) + { + io_status->u.Status = status; + io_status->Information = total; +-- +2.1.3 + diff --git a/patches/kernel32-Named_Pipe/0011-kernel32-tests-Add-more-tests-with-overlapped-IO-and.patch b/patches/kernel32-Named_Pipe/0011-kernel32-tests-Add-more-tests-with-overlapped-IO-and.patch new file mode 100644 index 00000000..ea95c994 --- /dev/null +++ b/patches/kernel32-Named_Pipe/0011-kernel32-tests-Add-more-tests-with-overlapped-IO-and.patch @@ -0,0 +1,188 @@ +From d94857ffb00c9e24dcaff68aed1e14a6b99745f5 Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Sun, 17 Aug 2014 00:47:26 +0200 +Subject: kernel32/tests: Add more tests with overlapped IO and partial reads + from named pipes. + +--- + dlls/kernel32/tests/pipe.c | 150 +++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 150 insertions(+) + +diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c +index 6a27826..ba49974 100644 +--- a/dlls/kernel32/tests/pipe.c ++++ b/dlls/kernel32/tests/pipe.c +@@ -2300,6 +2300,7 @@ static void test_readfileex_pending(void) + OVERLAPPED overlapped; + char read_buf[1024]; + char write_buf[1024]; ++ const char long_test_string[] = "12test3456ab"; + const char test_string[] = "test"; + int i; + +@@ -2339,6 +2340,9 @@ static void test_readfileex_pending(void) + ret = ReadFileEx(server, read_buf, sizeof(read_buf), &overlapped, completion_routine); + ok(ret == TRUE, "ReadFileEx failed, err=%i\n", GetLastError()); + ok(completion_called == 0, "completion routine called before ReadFileEx returned\n"); ++ wait = WaitForSingleObject(event, 100); ++ ok(wait == WAIT_TIMEOUT, "WaitForSingleObjectEx returned %x\n", wait); ++ ok(completion_called == 0, "completion routine called before WriteFile started\n"); + + ret = WriteFile(client, test_string, strlen(test_string), &num_bytes, NULL); + ok(ret == TRUE, "WriteFile failed\n"); +@@ -2449,6 +2453,152 @@ todo_wine + + CloseHandle(client); + CloseHandle(server); ++ ++ server = CreateNamedPipeA(PIPENAME, FILE_FLAG_OVERLAPPED | PIPE_ACCESS_DUPLEX, ++ /* dwOpenMode */ PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, ++ /* nMaxInstances */ 1, ++ /* nOutBufSize */ 1024, ++ /* nInBufSize */ 1024, ++ /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT, ++ /* lpSecurityAttrib */ NULL); ++ ok(server != INVALID_HANDLE_VALUE, "cf failed\n"); ++ ++ client = CreateFileA(PIPENAME, GENERIC_READ|GENERIC_WRITE, 0, NULL, ++ OPEN_EXISTING, 0, NULL); ++ ok(client != INVALID_HANDLE_VALUE, "cf failed\n"); ++ ++ memset(&overlapped, 0, sizeof(overlapped)); ++ overlapped.hEvent = event; ++ ++ /* Start a call to ReadFileEx which cannot complete immediately */ ++ memset(read_buf, 0, sizeof(read_buf)); ++ completion_called = 0; ++ ResetEvent(event); ++ ret = ReadFileEx(server, read_buf, 4, &overlapped, completion_routine); ++ ok(ret == TRUE, "ReadFileEx failed, err=%i\n", GetLastError()); ++ ok(completion_called == 0, "completion routine called before ReadFileEx returned\n"); ++ wait = WaitForSingleObject(event, 100); ++ ok(wait == WAIT_TIMEOUT, "WaitForSingleObject returned %x\n", wait); ++ ok(completion_called == 0, "completion routine called before WriteFile started\n"); ++ ++ ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL); ++ ok(ret == TRUE, "WriteFile failed\n"); ++ ok(num_bytes == strlen(long_test_string), "only %i bytes written\n", num_bytes); ++ ok(completion_called == 0, "completion routine called during WriteFile\n"); ++ wait = WaitForSingleObjectEx(event, 0, TRUE); ++ ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObjectEx returned %x\n", wait); ++ ++ ok(completion_called == 1, "completion not called after writing pipe\n"); ++ todo_wine ++ ok(completion_errorcode == 0, "completion called with error %x\n", completion_errorcode); ++ ok(completion_num_bytes == 4, "ReadFileEx returned only %d bytes\n", completion_num_bytes); ++ ok(completion_lpoverlapped == &overlapped, "completion called with wrong overlapped pointer\n"); ++ ok(!memcmp(long_test_string, read_buf, 4), "ReadFileEx read wrong bytes\n"); ++ ++ ret = ReadFile(server, read_buf + 4, 4, &num_bytes, NULL); ++ ok(ret == FALSE, "ReadFile succeeded\n"); ++ ok(num_bytes == 4, "ReadFile returned only %d bytes\n", num_bytes); ++ ok(GetLastError() == ERROR_MORE_DATA, "wrong error\n"); ++ ret = ReadFile(server, read_buf + 8, sizeof(read_buf) - 8, &num_bytes, NULL); ++ ok(ret == TRUE, "ReadFile failed\n"); ++ ok(num_bytes == strlen(long_test_string)-8, "ReadFile returned only %d bytes\n", num_bytes); ++ ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n"); ++ ++ /* Call ReadFileEx when there is already some content in the pipe */ ++ ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL); ++ ok(ret == TRUE, "WriteFile failed\n"); ++ ok(num_bytes == strlen(long_test_string), "only %i bytes written\n", num_bytes); ++ ++ memset(read_buf, 0, sizeof(read_buf)); ++ completion_called = 0; ++ ResetEvent(event); ++ ret = ReadFileEx(server, read_buf, 4, &overlapped, completion_routine); ++ todo_wine ++ ok(ret == TRUE, "ReadFileEx failed, err=%i\n", GetLastError()); ++ ok(completion_called == 0, "completion routine called before ReadFileEx returned\n"); ++ wait = WaitForSingleObjectEx(event, 0, TRUE); ++ todo_wine ++ ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObjectEx returned %x\n", wait); ++ todo_wine ++ ok(completion_called == 1, "completion not called after writing pipe\n"); ++ todo_wine ++ ok(completion_errorcode == 0, "completion called with error %x\n", completion_errorcode); ++ ok(completion_num_bytes == 4, "ReadFileEx returned only %d bytes\n", completion_num_bytes); ++ ok(completion_lpoverlapped == &overlapped, "completion called with wrong overlapped pointer\n"); ++ ok(!memcmp(long_test_string, read_buf, 4), "ReadFileEx read wrong bytes\n"); ++ ++ ret = ReadFile(server, read_buf + 4, sizeof(read_buf) - 4, &num_bytes, NULL); ++ ok(ret == TRUE, "ReadFile failed\n"); ++ ok(num_bytes == strlen(long_test_string)-4, "ReadFile returned only %d bytes\n", num_bytes); ++ ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n"); ++ ++ /* Check content of overlapped structure */ ++ memset(read_buf, 0, sizeof(read_buf)); ++ S(U(overlapped)).Offset = 0; ++ S(U(overlapped)).OffsetHigh = 0; ++ overlapped.Internal = -1; ++ overlapped.InternalHigh = -1; ++ overlapped.hEvent = event; ++ num_bytes = 0xdeadbeef; ++ SetLastError(0xdeadbeef); ++ ret = ReadFile(server, read_buf, 4, &num_bytes, &overlapped); ++ ok(GetLastError() == ERROR_IO_PENDING, "expected ERROR_IO_PENDING, got %d\n", GetLastError()); ++ ok(num_bytes == 0, "bytes %u\n", num_bytes); ++ ok((NTSTATUS)overlapped.Internal == STATUS_PENDING, "expected STATUS_PENDING, got %#lx\n", overlapped.Internal); ++ todo_wine ++ ok(overlapped.InternalHigh == -1, "expected -1, got %lu\n", overlapped.InternalHigh); ++ wait = WaitForSingleObject(event, 100); ++ ok(wait == WAIT_TIMEOUT, "WaitForSingleObject returned %x\n", wait); ++ ok((NTSTATUS)overlapped.Internal == STATUS_PENDING, "expected STATUS_PENDING, got %#lx\n", overlapped.Internal); ++ ++ num_bytes = 0xdeadbeef; ++ ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL); ++ ok(ret, "WriteFile failed\n"); ++ ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes); ++ wait = WaitForSingleObject(event, 100); ++ ok(wait == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", wait); ++ ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes); ++ ok((NTSTATUS)overlapped.Internal == STATUS_BUFFER_OVERFLOW, "expected STATUS_BUFFER_OVERFLOW, got %#lx\n", overlapped.Internal); ++ ok(overlapped.InternalHigh == 4, "expected 4, got %lu\n", overlapped.InternalHigh); ++ ++ ret = ReadFile(server, read_buf + 4, sizeof(read_buf) - 4, &num_bytes, NULL); ++ ok(ret == TRUE, "ReadFile failed\n"); ++ ok(num_bytes == strlen(long_test_string)-4, "ReadFile returned only %d bytes\n", num_bytes); ++ ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n"); ++ ++ /* Call ReadFile when there is already some content in the pipe */ ++ num_bytes = 0xdeadbeef; ++ ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL); ++ ok(ret, "WriteFile failed\n"); ++ ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes); ++ ++ memset(read_buf, 0, sizeof(read_buf)); ++ S(U(overlapped)).Offset = 0; ++ S(U(overlapped)).OffsetHigh = 0; ++ overlapped.Internal = -1; ++ overlapped.InternalHigh = -1; ++ overlapped.hEvent = event; ++ num_bytes = 0xdeadbeef; ++ SetLastError(0xdeadbeef); ++ ret = ReadFile(server, read_buf, 4, &num_bytes, &overlapped); ++ ok(ret == FALSE, "ReadFile succeeded\n"); ++ ok(GetLastError() == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", GetLastError()); ++ todo_wine ++ ok(num_bytes == 0, "ReadFile returned %d bytes\n", num_bytes); ++ wait = WaitForSingleObjectEx(event, 0, TRUE); ++ ok(wait == WAIT_OBJECT_0, "WaitForSingleObjectEx returned %x\n", wait); ++ todo_wine ++ ok(num_bytes == 0, "bytes %u\n", num_bytes); ++ ok((NTSTATUS)overlapped.Internal == STATUS_BUFFER_OVERFLOW, "expected STATUS_BUFFER_OVERFLOW, got %#lx\n", overlapped.Internal); ++ ok(overlapped.InternalHigh == 4, "expected 4, got %lu\n", overlapped.InternalHigh); ++ ++ ret = ReadFile(server, read_buf + 4, sizeof(read_buf) - 4, &num_bytes, NULL); ++ ok(ret == TRUE, "ReadFile failed\n"); ++ ok(num_bytes == strlen(long_test_string)-4, "ReadFile returned only %d bytes\n", num_bytes); ++ ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n"); ++ ++ CloseHandle(client); ++ CloseHandle(server); + CloseHandle(event); + } + +-- +2.1.3 + diff --git a/patches/kernel32-Named_Pipe/0012-ntdll-Fix-some-tests-for-overlapped-partial-reads.patch b/patches/kernel32-Named_Pipe/0012-ntdll-Fix-some-tests-for-overlapped-partial-reads.patch new file mode 100644 index 00000000..ea29cd0c --- /dev/null +++ b/patches/kernel32-Named_Pipe/0012-ntdll-Fix-some-tests-for-overlapped-partial-reads.patch @@ -0,0 +1,85 @@ +From 87e6095901f7405efc256997f1e1d6f0338ab2b5 Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Sun, 17 Aug 2014 01:13:44 +0200 +Subject: ntdll: Fix some tests for overlapped partial reads. + +Windows also sends as APC user notification for STATUS_BUFFER_OVERFLOW. +Moreover in some cases STATUS_BUFFER_OVERFLOW is reported as success, not +as failure. +--- + dlls/kernel32/file.c | 7 ++++--- + dlls/kernel32/tests/pipe.c | 5 ----- + dlls/ntdll/file.c | 4 ++-- + 3 files changed, 6 insertions(+), 10 deletions(-) + +diff --git a/dlls/kernel32/file.c b/dlls/kernel32/file.c +index 006db1c..78cfdb7 100644 +--- a/dlls/kernel32/file.c ++++ b/dlls/kernel32/file.c +@@ -325,8 +325,9 @@ BOOL WINAPI AreFileApisANSI(void) + static void WINAPI FILE_ReadWriteApc(void* apc_user, PIO_STATUS_BLOCK io_status, ULONG reserved) + { + LPOVERLAPPED_COMPLETION_ROUTINE cr = apc_user; +- +- cr(RtlNtStatusToDosError(io_status->u.Status), io_status->Information, (LPOVERLAPPED)io_status); ++ NTSTATUS status = io_status->u.Status; ++ if (status == STATUS_BUFFER_OVERFLOW) status = STATUS_SUCCESS; ++ cr(RtlNtStatusToDosError(status), io_status->Information, (LPOVERLAPPED)io_status); + } + + +@@ -358,7 +359,7 @@ BOOL WINAPI ReadFileEx(HANDLE hFile, LPVOID buffer, DWORD bytesToRead, + status = NtReadFile(hFile, NULL, FILE_ReadWriteApc, lpCompletionRoutine, + io_status, buffer, bytesToRead, &offset, NULL); + +- if (status && status != STATUS_PENDING) ++ if (status && status != STATUS_PENDING && status != STATUS_BUFFER_OVERFLOW) + { + SetLastError( RtlNtStatusToDosError(status) ); + return FALSE; +diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c +index ba49974..53f8f30 100644 +--- a/dlls/kernel32/tests/pipe.c ++++ b/dlls/kernel32/tests/pipe.c +@@ -2489,7 +2489,6 @@ todo_wine + ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObjectEx returned %x\n", wait); + + ok(completion_called == 1, "completion not called after writing pipe\n"); +- todo_wine + ok(completion_errorcode == 0, "completion called with error %x\n", completion_errorcode); + ok(completion_num_bytes == 4, "ReadFileEx returned only %d bytes\n", completion_num_bytes); + ok(completion_lpoverlapped == &overlapped, "completion called with wrong overlapped pointer\n"); +@@ -2513,15 +2512,11 @@ todo_wine + completion_called = 0; + ResetEvent(event); + ret = ReadFileEx(server, read_buf, 4, &overlapped, completion_routine); +- todo_wine + ok(ret == TRUE, "ReadFileEx failed, err=%i\n", GetLastError()); + ok(completion_called == 0, "completion routine called before ReadFileEx returned\n"); + wait = WaitForSingleObjectEx(event, 0, TRUE); +- todo_wine + ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObjectEx returned %x\n", wait); +- todo_wine + ok(completion_called == 1, "completion not called after writing pipe\n"); +- todo_wine + ok(completion_errorcode == 0, "completion called with error %x\n", completion_errorcode); + ok(completion_num_bytes == 4, "ReadFileEx returned only %d bytes\n", completion_num_bytes); + ok(completion_lpoverlapped == &overlapped, "completion called with wrong overlapped pointer\n"); +diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c +index 81f941d..d3f0c0e 100644 +--- a/dlls/ntdll/file.c ++++ b/dlls/ntdll/file.c +@@ -885,8 +885,8 @@ err: + io_status->Information = total; + TRACE("= SUCCESS (%u)\n", total); + if (hEvent) NtSetEvent( hEvent, NULL ); +- if (apc && !status) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc, +- (ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 ); ++ if (apc && status != STATUS_END_OF_FILE) NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)apc, ++ (ULONG_PTR)apc_user, (ULONG_PTR)io_status, 0 ); + } + else + { +-- +2.1.3 + diff --git a/patches/kernel32-Named_Pipe/0013-kernel32-tests-Test-sending-peeking-and-receiving-an.patch b/patches/kernel32-Named_Pipe/0013-kernel32-tests-Test-sending-peeking-and-receiving-an.patch new file mode 100644 index 00000000..8391cbb3 --- /dev/null +++ b/patches/kernel32-Named_Pipe/0013-kernel32-tests-Test-sending-peeking-and-receiving-an.patch @@ -0,0 +1,384 @@ +From 186746674015db7533c9b25c8b633c2e3881334e Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Mon, 11 Aug 2014 00:56:46 +0200 +Subject: kernel32/tests: Test sending, peeking and receiving an empty message. + +Changes in v2: + * As async handling is now working correctly, it breaks some tests :/ + We need a lot of ugly code to prevent the tests from deadlocking... + * Fix issue in broken pipe check, should be moved into an earlier patch. +--- + dlls/kernel32/tests/pipe.c | 336 +++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 336 insertions(+) + +diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c +index 53f8f30..89a13f5 100644 +--- a/dlls/kernel32/tests/pipe.c ++++ b/dlls/kernel32/tests/pipe.c +@@ -337,6 +337,146 @@ static void test_CreateNamedPipe(int pipemode) + ok(readden == sizeof(obuf2) - 8, "read got %d bytes\n", readden); + ok(memcmp(obuf2, ibuf, written) == 0, "content check\n"); + ++ /* Tests for sending empty messages */ ++ memset(ibuf, 0, sizeof(ibuf)); ++ ok(WriteFile(hnp, obuf, 0, &written, NULL), "WriteFile\n"); ++ ok(written == 0, "write file len\n"); ++ if (pipemode != PIPE_TYPE_BYTE) ++ { ++ ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n"); ++ ok(readden == 0, "read got %d bytes\n", readden); ++ } ++ ++ memset(ibuf, 0, sizeof(ibuf)); ++ ok(WriteFile(hFile, obuf, 0, &written, NULL), "WriteFile\n"); ++ ok(written == 0, "write file len\n"); ++ if (pipemode != PIPE_TYPE_BYTE) ++ { ++ ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n"); ++ ok(readden == 0, "read got %d bytes\n", readden); ++ } ++ ++ /* similar to above, but with an additional call to PeekNamedPipe inbetween */ ++ memset(ibuf, 0, sizeof(ibuf)); ++ ok(WriteFile(hnp, obuf, 0, &written, NULL), "WriteFile\n"); ++ ok(written == 0, "write file len\n"); ++ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, NULL), "Peek\n"); ++ ok(readden == 0, "peek got %d bytes\n", readden); ++ if (pipemode != PIPE_TYPE_BYTE) ++ { ++ struct rpcThreadArgs rpcargs; ++ HANDLE thread; ++ DWORD threadId; ++ ++ rpcargs.returnValue = 0; ++ rpcargs.lastError = GetLastError(); ++ rpcargs.op = RPC_READFILE; ++ rpcargs.args[0] = (ULONG_PTR)hFile; ++ rpcargs.args[1] = (ULONG_PTR)ibuf; ++ rpcargs.args[2] = (ULONG_PTR)sizeof(ibuf); ++ rpcargs.args[3] = (ULONG_PTR)&readden; ++ rpcargs.args[4] = (ULONG_PTR)NULL; ++ ++ thread = CreateThread(NULL, 0, rpcThreadMain, (void *)&rpcargs, 0, &threadId); ++ ok(thread != NULL, "CreateThread failed. %d\n", GetLastError()); ++ ret = WaitForSingleObject(thread, 200); ++ todo_wine ++ ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %d instead of %d.\n", ret, WAIT_OBJECT_0); ++ if (ret == WAIT_TIMEOUT) ++ { ++ ok(WriteFile(hnp, obuf, 0, &written, NULL), "WriteFile\n"); ++ ok(written == 0, "write file len\n"); ++ ret = WaitForSingleObject(thread, 200); ++ ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %d instead of %d.\n", ret, WAIT_OBJECT_0); ++ } ++ CloseHandle(thread); ++ ok((BOOL)rpcargs.returnValue, "ReadFile\n"); ++ ok(readden == 0, "read got %d bytes\n", readden); ++ } ++ ++ memset(ibuf, 0, sizeof(ibuf)); ++ ok(WriteFile(hFile, obuf, 0, &written, NULL), "WriteFile\n"); ++ ok(written == 0, "write file len\n"); ++ ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, NULL), "Peek\n"); ++ ok(readden == 0, "peek got %d bytes\n", readden); ++ if (pipemode != PIPE_TYPE_BYTE) ++ { ++ struct rpcThreadArgs rpcargs; ++ HANDLE thread; ++ DWORD threadId; ++ ++ rpcargs.returnValue = 0; ++ rpcargs.lastError = GetLastError(); ++ rpcargs.op = RPC_READFILE; ++ rpcargs.args[0] = (ULONG_PTR)hnp; ++ rpcargs.args[1] = (ULONG_PTR)ibuf; ++ rpcargs.args[2] = (ULONG_PTR)sizeof(ibuf); ++ rpcargs.args[3] = (ULONG_PTR)&readden; ++ rpcargs.args[4] = (ULONG_PTR)NULL; ++ ++ thread = CreateThread(NULL, 0, rpcThreadMain, (void *)&rpcargs, 0, &threadId); ++ ok(thread != NULL, "CreateThread failed. %d\n", GetLastError()); ++ ret = WaitForSingleObject(thread, 200); ++ todo_wine ++ ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %d instead of %d.\n", ret, WAIT_OBJECT_0); ++ if (ret == WAIT_TIMEOUT) ++ { ++ ok(WriteFile(hFile, obuf, 0, &written, NULL), "WriteFile\n"); ++ ok(written == 0, "write file len\n"); ++ ret = WaitForSingleObject(thread, 200); ++ ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %d instead of %d.\n", ret, WAIT_OBJECT_0); ++ } ++ CloseHandle(thread); ++ ok((BOOL)rpcargs.returnValue, "ReadFile\n"); ++ ok(readden == 0, "read got %d bytes\n", readden); ++ } ++ ++ /* similar to above, but now with PeekNamedPipe and multiple messages */ ++ memset(ibuf, 0, sizeof(ibuf)); ++ ok(WriteFile(hnp, obuf, 0, &written, NULL), "WriteFile\n"); ++ ok(written == 0, "write file len\n"); ++ ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile\n"); ++ ok(written == sizeof(obuf), "write file len\n"); ++ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "Peek\n"); ++ ok(readden == sizeof(obuf), "peek got %d bytes\n", readden); ++ ok(leftmsg == 0, "peek got %d bytes left in msg\n", leftmsg); ++ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "Peek\n"); ++ ok(readden == sizeof(obuf), "peek got %d bytes\n", readden); ++ if (pipemode != PIPE_TYPE_BYTE) ++ todo_wine ++ ok(leftmsg == 0, "peek got %d bytes left in msg\n", leftmsg); ++ else ++ ok(leftmsg == 0, "peek got %d bytes left in msg\n", leftmsg); ++ ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n"); ++ ok(readden == sizeof(obuf), "read got %d bytes\n", readden); ++ ok(memcmp(obuf, ibuf, sizeof(obuf)) == 0, "content check\n"); ++ ++ memset(ibuf, 0, sizeof(ibuf)); ++ ok(WriteFile(hFile, obuf2, 0, &written, NULL), "WriteFile\n"); ++ ok(written == 0, "write file len\n"); ++ ok(WriteFile(hFile, obuf2, sizeof(obuf2), &written, NULL), "WriteFile\n"); ++ ok(written == sizeof(obuf2), "write file len\n"); ++ ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "Peek\n"); ++ ok(readden == sizeof(obuf2), "peek got %d bytes\n", readden); ++ ok(leftmsg == 0, "peek got %d bytes left in msg\n", leftmsg); ++ ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "Peek\n"); ++ ok(readden == sizeof(obuf2), "peek got %d bytes\n", readden); ++ if (pipemode != PIPE_TYPE_BYTE) ++ todo_wine ++ ok(leftmsg == 0, "peek got %d bytes left in msg\n", leftmsg); ++ else ++ ok(leftmsg == 0, "peek got %d bytes left in msg\n", leftmsg); ++ ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n"); ++ if (pipemode != PIPE_TYPE_BYTE) ++ { ++ todo_wine ++ ok(readden == 0, "read got %d bytes\n", readden); ++ if (readden == 0) ++ ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n"); ++ } ++ ok(readden == sizeof(obuf2), "read got %d bytes\n", readden); ++ ok(memcmp(obuf2, ibuf, sizeof(obuf2)) == 0, "content check\n"); ++ + /* Test reading of multiple writes */ + memset(ibuf, 0, sizeof(ibuf)); + ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile3a\n"); +@@ -455,6 +595,133 @@ static void test_CreateNamedPipe(int pipemode) + if (readden <= sizeof(obuf)) + ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n"); + ++ /* Tests for sending empty messages */ ++ memset(ibuf, 0, sizeof(ibuf)); ++ ok(WriteFile(hnp, obuf, 0, &written, NULL), "WriteFile\n"); ++ ok(written == 0, "write file len\n"); ++ ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n"); ++ ok(readden == 0, "read got %d bytes\n", readden); ++ ++ memset(ibuf, 0, sizeof(ibuf)); ++ ok(WriteFile(hFile, obuf, 0, &written, NULL), "WriteFile\n"); ++ ok(written == 0, "write file len\n"); ++ ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n"); ++ ok(readden == 0, "read got %d bytes\n", readden); ++ ++ /* similar to above, but with an additional call to PeekNamedPipe inbetween */ ++ memset(ibuf, 0, sizeof(ibuf)); ++ ok(WriteFile(hnp, obuf, 0, &written, NULL), "WriteFile\n"); ++ ok(written == 0, "write file len\n"); ++ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, NULL), "Peek\n"); ++ ok(readden == 0, "peek got %d bytes\n", readden); ++ { ++ struct rpcThreadArgs rpcargs; ++ HANDLE thread; ++ DWORD threadId; ++ ++ rpcargs.returnValue = 0; ++ rpcargs.lastError = GetLastError(); ++ rpcargs.op = RPC_READFILE; ++ rpcargs.args[0] = (ULONG_PTR)hFile; ++ rpcargs.args[1] = (ULONG_PTR)ibuf; ++ rpcargs.args[2] = (ULONG_PTR)sizeof(ibuf); ++ rpcargs.args[3] = (ULONG_PTR)&readden; ++ rpcargs.args[4] = (ULONG_PTR)NULL; ++ ++ thread = CreateThread(NULL, 0, rpcThreadMain, (void *)&rpcargs, 0, &threadId); ++ ok(thread != NULL, "CreateThread failed. %d\n", GetLastError()); ++ ret = WaitForSingleObject(thread, 200); ++ todo_wine ++ ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %d instead of %d.\n", ret, WAIT_OBJECT_0); ++ if (ret == WAIT_TIMEOUT) ++ { ++ ok(WriteFile(hnp, obuf, 0, &written, NULL), "WriteFile\n"); ++ ok(written == 0, "write file len\n"); ++ ret = WaitForSingleObject(thread, 200); ++ ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %d instead of %d.\n", ret, WAIT_OBJECT_0); ++ } ++ CloseHandle(thread); ++ ok((BOOL)rpcargs.returnValue, "ReadFile\n"); ++ ok(readden == 0, "read got %d bytes\n", readden); ++ } ++ ++ memset(ibuf, 0, sizeof(ibuf)); ++ ok(WriteFile(hFile, obuf, 0, &written, NULL), "WriteFile\n"); ++ ok(written == 0, "write file len\n"); ++ ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, NULL), "Peek\n"); ++ ok(readden == 0, "peek got %d bytes\n", readden); ++ { ++ struct rpcThreadArgs rpcargs; ++ HANDLE thread; ++ DWORD threadId; ++ ++ rpcargs.returnValue = 0; ++ rpcargs.lastError = GetLastError(); ++ rpcargs.op = RPC_READFILE; ++ rpcargs.args[0] = (ULONG_PTR)hnp; ++ rpcargs.args[1] = (ULONG_PTR)ibuf; ++ rpcargs.args[2] = (ULONG_PTR)sizeof(ibuf); ++ rpcargs.args[3] = (ULONG_PTR)&readden; ++ rpcargs.args[4] = (ULONG_PTR)NULL; ++ ++ thread = CreateThread(NULL, 0, rpcThreadMain, (void *)&rpcargs, 0, &threadId); ++ ok(thread != NULL, "CreateThread failed. %d\n", GetLastError()); ++ ret = WaitForSingleObject(thread, 200); ++ todo_wine ++ ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %d instead of %d.\n", ret, WAIT_OBJECT_0); ++ if (ret == WAIT_TIMEOUT) ++ { ++ ok(WriteFile(hFile, obuf, 0, &written, NULL), "WriteFile\n"); ++ ok(written == 0, "write file len\n"); ++ ret = WaitForSingleObject(thread, 200); ++ ok(ret == WAIT_OBJECT_0, "WaitForSingleObject returned %d instead of %d.\n", ret, WAIT_OBJECT_0); ++ } ++ CloseHandle(thread); ++ ok((BOOL)rpcargs.returnValue, "ReadFile\n"); ++ ok(readden == 0, "read got %d bytes\n", readden); ++ } ++ ++ /* similar to above, but now with PeekNamedPipe and multiple messages */ ++ memset(ibuf, 0, sizeof(ibuf)); ++ ok(WriteFile(hnp, obuf, 0, &written, NULL), "WriteFile\n"); ++ ok(written == 0, "write file len\n"); ++ ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile\n"); ++ ok(written == sizeof(obuf), "write file len\n"); ++ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "Peek\n"); ++ ok(readden == sizeof(obuf), "peek got %d bytes\n", readden); ++ ok(leftmsg == 0, "peek got %d bytes left in msg\n", leftmsg); ++ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, &leftmsg), "Peek\n"); ++ ok(readden == sizeof(obuf), "peek got %d bytes\n", readden); ++ todo_wine ++ ok(leftmsg == 0, "peek got %d bytes left in msg\n", leftmsg); ++ ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n"); ++ todo_wine ++ ok(readden == 0, "read got %d bytes\n", readden); ++ if (readden == 0) ++ ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n"); ++ ok(readden == sizeof(obuf), "read got %d bytes\n", readden); ++ ok(memcmp(obuf, ibuf, sizeof(obuf)) == 0, "content check\n"); ++ ++ memset(ibuf, 0, sizeof(ibuf)); ++ ok(WriteFile(hFile, obuf2, 0, &written, NULL), "WriteFile\n"); ++ ok(written == 0, "write file len\n"); ++ ok(WriteFile(hFile, obuf2, sizeof(obuf2), &written, NULL), "WriteFile\n"); ++ ok(written == sizeof(obuf2), "write file len\n"); ++ ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "Peek\n"); ++ ok(readden == sizeof(obuf2), "peek got %d bytes\n", readden); ++ ok(leftmsg == 0, "peek got %d bytes left in msg\n", leftmsg); ++ ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, &leftmsg), "Peek\n"); ++ ok(readden == sizeof(obuf2), "peek got %d bytes\n", readden); ++ todo_wine ++ ok(leftmsg == 0, "peek got %d bytes left in msg\n", leftmsg); ++ ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n"); ++ todo_wine ++ ok(readden == 0, "read got %d bytes\n", readden); ++ if (readden == 0) ++ ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile\n"); ++ ok(readden == sizeof(obuf2), "read got %d bytes\n", readden); ++ ok(memcmp(obuf2, ibuf, sizeof(obuf2)) == 0, "content check\n"); ++ + /* Test how ReadFile behaves when the buffer is not big enough for the whole message */ + memset(ibuf, 0, sizeof(ibuf)); + ok(WriteFile(hnp, obuf2, sizeof(obuf2), &written, NULL), "WriteFile 7\n"); +@@ -938,6 +1205,41 @@ static void test_CloseNamedPipe(void) + hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); + ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed (%d)\n", GetLastError()); + ++ /* don't try to do i/o if one side couldn't be opened, as it hangs */ ++ if (hFile != INVALID_HANDLE_VALUE) ++ { ++ ok(WriteFile(hnp, obuf, 0, &written, NULL), "WriteFile\n"); ++ ok(written == 0, "write file len 1\n"); ++ ++ /* close server end without disconnecting */ ++ ok(CloseHandle(hnp), "CloseHandle() failed: %08x\n", GetLastError()); ++ ++ todo_wine ++ ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() failed: %08x\n", GetLastError()); ++ ok(readden == 0, "got %d bytes\n", readden); ++ /* pipe is empty now */ ++ ++ SetLastError(0xdeadbeef); ++ ok(!ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() succeeded\n"); ++ todo_wine ++ ok(GetLastError() == ERROR_BROKEN_PIPE, "GetLastError() returned %08x, expected ERROR_BROKEN_PIPE\n", GetLastError()); ++ SetLastError(0); ++ ++ CloseHandle(hFile); ++ } ++ ++ hnp = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX, ++ PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, ++ /* nMaxInstances */ 1, ++ /* nOutBufSize */ 1024, ++ /* nInBufSize */ 1024, ++ /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT, ++ /* lpSecurityAttrib */ NULL); ++ ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n"); ++ ++ hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); ++ ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed (%d)\n", GetLastError()); ++ + if (hFile != INVALID_HANDLE_VALUE) + { + /* Make sure we can read and write a few bytes in both directions */ +@@ -966,6 +1268,40 @@ static void test_CloseNamedPipe(void) + + CloseHandle(hnp); + } ++ ++ hnp = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX, ++ PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, ++ /* nMaxInstances */ 1, ++ /* nOutBufSize */ 1024, ++ /* nInBufSize */ 1024, ++ /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT, ++ /* lpSecurityAttrib */ NULL); ++ ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n"); ++ ++ hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); ++ ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed (%d)\n", GetLastError()); ++ ++ /* don't try to do i/o if one side couldn't be opened, as it hangs */ ++ if (hFile != INVALID_HANDLE_VALUE) ++ { ++ ok(WriteFile(hFile, obuf, 0, &written, NULL), "WriteFile\n"); ++ ok(written == 0, "write file len 1\n"); ++ ++ /* close server end without disconnecting */ ++ ok(CloseHandle(hFile), "CloseHandle() failed: %08x\n", GetLastError()); ++ ++ todo_wine ++ ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() failed: %08x\n", GetLastError()); ++ ok(readden == 0, "got %d bytes\n", readden); ++ /* pipe is empty now */ ++ ++ SetLastError(0xdeadbeef); ++ ok(!ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() succeeded\n"); ++ ok(GetLastError() == ERROR_BROKEN_PIPE, "GetLastError() returned %08x, expected ERROR_BROKEN_PIPE\n", GetLastError()); ++ SetLastError(0); ++ ++ CloseHandle(hnp); ++ } + } + + /** implementation of alarm() */ +-- +2.1.3 + diff --git a/patches/kernel32-Named_Pipe/0014-ntdll-Add-support-for-nonblocking-pipes.patch b/patches/kernel32-Named_Pipe/0014-ntdll-Add-support-for-nonblocking-pipes.patch new file mode 100644 index 00000000..db472eaf --- /dev/null +++ b/patches/kernel32-Named_Pipe/0014-ntdll-Add-support-for-nonblocking-pipes.patch @@ -0,0 +1,52 @@ +From fb6d82077a362f002300cd171547c292cbb5d0bd Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Sun, 17 Aug 2014 01:29:06 +0200 +Subject: ntdll: Add support for nonblocking pipes. + +--- + dlls/ntdll/file.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c +index d3f0c0e..ba3814e 100644 +--- a/dlls/ntdll/file.c ++++ b/dlls/ntdll/file.c +@@ -472,6 +472,10 @@ static NTSTATUS read_unix_fd(int fd, char *buf, ULONG *total, ULONG length, + { + if (pipe_flags & NAMED_PIPE_MESSAGE_STREAM_WRITE) + { ++ int recvmsg_flags = MSG_PEEK; ++ if (*total || (pipe_flags & NAMED_PIPE_NONBLOCKING_MODE)) ++ recvmsg_flags |= MSG_DONTWAIT; ++ + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; +@@ -483,7 +487,7 @@ static NTSTATUS read_unix_fd(int fd, char *buf, ULONG *total, ULONG length, + iov.iov_base = buf + *total; + iov.iov_len = length - *total; + +- result = recvmsg( fd, &msg, MSG_PEEK | (*total ? MSG_DONTWAIT : 0) ); ++ result = recvmsg( fd, &msg, recvmsg_flags ); + if (result >= 0 && !(msg.msg_flags & MSG_TRUNC)) + { + int ret; +@@ -527,7 +531,14 @@ static NTSTATUS read_unix_fd(int fd, char *buf, ULONG *total, ULONG length, + return STATUS_PENDING; + } + else if (errno == EAGAIN) +- return (avail_mode && *total) ? STATUS_SUCCESS : STATUS_PENDING; ++ { ++ if (avail_mode && *total) ++ return STATUS_SUCCESS; ++ else if (pipe_flags & NAMED_PIPE_NONBLOCKING_MODE) ++ return *total ? STATUS_SUCCESS : STATUS_PIPE_EMPTY; ++ else ++ return STATUS_PENDING; ++ } + else if (errno != EINTR) + return FILE_GetNtStatus(); + } +-- +2.1.3 + diff --git a/patches/kernel32-Named_Pipe/0015-kernel32-tests-Add-tests-for-PIPE_NOWAIT-in-message-.patch b/patches/kernel32-Named_Pipe/0015-kernel32-tests-Add-tests-for-PIPE_NOWAIT-in-message-.patch new file mode 100644 index 00000000..580f3fc1 --- /dev/null +++ b/patches/kernel32-Named_Pipe/0015-kernel32-tests-Add-tests-for-PIPE_NOWAIT-in-message-.patch @@ -0,0 +1,126 @@ +From bd5a5c11c29a52bd7891e8c3da6ff77846085ecd Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Mon, 11 Aug 2014 04:19:49 +0200 +Subject: kernel32/tests: Add tests for PIPE_NOWAIT in message mode. + +--- + dlls/kernel32/tests/pipe.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 96 insertions(+) + +diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c +index 89a13f5..49a1017 100644 +--- a/dlls/kernel32/tests/pipe.c ++++ b/dlls/kernel32/tests/pipe.c +@@ -2527,6 +2527,101 @@ static void test_overlapped(void) + CloseHandle(thread); + } + ++static void test_nowait(void) ++{ ++ HANDLE hnp; ++ HANDLE hFile; ++ static const char obuf[] = "Bit Bucket"; ++ char ibuf[32]; ++ DWORD written; ++ DWORD readden; ++ DWORD lpmode; ++ ++ hnp = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX, ++ PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_NOWAIT, ++ /* nMaxInstances */ 1, ++ /* nOutBufSize */ 1024, ++ /* nInBufSize */ 1024, ++ /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT, ++ /* lpSecurityAttrib */ NULL); ++ ok(hnp != INVALID_HANDLE_VALUE, "CreateNamedPipe failed\n"); ++ ++ hFile = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); ++ ok(hFile != INVALID_HANDLE_VALUE, "CreateFile failed (%d)\n", GetLastError()); ++ ++ /* don't try to do i/o if one side couldn't be opened, as it hangs */ ++ if (hFile != INVALID_HANDLE_VALUE) ++ { ++ /* send message from client to server */ ++ ok(WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile\n"); ++ ok(written == sizeof(obuf), "write file len\n"); ++ ok(PeekNamedPipe(hnp, NULL, 0, NULL, &readden, NULL), "Peek\n"); ++ ok(readden == sizeof(obuf), "got %d bytes\n", readden); ++ ++ memset(ibuf, 0, sizeof(ibuf)); ++ ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() failed: %08x\n", GetLastError()); ++ ok(readden == sizeof(obuf), "got %d bytes\n", readden); ++ ok(memcmp(obuf, ibuf, sizeof(obuf)) == 0, "content check\n"); ++ ++ readden = 0xdeadbeef; ++ SetLastError(0xdeadbeef); ++ ok(!ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() succeeded\n"); ++ ok(readden == 0, "got %d bytes\n", readden); ++ ok(GetLastError() == ERROR_NO_DATA, "GetLastError() returned %08x, expected ERROR_NO_DATA\n", GetLastError()); ++ ++ lpmode = PIPE_READMODE_MESSAGE | PIPE_NOWAIT; ++ ok(SetNamedPipeHandleState(hFile, &lpmode, NULL, NULL), "Change mode\n"); ++ ++ /* send message from server to client */ ++ ok(WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile\n"); ++ ok(written == sizeof(obuf), "write file len\n"); ++ ok(PeekNamedPipe(hFile, NULL, 0, NULL, &readden, NULL), "Peek\n"); ++ ok(readden == sizeof(obuf), "got %d bytes\n", readden); ++ ++ memset(ibuf, 0, sizeof(ibuf)); ++ ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() failed: %08x\n", GetLastError()); ++ ok(readden == sizeof(obuf), "got %d bytes\n", readden); ++ ok(memcmp(obuf, ibuf, sizeof(obuf)) == 0, "content check\n"); ++ ++ readden = 0xdeadbeef; ++ SetLastError(0xdeadbeef); ++ ok(!ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() succeeded\n"); ++ ok(readden == 0, "got %d bytes\n", readden); ++ ok(GetLastError() == ERROR_NO_DATA, "GetLastError() returned %08x, expected ERROR_NO_DATA\n", GetLastError()); ++ ++ /* now again the bad zero byte message test */ ++ ok(WriteFile(hFile, obuf, 0, &written, NULL), "WriteFile\n"); ++ ok(written == 0, "write file len\n"); ++ ++ ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() failed: %08x\n", GetLastError()); ++ ok(readden == 0, "got %d bytes\n", readden); ++ ++ readden = 0xdeadbeef; ++ SetLastError(0xdeadbeef); ++ ok(!ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() succeeded\n"); ++ ok(readden == 0, "got %d bytes\n", readden); ++ ok(GetLastError() == ERROR_NO_DATA, "GetLastError() returned %08x, expected ERROR_NO_DATA\n", GetLastError()); ++ ++ /* and the same for the reverse direction */ ++ ok(WriteFile(hnp, obuf, 0, &written, NULL), "WriteFile\n"); ++ ok(written == 0, "write file len\n"); ++ ++ ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() failed: %08x\n", GetLastError()); ++ ok(readden == 0, "got %d bytes\n", readden); ++ ++ readden = 0xdeadbeef; ++ SetLastError(0xdeadbeef); ++ ok(!ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() succeeded\n"); ++ ok(readden == 0, "got %d bytes\n", readden); ++ ok(GetLastError() == ERROR_NO_DATA, "GetLastError() returned %08x, expected ERROR_NO_DATA\n", GetLastError()); ++ ++ ok(CloseHandle(hFile), "CloseHandle\n"); ++ } ++ ++ ok(CloseHandle(hnp), "CloseHandle\n"); ++ ++} ++ + static void test_NamedPipeHandleState(void) + { + HANDLE server, client; +@@ -2952,6 +3047,7 @@ START_TEST(pipe) + test_CreatePipe(); + test_impersonation(); + test_overlapped(); ++ test_nowait(); + test_NamedPipeHandleState(); + test_readfileex_pending(); + } +-- +2.1.3 + diff --git a/patches/kernel32-Named_Pipe/0016-ntdll-Allow-to-set-PIPE_NOWAIT-on-byte-mode-pipes.patch b/patches/kernel32-Named_Pipe/0016-ntdll-Allow-to-set-PIPE_NOWAIT-on-byte-mode-pipes.patch new file mode 100644 index 00000000..368d8043 --- /dev/null +++ b/patches/kernel32-Named_Pipe/0016-ntdll-Allow-to-set-PIPE_NOWAIT-on-byte-mode-pipes.patch @@ -0,0 +1,112 @@ +From f0904b45622aa329e02dba205bfedd78379cde98 Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Mon, 11 Aug 2014 05:34:19 +0200 +Subject: ntdll: Allow to set PIPE_NOWAIT on byte-mode pipes. + +This patch implements the functionality to set PIPE_NOWAIT on regular bytemode +pipes. This patch also extends the test to show that the implemented behaviour +matches the native implementation. +--- + dlls/kernel32/tests/pipe.c | 37 +++++++++++++++++++++++++++++-------- + dlls/ntdll/file.c | 2 ++ + 2 files changed, 31 insertions(+), 8 deletions(-) + +diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c +index 49a1017..f90401a 100644 +--- a/dlls/kernel32/tests/pipe.c ++++ b/dlls/kernel32/tests/pipe.c +@@ -2527,7 +2527,7 @@ static void test_overlapped(void) + CloseHandle(thread); + } + +-static void test_nowait(void) ++static void test_nowait(int pipemode) + { + HANDLE hnp; + HANDLE hFile; +@@ -2538,7 +2538,7 @@ static void test_nowait(void) + DWORD lpmode; + + hnp = CreateNamedPipeA(PIPENAME, PIPE_ACCESS_DUPLEX, +- PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_NOWAIT, ++ pipemode | PIPE_NOWAIT, + /* nMaxInstances */ 1, + /* nOutBufSize */ 1024, + /* nInBufSize */ 1024, +@@ -2569,7 +2569,7 @@ static void test_nowait(void) + ok(readden == 0, "got %d bytes\n", readden); + ok(GetLastError() == ERROR_NO_DATA, "GetLastError() returned %08x, expected ERROR_NO_DATA\n", GetLastError()); + +- lpmode = PIPE_READMODE_MESSAGE | PIPE_NOWAIT; ++ lpmode = (pipemode & PIPE_READMODE_MESSAGE) | PIPE_NOWAIT; + ok(SetNamedPipeHandleState(hFile, &lpmode, NULL, NULL), "Change mode\n"); + + /* send message from server to client */ +@@ -2593,8 +2593,18 @@ static void test_nowait(void) + ok(WriteFile(hFile, obuf, 0, &written, NULL), "WriteFile\n"); + ok(written == 0, "write file len\n"); + +- ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() failed: %08x\n", GetLastError()); +- ok(readden == 0, "got %d bytes\n", readden); ++ if (pipemode != PIPE_TYPE_BYTE) ++ { ++ ok(ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() failed: %08x\n", GetLastError()); ++ ok(readden == 0, "got %d bytes\n", readden); ++ } ++ else ++ { ++ SetLastError(0xdeadbeef); ++ ok(!ReadFile(hnp, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() succeeded\n"); ++ ok(readden == 0, "got %d bytes\n", readden); ++ ok(GetLastError() == ERROR_NO_DATA, "GetLastError() returned %08x, expected ERROR_NO_DATA\n", GetLastError()); ++ } + + readden = 0xdeadbeef; + SetLastError(0xdeadbeef); +@@ -2606,8 +2616,18 @@ static void test_nowait(void) + ok(WriteFile(hnp, obuf, 0, &written, NULL), "WriteFile\n"); + ok(written == 0, "write file len\n"); + +- ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() failed: %08x\n", GetLastError()); +- ok(readden == 0, "got %d bytes\n", readden); ++ if (pipemode != PIPE_TYPE_BYTE) ++ { ++ ok(ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() failed: %08x\n", GetLastError()); ++ ok(readden == 0, "got %d bytes\n", readden); ++ } ++ else ++ { ++ SetLastError(0xdeadbeef); ++ ok(!ReadFile(hFile, ibuf, sizeof(ibuf), &readden, NULL), "ReadFile() succeeded\n"); ++ ok(readden == 0, "got %d bytes\n", readden); ++ ok(GetLastError() == ERROR_NO_DATA, "GetLastError() returned %08x, expected ERROR_NO_DATA\n", GetLastError()); ++ } + + readden = 0xdeadbeef; + SetLastError(0xdeadbeef); +@@ -3047,7 +3067,8 @@ START_TEST(pipe) + test_CreatePipe(); + test_impersonation(); + test_overlapped(); +- test_nowait(); ++ test_nowait(PIPE_TYPE_BYTE); ++ test_nowait(PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE); + test_NamedPipeHandleState(); + test_readfileex_pending(); + } +diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c +index ba3814e..e564bdd 100644 +--- a/dlls/ntdll/file.c ++++ b/dlls/ntdll/file.c +@@ -495,6 +495,8 @@ static NTSTATUS read_unix_fd(int fd, char *buf, ULONG *total, ULONG length, + if (ret < 0) ERR("dequeue message failed reason: %s\n", strerror(errno)); + } + } ++ else if (pipe_flags & NAMED_PIPE_NONBLOCKING_MODE) ++ result = recv( fd, buf + *total, length - *total, MSG_DONTWAIT ); + else + result = read( fd, buf + *total, length - *total ); + +-- +2.1.3 + diff --git a/patches/kernel32-Named_Pipe/0017-kernel32-tests-Add-additional-tests-for-PIPE_NOWAIT-.patch b/patches/kernel32-Named_Pipe/0017-kernel32-tests-Add-additional-tests-for-PIPE_NOWAIT-.patch new file mode 100644 index 00000000..cd85634e --- /dev/null +++ b/patches/kernel32-Named_Pipe/0017-kernel32-tests-Add-additional-tests-for-PIPE_NOWAIT-.patch @@ -0,0 +1,333 @@ +From c0f999092e3f10053fb710d7f2ab134f9fdea592 Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Sun, 17 Aug 2014 02:56:57 +0200 +Subject: kernel32/tests: Add additional tests for PIPE_NOWAIT in overlapped + mode. + +--- + dlls/kernel32/tests/pipe.c | 295 ++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 294 insertions(+), 1 deletion(-) + +diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c +index f90401a..2107294 100644 +--- a/dlls/kernel32/tests/pipe.c ++++ b/dlls/kernel32/tests/pipe.c +@@ -2747,7 +2747,7 @@ static void test_readfileex_pending(void) + { + HANDLE server, client, event; + BOOL ret; +- DWORD err, wait, num_bytes; ++ DWORD err, wait, num_bytes, lpmode; + OVERLAPPED overlapped; + char read_buf[1024]; + char write_buf[1024]; +@@ -2905,6 +2905,160 @@ todo_wine + CloseHandle(client); + CloseHandle(server); + ++ /* On Windows versions > 2000 it is not possible to add PIPE_NOWAIT to a byte-mode ++ * PIPE after creating. Create a new pipe for the following tests. */ ++ server = CreateNamedPipeA(PIPENAME, FILE_FLAG_OVERLAPPED | PIPE_ACCESS_DUPLEX, ++ /* dwOpenMode */ PIPE_TYPE_BYTE | PIPE_NOWAIT, ++ /* nMaxInstances */ 1, ++ /* nOutBufSize */ 1024, ++ /* nInBufSize */ 1024, ++ /* nDefaultWait */ NMPWAIT_USE_DEFAULT_WAIT, ++ /* lpSecurityAttrib */ NULL); ++ ok(server != INVALID_HANDLE_VALUE, "cf failed\n"); ++ ++ client = CreateFileA(PIPENAME, GENERIC_READ|GENERIC_WRITE, 0, NULL, ++ OPEN_EXISTING, 0, NULL); ++ ok(client != INVALID_HANDLE_VALUE, "cf failed\n"); ++ ++ memset(&overlapped, 0, sizeof(overlapped)); ++ overlapped.hEvent = event; ++ ++ /* Initial check with empty pipe */ ++ memset(read_buf, 0, sizeof(read_buf)); ++ completion_called = 0; ++ ResetEvent(event); ++ ret = ReadFileEx(server, read_buf, 4, &overlapped, completion_routine); ++ ok(ret == FALSE, "ReadFileEx succeded\n"); ++ ok(completion_called == 0, "completion routine called before ReadFileEx returned\n"); ++ ok(GetLastError() == ERROR_NO_DATA, "expected ERROR_NO_DATA, got %d\n", GetLastError()); ++ wait = WaitForSingleObjectEx(event, 0, TRUE); ++ todo_wine ++ ok(wait == WAIT_TIMEOUT, "WaitForSingleObjectEx returned %x\n", wait); ++ ok(completion_called == 0, "completion routine called before writing to file\n"); ++ ++ /* Call ReadFileEx after writing content to the pipe */ ++ num_bytes = 0xdeadbeef; ++ ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL); ++ ok(ret, "WriteFile failed, err=%i\n", GetLastError()); ++ ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes); ++ ++ memset(read_buf, 0, sizeof(read_buf)); ++ completion_called = 0; ++ ResetEvent(event); ++ ret = ReadFileEx(server, read_buf, 4, &overlapped, completion_routine); ++ ok(ret == TRUE, "ReadFileEx failed, err=%i\n", GetLastError()); ++ ok(completion_called == 0, "completion routine called before ReadFileEx returned\n"); ++ wait = WaitForSingleObjectEx(event, 0, TRUE); ++ ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObjectEx returned %x\n", wait); ++ ok(completion_called == 1, "completion not called after writing pipe\n"); ++ ok(completion_errorcode == 0, "completion called with error %x\n", completion_errorcode); ++ ok(completion_num_bytes == 4, "ReadFileEx returned only %d bytes\n", completion_num_bytes); ++ ok(completion_lpoverlapped == &overlapped, "completion called with wrong overlapped pointer\n"); ++ ++ ret = ReadFile(server, read_buf + 4, sizeof(read_buf) - 4, &num_bytes, NULL); ++ ok(ret == TRUE, "ReadFile succeeded\n"); ++ ok(num_bytes == strlen(long_test_string)-4, "ReadFile returned only %d bytes\n", num_bytes); ++ ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n"); ++ ++ /* Same again, but read as a single part */ ++ num_bytes = 0xdeadbeef; ++ ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL); ++ ok(ret, "WriteFile failed, err=%i\n", GetLastError()); ++ ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes); ++ ++ memset(read_buf, 0, sizeof(read_buf)); ++ completion_called = 0; ++ ResetEvent(event); ++ ret = ReadFileEx(server, read_buf, sizeof(read_buf), &overlapped, completion_routine); ++ ok(ret == TRUE, "ReadFileEx failed, err=%i\n", GetLastError()); ++ ok(completion_called == 0, "completion routine called before ReadFileEx returned\n"); ++ wait = WaitForSingleObjectEx(event, 0, TRUE); ++ ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObjectEx returned %x\n", wait); ++ ok(completion_called == 1, "completion not called after writing pipe\n"); ++ ok(completion_errorcode == 0, "completion called with error %x\n", completion_errorcode); ++ ok(completion_num_bytes == strlen(long_test_string), "ReadFileEx returned only %d bytes\n", completion_num_bytes); ++ ok(completion_lpoverlapped == &overlapped, "completion called with wrong overlapped pointer\n"); ++ ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n"); ++ ++ /* Check content of overlapped structure */ ++ memset(read_buf, 0, sizeof(read_buf)); ++ S(U(overlapped)).Offset = 0; ++ S(U(overlapped)).OffsetHigh = 0; ++ overlapped.Internal = -1; ++ overlapped.InternalHigh = -1; ++ overlapped.hEvent = event; ++ num_bytes = 0xdeadbeef; ++ SetLastError(0xdeadbeef); ++ ret = ReadFile(server, read_buf, 4, &num_bytes, &overlapped); ++ ok(ret == FALSE, "ReadFile succeeded\n"); ++ ok(GetLastError() == ERROR_NO_DATA, "expected ERROR_NO_DATA, got %d\n", GetLastError()); ++ ok(num_bytes == 0, "bytes %u\n", num_bytes); ++ ok((NTSTATUS)overlapped.Internal == STATUS_PENDING, "expected STATUS_PENDING, got %#lx\n", overlapped.Internal); ++ todo_wine ++ ok(overlapped.InternalHigh == -1, "expected -1, got %lu\n", overlapped.InternalHigh); ++ wait = WaitForSingleObject(event, 100); ++ ok(wait == WAIT_TIMEOUT, "WaitForSingleObjectEx returned %x\n", wait); ++ ok((NTSTATUS)overlapped.Internal == STATUS_PENDING, "expected STATUS_PENDING, got %#lx\n", overlapped.Internal); ++ todo_wine ++ ok(overlapped.InternalHigh == -1, "expected -1, got %lu\n", overlapped.InternalHigh); ++ ++ /* Call ReadFile after writing to the pipe */ ++ num_bytes = 0xdeadbeef; ++ ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL); ++ ok(ret, "WriteFile failed, err=%i\n", GetLastError()); ++ ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes); ++ ++ memset(read_buf, 0, sizeof(read_buf)); ++ S(U(overlapped)).Offset = 0; ++ S(U(overlapped)).OffsetHigh = 0; ++ overlapped.Internal = -1; ++ overlapped.InternalHigh = -1; ++ overlapped.hEvent = event; ++ num_bytes = 0xdeadbeef; ++ SetLastError(0xdeadbeef); ++ ret = ReadFile(server, read_buf, 4, &num_bytes, &overlapped); ++ ok(ret == TRUE, "ReadFile failed, err=%i\n", GetLastError()); ++ ok(num_bytes == 4, "bytes %u\n", num_bytes); ++ ok((NTSTATUS)overlapped.Internal == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#lx\n", overlapped.Internal); ++ ok(overlapped.InternalHigh == 4, "expected 4, got %lu\n", overlapped.InternalHigh); ++ wait = WaitForSingleObject(event, 100); ++ ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", wait); ++ ok((NTSTATUS)overlapped.Internal == STATUS_SUCCESS, "expected STATUS_SUCCESS, got %#lx\n", overlapped.Internal); ++ ok(overlapped.InternalHigh == 4, "expected 4, got %lu\n", overlapped.InternalHigh); ++ ++ ret = ReadFile(server, read_buf + 4, sizeof(read_buf) - 4, &num_bytes, NULL); ++ ok(ret == TRUE, "ReadFile failed\n"); ++ ok(num_bytes == strlen(long_test_string)-4, "ReadFile returned only %d bytes\n", num_bytes); ++ ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n"); ++ ++ /* Same again, but read as a single part */ ++ num_bytes = 0xdeadbeef; ++ ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL); ++ ok(ret, "WriteFile failed, err=%i\n", GetLastError()); ++ ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes); ++ ++ memset(read_buf, 0, sizeof(read_buf)); ++ S(U(overlapped)).Offset = 0; ++ S(U(overlapped)).OffsetHigh = 0; ++ overlapped.Internal = -1; ++ overlapped.InternalHigh = -1; ++ overlapped.hEvent = event; ++ num_bytes = 0xdeadbeef; ++ SetLastError(0xdeadbeef); ++ ret = ReadFile(server, read_buf, sizeof(read_buf), &num_bytes, &overlapped); ++ ok(ret == TRUE, "ReadFile failed, err=%i\n", GetLastError()); ++ ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes); ++ ok((NTSTATUS)overlapped.Internal == 0, "expected 0, got %#lx\n", overlapped.Internal); ++ ok(overlapped.InternalHigh == strlen(long_test_string), "expected %d, got %lu\n", strlen(long_test_string), overlapped.InternalHigh); ++ wait = WaitForSingleObject(event, 100); ++ ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", wait); ++ ok((NTSTATUS)overlapped.Internal == 0, "expected 0, got %#lx\n", overlapped.Internal); ++ ok(overlapped.InternalHigh == strlen(long_test_string), "expected %d, got %lu\n", strlen(long_test_string), overlapped.InternalHigh); ++ ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n"); ++ ++ CloseHandle(client); ++ CloseHandle(server); ++ + server = CreateNamedPipeA(PIPENAME, FILE_FLAG_OVERLAPPED | PIPE_ACCESS_DUPLEX, + /* dwOpenMode */ PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, + /* nMaxInstances */ 1, +@@ -3043,6 +3197,145 @@ todo_wine + ok(num_bytes == strlen(long_test_string)-4, "ReadFile returned only %d bytes\n", num_bytes); + ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n"); + ++ /* Tests for PIPE_NOWAIT in message mode */ ++ lpmode = PIPE_READMODE_MESSAGE | PIPE_NOWAIT; ++ ok(SetNamedPipeHandleState(server, &lpmode, NULL, NULL), "Change mode\n"); ++ ++ /* Initial check with empty pipe */ ++ memset(read_buf, 0, sizeof(read_buf)); ++ completion_called = 0; ++ ResetEvent(event); ++ ret = ReadFileEx(server, read_buf, 4, &overlapped, completion_routine); ++ ok(ret == FALSE, "ReadFileEx succeded\n"); ++ ok(completion_called == 0, "completion routine called before ReadFileEx returned\n"); ++ ok(GetLastError() == ERROR_NO_DATA, "expected ERROR_NO_DATA, got %d\n", GetLastError()); ++ wait = WaitForSingleObjectEx(event, 0, TRUE); ++ todo_wine ++ ok(wait == WAIT_TIMEOUT, "WaitForSingleObjectEx returned %x\n", wait); ++ ok(completion_called == 0, "completion routine called before writing to file\n"); ++ ++ /* Call ReadFileEx after writing content to the pipe */ ++ num_bytes = 0xdeadbeef; ++ ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL); ++ ok(ret, "WriteFile failed, err=%i\n", GetLastError()); ++ ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes); ++ ++ memset(read_buf, 0, sizeof(read_buf)); ++ completion_called = 0; ++ ResetEvent(event); ++ ret = ReadFileEx(server, read_buf, 4, &overlapped, completion_routine); ++ ok(ret == TRUE, "ReadFileEx failed, err=%i\n", GetLastError()); ++ ok(completion_called == 0, "completion routine called before ReadFileEx returned\n"); ++ wait = WaitForSingleObjectEx(event, 0, TRUE); ++ ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObjectEx returned %x\n", wait); ++ ok(completion_called == 1, "completion not called after writing pipe\n"); ++ ok(completion_errorcode == 0, "completion called with error %x\n", completion_errorcode); ++ ok(completion_num_bytes == 4, "ReadFileEx returned only %d bytes\n", completion_num_bytes); ++ ok(completion_lpoverlapped == &overlapped, "completion called with wrong overlapped pointer\n"); ++ ++ ret = ReadFile(server, read_buf + 4, sizeof(read_buf) - 4, &num_bytes, NULL); ++ ok(ret == TRUE, "ReadFile succeeded\n"); ++ ok(num_bytes == strlen(long_test_string)-4, "ReadFile returned only %d bytes\n", num_bytes); ++ ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n"); ++ ++ /* Same again, but read as a single part */ ++ num_bytes = 0xdeadbeef; ++ ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL); ++ ok(ret, "WriteFile failed, err=%i\n", GetLastError()); ++ ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes); ++ ++ memset(read_buf, 0, sizeof(read_buf)); ++ completion_called = 0; ++ ResetEvent(event); ++ ret = ReadFileEx(server, read_buf, sizeof(read_buf), &overlapped, completion_routine); ++ ok(ret == TRUE, "ReadFileEx failed, err=%i\n", GetLastError()); ++ ok(completion_called == 0, "completion routine called before ReadFileEx returned\n"); ++ wait = WaitForSingleObjectEx(event, 0, TRUE); ++ ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObjectEx returned %x\n", wait); ++ ok(completion_called == 1, "completion not called after writing pipe\n"); ++ ok(completion_errorcode == 0, "completion called with error %x\n", completion_errorcode); ++ ok(completion_num_bytes == strlen(long_test_string), "ReadFileEx returned only %d bytes\n", completion_num_bytes); ++ ok(completion_lpoverlapped == &overlapped, "completion called with wrong overlapped pointer\n"); ++ ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n"); ++ ++ /* Check content of overlapped structure */ ++ memset(read_buf, 0, sizeof(read_buf)); ++ S(U(overlapped)).Offset = 0; ++ S(U(overlapped)).OffsetHigh = 0; ++ overlapped.Internal = -1; ++ overlapped.InternalHigh = -1; ++ overlapped.hEvent = event; ++ num_bytes = 0xdeadbeef; ++ SetLastError(0xdeadbeef); ++ ret = ReadFile(server, read_buf, 4, &num_bytes, &overlapped); ++ ok(ret == FALSE, "ReadFile succeeded\n"); ++ ok(GetLastError() == ERROR_NO_DATA, "expected ERROR_NO_DATA, got %d\n", GetLastError()); ++ ok(num_bytes == 0, "bytes %u\n", num_bytes); ++ ok((NTSTATUS)overlapped.Internal == STATUS_PENDING, "expected STATUS_PENDING, got %#lx\n", overlapped.Internal); ++ todo_wine ++ ok(overlapped.InternalHigh == -1, "expected -1, got %lu\n", overlapped.InternalHigh); ++ wait = WaitForSingleObject(event, 100); ++ ok(wait == WAIT_TIMEOUT, "WaitForSingleObjectEx returned %x\n", wait); ++ ok((NTSTATUS)overlapped.Internal == STATUS_PENDING, "expected STATUS_PENDING, got %#lx\n", overlapped.Internal); ++ todo_wine ++ ok(overlapped.InternalHigh == -1, "expected -1, got %lu\n", overlapped.InternalHigh); ++ ++ /* Call ReadFile after writing to the pipe */ ++ num_bytes = 0xdeadbeef; ++ ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL); ++ ok(ret, "WriteFile failed, err=%i\n", GetLastError()); ++ ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes); ++ ++ memset(read_buf, 0, sizeof(read_buf)); ++ S(U(overlapped)).Offset = 0; ++ S(U(overlapped)).OffsetHigh = 0; ++ overlapped.Internal = -1; ++ overlapped.InternalHigh = -1; ++ overlapped.hEvent = event; ++ num_bytes = 0xdeadbeef; ++ SetLastError(0xdeadbeef); ++ ret = ReadFile(server, read_buf, 4, &num_bytes, &overlapped); ++ ok(ret == FALSE, "ReadFile succeeded\n"); ++ ok(GetLastError() == ERROR_MORE_DATA, "expected ERROR_MORE_DATA, got %d\n", GetLastError()); ++ todo_wine ++ ok(num_bytes == 0, "bytes %u\n", num_bytes); ++ ok((NTSTATUS)overlapped.Internal == STATUS_BUFFER_OVERFLOW, "expected STATUS_BUFFER_OVERFLOW, got %#lx\n", overlapped.Internal); ++ ok(overlapped.InternalHigh == 4, "expected 4, got %lu\n", overlapped.InternalHigh); ++ wait = WaitForSingleObject(event, 100); ++ ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", wait); ++ ok((NTSTATUS)overlapped.Internal == STATUS_BUFFER_OVERFLOW, "expected STATUS_BUFFER_OVERFLOW, got %#lx\n", overlapped.Internal); ++ ok(overlapped.InternalHigh == 4, "expected 4, got %lu\n", overlapped.InternalHigh); ++ ++ ret = ReadFile(server, read_buf + 4, sizeof(read_buf) - 4, &num_bytes, NULL); ++ ok(ret == TRUE, "ReadFile failed\n"); ++ ok(num_bytes == strlen(long_test_string)-4, "ReadFile returned only %d bytes\n", num_bytes); ++ ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n"); ++ ++ /* Same again, but read as a single part */ ++ num_bytes = 0xdeadbeef; ++ ret = WriteFile(client, long_test_string, strlen(long_test_string), &num_bytes, NULL); ++ ok(ret, "WriteFile failed, err=%i\n", GetLastError()); ++ ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes); ++ ++ memset(read_buf, 0, sizeof(read_buf)); ++ S(U(overlapped)).Offset = 0; ++ S(U(overlapped)).OffsetHigh = 0; ++ overlapped.Internal = -1; ++ overlapped.InternalHigh = -1; ++ overlapped.hEvent = event; ++ num_bytes = 0xdeadbeef; ++ SetLastError(0xdeadbeef); ++ ret = ReadFile(server, read_buf, sizeof(read_buf), &num_bytes, &overlapped); ++ ok(ret == TRUE, "ReadFile failed, err=%i\n", GetLastError()); ++ ok(num_bytes == strlen(long_test_string), "bytes %u\n", num_bytes); ++ ok((NTSTATUS)overlapped.Internal == 0, "expected 0, got %#lx\n", overlapped.Internal); ++ ok(overlapped.InternalHigh == strlen(long_test_string), "expected %d, got %lu\n", strlen(long_test_string), overlapped.InternalHigh); ++ wait = WaitForSingleObject(event, 100); ++ ok(wait == WAIT_IO_COMPLETION || wait == WAIT_OBJECT_0, "WaitForSingleObject returned %x\n", wait); ++ ok((NTSTATUS)overlapped.Internal == 0, "expected 0, got %#lx\n", overlapped.Internal); ++ ok(overlapped.InternalHigh == strlen(long_test_string), "expected %d, got %lu\n", strlen(long_test_string), overlapped.InternalHigh); ++ ok(!memcmp(long_test_string, read_buf, strlen(long_test_string)), "ReadFile read wrong bytes\n"); ++ + CloseHandle(client); + CloseHandle(server); + CloseHandle(event); +-- +2.1.3 + diff --git a/patches/kernel32-Named_Pipe/definition b/patches/kernel32-Named_Pipe/definition index e2806127..c5a3bf24 100644 --- a/patches/kernel32-Named_Pipe/definition +++ b/patches/kernel32-Named_Pipe/definition @@ -1 +1,2 @@ Fixes: [16550] Fix for ConnectNamedPort return value in overlapped mode +Fixes: [17195] Support for named pipe message mode diff --git a/patches/ws2_32-TransmitFile/0005-ws2_32-Add-support-for-TF_DISCONNECT-and-TF_REUSE_SO.patch b/patches/ws2_32-TransmitFile/0005-ws2_32-Add-support-for-TF_DISCONNECT-and-TF_REUSE_SO.patch index fc1eb5d9..e36ccfd7 100644 --- a/patches/ws2_32-TransmitFile/0005-ws2_32-Add-support-for-TF_DISCONNECT-and-TF_REUSE_SO.patch +++ b/patches/ws2_32-TransmitFile/0005-ws2_32-Add-support-for-TF_DISCONNECT-and-TF_REUSE_SO.patch @@ -1,22 +1,22 @@ -From 8acfd293ecd49b7cad340dc90e6ea6b0ed07289a Mon Sep 17 00:00:00 2001 +From 9986fca2fe9cc57f9c7a01f08fc6a826a398de47 Mon Sep 17 00:00:00 2001 From: "Erich E. Hoover" Date: Thu, 16 Jan 2014 19:08:30 -0700 Subject: ws2_32: Add support for TF_DISCONNECT and TF_REUSE_SOCKET to TransmitFile. --- - dlls/ws2_32/socket.c | 17 ++++++++++-- - dlls/ws2_32/tests/sock.c | 11 +++++++- - include/winsock.h | 1 + - server/protocol.def | 6 +++++ - server/sock.c | 66 +++++++++++++++++++++++++++++++++++++++------- - 5 files changed, 89 insertions(+), 12 deletions(-) + dlls/ws2_32/socket.c | 17 +++++++++++-- + dlls/ws2_32/tests/sock.c | 11 +++++++- + include/winsock.h | 1 + + server/protocol.def | 6 +++++ + server/sock.c | 65 +++++++++++++++++++++++++++++++++++++++++------- + 5 files changed, 88 insertions(+), 12 deletions(-) diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c -index 42c7832..ddb50a5 100644 +index dbcadb3..e74aa7c 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c -@@ -2558,6 +2558,18 @@ static BOOL WS2_transmitfile_base( SOCKET s, HANDLE h, DWORD total_bytes, DWORD +@@ -2560,6 +2560,18 @@ static BOOL WS2_transmitfile_base( SOCKET s, HANDLE h, DWORD total_bytes, DWORD if (buffers && WS_send( s, buffers->Tail, buffers->TailLength, 0 ) == SOCKET_ERROR) goto cleanup; @@ -35,7 +35,7 @@ index 42c7832..ddb50a5 100644 ret = TRUE; cleanup: -@@ -2599,6 +2611,7 @@ static BOOL WINAPI WS2_TransmitFile( SOCKET s, HANDLE h, DWORD total_bytes, DWOR +@@ -2601,6 +2613,7 @@ static BOOL WINAPI WS2_TransmitFile( SOCKET s, HANDLE h, DWORD total_bytes, DWOR { union generic_unix_sockaddr uaddr; unsigned int uaddrlen = sizeof(uaddr); @@ -43,7 +43,7 @@ index 42c7832..ddb50a5 100644 IO_STATUS_BLOCK *iosb = (IO_STATUS_BLOCK *)overlapped; struct ws2_transmitfile_async *wsa; int status, fd; -@@ -2619,8 +2632,8 @@ static BOOL WINAPI WS2_TransmitFile( SOCKET s, HANDLE h, DWORD total_bytes, DWOR +@@ -2621,8 +2634,8 @@ static BOOL WINAPI WS2_TransmitFile( SOCKET s, HANDLE h, DWORD total_bytes, DWOR return FALSE; } release_sock_fd( s, fd ); @@ -55,10 +55,10 @@ index 42c7832..ddb50a5 100644 if (!overlapped) return WS2_transmitfile_base( s, h, total_bytes, bytes_per_send, overlapped, buffers, flags ); diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c -index dbb762a..5bf23a0 100644 +index 9708cf1..cf9ba23 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c -@@ -6684,8 +6684,17 @@ static void test_TransmitFile(void) +@@ -7008,8 +7008,17 @@ static void test_TransmitFile(void) ok(iret == WAIT_OBJECT_0, "Overlapped TransmitFile failed.\n"); compare_file(file, dest, 10); @@ -78,10 +78,10 @@ index dbb762a..5bf23a0 100644 bret = pTransmitFile(client, NULL, 0, 0, NULL, NULL, 0); err = WSAGetLastError(); diff --git a/include/winsock.h b/include/winsock.h -index 06e6309..4426557 100644 +index 50237e8..e53aa1e 100644 --- a/include/winsock.h +++ b/include/winsock.h -@@ -810,6 +810,7 @@ typedef struct WS(WSAData) +@@ -814,6 +814,7 @@ typedef struct WS(WSAData) /* internal per-socket flags */ #ifdef __WINESRC__ @@ -90,7 +90,7 @@ index 06e6309..4426557 100644 #define FD_WINE_NONBLOCKING 0x20000000 #define FD_WINE_CONNECTED 0x40000000 diff --git a/server/protocol.def b/server/protocol.def -index c9270ea..328f8a8 100644 +index fc6bec5..64e3f18 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1208,6 +1208,12 @@ enum server_fd_type @@ -107,7 +107,7 @@ index c9270ea..328f8a8 100644 @REQ(set_socket_event) obj_handle_t handle; /* handle to the socket */ diff --git a/server/sock.c b/server/sock.c -index 4adad0f..15afe81 100644 +index 7c0212e..4d51950 100644 --- a/server/sock.c +++ b/server/sock.c @@ -80,6 +80,7 @@ @@ -118,16 +118,15 @@ index 4adad0f..15afe81 100644 #define FD_WINE_LISTENING 0x10000000 #define FD_WINE_NONBLOCKING 0x20000000 #define FD_WINE_CONNECTED 0x40000000 -@@ -124,6 +125,8 @@ static void sock_queue_async( struct fd *fd, const async_data_t *data, int type, +@@ -124,6 +125,7 @@ static enum server_fd_type sock_get_fd_type( struct fd *fd ); + static void sock_queue_async( struct fd *fd, const async_data_t *data, int type, int count ); static void sock_reselect_async( struct fd *fd, struct async_queue *queue ); static void sock_cancel_async( struct fd *fd, struct process *process, struct thread *thread, client_ptr_t iosb ); - +static int sock_close_handle( struct object *obj, struct process *process, obj_handle_t handle ); -+ + static int sock_get_ntstatus( int err ); static int sock_get_error( int err ); - static void sock_set_error(void); -@@ -144,7 +147,7 @@ static const struct object_ops sock_ops = +@@ -145,7 +147,7 @@ static const struct object_ops sock_ops = default_set_sd, /* set_sd */ no_lookup_name, /* lookup_name */ no_open_file, /* open_file */ @@ -136,7 +135,7 @@ index 4adad0f..15afe81 100644 sock_destroy /* destroy */ }; -@@ -583,6 +586,47 @@ static struct fd *sock_get_fd( struct object *obj ) +@@ -585,6 +587,47 @@ static struct fd *sock_get_fd( struct object *obj ) return (struct fd *)grab_object( sock->fd ); } @@ -184,7 +183,7 @@ index 4adad0f..15afe81 100644 static void sock_destroy( struct object *obj ) { struct sock *sock = (struct sock *)obj; -@@ -630,15 +674,8 @@ static struct object *create_socket( int family, int type, int protocol, unsigne +@@ -633,15 +676,8 @@ static struct object *create_socket( int family, int type, int protocol, unsigne struct sock *sock; int sockfd; @@ -201,7 +200,7 @@ index 4adad0f..15afe81 100644 if (!(sock = alloc_object( &sock_ops ))) { close( sockfd ); -@@ -963,6 +1000,17 @@ DECL_HANDLER(accept_into_socket) +@@ -969,6 +1005,17 @@ DECL_HANDLER(accept_into_socket) release_object( sock ); } @@ -220,5 +219,5 @@ index 4adad0f..15afe81 100644 DECL_HANDLER(set_socket_event) { -- -1.7.9.5 +2.1.3