From e8df666c2e0e122dc57f18ebd0b7abc15adac623 Mon Sep 17 00:00:00 2001 From: Jeffrey Finkelstein Date: Sun, 23 Jan 2022 10:45:17 -0500 Subject: [PATCH] dd: support seek=N when destination is stdout Add support for the `seek=N` argument when the destination is stdout and not a file. Previously, the argument was ignored when writing to stdout. --- src/uu/dd/src/dd.rs | 13 +++++++++++-- tests/by-util/test_dd.rs | 14 +++++++++++++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/uu/dd/src/dd.rs b/src/uu/dd/src/dd.rs index 3e8cd19c4..0cac95431 100644 --- a/src/uu/dd/src/dd.rs +++ b/src/uu/dd/src/dd.rs @@ -5,7 +5,7 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -// spell-checker:ignore fname, tname, fpath, specfile, testfile, unspec, ifile, ofile, outfile, fullblock, urand, fileio, atoe, atoibm, behaviour, bmax, bremain, btotal, cflags, creat, ctable, ctty, datastructures, doesnt, etoa, fileout, fname, gnudd, iconvflags, nocache, noctty, noerror, nofollow, nolinks, nonblock, oconvflags, outfile, parseargs, rlen, rmax, rposition, rremain, rsofar, rstat, sigusr, sigval, wlen, wstat +// spell-checker:ignore fname, tname, fpath, specfile, testfile, unspec, ifile, ofile, outfile, fullblock, urand, fileio, atoe, atoibm, behaviour, bmax, bremain, btotal, cflags, creat, ctable, ctty, datastructures, doesnt, etoa, fileout, fname, gnudd, iconvflags, nocache, noctty, noerror, nofollow, nolinks, nonblock, oconvflags, outfile, parseargs, rlen, rmax, rposition, rremain, rsofar, rstat, sigusr, sigval, wlen, wstat seekable #[cfg(test)] mod dd_unit_tests; @@ -294,8 +294,17 @@ impl OutputTrait for Output { fn new(matches: &Matches) -> UResult { let obs = parseargs::parse_obs(matches)?; let cflags = parseargs::parse_conv_flag_output(matches)?; + let oflags = parseargs::parse_oflags(matches)?; + let seek = parseargs::parse_seek_amt(&obs, &oflags, matches)?; - let dst = io::stdout(); + let mut dst = io::stdout(); + + // stdout is not seekable, so we just write null bytes. + if let Some(amt) = seek { + let bytes = vec![b'\0'; amt]; + dst.write_all(&bytes) + .map_err_context(|| String::from("write error"))?; + } Ok(Output { dst, obs, cflags }) } diff --git a/tests/by-util/test_dd.rs b/tests/by-util/test_dd.rs index 43a59808a..3b3706e22 100644 --- a/tests/by-util/test_dd.rs +++ b/tests/by-util/test_dd.rs @@ -1,4 +1,4 @@ -// spell-checker:ignore fname, tname, fpath, specfile, testfile, unspec, ifile, ofile, outfile, fullblock, urand, fileio, atoe, atoibm, availible, behaviour, bmax, bremain, btotal, cflags, creat, ctable, ctty, datastructures, doesnt, etoa, fileout, fname, gnudd, iconvflags, nocache, noctty, noerror, nofollow, nolinks, nonblock, oconvflags, outfile, parseargs, rlen, rmax, rposition, rremain, rsofar, rstat, sigusr, sigval, wlen, wstat +// spell-checker:ignore fname, tname, fpath, specfile, testfile, unspec, ifile, ofile, outfile, fullblock, urand, fileio, atoe, atoibm, availible, behaviour, bmax, bremain, btotal, cflags, creat, ctable, ctty, datastructures, doesnt, etoa, fileout, fname, gnudd, iconvflags, nocache, noctty, noerror, nofollow, nolinks, nonblock, oconvflags, outfile, parseargs, rlen, rmax, rposition, rremain, rsofar, rstat, sigusr, sigval, wlen, wstat abcdefghijklm use crate::common::util::*; @@ -592,5 +592,17 @@ fn test_conv_ebcdic_implies_block() { .stdout_is_bytes(b"\x40\xc1\x40\xc1\x40\xc1\x40\x40"); } +/// Test for seeking forward N bytes in the output file before copying. +#[test] +fn test_seek_bytes() { + // Since the output file is stdout, seeking forward by eight bytes + // results in a prefix of eight null bytes. + new_ucmd!() + .args(&["seek=8", "oflag=seek_bytes"]) + .pipe_in("abcdefghijklm\n") + .succeeds() + .stdout_is("\0\0\0\0\0\0\0\0abcdefghijklm\n"); +} + // conv=[ascii,ebcdic,ibm], conv=[ucase,lcase], conv=[block,unblock], conv=sync // TODO: Move conv tests from unit test module