dd: new option: iflag=fullblock to accumulate full input blocks
authorKamil Dudka <kdudka@redhat.com>
Wed, 23 Jul 2008 09:29:21 +0000 (11:29 +0200)
committerJim Meyering <meyering@redhat.com>
Wed, 23 Jul 2008 13:55:45 +0000 (15:55 +0200)
* src/dd.c (iread_fullblock): New function for reading full blocks.
(scanargs): Check for new parameter iflag=fullblock.
(skip): Use iread_fnc pointer instead of iread function.
(dd_copy): Use iread_fnc pointer instead of iread function.
* tests/dd/misc: Add test for dd - read full blocks.
* doc/coretuils.texi: Mention new parameter iflag=fullblock.
* NEWS: Mentioned the change.

NEWS
doc/coreutils.texi
src/dd.c
tests/dd/misc

diff --git a/NEWS b/NEWS
index d6ed89e8c9adbfa17905bf7734b2a2a3f02b2c40..68a27fae928df0f3c9b89c9a33fa1cddc6e587ca 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -27,6 +27,10 @@ GNU coreutils NEWS                                    -*- outline -*-
   represents the maximum number of inputs that will be merged at once.
   When processing more than NMERGE inputs, sort uses temporary files.
 
   represents the maximum number of inputs that will be merged at once.
   When processing more than NMERGE inputs, sort uses temporary files.
 
+  dd accepts a new parameter iflag=fullblock which turn on reading of full
+  blocks  where possible. If this parameter is used and 'read' call is
+  terminated during read, it will be called again for remainder input.
+
 ** Bug fixes
 
   chcon --verbose now prints a newline after each message
 ** Bug fixes
 
   chcon --verbose now prints a newline after each message
index 81e3b911c27d3a8c9ce40bbea9d0e2256131b807..b95f8dc50506303377882f3909dae60f39a3c173 100644 (file)
@@ -7719,6 +7719,12 @@ platforms that distinguish binary from text I/O.
 Use text I/O.  Like @samp{binary}, this option has no effect on
 standard platforms.
 
 Use text I/O.  Like @samp{binary}, this option has no effect on
 standard platforms.
 
+@item fullblock
+@opindex fullblock
+Read full blocks from input if possible. read() may return early
+if a full block is not available, so retry until data is available
+or end of file is reached. This flag can be used only for the iflag option.
+
 @end table
 
 These flags are not supported on all systems, and @samp{dd} rejects
 @end table
 
 These flags are not supported on all systems, and @samp{dd} rejects
index 5e3547d16bccf841b75bcb7e3d570e86dcfe3264..0c24b468ab25854c85a240e628c7990451ff4059 100644 (file)
--- a/src/dd.c
+++ b/src/dd.c
@@ -225,6 +225,9 @@ static sig_atomic_t volatile interrupt_signal;
 /* A count of the number of pending info signals that have been received.  */
 static sig_atomic_t volatile info_signal_count;
 
 /* A count of the number of pending info signals that have been received.  */
 static sig_atomic_t volatile info_signal_count;
 
+/* Function used for read (to handle iflag=fullblock parameter) */
+static ssize_t (*iread_fnc) (int fd, char *buf, size_t size);
+
 /* A longest symbol in the struct symbol_values tables below.  */
 #define LONGEST_SYMBOL "fdatasync"
 
 /* A longest symbol in the struct symbol_values tables below.  */
 #define LONGEST_SYMBOL "fdatasync"
 
@@ -257,6 +260,7 @@ static struct symbol_value const conversions[] =
 };
 
 /* Flags, for iflag="..." and oflag="...".  */
 };
 
 /* Flags, for iflag="..." and oflag="...".  */
+#define O_FULLBLOCK 010000000 /* Read only full blocks from input */
 static struct symbol_value const flags[] =
 {
   {"append",   O_APPEND},
 static struct symbol_value const flags[] =
 {
   {"append",   O_APPEND},
@@ -271,6 +275,7 @@ static struct symbol_value const flags[] =
   {"nonblock", O_NONBLOCK},
   {"sync",     O_SYNC},
   {"text",     O_TEXT},
   {"nonblock", O_NONBLOCK},
   {"sync",     O_SYNC},
   {"text",     O_TEXT},
+  {"fullblock", O_FULLBLOCK}, /* Read only full blocks from input */
   {"",         0}
 };
 
   {"",         0}
 };
 
