diff --git a/src/uu/dd/src/dd.rs b/src/uu/dd/src/dd.rs index 5ea49cc84..fe26bd12a 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 2c3864d0c..e73fe0673 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