dd: fix handling of short result of full_write(), closes 11711
authorDenys Vlasenko <vda.linux@googlemail.com>
Tue, 14 May 2019 15:46:18 +0000 (17:46 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Tue, 14 May 2019 15:49:14 +0000 (17:49 +0200)
$ dd bs=1G <sda1 of=/dev/sda1
dd: error writing '/dev/sda1': No space left on device
1+0 records in
0+0 records out
999292928 bytes (953.0MB) copied, 0.784617 seconds, 1.2GB/s

function                                             old     new   delta
write_and_stats                                       99     102      +3

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
coreutils/dd.c
libbb/full_write.c

index 2fb9da77c13ae4d4aeeec49dc0a3f16b66643fde..b5f3cbec5d4aa4297a97f18d9dc5fd99dabf073c 100644 (file)
@@ -192,23 +192,15 @@ static void dd_output_status(int UNUSED_PARAM cur_signal)
 #endif
 }
 
-static ssize_t full_write_or_warn(const void *buf, size_t len,
-       const char *const filename)
-{
-       ssize_t n = full_write(ofd, buf, len);
-       if (n < 0)
-               bb_perror_msg("writing '%s'", filename);
-       return n;
-}
-
 static bool write_and_stats(const void *buf, size_t len, size_t obs,
        const char *filename)
 {
-       ssize_t n = full_write_or_warn(buf, len, filename);
-       if (n < 0)
-               return 1;
+       ssize_t n;
+
+       n = full_write(ofd, buf, len);
 #if ENABLE_FEATURE_DD_THIRD_STATUS_LINE
-       G.total_bytes += n;
+       if (n > 0)
+               G.total_bytes += n;
 #endif
        if ((size_t)n == obs) {
                G.out_full++;
@@ -218,6 +210,14 @@ static bool write_and_stats(const void *buf, size_t len, size_t obs,
                G.out_part++;
                return 0;
        }
+       /* n is < len (and possibly is -1).
+        * Even if n >= 0, errno is usually set correctly.
+        * For example, if writing to block device and getting ENOSPC,
+        * full_write() first sees a short write, then tries to write
+        * the remainder and gets errno set to ENOSPC.
+        * It returns n > 0 (the amount which it did write).
+        */
+       bb_perror_msg("error writing '%s'", filename);
        return 1;
 }
 
index 2b7983f4c1e3da76de0beeba807eb50b1fbaaa18..15766fc6cf2fee4aef1c7b73a7b687b45b9c2d36 100644 (file)
@@ -11,7 +11,8 @@
 /*
  * Write all of the supplied buffer out to a file.
  * This does multiple writes as necessary.
- * Returns the amount written, or -1 on an error.
+ * Returns the amount written, or -1 if error was seen
+ * on the very first write.
  */
 ssize_t FAST_FUNC full_write(int fd, const void *buf, size_t len)
 {