10de1c1
From 9f8be4b0b83d1e0cbf1326f8cb7e077d026d9b0b Mon Sep 17 00:00:00 2001
10de1c1
From: Kamil Dudka <kdudka@redhat.com>
10de1c1
Date: Wed, 23 Jul 2008 11:29:21 +0200
10de1c1
Subject: [PATCH] dd: iflag=fullblock now read full blocks if possible
10de1c1
* src/dd.c (iread_fullblock): New function for reading full blocks.
10de1c1
(scanargs): Check for new parameter iflag=fullblock.
10de1c1
(skip): Use iread_fnc pointer instead of iread function.
10de1c1
(dd_copy): Use iread_fnc pointer instead of iread function.
10de1c1
* tests/dd/misc: Add test for dd - read full blocks.
10de1c1
* doc/coretuils.texi: Mention new parameter iflag=fullblock.
10de1c1
* NEWS: Mentioned the change.
10de1c1
10de1c1
---
10de1c1
 NEWS               |    4 ++++
10de1c1
 doc/coreutils.texi |    6 ++++++
10de1c1
 src/dd.c           |   39 +++++++++++++++++++++++++++++++++++++--
10de1c1
 tests/dd/misc      |    9 +++++++++
10de1c1
 4 files changed, 56 insertions(+), 2 deletions(-)
10de1c1
10de1c1
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
10de1c1
index 81e3b91..b95f8dc 100644
10de1c1
--- a/doc/coreutils.texi
10de1c1
+++ b/doc/coreutils.texi
10de1c1
@@ -7719,6 +7719,12 @@ platforms that distinguish binary from text I/O.
10de1c1
 Use text I/O.  Like @samp{binary}, this option has no effect on
10de1c1
 standard platforms.
10de1c1
 
10de1c1
+@item fullblock
10de1c1
+@opindex fullblock
10de1c1
+Read full blocks from input if possible. read() may return early
10de1c1
+if a full block is not available, so retry until data is available
10de1c1
+or end of file is reached. This flag can be used only for the iflag option.
10de1c1
+
10de1c1
 @end table
10de1c1
 
10de1c1
 These flags are not supported on all systems, and @samp{dd} rejects
10de1c1
diff --git a/src/dd.c b/src/dd.c
10de1c1
index ead9574..1b620df 100644
10de1c1
--- a/src/dd.c
10de1c1
+++ b/src/dd.c
10de1c1
@@ -225,6 +225,9 @@ static sig_atomic_t volatile interrupt_signal;
10de1c1
 /* A count of the number of pending info signals that have been received.  */
10de1c1
 static sig_atomic_t volatile info_signal_count;
10de1c1
 
10de1c1
+/* Function used for read (to handle iflag=fullblock parameter) */
10de1c1
+static ssize_t (*iread_fnc) (int fd, char *buf, size_t size);
10de1c1
+
10de1c1
 /* A longest symbol in the struct symbol_values tables below.  */
10de1c1
 #define LONGEST_SYMBOL "fdatasync"
10de1c1
 
10de1c1
@@ -257,6 +260,7 @@ static struct symbol_value const conversions[] =
10de1c1
 };
10de1c1
 
10de1c1
 /* Flags, for iflag="..." and oflag="...".  */
10de1c1
+#define O_FULLBLOCK 010000000 /* Read only full blocks from input */
10de1c1
 static struct symbol_value const flags[] =
10de1c1
 {
10de1c1
   {"append",	O_APPEND},
10de1c1
@@ -271,6 +275,7 @@ static struct symbol_value const flags[] =
10de1c1
   {"nonblock",	O_NONBLOCK},
10de1c1
   {"sync",	O_SYNC},
10de1c1
   {"text",	O_TEXT},
10de1c1
+  {"fullblock", O_FULLBLOCK}, /* Read only full blocks from input */
10de1c1
   {"",		0}
10de1c1
 };
10de1c1
 
10de1c1
@@ -762,6 +767,27 @@ iread (int fd, char *buf, size_t size)
10de1c1
     }
10de1c1
 }
10de1c1
 
