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.
This commit is contained in:
Pádraig Brady
2017-10-15 23:54:29 -07:00
parent 559c7a57c7
commit 5f02cddc18
3 changed files with 15 additions and 6 deletions

2
NEWS
View File

@@ -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.

View File

@@ -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;
}

View File

@@ -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