@@ -762,6 +767,27 @@ iread (int fd, char *buf, size_t size)
     }
 }
 
     }
 }
 
+/* Wrapper around iread function which reads full blocks if possible */
+static ssize_t
+iread_fullblock (int fd, char *buf, size_t size)
+{
+  ssize_t nread = 0;
+
+  while (0 < size)
+    {
+      ssize_t ncurr = iread(fd, buf, size);
+      if (ncurr < 0)
+       return ncurr;
+      if (ncurr == 0)
+       break;
+      nread += ncurr;
+      buf   += ncurr;
+      size  -= ncurr;
+    }
+
+  return nread;
+}
+
 /* Write to FD the buffer BUF of size SIZE, processing any signals
    that arrive.  Return the number of bytes written, setting errno if
    this is less than SIZE.  Keep trying if there are partial
 /* Write to FD the buffer BUF of size SIZE, processing any signals
    that arrive.  Return the number of bytes written, setting errno if
    this is less than SIZE.  Keep trying if there are partial
@@ -1000,6 +1026,15 @@ scanargs (int argc, char *const *argv)
   if (input_flags & (O_DSYNC | O_SYNC))
     input_flags |= O_RSYNC;
 
   if (input_flags & (O_DSYNC | O_SYNC))
     input_flags |= O_RSYNC;
 
+  if (output_flags & O_FULLBLOCK)
+    {
+      error (0, 0, "%s: %s", _("invalid output flag"), "'fullblock'");
+      usage (EXIT_FAILURE);
+    }
+  iread_fnc = (input_flags & O_FULLBLOCK)?
+    iread_fullblock:
+    iread;
+
   if (multiple_bits_set (conversions_mask & (C_ASCII | C_EBCDIC | C_IBM)))
     error (EXIT_FAILURE, 0, _("cannot combine any two of {ascii,ebcdic,ibm}"));
   if (multiple_bits_set (conversions_mask & (C_BLOCK | C_UNBLOCK)))
   if (multiple_bits_set (conversions_mask & (C_ASCII | C_EBCDIC | C_IBM)))
     error (EXIT_FAILURE, 0, _("cannot combine any two of {ascii,ebcdic,ibm}"));
   if (multiple_bits_set (conversions_mask & (C_BLOCK | C_UNBLOCK)))
@@ -1197,7 +1232,7 @@ skip (int fdesc, char const *file, uintmax_t records, size_t blocksize,
 
       do
        {
 
       do
        {
-         ssize_t nread = iread (fdesc, buf, blocksize);
+         ssize_t nread = iread_fnc (fdesc, buf, blocksize);
          if (nread < 0)
            {
              if (fdesc == STDIN_FILENO)
          if (nread < 0)
            {
              if (fdesc == STDIN_FILENO)
@@ -1508,7 +1543,7 @@ dd_copy (void)
                (conversions_mask & (C_BLOCK | C_UNBLOCK)) ? ' ' : '\0',
                input_blocksize);
 
                (conversions_mask & (C_BLOCK | C_UNBLOCK)) ? ' ' : '\0',
                input_blocksize);
 
-      nread = iread (STDIN_FILENO, ibuf, input_blocksize);
+      nread = iread_fnc (STDIN_FILENO, ibuf, input_blocksize);
 
       if (nread == 0)
        break;                  /* EOF.  */
 
       if (nread == 0)
        break;                  /* EOF.  */
index d54fbfaee8e158594ad104980f35d8be356ba557..24e5eba55d5de0fcd578d1edb08edc120378e3c0 100755 (executable)
@@ -88,6 +88,15 @@ fi
 outbytes=`echo x | dd bs=3 ibs=10 obs=10 conv=sync 2>/dev/null | wc -c`
 test "$outbytes" -eq 3 || fail=1
 
 outbytes=`echo x | dd bs=3 ibs=10 obs=10 conv=sync 2>/dev/null | wc -c`
 test "$outbytes" -eq 3 || fail=1
 
+(echo a; sleep .1; echo b) \
+  | LC_ALL=C dd bs=4 status=noxfer iflag=fullblock >out 2>err || fail=1
+echo "a
+b" > out_ok
+echo "1+0 records in
+1+0 records out" > err_ok
+compare out out_ok || fail=1
+compare err err_ok || fail=1
+
 test $fail -eq 0 && fail=$warn
 
 (exit $fail); exit $fail
 test $fail -eq 0 && fail=$warn
 
 (exit $fail); exit $fail