summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>2000-08-24 11:39:08 +0000
committerJim Meyering <jim@meyering.net>2000-08-24 11:39:08 +0000
commit44256afd615252c234fbd53339d2a8fc252876cf (patch)
treea3cc0ce31d091bcf5445f8fd9297e87a5fe18624 /src
parent078fb9958e3ac142645c86bc83e2fdd2522bcbdc (diff)
downloadcoreutils-44256afd615252c234fbd53339d2a8fc252876cf.tar.xz
Put back the kluge. It's necessary after all.
(buggy_lseek_support): New function. (skip): Use it. Frank Adler reported that although _llseek returns 0, lseek erroneously returns an offset suggesting the operation succeeded even though it fails.
Diffstat (limited to 'src')
-rw-r--r--src/dd.c36
1 files changed, 34 insertions, 2 deletions
diff --git a/src/dd.c b/src/dd.c
index 9291a1a2c..6eaf8fed1 100644
--- a/src/dd.c
+++ b/src/dd.c
@@ -718,6 +718,37 @@ swab_buffer (unsigned char *buf, size_t *nread)
return ++bufstart;
}
+/* Return nonzero iff the file referenced by FDESC is of a type for
+ which lseek's return value is known to be invalid on some systems.
+ Otherwise, return zero.
+ For example, return nonzero if FDESC references a character device
+ (on any system) because the lseek on many Linux systems incorrectly
+ returns an offset implying it succeeds for tape devices, even though
+ the function fails to perform the requested operation. In that case,
+ lseek should return nonzero and set errno. */
+
+static int
+buggy_lseek_support (int fdesc)
+{
+ /* We have to resort to this because on some systems, lseek doesn't work
+ on some special files but doesn't return an error, either.
+ In particular, the Linux tape drivers are a problem.
+ For example, when I did the following using dd-4.0y or earlier on a
+ Linux-2.2.17 system with a Exabyte SCSI tape drive:
+
+ dev=/dev/nst0
+ reset='mt -f $dev rewind; mt -f $dev fsf 1'
+ eval $reset; dd if=$dev bs=32k of=out1
+ eval $reset; dd if=$dev bs=32k of=out2 skip=1
+
+ the resulting files, out1 and out2, would compare equal. */
+
+ struct stat stats;
+
+ return (fstat (fdesc, &stats) == 0
+ && (S_ISCHR (stats.st_mode)));
+}
+
/* Throw away RECORDS blocks of BLOCKSIZE bytes on file descriptor FDESC,
which is open with read permission for FILE. Store up to BLOCKSIZE
bytes of the data at a time in BUF, if necessary. RECORDS must be
@@ -731,10 +762,11 @@ skip (int fdesc, char *file, uintmax_t records, size_t blocksize,
/* Try lseek and if an error indicates it was an inappropriate
operation, fall back on using read. Some broken versions of
- lseek return zero, so count that as an error too as a valid zero
- return is not possible here. */
+ lseek may return zero, so count that as an error too as a valid
+ zero return is not possible here. */
o = records * blocksize;
if (o / blocksize != records
+ || buggy_lseek_support (fdesc)
|| lseek (fdesc, o, SEEK_CUR) <= 0)
{
while (records-- > 0)