From 316869b273ce8bbed968d6380c1b89f07187090a Mon Sep 17 00:00:00 2001 From: Dan Kegel Date: Sat, 9 Feb 2008 08:27:35 -0800 Subject: [PATCH] msvcrt: Fix EOF behavior on read from pipe or console. The canonical way to detect EOF on read is when you request more than zero bytes, but zero bytes come back. Switching to this method seems to handle a few problem cases better. Also handle ERROR_BROKEN_PIPE properly just in case. --- dlls/msvcrt/file.c | 5 ++++- dlls/msvcrt/tests/file.c | 45 ++++++++++++++++++++++++++++++++-------- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/dlls/msvcrt/file.c b/dlls/msvcrt/file.c index b4ccdc0de8a..e8189a1f1a6 100644 --- a/dlls/msvcrt/file.c +++ b/dlls/msvcrt/file.c @@ -1692,11 +1692,13 @@ static int read_i(int fd, void *buf, unsigned int count) if (bufstart[i] == 0x1a) { num_read = i; + MSVCRT_fdesc[fd].wxflag |= (WX_ATEOF|WX_READEOF); + TRACE(":^Z EOF %s\n",debugstr_an(buf,num_read)); break; } } } - if (num_read != count) + if (count != 0 && num_read == 0) { MSVCRT_fdesc[fd].wxflag |= (WX_ATEOF|WX_READEOF); TRACE(":EOF %s\n",debugstr_an(buf,num_read)); @@ -1707,6 +1709,7 @@ static int read_i(int fd, void *buf, unsigned int count) if (GetLastError() == ERROR_BROKEN_PIPE) { TRACE(":end-of-pipe\n"); + MSVCRT_fdesc[fd].wxflag |= (WX_ATEOF|WX_READEOF); return 0; } else diff --git a/dlls/msvcrt/tests/file.c b/dlls/msvcrt/tests/file.c index e0f1b997e1f..d406ae500cc 100644 --- a/dlls/msvcrt/tests/file.c +++ b/dlls/msvcrt/tests/file.c @@ -918,9 +918,14 @@ static void test_stat(void) static const char* pipe_string="Hello world"; +/* How many messages to transfer over the pipe */ +#define N_TEST_MESSAGES 3 + static void test_pipes_child(int argc, char** args) { int fd; + int nwritten; + int i; if (argc < 5) { @@ -932,7 +937,15 @@ static void test_pipes_child(int argc, char** args) ok(close(fd) == 0, "unable to close %d: %d\n", fd, errno); fd=atoi(args[4]); - write(fd, pipe_string, strlen(pipe_string)); + + for (i=0; i 0) - buf[r]='\0'; - ok(strcmp(buf, pipe_string) == 0, "expected to read '%s', got '%s'\n", pipe_string, buf); + for (i=0; i 0) + buf[r]='\0'; + ok(strcmp(buf, pipe_string) == 0, "expected to read '%s', got '%s'\n", pipe_string, buf); + } + r=read(pipes[0], buf, sizeof(buf)-1); ok(r == 0, "expected to read 0 bytes, got %d\n", r); ok(close(pipes[0]) == 0, "unable to close %d: %d\n", pipes[0], errno); @@ -987,12 +1005,21 @@ static void test_pipes(const char* selfname) ok(close(pipes[1]) == 0, "unable to close %d: %d\n", pipes[1], errno); file=fdopen(pipes[0], "r"); + /* In blocking mode, fread will keep calling read() until it gets + * enough bytes, or EOF, even on Unix. (If this were a Unix terminal + * in cooked mode instead of a pipe, it would also stop on EOL.) + */ + expected[0] = 0; + for (i=0; i 0) - buf[r]='\0'; - ok(strcmp(buf, pipe_string) == 0, "got '%s' expected '%s'\n", buf, pipe_string); + buf[r]='\0'; + ok(strcmp(buf, expected) == 0, "got '%s' expected '%s'\n", buf, expected); + /* Let child close the file before we read, so we can sense EOF reliably */ + Sleep(100); r=fread(buf, 1, sizeof(buf)-1, file); ok(r == 0, "fread() returned %d instead of 0\n", r); ok(ferror(file) == 0, "got ferror() = %d\n", ferror(file));