bskip/bseek patch from Chris Sylvain <csylvain@umm.edu> merged in

This commit is contained in:
Jim Meyering
2000-11-24 21:54:31 +00:00
parent 3d6852f7fa
commit c8a0eec3f6
+122 -10
View File
@@ -102,6 +102,12 @@ static uintmax_t skip_records = 0;
/* Skip this many records of `output_blocksize' bytes before output. */
static uintmax_t seek_record = 0;
/* Skip this many bytes before input. */
static uintmax_t skip_bytes = 0;
/* Skip this many bytes before output. */
static uintmax_t seek_bytes = 0;
/* Copy only this many records. The default is effectively infinity. */
static uintmax_t max_records = (uintmax_t) -1;
@@ -294,10 +300,15 @@ Copy a file, converting and formatting according to the options.\n\
obs=BYTES write BYTES bytes at a time\n\
of=FILE write to FILE instead of stdout\n\
seek=BLOCKS skip BLOCKS obs-sized blocks at start of output\n\
bseek=BYTES skip BYTES at start of output\n\
skip=BLOCKS skip BLOCKS ibs-sized blocks at start of input\n\
bskip=BYTES skip BYTES at start of input\n\
--help display this help and exit\n\
--version output version information and exit\n\
\n\
Only one of each of the [b]seek or [b]skip option pairs may be used\n\
at any one time.\n\
\n\
BYTES may be followed by the following multiplicative suffixes:\n\
xM M, c 1, w 2, b 512, kD 1000, k 1024, MD 1,000,000, M 1,048,576,\n\
GD 1,000,000,000, G 1,073,741,824, and so on for T, P, E, Z, Y.\n\
@@ -581,9 +592,29 @@ scanargs (int argc, char **argv)
|| conversion_blocksize == 0);
}
else if (STREQ (name, "skip"))
skip_records = n;
{
skip_records = n;
/* may use option only when bskip=BYTES option is not used */
invalid |= skip_bytes != 0;
}
else if (STREQ (name, "seek"))
seek_record = n;
{
seek_record = n;
/* may use option only when bseek=BYTES option is not used */
invalid |= seek_bytes != 0;
}
else if (STREQ (name, "bseek"))
{
seek_bytes = n;
/* may use option only when seek=BLOCKS option is not used */
invalid |= seek_record != 0;
}
else if (STREQ (name, "bskip"))
{
skip_bytes = n;
/* may use option only when skip=BLOCKS option is not used */
invalid |= skip_records != 0;
}
else if (STREQ (name, "count"))
max_records = n;
else
@@ -788,6 +819,63 @@ skip (int fdesc, char const *file, uintmax_t records, size_t blocksize,
}
}
/* Throw away BYTES on file descriptor FDESC,
which is open with read permission for FILE.
Store up to BYTES of the data (one BLOCKSIZE at a time) in BUF,
if necessary. */
static void
bskip (int fdesc, char *file, uintmax_t bytes, size_t blocksize,
unsigned char *buf)
{
struct stat stats;
/* Use fstat instead of checking for errno == ESPIPE because
lseek doesn't work on some special files but doesn't return an
error, either. */
/* FIXME: can this really happen? What system? */
if (fstat (fdesc, &stats))
{
error (0, errno, "%s", file);
quit (1);
}
/* Try lseek and if an error indicates it was an inappropriate
operation, fall back on using read. */
if (lseek (fdesc, bytes, SEEK_SET) == -1)
{
int nread;
while ((bytes-=blocksize) >= 0)
{
nread = safe_read (fdesc, buf, blocksize);
if (nread < 0)
{
error (0, errno, "%s", file);
quit (1);
}
/* POSIX doesn't say what to do when dd detects it has been
asked to skip past EOF, so I assume it's non-fatal.
FIXME: maybe give a warning. */
if (nread == 0)
break;
}
/* sop up any residue .. */
if (bytes < 0)
{
bytes += blocksize;
nread = safe_read (fdesc, buf, bytes);
if (nread < 0)
{
error (0, errno, "%s", file);
quit (1);
}
}
}
}
/* Copy NREAD bytes of BUF, with no conversions. */
static void
@@ -935,6 +1023,9 @@ dd_copy (void)
if (skip_records != 0)
skip (STDIN_FILENO, input_file, skip_records, input_blocksize, ibuf);
if (skip_bytes != 0)
bskip (STDIN_FILENO, input_file, skip_bytes, input_blocksize, ibuf);
if (seek_record != 0)
{
/* FIXME: this loses for
@@ -948,6 +1039,9 @@ dd_copy (void)
obuf);
}
if (seek_bytes != 0)
bskip (STDOUT_FILENO, output_file, seek_bytes, output_blocksize, obuf);
if (max_records == 0)
quit (exit_status);
@@ -1143,17 +1237,28 @@ main (int argc, char **argv)
/* Open the output file with *read* access only if we might
need to read to satisfy a `seek=' request. If we can't read
the file, go ahead with write-only access; it might work. */
if ((! seek_record
if (((seek_record == 0
&& seek_bytes == 0)
|| open_fd (STDOUT_FILENO, output_file, O_RDWR | opts, perms) < 0)
&& open_fd (STDOUT_FILENO, output_file, O_WRONLY | opts, perms) < 0)
error (1, errno, _("opening %s"), quote (output_file));
#if HAVE_FTRUNCATE
if (seek_record != 0 && !(conversions_mask & C_NOTRUNC))
if ((seek_record != 0 || seek_bytes != 0)
&& !(conversions_mask & C_NOTRUNC))
{
struct stat stdout_stat;
off_t o = seek_record * output_blocksize;
if (o / output_blocksize != seek_record)
error (1, 0, _("file offset out of range"));
off_t o;
if (seek_record)
{
o = seek_record * output_blocksize;
if (o / output_blocksize != seek_record)
error (1, 0, _("file offset out of range"));
}
else
{
o = seek_bytes;
}
/* Attempt to use ftruncate only if STDOUT refers to a regular file.
On Linux 2.4.0, ftruncate fails with for non-regular files. */
@@ -1162,9 +1267,16 @@ main (int argc, char **argv)
&& ftruncate (STDOUT_FILENO, o) < 0)
{
char buf[LONGEST_HUMAN_READABLE + 1];
error (1, errno, _("advancing past %s blocks in output file %s"),
human_readable (seek_record, buf, 1, 1),
quote (output_file));
if (seek_record)
error (1, errno,
_("advancing past %s blocks in output file %s"),
human_readable (seek_record, buf, 1, 1),
quote (output_file));
else
error (1, errno,
_("advancing past %s bytes in output file %s"),
human_readable (seek_bytes, buf, 1, 1),
quote (output_file));
}
}
#endif