Added patches to fix error code for ReadFile/WriteFile on closed pipe (fixes Wine Staging Bug #348).

This commit is contained in:
Sebastian Lackner 2015-06-06 01:56:11 +02:00
parent a110e490b8
commit 9149fde0ff
6 changed files with 296 additions and 0 deletions

2
debian/changelog vendored
View File

@ -26,6 +26,8 @@ wine-staging (1.7.45) UNRELEASED; urgency=low
Smudde).
* Added patch to support AT_ROUND_TO_PAGE flag in NtMapViewOfSection (fixes
Wine Staging Bug 347).
* Added patches to fix error code for ReadFile/WriteFile on closed pipe (fixes
Wine Staging Bug #348).
* Removed patch to handle '\r' as whitespace in wbemprox queries (accepted
upstream).
* Removed patch to make sure OpenClipboard with current owner doesn't fail

View File

@ -0,0 +1,68 @@
From 7939dafa125d74e832436adf2443a19f2689425e Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Fri, 5 Jun 2015 23:06:29 +0200
Subject: kernel32/tests: Add tests for behaviour of WriteFile on closed pipe.
---
dlls/kernel32/tests/pipe.c | 24 ++++++++++++++++++++----
1 file changed, 20 insertions(+), 4 deletions(-)
diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c
index 654d508..0fca432 100644
--- a/dlls/kernel32/tests/pipe.c
+++ b/dlls/kernel32/tests/pipe.c
@@ -1189,7 +1189,11 @@ static void test_CloseNamedPipe(void)
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);
+
+ SetLastError(0xdeadbeef);
+ ok(!WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile() succeeded\n");
+ todo_wine
+ ok(GetLastError() == ERROR_NO_DATA, "GetLastError() returned %08x, expected ERROR_NO_DATA\n", GetLastError());
CloseHandle(hFile);
}
@@ -1224,7 +1228,11 @@ static void test_CloseNamedPipe(void)
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);
+
+ SetLastError(0xdeadbeef);
+ ok(!WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile() succeeded\n");
+ todo_wine
+ ok(GetLastError() == ERROR_NO_DATA, "GetLastError() returned %08x, expected ERROR_NO_DATA\n", GetLastError());
CloseHandle(hFile);
}
@@ -1265,7 +1273,11 @@ static void test_CloseNamedPipe(void)
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);
+
+ SetLastError(0xdeadbeef);
+ ok(!WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile() succeeded\n");
+ todo_wine
+ ok(GetLastError() == ERROR_NO_DATA, "GetLastError() returned %08x, expected ERROR_NO_DATA\n", GetLastError());
CloseHandle(hnp);
}
@@ -1299,7 +1311,11 @@ static void test_CloseNamedPipe(void)
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);
+
+ SetLastError(0xdeadbeef);
+ ok(!WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile() succeeded\n");
+ todo_wine
+ ok(GetLastError() == ERROR_NO_DATA, "GetLastError() returned %08x, expected ERROR_NO_DATA\n", GetLastError());
CloseHandle(hnp);
}
--
2.4.2

View File

