This is follow-up of my investigation and proposed
fix at
http://old.nabble.com/named-pipe-is-borken-and-proposed-fix-td31753483.html#a31753483

The testing programs worked well with glibc, but failed in uClibc-0.9.32.

As Laurent pointed out, this is undefined in standard. For the sake of
application developers who want to port apps from glibc to uClibc without
worrying about the subtle difference, it is nice to help them out with
following patch.

The problem is that FIFO is a special file type, and the conventional EOF
is useless, and should not be set.

The fix is to avoid setting __FLAG_EOF for stream associated with FIFO file
after all senders were closed.

Signed-off-by: Jian Peng <jipeng2...@gmail.com>
---
 libc/stdio/_READ.c                            |   29 ++++++++++++++++++++++++-
 libc/sysdeps/linux/common/bits/uClibc_stdio.h |    1 +
 2 files changed, 29 insertions(+), 1 deletions(-)

diff --git a/libc/stdio/_READ.c b/libc/stdio/_READ.c
index 02601c0..2ecc920 100644
--- a/libc/stdio/_READ.c
+++ b/libc/stdio/_READ.c
@@ -6,7 +6,25 @@
  */
 
 #include "_stdio.h"
+#include <sys/syscall.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include "xstatconv.h"
 
+#define __NR___syscall_fstat __NR_fstat
+static __inline__ _syscall2(int, __syscall_fstat, int, fd, struct kernel_stat 
*, buf)
+
+int _my_fstat(int fd, struct stat *buf)
+{
+       int result;
+       struct kernel_stat kbuf;
+
+       result = __syscall_fstat(fd, &kbuf);
+       if (result == 0) {
+               __xstat_conv(&kbuf, buf);
+       }
+       return result;
+}
 
 /* Given a reading stream without its end-of-file indicator set and
  * with no buffered input or ungots, read at most 'bufsize' bytes
@@ -44,7 +62,16 @@ size_t attribute_hidden __stdio_READ(register FILE *stream,
 /*     RETRY: */
                if ((rv = __READ(stream, (char *) buf, bufsize)) <= 0) {
                        if (rv == 0) {
-                               __STDIO_STREAM_SET_EOF(stream);
+                               struct stat stat;
+
+                               if( (stream->__modeflags & __FLAG_FIFOFILE) ||
+                                       _my_fstat(stream->__filedes, &stat) >= 
0) {
+                                       if(S_ISFIFO(stat.st_mode))
+                                               stream->__modeflags |= 
__FLAG_FIFOFILE;
+                               }
+
+                               if(!(stream->__modeflags & __FLAG_FIFOFILE))
+                                       __STDIO_STREAM_SET_EOF(stream);
                        } else {
 /*                             if (errno == EINTR) goto RETRY; */
                                __STDIO_STREAM_SET_ERROR(stream);
diff --git a/libc/sysdeps/linux/common/bits/uClibc_stdio.h 
b/libc/sysdeps/linux/common/bits/uClibc_stdio.h
index a8cf4eb..1d2cc11 100644
--- a/libc/sysdeps/linux/common/bits/uClibc_stdio.h
+++ b/libc/sysdeps/linux/common/bits/uClibc_stdio.h
@@ -331,6 +331,7 @@ struct __STDIO_FILE_STRUCT {
 #define __FLAG_FREEBUF         0x4000U
 #define __FLAG_LARGEFILE       0x8000U /* fixed! == 0_LARGEFILE for linux */
 #define __FLAG_FAILED_FREOPEN  __FLAG_LARGEFILE
+#define __FLAG_FIFOFILE                0x1000U /* handle FIFO differently */
 
 /* Note: In no-buffer mode, it would be possible to pack the necessary
  * flags into one byte.  Since we wouldn't be buffering and there would
-- 
1.7.4.1


_______________________________________________
uClibc mailing list
uClibc@uclibc.org
http://lists.busybox.net/mailman/listinfo/uclibc

Reply via email to