Pádraig, all, I took into account general comments on my commits. I attached the improved patch for feature. Improvements are: - Add by file description, - I put back accents on my name (Jérémy instead of Jeremy),
Cheers, Jérémy ---
>From 53c65c4bc125217b935c824c193449e592011a74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Compostella?= <[email protected]> Date: Sat, 4 Feb 2012 15:25:54 +0100 Subject: [PATCH] dd: add skip_bytes and count_bytes operands dd now accepts: - the skip_bytes=N operand: When specified, dd skip N bytes before copying. 'skip' and 'skip_bytes" operands are mutually exclusive. - the count_bytes=N operand: When specified, dd copy N bytes. 'count' and 'count_bytes' are mutually exclusive. * src/dd.c (scanargs): Compute skip_records and skip_bytes when 'skip_bytes' operand is used. Compute max_records and max_bytes when 'count_bytes' operand is used. Raise a "mutually exclusive" error when 'skip' and 'skip_bytes' are both used or when 'count' and 'count_bytes' are both used. (skip_via_lseek): Use new 'bytes' parameter and handle potential 'records' equals to zero. Update the header comments. (dd_copy): Skip accordingly to skip_records AND skip_bytes. Count accordingly to max_records AND max_bytes. * NEWS (New features): Mention it. * doc/coreutils.texi (New features): Detail new operands and behaviors. * tests/dd/bytes: New file. Tests for these two new operands. * tests/Makefile.am (TESTS): Add it. --- NEWS | 10 +++++- doc/coreutils.texi | 11 ++++++ src/dd.c | 99 +++++++++++++++++++++++++++++++++++++++------------ tests/Makefile.am | 1 + tests/dd/bytes | 37 +++++++++++++++++++ 5 files changed, 133 insertions(+), 25 deletions(-) create mode 100755 tests/dd/bytes diff --git a/NEWS b/NEWS index 9eebbf6..adf6140 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,15 @@ GNU coreutils NEWS -*- outline -*- * Noteworthy changes in release ?.? (????-??-??) [?] +** New features + + dd now accepts: + - the skip_bytes=N operand. When specified, dd skip N + bytes before copying. 'skip' and 'skip_bytes' operands are mutually + exclusive. + - the count_bytes=N operand. When specified, dd copy N bytes. 'count' + and 'count_bytes' are mutually exclusive. + ** Bug fixes mv now lets you move a symlink onto a same-inode destination file that @@ -11,7 +20,6 @@ GNU coreutils NEWS -*- outline -*- referent, there is no risk of data loss, since the symlink will typically still point to one of the hard links. - * Noteworthy changes in release 8.15 (2012-01-06) [stable] ** New programs diff --git a/doc/coreutils.texi b/doc/coreutils.texi index 52838e7..e671a8b 100644 --- a/doc/coreutils.texi +++ b/doc/coreutils.texi @@ -8061,6 +8061,11 @@ use @var{bytes} as the fixed record length. @opindex skip Skip @var{blocks} @samp{ibs}-byte blocks in the input file before copying. +@item skip_bytes=@var{n} +@opindex skip_bytes +Skip @var{n} bytes in the input file before copying. +@samp{skip_bytes} and @samp{skip} are mutually exclusive. + @item seek=@var{blocks} @opindex seek Skip @var{blocks} @samp{obs}-byte blocks in the output file before copying. @@ -8070,6 +8075,12 @@ Skip @var{blocks} @samp{obs}-byte blocks in the output file before copying. Copy @var{blocks} @samp{ibs}-byte blocks from the input file, instead of everything until the end of the file. +@item count_bytes=@var{n} +@opindex count +Copy @var{n} bytes from the input file, instead of everything until +the end of the file. @samp{count} and @samp{count_bytes} are mutually +exclusive. + @item status=noxfer @opindex status Do not print the overall transfer rate and volume statistics diff --git a/src/dd.c b/src/dd.c index 9d24791..7c65653 100644 --- a/src/dd.c +++ b/src/dd.c @@ -156,12 +156,19 @@ static size_t conversion_blocksize = 0; /* Skip this many records of 'input_blocksize' bytes before input. */ static uintmax_t skip_records = 0; +/* Skip this many bytes before input in addition of 'skip_records' + records. */ +static size_t skip_bytes = 0; + /* Skip this many records of 'output_blocksize' bytes before output. */ static uintmax_t seek_records = 0; /* Copy only this many records. The default is effectively infinity. */ static uintmax_t max_records = (uintmax_t) -1; +/* Copy this many bytes in addition to 'max_records' records. */ +static size_t max_bytes = 0; + /* Bit vector of conversions to apply. */ static int conversions_mask = 0; @@ -490,6 +497,8 @@ Copy a file, converting and formatting according to the operands.\n\ cbs=BYTES convert BYTES bytes at a time\n\ conv=CONVS convert the file as per the comma separated symbol list\n\ count=BLOCKS copy only BLOCKS input blocks\n\ + count_bytes=N copy only N bytes. count and count_bytes operands are mutually\n\ + exclusive\n\ ibs=BYTES read up to BYTES bytes at a time (default: 512)\n\ "), stdout); fputs (_("\ @@ -500,6 +509,8 @@ Copy a file, converting and formatting according to the operands.\n\ oflag=FLAGS write as per the comma separated symbol list\n\ seek=BLOCKS skip BLOCKS obs-sized blocks at start of output\n\ skip=BLOCKS skip BLOCKS ibs-sized blocks at start of input\n\ + skip_bytes=N skip N bytes at start of input. skip and skip_bytes operands\n\ + are mutually exclusive\n\ status=noxfer suppress transfer statistics\n\ "), stdout); fputs (_("\ @@ -1120,6 +1131,8 @@ scanargs (int argc, char *const *argv) { int i; size_t blocksize = 0; + uintmax_t count_in_bytes = 0; + uintmax_t skip_in_bytes = 0; for (i = optind; i < argc; i++) { @@ -1176,10 +1189,14 @@ scanargs (int argc, char *const *argv) } else if (operand_is (name, "skip")) skip_records = n; + else if (operand_is (name, "skip_bytes")) + skip_in_bytes = n; else if (operand_is (name, "seek")) seek_records = n; else if (operand_is (name, "count")) max_records = n; + else if (operand_is (name, "count_bytes")) + count_in_bytes = n; else { error (0, 0, _("unrecognized operand %s"), quote (name)); @@ -1216,6 +1233,30 @@ scanargs (int argc, char *const *argv) usage (EXIT_FAILURE); } + if (skip_in_bytes != 0 && skip_records != 0) + { + error (0, 0, _("'skip_bytes' and 'skip' operands are mutually exclusive")); + usage (EXIT_FAILURE); + } + + if (skip_in_bytes != 0) + { + skip_records = skip_in_bytes / input_blocksize; + skip_bytes = skip_in_bytes % input_blocksize; + } + + if (count_in_bytes != 0 && max_records != (uintmax_t) -1) + { + error (0, 0, _("'count_bytes' and 'count' operands are mutually exclusive")); + usage (EXIT_FAILURE); + } + + if (count_in_bytes != 0) + { + max_records = count_in_bytes / input_blocksize; + max_bytes = count_in_bytes % input_blocksize; + } + /* Warn about partial reads if bs=SIZE is given and iflag=fullblock is not, and if counting or skipping bytes or using direct I/O. This helps to avoid confusion with miscounts, and to avoid issues @@ -1411,18 +1452,19 @@ skip_via_lseek (char const *filename, int fdesc, off_t offset, int whence) # define skip_via_lseek(Filename, Fd, Offset, Whence) lseek (Fd, Offset, Whence) #endif -/* 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 - nonzero. If fdesc is STDIN_FILENO, advance the input offset. - Return the number of records remaining, i.e., that were not skipped - because EOF was reached. */ +/* Throw away RECORDS blocks of BLOCKSIZE bytes plus BYTES 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 or BYTES must be nonzero. If FDESC is + STDIN_FILENO, advance the input offset. Return the number of + records remaining, i.e., that were not skipped because EOF was + reached. */ static uintmax_t skip (int fdesc, char const *file, uintmax_t records, size_t blocksize, - char *buf) + size_t bytes, char *buf) { - uintmax_t offset = records * blocksize; + uintmax_t offset = records * blocksize + bytes; /* Try lseek and if an error indicates it was an inappropriate operation -- or if the file offset is not representable as an off_t -- @@ -1491,29 +1533,35 @@ skip (int fdesc, char const *file, uintmax_t records, size_t blocksize, do { - ssize_t nread = iread_fnc (fdesc, buf, blocksize); + ssize_t nread; + if (records != 0) + nread = iread_fnc (fdesc, buf, blocksize); + else + nread = iread_fnc (fdesc, buf, bytes); + if (nread < 0) { if (fdesc == STDIN_FILENO) { error (0, errno, _("reading %s"), quote (file)); if (conversions_mask & C_NOERROR) - { - print_stats (); - continue; - } + print_stats (); } else error (0, lseek_errno, _("%s: cannot seek"), quote (file)); quit (EXIT_FAILURE); } - - if (nread == 0) + else if (nread == 0) break; - if (fdesc == STDIN_FILENO) + else if (fdesc == STDIN_FILENO) advance_input_offset (nread); + + if (records != 0) + --records; + else + bytes = 0; } - while (--records != 0); + while (records != 0 || bytes != 0); return records; } @@ -1777,11 +1825,11 @@ dd_copy (void) obuf = ibuf; } - if (skip_records != 0) + if (skip_records != 0 || skip_bytes != 0) { - uintmax_t us_bytes = input_offset + (skip_records * input_blocksize); + uintmax_t us_bytes = input_offset + (skip_records * input_blocksize) + skip_bytes; uintmax_t us_blocks = skip (STDIN_FILENO, input_file, - skip_records, input_blocksize, ibuf); + skip_records, input_blocksize, skip_bytes, ibuf); us_bytes -= input_offset; /* POSIX doesn't say what to do when dd detects it has been @@ -1800,7 +1848,7 @@ dd_copy (void) if (seek_records != 0) { uintmax_t write_records = skip (STDOUT_FILENO, output_file, - seek_records, output_blocksize, obuf); + seek_records, output_blocksize, 0, obuf); if (write_records != 0) { @@ -1819,12 +1867,12 @@ dd_copy (void) } } - if (max_records == 0) + if (max_records == 0 && max_bytes == 0) return exit_status; while (1) { - if (r_partial + r_full >= max_records) + if (r_partial + r_full >= max_records + (max_bytes ? 1 : 0)) break; /* Zero the buffer before reading, so that if we get a read error, @@ -1835,7 +1883,10 @@ dd_copy (void) (conversions_mask & (C_BLOCK | C_UNBLOCK)) ? ' ' : '\0', input_blocksize); - nread = iread_fnc (STDIN_FILENO, ibuf, input_blocksize); + if (r_partial + r_full >= max_records) + nread = iread_fnc (STDIN_FILENO, ibuf, max_bytes); + else + nread = iread_fnc (STDIN_FILENO, ibuf, input_blocksize); if (nread >= 0 && i_nocache) invalidate_cache (STDIN_FILENO, nread); diff --git a/tests/Makefile.am b/tests/Makefile.am index a94aaa2..31bb050 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -369,6 +369,7 @@ TESTS = \ dd/reblock \ dd/skip-seek \ dd/skip-seek2 \ + dd/bytes \ dd/skip-seek-past-file \ dd/stderr \ dd/unblock \ diff --git a/tests/dd/bytes b/tests/dd/bytes new file mode 100755 index 0000000..d0c72f8 --- /dev/null +++ b/tests/dd/bytes @@ -0,0 +1,37 @@ +#!/bin/sh + +# Copyright (C) 2012 Free Software Foundation, Inc. + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +. "${srcdir=.}/init.sh"; path_prepend_ ../src +print_ver_ dd + +# count_bytes +echo 0123456789abcefghijklm > in || fail=1 +(dd count_bytes=14 conv=swab) < in > out 2> /dev/null || fail=1 +case `cat out` in + 1032547698baec) ;; + *) fail=1 ;; +esac + +# skip_bytes +echo 0123456789abcefghijklm > in || fail=1 +(dd skip_bytes=10) < in > out 2> /dev/null || fail=1 +case `cat out` in + abcefghijklm) ;; + *) fail=1 ;; +esac + +Exit $fail -- 1.7.2.5