@ -0,0 +1,166 @@
From 4b593f0dd46be8b51cb4e1d31efc5e16bc61cdc9 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Sat, 6 Jun 2015 01:21:05 +0200
Subject: server: Return correct error codes for NtWriteFile when pipes are
closed without disconnecting.
---
dlls/kernel32/tests/pipe.c | 3 ---
dlls/ntdll/file.c | 3 +++
server/named_pipe.c | 43 +++++++++++++++++++++++++++++++++++++++++--
server/protocol.def | 1 +
4 files changed, 45 insertions(+), 5 deletions(-)
diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c
index 0fca432..4590d3c 100644
--- a/dlls/kernel32/tests/pipe.c
+++ b/dlls/kernel32/tests/pipe.c
@@ -1192,7 +1192,6 @@ static void test_CloseNamedPipe(void)
SetLastError(0xdeadbeef);
ok(!WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile() succeeded\n");
- todo_wine
ok(GetLastError() == ERROR_NO_DATA, "GetLastError() returned %08x, expected ERROR_NO_DATA\n", GetLastError());
CloseHandle(hFile);
@@ -1276,7 +1275,6 @@ static void test_CloseNamedPipe(void)
SetLastError(0xdeadbeef);
ok(!WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile() succeeded\n");
- todo_wine
ok(GetLastError() == ERROR_NO_DATA, "GetLastError() returned %08x, expected ERROR_NO_DATA\n", GetLastError());
CloseHandle(hnp);
@@ -1314,7 +1312,6 @@ static void test_CloseNamedPipe(void)
SetLastError(0xdeadbeef);
ok(!WriteFile(hnp, obuf, sizeof(obuf), &written, NULL), "WriteFile() succeeded\n");
- todo_wine
ok(GetLastError() == ERROR_NO_DATA, "GetLastError() returned %08x, expected ERROR_NO_DATA\n", GetLastError());
CloseHandle(hnp);
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index f0d816f..26707e2 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -1198,6 +1198,9 @@ static NTSTATUS write_unix_fd(int fd, const char *buf, ULONG *total, ULONG lengt
return STATUS_SUCCESS;
else if (errno == EFAULT)
return STATUS_INVALID_USER_BUFFER;
+ else if (type == FD_TYPE_PIPE && (errno == EPIPE || errno == ECONNRESET))
+ return (get_pipe_flags( fd ) & NAMED_PIPE_CLOSED_HANDLE) ?
+ STATUS_PIPE_EMPTY : STATUS_PIPE_DISCONNECTED;
return FILE_GetNtStatus();
}
}
diff --git a/server/named_pipe.c b/server/named_pipe.c
index cd647c4..4718d1b 100644
--- a/server/named_pipe.c
+++ b/server/named_pipe.c
@@ -144,6 +144,7 @@ static const struct object_ops named_pipe_ops =
/* server end functions */
static void pipe_server_dump( struct object *obj, int verbose );
static struct fd *pipe_server_get_fd( struct object *obj );
+static int pipe_server_close_handle( struct object *obj, struct process *process, obj_handle_t handle );
static void pipe_server_destroy( struct object *obj);
static obj_handle_t pipe_server_flush( struct fd *fd, const async_data_t *async, int blocking );
static enum server_fd_type pipe_server_get_fd_type( struct fd *fd );
@@ -166,7 +167,7 @@ static const struct object_ops pipe_server_ops =
default_set_sd, /* set_sd */
no_lookup_name, /* lookup_name */
no_open_file, /* open_file */
- fd_close_handle, /* close_handle */
+ pipe_server_close_handle, /* close_handle */
pipe_server_destroy /* destroy */
};
@@ -188,6 +189,7 @@ static const struct fd_ops pipe_server_fd_ops =
static void pipe_client_dump( struct object *obj, int verbose );
static int pipe_client_signaled( struct object *obj, struct wait_queue_entry *entry );
static struct fd *pipe_client_get_fd( struct object *obj );
+static int pipe_client_close_handle( struct object *obj, struct process *process, obj_handle_t handle );
static void pipe_client_destroy( struct object *obj );
static obj_handle_t pipe_client_flush( struct fd *fd, const async_data_t *async, int blocking );
static enum server_fd_type pipe_client_get_fd_type( struct fd *fd );
@@ -208,7 +210,7 @@ static const struct object_ops pipe_client_ops =
default_set_sd, /* set_sd */
no_lookup_name, /* lookup_name */
no_open_file, /* open_file */
- fd_close_handle, /* close_handle */
+ pipe_client_close_handle, /* close_handle */
pipe_client_destroy /* destroy */
};
@@ -272,6 +274,8 @@ static const struct fd_ops named_pipe_device_fd_ops =
default_fd_cancel_async /* cancel_async */
};
+static inline int messagemode_flags( int flags );
+
static void named_pipe_dump( struct object *obj, int verbose )
{
struct named_pipe *pipe = (struct named_pipe *) obj;
@@ -386,6 +390,23 @@ static void do_disconnect( struct pipe_server *server )
server->fd = NULL;
}
+static int pipe_server_close_handle( struct object *obj, struct process *process, obj_handle_t handle )
+{
+#ifdef __linux__
+ struct pipe_server *server = (struct pipe_server *)obj;
+ struct pipe_client *client = server->client;
+ int unix_fd;
+
+ assert( obj->ops == &pipe_server_ops );
+ if (obj->handle_count == 1 && client && client->fd && (unix_fd = get_unix_fd( client->fd )) != -1)
+ {
+ /* set the NAMED_PIPE_CLOSED_HANDLE flag, to distinguish disconnect / closing pipe */
+ fcntl( unix_fd, F_SETSIG, messagemode_flags( client->pipe_flags ) | NAMED_PIPE_CLOSED_HANDLE );
+ }
+#endif
+ return 1;
+}
+
static void pipe_server_destroy( struct object *obj)
{
struct pipe_server *server = (struct pipe_server *)obj;
@@ -412,6 +433,24 @@ static void pipe_server_destroy( struct object *obj)
release_object( server->pipe );
}
+static int pipe_client_close_handle( struct object *obj, struct process *process, obj_handle_t handle )
+{
+#ifdef __linux__
+ struct pipe_client *client = (struct pipe_client *)obj;
+ struct pipe_server *server = client->server;
+ int unix_fd;
+
+ assert( obj->ops == &pipe_client_ops );
+ if (obj->handle_count == 1 && server && server->fd && server->state != ps_disconnected_server &&
+ server->state != ps_wait_connect && (unix_fd = get_unix_fd( server->fd )) != -1)
+ {
+ /* set the NAMED_PIPE_CLOSED_HANDLE flag, to distinguish disconnect / closing pipe */
+ fcntl( unix_fd, F_SETSIG, messagemode_flags( server->pipe_flags ) | NAMED_PIPE_CLOSED_HANDLE );
+ }
+#endif
+ return 1;
+}
+
static void pipe_client_destroy( struct object *obj)
{
struct pipe_client *client = (struct pipe_client *)obj;
diff --git a/server/protocol.def b/server/protocol.def
index 428f2e0..4efda91 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -2351,6 +2351,7 @@ enum message_type
#define NAMED_PIPE_MESSAGE_STREAM_WRITE 0x0001
#define NAMED_PIPE_MESSAGE_STREAM_READ 0x0002
#define NAMED_PIPE_NONBLOCKING_MODE 0x0004
+#define NAMED_PIPE_CLOSED_HANDLE 0x0008
#define NAMED_PIPE_SERVER_END 0x8000
/* Get named pipe information by handle */
--
2.4.2

View File

@ -0,0 +1,53 @@
From 2fc1f5ba4668fb0a33ee55118da34a43668fe169 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Sat, 6 Jun 2015 01:44:20 +0200
Subject: ntdll: Pre-cache file descriptors after opening a file.
---
dlls/kernel32/tests/pipe.c | 2 --
dlls/ntdll/file.c | 12 +++++++++++-
2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c
index 146b7f7..ddad351 100644
--- a/dlls/kernel32/tests/pipe.c
+++ b/dlls/kernel32/tests/pipe.c
@@ -1235,12 +1235,10 @@ static void test_CloseNamedPipe(void)
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(0xdeadbeef);
ok(!WriteFile(hFile, obuf, sizeof(obuf), &written, NULL), "WriteFile() succeeded\n");
- todo_wine
ok(GetLastError() == ERROR_NO_DATA, "GetLastError() returned %08x, expected ERROR_NO_DATA\n", GetLastError());
CloseHandle(hFile);
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index ff0d306..25e9826 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -274,7 +274,17 @@ static NTSTATUS FILE_CreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATT
*handle = wine_server_ptr_handle( reply->handle );
}
SERVER_END_REQ;
- if (io->u.Status == STATUS_SUCCESS) io->Information = FILE_OPENED;
+ if (io->u.Status == STATUS_SUCCESS)
+ {
+ /* pre-cache the file descriptor. this is necessary because the fd cannot be
+ * acquired anymore after one end of the pipe has been closed - see kernel32/pipe
+ * tests. */
+ int unix_fd, needs_close;
+ int ret = server_get_unix_fd( *handle, 0, &unix_fd, &needs_close, NULL, NULL );
+ if (!ret && needs_close) close( unix_fd );
+ io->Information = FILE_OPENED;
+ }
+
return io->u.Status;
}
--
2.4.2

