[ As said requested in the original message, please keep me in Cc ]

On 05/08/2020, Paul Eggert wrote:
> On 8/5/20 11:47 AM, Nikos Tsipinakis wrote:
> > Can you elaborate? I can't find a code path that loses the errno.
> 
> full_read reads a partial block and then tries to read again. The second
> read fails with errno == EIO. full_read then returns the number of bytes
> successfully read, and the caller ignores errno.

Apologies for the delay, but now I have the time and energy to get this through
the finish line. The easiest way to do fix this is probably to make
`blocking_read` check errno and return an error if bytes < count (see attached
patch)
>From 8dbbf9cc23e769faf580f53d6ee0fff5f3c68356 Mon Sep 17 00:00:00 2001
From: Nikos Tsipinakis <ni...@tsipinakis.com>
Date: Sat, 26 Sep 2020 16:41:54 +0300
Subject: [PATCH] Use full_read to avoid errors due to short reads

In networked filesystems such as 9p, read() can return short reads even
for regular files.
---
 gnulib.modules | 1 +
 src/common.h   | 1 +
 src/misc.c     | 8 ++++++--
 3 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/gnulib.modules b/gnulib.modules
index 82f5e1c..9ded7da 100644
--- a/gnulib.modules
+++ b/gnulib.modules
@@ -44,6 +44,7 @@ fprintftime
 fseeko
 fstatat
 full-write
+full-read
 futimens
 getline
 getopt-gnu
diff --git a/src/common.h b/src/common.h
index a451999..7f696c5 100644
--- a/src/common.h
+++ b/src/common.h
@@ -57,6 +57,7 @@
 #include "arith.h"
 #include <backupfile.h>
 #include <exclude.h>
+#include <full-read.h>
 #include <full-write.h>
 #include <modechange.h>
 #include <quote.h>
diff --git a/src/misc.c b/src/misc.c
index d833b8d..f39707d 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -804,7 +804,7 @@ deref_stat (char const *name, struct stat *buf)
 size_t
 blocking_read (int fd, void *buf, size_t count)
 {
-  size_t bytes = safe_read (fd, buf, count);
+  size_t bytes = full_read (fd, buf, count);
 
 #if defined F_SETFL && O_NONBLOCK
   if (bytes == SAFE_READ_ERROR && errno == EAGAIN)
@@ -812,10 +812,14 @@ blocking_read (int fd, void *buf, size_t count)
       int flags = fcntl (fd, F_GETFL);
       if (0 <= flags && flags & O_NONBLOCK
 	  && fcntl (fd, F_SETFL, flags & ~O_NONBLOCK) != -1)
-	bytes = safe_read (fd, buf, count);
+	bytes = full_read (fd, buf, count);
     }
 #endif
 
+  if (bytes < count && errno != 0) {
+        return SAFE_READ_ERROR;
+  }
+
   return bytes;
 }
 
-- 
2.28.0

Reply via email to