[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
dd: add 'skip_bytes' and 'count_bytes' operands
From: |
Jérémy Compostella |
Subject: |
dd: add 'skip_bytes' and 'count_bytes' operands |
Date: |
Sun, 05 Feb 2012 13:25:46 +0100 |
All,
I worked on the 'skip_bytes' and 'count_bytes' features reported in the
following mail thread:
http://lists.gnu.org/archive/html/bug-coreutils/2009-10/msg00061.html
If anybody have started working on it or have guidance for it, please
let me know.
I wrote the attached patch which implements these features. As I'm new
in this project and I'm not really comfortable with project specific
good practices do not hesitate to comment this patch. I will take into
account whatever you want.
I added a special test suite to satisfy these new operands. tests/dd/bytes
Writing this patch I thought it would be nice having the seek_bytes
operand too. What is your opinion about this ?
Cheers,
Jérémy
>From 732f14abfc8b1b5aa711a41cc4dd7fdc0b3d045a Mon Sep 17 00:00:00 2001
From: Jeremy Compostella <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.
Signed-off-by: Jeremy Compostella <address@hidden>
---
NEWS | 8 ++++
doc/coreutils.texi | 11 ++++++
src/dd.c | 99 +++++++++++++++++++++++++++++++++++++++------------
tests/Makefile.am | 1 +
tests/dd/bytes | 37 +++++++++++++++++++
5 files changed, 132 insertions(+), 24 deletions(-)
create mode 100755 tests/dd/bytes
diff --git a/NEWS b/NEWS
index 2b0926f..445d87b 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,14 @@ 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.
* Noteworthy changes in release 8.15 (2012-01-06) [stable]
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index 0d3b739..4124927 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 8c687b3..461b9e0 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)
{
@@ -1817,12 +1865,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,
@@ -1833,7 +1881,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 8b670fc..c6b8737 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 <=
- 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, 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