View File

@ -0,0 +1 @@
Fixes: Support for AT_ROUND_TO_PAGE flag in NtMapViewOfSection

View File

@ -3178,6 +3178,9 @@ if test "$enable_kernel32_Named_Pipe" -eq 1; then
patch_apply kernel32-Named_Pipe/0017-kernel32-tests-Add-additional-tests-for-PIPE_NOWAIT-.patch
patch_apply kernel32-Named_Pipe/0018-ntdll-Improve-ReadDataAvailable-handling-in-FilePipe.patch
patch_apply kernel32-Named_Pipe/0019-ntdll-Set-NamedPipeState-to-FILE_PIPE_CLOSING_STATE-.patch
patch_apply kernel32-Named_Pipe/0020-kernel32-tests-Add-tests-for-behaviour-of-WriteFile-.patch
patch_apply kernel32-Named_Pipe/0021-server-Return-correct-error-codes-for-NtWriteFile-wh.patch
patch_apply kernel32-Named_Pipe/0022-ntdll-Pre-cache-file-descriptors-after-opening-a-fil.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 },';
@ -3198,6 +3201,9 @@ if test "$enable_kernel32_Named_Pipe" -eq 1; then
echo '+ { "Sebastian Lackner", "kernel32/tests: Add additional tests for PIPE_NOWAIT in overlapped mode.", 1 },';
echo '+ { "Qian Hong", "ntdll: Improve ReadDataAvailable handling in FilePipeLocalInformation class support.", 1 },';
echo '+ { "Sebastian Lackner", "ntdll: Set NamedPipeState to FILE_PIPE_CLOSING_STATE on broken pipe in NtQueryInformationFile.", 1 },';
echo '+ { "Sebastian Lackner", "kernel32/tests: Add tests for behaviour of WriteFile on closed pipe.", 1 },';
echo '+ { "Sebastian Lackner", "server: Return correct error codes for NtWriteFile when pipes are closed without disconnecting.", 1 },';
echo '+ { "Sebastian Lackner", "ntdll: Pre-cache file descriptors after opening a file.", 1 },';
) >> "$patchlist"
fi