From 5f02cddc184a55b47d2b27c50c25d093d35ce13a Mon Sep 17 00:00:00 2001 From: =?utf8?q?P=C3=A1draig=20Brady?=
Date: Sun, 15 Oct 2017 23:54:29 -0700 Subject: [PATCH] dd: support iflag=direct with arbitrary sized files * src/dd.c (iread): Handle read error with a non-aligned file offset in the O_DIRECT case. This is not an issue on XFS at least, but on EXT4 the final read will return EINVAL rather than the expected 0 to indicate EOF. * tests/dd/direct.sh: Test the iflag=direct case also. * NEWS: Mention the improvement. --- NEWS | 2 ++ src/dd.c | 15 +++++++++++---- tests/dd/direct.sh | 4 ++-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/NEWS b/NEWS index 4c697b591e..d5060d1c8e 100644 --- a/NEWS +++ b/NEWS @@ -37,6 +37,8 @@ GNU coreutils NEWS -*- outline -*- ** Improvements + dd now supports iflag=direct with arbitrary sized files on all file systems. + tail --bytes=NUM will efficiently seek to the end of block devices, rather than reading from the start. diff --git a/src/dd.c b/src/dd.c index b6ceb4fd7c..0ff618c963 100644 --- a/src/dd.c +++ b/src/dd.c @@ -1108,11 +1108,21 @@ static ssize_t iread (int fd, char *buf, size_t size) { ssize_t nread; + static ssize_t prev_nread; do { process_signals (); nread = read (fd, buf, size); + /* Ignore final read error with iflag=direct as that + returns EINVAL due to the non aligned file offset. */ + if (nread == -1 && errno == EINVAL + && 0 < prev_nread && prev_nread < size + && (input_flags & O_DIRECT)) + { + errno = 0; + nread = 0; + } } while (nread < 0 && errno == EINTR); @@ -1122,8 +1132,6 @@ iread (int fd, char *buf, size_t size) if (0 < nread && warn_partial_read) { - static ssize_t prev_nread; - if (0 < prev_nread && prev_nread < size) { uintmax_t prev = prev_nread; @@ -1136,10 +1144,9 @@ iread (int fd, char *buf, size_t size) prev); warn_partial_read = false; } - - prev_nread = nread; } + prev_nread = nread; return nread; } diff --git a/tests/dd/direct.sh b/tests/dd/direct.sh index 55f92aea9e..b2a355c0ff 100755 --- a/tests/dd/direct.sh +++ b/tests/dd/direct.sh @@ -1,5 +1,5 @@ #!/bin/sh -# ensure that dd's oflag=direct works +# ensure that dd's iflag=direct and oflag=direct work # Copyright (C) 2009-2017 Free Software Foundation, Inc. @@ -29,7 +29,7 @@ truncate -s 8193 p1 || framework_failure_ for i in short m1 p1; do rm -f out - dd if=$i oflag=direct of=out || fail=1 + dd if=$i iflag=direct oflag=direct of=out || fail=1 done Exit $fail -- 2.47.2