[PATCH] dd: add 'fullblock' iflag.

Nicholas Clark nicholas.clark at gmail.com
Wed Nov 29 20:51:28 UTC 2017


Adds a fullblock iflag for improved compatibility with GNU dd.
The new iflag can be used to ensure that dd calls retrieve the
expected amount of data when reading from pipes or unusual
filesystems.

Signed-off-by: Nicholas Clark <nicholas.clark at gmail.com>
---
 coreutils/dd.c             | 64 +++++++++++++++++++++++++++++++++++++++-------
 docs/posix_conformance.txt |  5 ++--
 2 files changed, 58 insertions(+), 11 deletions(-)

diff --git a/coreutils/dd.c b/coreutils/dd.c
index d302f35d3..760420687 100644
--- a/coreutils/dd.c
+++ b/coreutils/dd.c
@@ -37,7 +37,7 @@
 //config:	elapsed time and speed.
 //config:
 //config:config FEATURE_DD_IBS_OBS
-//config:	bool "Enable ibs, obs and conv options"
+//config:	bool "Enable ibs, obs, iflag and conv options"
 //config:	default y
 //config:	depends on DD
 //config:	help
@@ -57,7 +57,7 @@
 
 //usage:#define dd_trivial_usage
 //usage:       "[if=FILE] [of=FILE] " IF_FEATURE_DD_IBS_OBS("[ibs=N] [obs=N] ") "[bs=N] [count=N] [skip=N]\n"
-//usage:       "	[seek=N]" IF_FEATURE_DD_IBS_OBS(" [conv=notrunc|noerror|sync|fsync] [iflag=skip_bytes]")
+//usage:       "	[seek=N]" IF_FEATURE_DD_IBS_OBS(" [conv=notrunc|noerror|sync|fsync] [iflag=skip_bytes|fullblock]")
 //usage:#define dd_full_usage "\n\n"
 //usage:       "Copy a file with converting and formatting\n"
 //usage:     "\n	if=FILE		Read from FILE instead of stdin"
@@ -79,6 +79,7 @@
 //usage:     "\n	conv=fsync	Physically write data out before finishing"
 //usage:     "\n	conv=swab	Swap every pair of bytes"
 //usage:     "\n	iflag=skip_bytes	skip=N is in bytes"
+//usage:     "\n	iflag=fullblock	Try to read full blocks from input"
 //usage:	)
 //usage:	IF_FEATURE_DD_STATUS(
 //usage:     "\n	status=noxfer	Suppress rate output"
@@ -110,6 +111,10 @@ struct globals {
 	unsigned long long begin_time_us;
 #endif
 	int flags;
+#if ENABLE_FEATURE_DD_IBS_OBS
+	char warn_en;
+	char previous_partial;
+#endif
 } FIX_ALIASING;
 #define G (*(struct globals*)bb_common_bufsiz1)
 #define INIT_G() do { \
@@ -130,11 +135,13 @@ enum {
 	/* start of input flags */
 	FLAG_IFLAG_SHIFT = 5,
 	FLAG_SKIP_BYTES = (1 << 5) * ENABLE_FEATURE_DD_IBS_OBS,
+	FLAG_FULLBLOCK = (1 << 6) * ENABLE_FEATURE_DD_IBS_OBS,
 	/* end of input flags */
-	FLAG_TWOBUFS = (1 << 6) * ENABLE_FEATURE_DD_IBS_OBS,
-	FLAG_COUNT   = 1 << 7,
-	FLAG_STATUS_NONE = 1 << 8,
-	FLAG_STATUS_NOXFER = 1 << 9,
+	FLAG_TWOBUFS = (1 << 7) * ENABLE_FEATURE_DD_IBS_OBS,
+	FLAG_COUNT   = 1 << 8,
+	FLAG_BS   = 1 << 9,
+	FLAG_STATUS_NONE = 1 << 10,
+	FLAG_STATUS_NOXFER = 1 << 11,
 };
 
 static void dd_output_status(int UNUSED_PARAM cur_signal)
@@ -189,6 +196,25 @@ static ssize_t full_write_or_warn(const void *buf, size_t len,
 	return n;
 }
 
