*** dd.c.orig Sat Sep 19 13:09:23 1998 --- dd.c Thu Oct 19 11:42:19 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 *************** *** 964,973 **** --- 1055,1067 ---- */ 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) { *************** *** 1146,1156 **** if (output_file != NULL) { int omode = O_RDWR | O_CREAT; ! if (seek_record == 0 && !(conversions_mask & C_NOTRUNC)) omode |= O_TRUNC; output_fd = open (output_file, omode, 0666); if (output_fd < 0) error (1, errno, "%s", output_file); #if HAVE_FTRUNCATE --- 1240,1251 ---- if (output_file != NULL) { int omode = O_RDWR | O_CREAT; ! if ((seek_record == 0 && seek_bytes == 0) ! && !(conversions_mask & C_NOTRUNC)) omode |= O_TRUNC; output_fd = open (output_file, omode, 0666); if (output_fd < 0) error (1, errno, "%s", output_file); #if HAVE_FTRUNCATE *************** *** 1158,1167 **** --- 1253,1268 ---- { off_t o = seek_record * output_blocksize; if (o / output_blocksize != seek_record) error (1, 0, _("file offset out of range")); if (ftruncate (output_fd, o) < 0) + error (0, errno, "%s", output_file); + } + + if (seek_bytes != 0 && !(conversions_mask & C_NOTRUNC)) + { + if (ftruncate (output_fd, seek_bytes) < 0) error (0, errno, "%s", output_file); } #endif } else