]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
dd: support iflag=direct with arbitrary sized files
authorPádraig Brady <P@draigBrady.com>
Mon, 16 Oct 2017 06:54:29 +0000 (23:54 -0700)
committerPádraig Brady <P@draigBrady.com>
Sat, 25 Nov 2017 00:28:57 +0000 (16:28 -0800)
* 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
src/dd.c
tests/dd/direct.sh

diff --git a/NEWS b/NEWS
index 4c697b591e4baaee0b66ee92817e361f864dcc5d..d5060d1c8e8e565200a54e9df562cb07eef48503 100644 (file)
--- 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.
 
index b6ceb4fd7cc6af18c6227ccc86c4cc8b4c34a4cc..0ff618c963532ec891dccc2099a435d4c8b01d6c 100644 (file)
--- 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;
 }
 
index 55f92aea9ebecaac0203d0c78288ce1fa80320ef..b2a355c0ff916abec06fdaa36b5d185770b61494 100755 (executable)
@@ -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