[PATCH] libbb: Converted safe_read to safe_write format

Martin Lewis martin.lewis.x84 at gmail.com
Sun Sep 15 16:38:34 UTC 2019


Changed safe_read to be symmetrical to safe_write, it shall
never return EINTR because it calls read multiple times,
the error is considered transient.

Also, as seen in gnu coreutils, handle an edge case where count is bigger
than INT_MAX by truncating it in order to avoid bugs on various linux platforms.

Signed-off-by: Martin Lewis <martin.lewis.x84 at gmail.com>
---
 include/libbb.h    | 14 ++++++++++++++
 libbb/read.c       | 15 +++++++++++++--
 libbb/safe_write.c |  3 +++
 3 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/include/libbb.h b/include/libbb.h
index 111d1b7..07b1d05 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -911,26 +911,40 @@ unsigned bb_clk_tck(void) FAST_FUNC;
 /* Autodetects gzip/bzip2 formats. fd may be in the middle of the file! */
 int setup_unzip_on_fd(int fd, int fail_if_not_compressed) FAST_FUNC;
 /* Autodetects .gz etc */
 extern int open_zipped(const char *fname, int fail_if_not_compressed) FAST_FUNC;
 extern void *xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC;
 #else
 # define setup_unzip_on_fd(...) (0)
 # define open_zipped(fname, fail_if_not_compressed)  open((fname), O_RDONLY);
 # define xmalloc_open_zipped_read_close(fname, maxsz_p) xmalloc_open_read_close((fname), (maxsz_p))
 #endif
 /* lzma has no signature, need a little helper. NB: exist only for ENABLE_FEATURE_SEAMLESS_LZMA=y */
 void setup_lzma_on_fd(int fd) FAST_FUNC;
 
+/*
+ * Code exported from gnu coreutils:
+ * Maximum number of bytes to read or write in a single system call.
+ * This can be useful for system calls like sendfile on GNU/Linux,
+ * which do not handle more than MAX_RW_COUNT bytes correctly.
+ * The Linux kernel MAX_RW_COUNT is at least ((INT_MAX >> 20) << 20),
+ * where the 20 comes from the Hexagon port with 1 MiB pages; use that
+ * as an approximation, as the exact value may not be available to us.
+ *
+ * Using this also works around a serious Linux bug before 2.6.16; see
+ * <https://bugzilla.redhat.com/show_bug.cgi?id=612839>.
+ */
+enum { SYS_BUFSIZE_MAX = ((INT_MAX >> 20) << 20)};
+
 extern ssize_t safe_write(int fd, const void *buf, size_t count) FAST_FUNC;
 // NB: will return short write on error, not -1,
 // if some data was written before error occurred
 extern ssize_t full_write(int fd, const void *buf, size_t count) FAST_FUNC;
 extern void xwrite(int fd, const void *buf, size_t count) FAST_FUNC;
 extern void xwrite_str(int fd, const char *str) FAST_FUNC;
 extern ssize_t full_write1_str(const char *str) FAST_FUNC;
 extern ssize_t full_write2_str(const char *str) FAST_FUNC;
 extern void xopen_xwrite_close(const char* file, const char *str) FAST_FUNC;
 
 /* Close fd, but check for failures (some types of write errors) */
 extern void xclose(int fd) FAST_FUNC;
 
diff --git a/libbb/read.c b/libbb/read.c
index 5906bc2..65ef18f 100644
--- a/libbb/read.c
+++ b/libbb/read.c
@@ -2,29 +2,40 @@
 /*
  * Utility routines.
  *
  * Copyright (C) 1999-2004 by Erik Andersen <andersen at codepoet.org>
  *
  * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  */
 #include "libbb.h"
 
 ssize_t FAST_FUNC safe_read(int fd, void *buf, size_t count)
 {
 	ssize_t n;
 
-	do {
+	if (count > SYS_BUFSIZE_MAX)
+		count = SYS_BUFSIZE_MAX;
+
+	for (;;) {
 		n = read(fd, buf, count);
-	} while (n < 0 && errno == EINTR);
+		if (n >= 0 || errno != EINTR)
+			break;
+		/* Some callers set errno=0, are upset when they see EINTR.
+		 * Returning EINTR is wrong since we retry read(),
+		 * the "error" was transient.
+		 */
+		errno = 0;
+		/* repeat the read() */
+	}
 
 	return n;
 }
 
 /*
  * Read all of the supplied buffer from a file.
  * This does multiple reads as necessary.
  * Returns the amount read, or -1 on an error.
  * A short read is returned on an end of file.
  */
 ssize_t FAST_FUNC full_read(int fd, void *buf, size_t len)
 {
 	ssize_t cc;
diff --git a/libbb/safe_write.c b/libbb/safe_write.c
index 12bb438..bfffe5b 100644
--- a/libbb/safe_write.c
+++ b/libbb/safe_write.c
@@ -2,26 +2,29 @@
 /*
  * Utility routines.
  *
  * Copyright (C) 1999-2004 by Erik Andersen <andersen at codepoet.org>
  *
  * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  */
 #include "libbb.h"
 
 ssize_t FAST_FUNC safe_write(int fd, const void *buf, size_t count)
 {
 	ssize_t n;
 
+	if (count > SYS_BUFSIZE_MAX)
+		count = SYS_BUFSIZE_MAX;
+
 	for (;;) {
 		n = write(fd, buf, count);
 		if (n >= 0 || errno != EINTR)
 			break;
 		/* Some callers set errno=0, are upset when they see EINTR.
 		 * Returning EINTR is wrong since we retry write(),
 		 * the "error" was transient.
 		 */
 		errno = 0;
 		/* repeat the write() */
 	}
 
 	return n;
-- 
1.9.1



More information about the busybox mailing list