+#if ENABLE_FEATURE_DD_IBS_OBS
+static ssize_t read_and_warn(int fd, void *buf, size_t count)
+{
+	ssize_t result = safe_read(fd, buf, count);
+
+	if (result <= 0) {
+		return result;
+	}
+
+	if (G.previous_partial && G.warn_en) {
+		G.warn_en = 0;
+		bb_error_msg("warn: partial read; suggest iflag=fullblock");
+	}
+
+	G.previous_partial = (result < count);
+	return result;
+}
+#endif
+
 static bool write_and_stats(const void *buf, size_t len, size_t obs,
 	const char *filename)
 {
@@ -251,7 +277,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
 	static const char conv_words[] ALIGN1 =
 		"notrunc\0""sync\0""noerror\0""fsync\0""swab\0";
 	static const char iflag_words[] ALIGN1 =
-		"skip_bytes\0";
+		"skip_bytes\0""fullblock\0";
 #endif
 #if ENABLE_FEATURE_DD_STATUS
 	static const char status_words[] ALIGN1 =
@@ -290,6 +316,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
 	/* Partially implemented: */
 	//swab          swap every pair of input bytes: will abort on non-even reads
 		OP_iflag_skip_bytes,
+		OP_iflag_fullblock,
 #endif
 	};
 	smallint exitcode = EXIT_FAILURE;
@@ -347,6 +374,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
 		if (what == OP_ibs) {
 			/* Must fit into positive ssize_t */
 			ibs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, cwbkMG_suffixes);
+			G.flags |= FLAG_BS;
 			/*continue;*/
 		}
 		if (what == OP_obs) {
@@ -365,6 +393,9 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
 		if (what == OP_bs) {
 			ibs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, cwbkMG_suffixes);
 			obs = ibs;
+#if ENABLE_FEATURE_DD_IBS_OBS
+			G.flags |= FLAG_BS;
+#endif
 			/*continue;*/
 		}
 		/* These can be large: */
@@ -405,6 +436,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
 	ibuf = xmalloc(ibs);
 	obuf = ibuf;
 #if ENABLE_FEATURE_DD_IBS_OBS
+	G.warn_en = (G.flags & (FLAG_BS + FLAG_COUNT)) == (FLAG_BS + FLAG_COUNT);
 	if (ibs != obs) {
 		G.flags |= FLAG_TWOBUFS;
 		obuf = xmalloc(obs);
@@ -450,7 +482,15 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
 		size_t blocksz = (G.flags & FLAG_SKIP_BYTES) ? 1 : ibs;
 		if (lseek(ifd, skip * blocksz, SEEK_CUR) < 0) {
 			do {
-				ssize_t n = safe_read(ifd, ibuf, blocksz);
+				ssize_t n;
+#if ENABLE_FEATURE_DD_IBS_OBS
+				if (G.flags & FLAG_FULLBLOCK)
+					n = full_read(ifd, ibuf, blocksz);
+				else
+					n = read_and_warn(ifd, ibuf, blocksz);
+#else
+				n = safe_read(ifd, ibuf, blocksz);
+#endif
 				if (n < 0)
 					goto die_infile;
 				if (n == 0)
@@ -465,8 +505,14 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
 
 	while (!(G.flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) {
 		ssize_t n;
-
+#if ENABLE_FEATURE_DD_IBS_OBS
+		if (G.flags & FLAG_FULLBLOCK)
+			n = full_read(ifd, ibuf, ibs);
+		else
+			n = read_and_warn(ifd, ibuf, ibs);
+#else
 		n = safe_read(ifd, ibuf, ibs);
+#endif
 		if (n == 0)
 			break;
 		if (n < 0) {
diff --git a/docs/posix_conformance.txt b/docs/posix_conformance.txt
index 8b9112020..cdf89b744 100644
--- a/docs/posix_conformance.txt
+++ b/docs/posix_conformance.txt
@@ -178,9 +178,10 @@ dd POSIX options:
   conv=noerror    |  yes   |           |
   conv=notrunc    |  yes   |           |
   conv=sync       |  yes   |           |
+dd compatibility options:
+  conv=fsync      |  yes   |           |
   iflag=skip_bytes|  yes   |           |
-dd Busybox specific options:
- conv=fsync
+  iflag=fullblock |  yes   |           |
 
 df POSIX options
  option           | exists | compliant | remarks
-- 
2.14.1



More information about the busybox mailing list