10de1c1
+/* Wrapper around iread function which reads full blocks if possible */
10de1c1
+static ssize_t
10de1c1
+iread_fullblock (int fd, char *buf, size_t size)
10de1c1
+{
10de1c1
+  ssize_t nread = 0;
10de1c1
+
10de1c1
+  while (0 < size)
10de1c1
+    {
10de1c1
+      ssize_t ncurr = iread(fd, buf, size);
10de1c1
+      if (ncurr < 0)
10de1c1
+	return ncurr;
10de1c1
+      if (ncurr == 0)
10de1c1
+	break;
10de1c1
+      nread += ncurr;
10de1c1
+      buf   += ncurr;
10de1c1
+      size  -= ncurr;
10de1c1
+    }
10de1c1
+
10de1c1
+  return nread;
10de1c1
+}
10de1c1
+
10de1c1
 /* Write to FD the buffer BUF of size SIZE, processing any signals
10de1c1
    that arrive.  Return the number of bytes written, setting errno if
10de1c1
    this is less than SIZE.  Keep trying if there are partial
10de1c1
@@ -1000,6 +1026,15 @@ scanargs (int argc, char *const *argv)
10de1c1
   if (input_flags & (O_DSYNC | O_SYNC))
10de1c1
     input_flags |= O_RSYNC;
10de1c1
 
10de1c1
+  if (output_flags & O_FULLBLOCK)
10de1c1
+    {
10de1c1
+      error (0, 0, "%s: %s", _("invalid output flag"), "'fullblock'");
10de1c1
+      usage (EXIT_FAILURE);
10de1c1
+    }
10de1c1
+  iread_fnc = (input_flags & O_FULLBLOCK)?
10de1c1
+    iread_fullblock:
10de1c1
+    iread;
10de1c1
+
10de1c1
   if (multiple_bits_set (conversions_mask & (C_ASCII | C_EBCDIC | C_IBM)))
10de1c1
     error (EXIT_FAILURE, 0, _("cannot combine any two of {ascii,ebcdic,ibm}"));
10de1c1
   if (multiple_bits_set (conversions_mask & (C_BLOCK | C_UNBLOCK)))
10de1c1
@@ -1197,7 +1232,7 @@ skip (int fdesc, char const *file, uintmax_t records, size_t blocksize,
10de1c1
 
10de1c1
       do
10de1c1
 	{
10de1c1
-	  ssize_t nread = iread (fdesc, buf, blocksize);
10de1c1
+	  ssize_t nread = iread_fnc (fdesc, buf, blocksize);
10de1c1
 	  if (nread < 0)
10de1c1
 	    {
10de1c1
 	      if (fdesc == STDIN_FILENO)
10de1c1
@@ -1508,7 +1543,7 @@ dd_copy (void)
10de1c1
 		(conversions_mask & (C_BLOCK | C_UNBLOCK)) ? ' ' : '\0',
10de1c1
 		input_blocksize);
10de1c1
 
10de1c1
-      nread = iread (STDIN_FILENO, ibuf, input_blocksize);
10de1c1
+      nread = iread_fnc (STDIN_FILENO, ibuf, input_blocksize);
10de1c1
 
10de1c1
       if (nread == 0)
10de1c1
 	break;			/* EOF.  */
10de1c1
diff --git a/tests/dd/misc b/tests/dd/misc
10de1c1
index d54fbfa..24e5eba 100755
10de1c1
--- a/tests/dd/misc
10de1c1
+++ b/tests/dd/misc
10de1c1
@@ -88,6 +88,15 @@ fi
10de1c1
 outbytes=`echo x | dd bs=3 ibs=10 obs=10 conv=sync 2>/dev/null | wc -c`
10de1c1
 test "$outbytes" -eq 3 || fail=1
10de1c1
 
10de1c1
+(echo a; sleep .1; echo b) \
10de1c1
+  | LC_ALL=C dd bs=4 status=noxfer iflag=fullblock >out 2>err || fail=1
10de1c1
+echo "a
10de1c1
+b" > out_ok
10de1c1
+echo "1+0 records in
10de1c1
+1+0 records out" > err_ok
10de1c1
+compare out out_ok || fail=1
10de1c1
+compare err err_ok || fail=1
10de1c1
+
10de1c1
 test $fail -eq 0 && fail=$warn
10de1c1
 
10de1c1
 (exit $fail); exit $fail
10de1c1
diff -ruN coreutils-6.12.old/doc/coreutils.info coreutils-6.12/doc/coreutils.info
10de1c1
--- coreutils-6.12.old/doc/coreutils.info	2008-07-24 12:49:57.000000000 +0200
10de1c1
+++ coreutils-6.12/doc/coreutils.info	2008-07-24 12:52:17.000000000 +0200
10de1c1
@@ -6112,6 +6112,12 @@
10de1c1
           Use text I/O.  Like `binary', this option has no effect on
10de1c1
           standard platforms.
10de1c1
 
10de1c1
+    'fullblock'
10de1c1
+          Read full blocks from input if possible. read() may return
10de1c1
+	  early if a full block is not available, so retry until data
10de1c1
+	  is available or end of file is reached. This flag can be used
10de1c1
+	  only for the iflag option.
10de1c1
+
10de1c1
 
10de1c1
      These flags are not supported on all systems, and `dd' rejects
10de1c1
      attempts to use them when they are not supported.  When reading
10de1c1
diff -ruN coreutils-6.12.old/man/dd.1 coreutils-6.12/man/dd.1
10de1c1
--- coreutils-6.12.old/man/dd.1	2008-07-24 12:51:06.000000000 +0200
10de1c1
+++ coreutils-6.12/man/dd.1	2008-07-24 12:59:06.000000000 +0200
10de1c1
@@ -111,6 +111,13 @@
10de1c1
 .TP
10de1c1
 direct
10de1c1
 use direct I/O for data
10de1c1
+.PP
10de1c1
+FLAG symbols only for iflag option:
10de1c1
+.TP
10de1c1
+fullblock
10de1c1
+Read full blocks from input if possible. read() may return early
10de1c1
+if a full block is not available, so retry until data is available
10de1c1
+or end of file is reached.
10de1c1
 .IP
10de1c1
 directory fail unless a directory
10de1c1
 dsync     use synchronized I/O for data