dd: fix handling of short result of full_write(), closes 11711

$ 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>
This commit is contained in:
Denys Vlasenko 2019-05-14 17:46:18 +02:00
parent 8c317f03f6
commit 875ce094cf
2 changed files with 15 additions and 14 deletions

View File

@ -192,23 +192,15 @@ static void dd_output_status(int UNUSED_PARAM cur_signal)
#endif #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, static bool write_and_stats(const void *buf, size_t len, size_t obs,
const char *filename) const char *filename)
{ {
ssize_t n = full_write_or_warn(buf, len, filename); ssize_t n;
if (n < 0)
return 1; n = full_write(ofd, buf, len);
#if ENABLE_FEATURE_DD_THIRD_STATUS_LINE #if ENABLE_FEATURE_DD_THIRD_STATUS_LINE
G.total_bytes += n; if (n > 0)
G.total_bytes += n;
#endif #endif
if ((size_t)n == obs) { if ((size_t)n == obs) {
G.out_full++; G.out_full++;
@ -218,6 +210,14 @@ static bool write_and_stats(const void *buf, size_t len, size_t obs,
G.out_part++; G.out_part++;
return 0; 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; return 1;
} }

View File

@ -11,7 +11,8 @@
/* /*
* Write all of the supplied buffer out to a file. * Write all of the supplied buffer out to a file.
* This does multiple writes as necessary. * 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) ssize_t FAST_FUNC full_write(int fd, const void *buf, size_t len)
{ {