|
@@ -59,7 +59,7 @@
|
|
|
//usage: "[if=FILE] [of=FILE] [" IF_FEATURE_DD_IBS_OBS("ibs=N obs=N/") "bs=N] [count=N] [skip=N] [seek=N]\n"
|
|
|
//usage: IF_FEATURE_DD_IBS_OBS(
|
|
|
//usage: " [conv=notrunc|noerror|sync|fsync]\n"
|
|
|
-//usage: " [iflag=skip_bytes|fullblock] [oflag=seek_bytes|append]"
|
|
|
+//usage: " [iflag=skip_bytes|fullblock|direct] [oflag=seek_bytes|append|direct]"
|
|
|
//usage: )
|
|
|
//usage:#define dd_full_usage "\n\n"
|
|
|
//usage: "Copy a file with converting and formatting\n"
|
|
@@ -82,9 +82,11 @@
|
|
|
//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 Read full blocks"
|
|
|
//usage: "\n oflag=seek_bytes seek=N is in bytes"
|
|
|
-//usage: "\n oflag=append Open output file in append mode"
|
|
|
+//usage: "\n iflag=direct O_DIRECT input"
|
|
|
+//usage: "\n oflag=direct O_DIRECT output"
|
|
|
+//usage: "\n iflag=fullblock Read full blocks"
|
|
|
+//usage: "\n oflag=append Open output in append mode"
|
|
|
//usage: )
|
|
|
//usage: IF_FEATURE_DD_STATUS(
|
|
|
//usage: "\n status=noxfer Suppress rate output"
|
|
@@ -137,16 +139,18 @@ enum {
|
|
|
FLAG_IFLAG_SHIFT = 5,
|
|
|
FLAG_SKIP_BYTES = (1 << 5) * ENABLE_FEATURE_DD_IBS_OBS,
|
|
|
FLAG_FULLBLOCK = (1 << 6) * ENABLE_FEATURE_DD_IBS_OBS,
|
|
|
+ FLAG_IDIRECT = (1 << 7) * ENABLE_FEATURE_DD_IBS_OBS,
|
|
|
/* end of input flags */
|
|
|
/* start of output flags */
|
|
|
- FLAG_OFLAG_SHIFT = 7,
|
|
|
- FLAG_SEEK_BYTES = (1 << 7) * ENABLE_FEATURE_DD_IBS_OBS,
|
|
|
- FLAG_APPEND = (1 << 8) * ENABLE_FEATURE_DD_IBS_OBS,
|
|
|
+ FLAG_OFLAG_SHIFT = 8,
|
|
|
+ FLAG_SEEK_BYTES = (1 << 8) * ENABLE_FEATURE_DD_IBS_OBS,
|
|
|
+ FLAG_APPEND = (1 << 9) * ENABLE_FEATURE_DD_IBS_OBS,
|
|
|
+ FLAG_ODIRECT = (1 << 10) * ENABLE_FEATURE_DD_IBS_OBS,
|
|
|
/* end of output flags */
|
|
|
- FLAG_TWOBUFS = (1 << 9) * ENABLE_FEATURE_DD_IBS_OBS,
|
|
|
- FLAG_COUNT = 1 << 10,
|
|
|
- FLAG_STATUS_NONE = 1 << 11,
|
|
|
- FLAG_STATUS_NOXFER = 1 << 12,
|
|
|
+ FLAG_TWOBUFS = (1 << 11) * ENABLE_FEATURE_DD_IBS_OBS,
|
|
|
+ FLAG_COUNT = 1 << 12,
|
|
|
+ FLAG_STATUS_NONE = 1 << 13,
|
|
|
+ FLAG_STATUS_NOXFER = 1 << 14,
|
|
|
};
|
|
|
|
|
|
static void dd_output_status(int UNUSED_PARAM cur_signal)
|
|
@@ -192,12 +196,50 @@ static void dd_output_status(int UNUSED_PARAM cur_signal)
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
+#if ENABLE_FEATURE_DD_IBS_OBS
|
|
|
+static int clear_O_DIRECT(int fd)
|
|
|
+{
|
|
|
+ if (errno == EINVAL) {
|
|
|
+ int fl = fcntl(fd, F_GETFL);
|
|
|
+ if (fl & O_DIRECT) {
|
|
|
+ fcntl(fd, F_SETFL, fl & ~O_DIRECT);
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+static ssize_t dd_read(void *ibuf, size_t ibs)
|
|
|
+{
|
|
|
+ ssize_t n;
|
|
|
+
|
|
|
+#if ENABLE_FEATURE_DD_IBS_OBS
|
|
|
+ read_again:
|
|
|
+ if (G.flags & FLAG_FULLBLOCK)
|
|
|
+ n = full_read(ifd, ibuf, ibs);
|
|
|
+ else
|
|
|
+#endif
|
|
|
+ n = safe_read(ifd, ibuf, ibs);
|
|
|
+#if ENABLE_FEATURE_DD_IBS_OBS
|
|
|
+ if (n < 0 && (G.flags & FLAG_IDIRECT) && clear_O_DIRECT(ifd))
|
|
|
+ goto read_again;
|
|
|
+#endif
|
|
|
+ return n;
|
|
|
+}
|
|
|
+
|
|
|
static bool write_and_stats(const void *buf, size_t len, size_t obs,
|
|
|
const char *filename)
|
|
|
{
|
|
|
ssize_t n;
|
|
|
|
|
|
+ IF_FEATURE_DD_IBS_OBS(write_again:)
|
|
|
n = full_write(ofd, buf, len);
|
|
|
+#if ENABLE_FEATURE_DD_IBS_OBS
|
|
|
+ if (n < 0 && (G.flags & FLAG_ODIRECT) && clear_O_DIRECT(ofd))
|
|
|
+ goto write_again;
|
|
|
+#endif
|
|
|
+
|
|
|
#if ENABLE_FEATURE_DD_THIRD_STATUS_LINE
|
|
|
if (n > 0)
|
|
|
G.total_bytes += n;
|
|
@@ -254,6 +296,14 @@ static int parse_comma_flags(char *val, const char *words, const char *error_in)
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
+static void *alloc_buf(size_t size)
|
|
|
+{
|
|
|
+ /* Important for "{i,o}flag=direct" - buffers must be page aligned */
|
|
|
+ if (size >= bb_getpagesize())
|
|
|
+ return xmmap_anon(size);
|
|
|
+ return xmalloc(size);
|
|
|
+}
|
|
|
+
|
|
|
int dd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
|
|
int dd_main(int argc UNUSED_PARAM, char **argv)
|
|
|
{
|
|
@@ -267,9 +317,9 @@ 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""fullblock\0";
|
|
|
+ "skip_bytes\0""fullblock\0""direct\0";
|
|
|
static const char oflag_words[] ALIGN1 =
|
|
|
- "seek_bytes\0append\0";
|
|
|
+ "seek_bytes\0append\0""direct\0";
|
|
|
#endif
|
|
|
#if ENABLE_FEATURE_DD_STATUS
|
|
|
static const char status_words[] ALIGN1 =
|
|
@@ -310,7 +360,9 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
|
|
|
//swab swap every pair of input bytes: will abort on non-even reads
|
|
|
OP_iflag_skip_bytes,
|
|
|
OP_iflag_fullblock,
|
|
|
+ OP_iflag_direct,
|
|
|
OP_oflag_seek_bytes,
|
|
|
+ OP_oflag_direct,
|
|
|
#endif
|
|
|
};
|
|
|
smallint exitcode = EXIT_FAILURE;
|
|
@@ -426,13 +478,12 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
|
|
|
#endif
|
|
|
} /* end of "for (argv[i])" */
|
|
|
|
|
|
-//XXX:FIXME for huge ibs or obs, malloc'ing them isn't the brightest idea ever
|
|
|
- ibuf = xmalloc(ibs);
|
|
|
+ ibuf = alloc_buf(ibs);
|
|
|
obuf = ibuf;
|
|
|
#if ENABLE_FEATURE_DD_IBS_OBS
|
|
|
if (ibs != obs) {
|
|
|
G.flags |= FLAG_TWOBUFS;
|
|
|
- obuf = xmalloc(obs);
|
|
|
+ obuf = alloc_buf(obs);
|
|
|
}
|
|
|
#endif
|
|
|
|
|
@@ -444,7 +495,12 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
|
|
|
#endif
|
|
|
|
|
|
if (infile) {
|
|
|
- xmove_fd(xopen(infile, O_RDONLY), ifd);
|
|
|
+ int iflag = O_RDONLY;
|
|
|
+#if ENABLE_FEATURE_DD_IBS_OBS
|
|
|
+ if (G.flags & FLAG_IDIRECT)
|
|
|
+ iflag |= O_DIRECT;
|
|
|
+#endif
|
|
|
+ xmove_fd(xopen(infile, iflag), ifd);
|
|
|
} else {
|
|
|
infile = bb_msg_standard_input;
|
|
|
}
|
|
@@ -455,7 +511,10 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
|
|
|
oflag |= O_TRUNC;
|
|
|
if (G.flags & FLAG_APPEND)
|
|
|
oflag |= O_APPEND;
|
|
|
-
|
|
|
+#if ENABLE_FEATURE_DD_IBS_OBS
|
|
|
+ if (G.flags & FLAG_ODIRECT)
|
|
|
+ oflag |= O_DIRECT;
|
|
|
+#endif
|
|
|
xmove_fd(xopen(outfile, oflag), ofd);
|
|
|
|
|
|
if (seek && !(G.flags & FLAG_NOTRUNC)) {
|
|
@@ -478,13 +537,7 @@ 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;
|
|
|
-#if ENABLE_FEATURE_DD_IBS_OBS
|
|
|
- if (G.flags & FLAG_FULLBLOCK)
|
|
|
- n = full_read(ifd, ibuf, blocksz);
|
|
|
- else
|
|
|
-#endif
|
|
|
- n = safe_read(ifd, ibuf, blocksz);
|
|
|
+ ssize_t n = dd_read(ibuf, blocksz);
|
|
|
if (n < 0)
|
|
|
goto die_infile;
|
|
|
if (n == 0)
|
|
@@ -499,13 +552,7 @@ 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
|
|
|
-#endif
|
|
|
- n = safe_read(ifd, ibuf, ibs);
|
|
|
+ ssize_t n = dd_read(ibuf, ibs);
|
|
|
if (n == 0)
|
|
|
break;
|
|
|
if (n < 0) {
|
|
@@ -600,11 +647,13 @@ int dd_main(int argc UNUSED_PARAM, char **argv)
|
|
|
if (!ENABLE_FEATURE_DD_STATUS || !(G.flags & FLAG_STATUS_NONE))
|
|
|
dd_output_status(0);
|
|
|
|
|
|
+#if 0 /* can't just free(), they can be mmap()ed */
|
|
|
if (ENABLE_FEATURE_CLEAN_UP) {
|
|
|
free(obuf);
|
|
|
if (G.flags & FLAG_TWOBUFS)
|
|
|
free(ibuf);
|
|
|
}
|
|
|
+#endif
|
|
|
|
|
|
return exitcode;
|
|
|
}
|