[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: dd: add 'skip_bytes' and 'count_bytes' operands
From: |
Jérémy Compostella |
Subject: |
Re: dd: add 'skip_bytes' and 'count_bytes' operands |
Date: |
Mon, 06 Feb 2012 15:01:15 +0100 |
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?= <address@hidden>
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
- dd: add 'skip_bytes' and 'count_bytes' operands, Jérémy Compostella, 2012/02/05
- Re: dd: add 'skip_bytes' and 'count_bytes' operands,
Jérémy Compostella <=
- Re: dd: add 'skip_bytes' and 'count_bytes' operands, Jérémy Compostella, 2012/02/06
- Re: dd: add 'skip_bytes' and 'count_bytes' operands, Pádraig Brady, 2012/02/06
- Re: dd: add 'skip_bytes' and 'count_bytes' operands, Jérémy Compostella, 2012/02/07
- Re: dd: add 'skip_bytes' and 'count_bytes' operands, Pádraig Brady, 2012/02/07
- Re: dd: add 'skip_bytes' and 'count_bytes' operands, Jérémy Compostella, 2012/02/08
- Re: dd: add 'skip_bytes' and 'count_bytes' operands, Jérémy Compostella, 2012/02/08
- Re: dd: add 'skip_bytes' and 'count_bytes' operands, Eric Blake, 2012/02/08
- Re: dd: add 'skip_bytes' and 'count_bytes' operands, Erik Auerswald, 2012/02/08
- RE: dd: add 'skip_bytes' and 'count_bytes' operands, Voelker, Bernhard, 2012/02/09