*** dd.c.orig Sat Sep 19 13:09:23 1998 --- dd.c Mon Oct 16 13:05:29 2000 *************** *** 93,102 **** --- 93,108 ---- 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; /* Bit vector of conversions to apply. */ static int conversions_mask = 0; *************** *** 298,311 **** --- 304,322 ---- ibs=BYTES read BYTES bytes at a time\n\ if=FILE read from FILE instead of stdin\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\ Each KEYWORD may be:\n\ \n\ *************** *** 319,329 **** ucase change lower case to upper case\n\ swab swap every pair of input bytes\n\ noerror continue after read errors\n\ sync pad every input block with NULs to ibs-size\n\ ")); ! puts (_("\nReport bugs to .")); close_stdout (); } exit (status); } --- 330,340 ---- ucase change lower case to upper case\n\ swab swap every pair of input bytes\n\ noerror continue after read errors\n\ sync pad every input block with NULs to ibs-size\n\ ")); ! puts (_("\nReport bugs to .")); close_stdout (); } exit (status); } *************** *** 651,663 **** conversion_blocksize = n; invalid |= (conversion_blocksize != n || conversion_blocksize == 0); } else if (STREQ (name, "skip")) ! skip_records = n; else if (STREQ (name, "seek")) ! seek_record = n; else if (STREQ (name, "count")) max_records = n; else { error (0, 0, _("unrecognized option `%s=%s'"), name, val); --- 662,694 ---- conversion_blocksize = n; invalid |= (conversion_blocksize != n || conversion_blocksize == 0); } else if (STREQ (name, "skip")) ! { ! 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; ! /* 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 { error (0, 0, _("unrecognized option `%s=%s'"), name, val); *************** *** 833,842 **** --- 864,930 ---- break; } } } + /* 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 copy_simple (unsigned char *buf, int nread) { *************** *** 952,961 **** --- 1040,1052 ---- obuf = ibuf; if (skip_records != 0) skip (input_fd, input_file, skip_records, input_blocksize, ibuf); + if (skip_bytes != 0) + bskip (input_fd, input_file, skip_bytes, input_blocksize, ibuf); + if (seek_record != 0) { /* FIXME: this loses for % ./dd if=dd seek=1 |: ./dd: a1 standard output: Bad file number *************** *** 963,972 **** --- 1054,1066 ---- 0+0 records out */ skip (output_fd, output_file, seek_record, output_blocksize, obuf); } + + if (seek_bytes != 0) + bskip (output_fd, output_file, seek_bytes, output_blocksize, obuf); if (max_records == 0) quit (exit_status); while (1)