Dan Kegel : msvcrt: Fix EOF behavior on read from pipe or console.

Alexandre Julliard julliard at winehq.org
Tue Feb 12 16:46:10 CST 2008


Module: wine
Branch: master
Commit: 316869b273ce8bbed968d6380c1b89f07187090a
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=316869b273ce8bbed968d6380c1b89f07187090a

Author: Dan Kegel <dank at kegel.com>
Date:   Sat Feb  9 08:27:35 2008 -0800

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 b4ccdc0..e8189a1 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 e0f1b99..d406ae5 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<N_TEST_MESSAGES; i++) {
+       nwritten=write(fd, pipe_string, strlen(pipe_string));
+       ok(nwritten == strlen(pipe_string), "i %d, expected to write %d bytes, wrote %d\n", i, strlen(pipe_string), nwritten);
+       /* let other process wake up so they can show off their "keep reading until EOF" behavior */
+       if (i < N_TEST_MESSAGES-1)
+           Sleep(100);
+    }
+
     ok(close(fd) == 0, "unable to close %d: %d\n", fd, errno);
 }
 
@@ -943,7 +956,9 @@ static void test_pipes(const char* selfname)
     FILE* file;
     const char* arg_v[6];
     char buf[4096];
+    char expected[4096];
     int r;
+    int i;
 
     /* Test reading from a pipe with read() */
     if (_pipe(pipes, 1024, O_BINARY) < 0)
@@ -961,11 +976,14 @@ static void test_pipes(const char* selfname)
     proc_handles[0] = (HANDLE)_spawnvp(_P_NOWAIT, selfname, arg_v);
     ok(close(pipes[1]) == 0, "unable to close %d: %d\n", pipes[1], errno);
 
-    r=read(pipes[0], buf, sizeof(buf)-1);
-    ok(r == strlen(pipe_string), "expected to read %d bytes, got %d\n", strlen(pipe_string)+1, r);
-    if (r > 0)
-        buf[r]='\0';
-    ok(strcmp(buf, pipe_string) == 0, "expected to read '%s', got '%s'\n", pipe_string, buf);
+    for (i=0; i<N_TEST_MESSAGES; i++) {
+       r=read(pipes[0], buf, sizeof(buf)-1);
+       ok(r == strlen(pipe_string), "i %d, expected to read %d bytes, got %d\n", i, strlen(pipe_string)+1, r);
+       if (r > 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<N_TEST_MESSAGES; i++)
+       strcat(expected, pipe_string);
     r=fread(buf, 1, sizeof(buf)-1, file);
-    ok(r == strlen(pipe_string), "fread() returned %d instead of %d: ferror=%d\n", r, strlen(pipe_string), ferror(file));
+    ok(r == strlen(expected), "fread() returned %d instead of %d: ferror=%d\n", r, strlen(expected), ferror(file));
     if (r > 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));




More information about the wine-cvs mailing list