mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 03:27:44 +00:00
dd: truncate to specified seek length
When specifying `seek=N` and *not* specifying `conv=notrunc`, truncate the output file to `N` blocks instead of truncating it to zero before starting to write output. For example $ printf "abc" > outfile $ printf "123" | dd bs=1 skip=1 seek=1 count=1 status=noxfer of=outfile 1+0 records in 1+0 records out $ cat outfile a2 Fixes #3068.
This commit is contained in:
parent
ebf33d775e
commit
1af709f642
2 changed files with 28 additions and 7 deletions
|
@ -469,7 +469,6 @@ impl OutputTrait for Output<File> {
|
||||||
let mut opts = OpenOptions::new();
|
let mut opts = OpenOptions::new();
|
||||||
opts.write(true)
|
opts.write(true)
|
||||||
.create(!cflags.nocreat)
|
.create(!cflags.nocreat)
|
||||||
.truncate(!cflags.notrunc)
|
|
||||||
.create_new(cflags.excl)
|
.create_new(cflags.excl)
|
||||||
.append(oflags.append);
|
.append(oflags.append);
|
||||||
|
|
||||||
|
@ -489,13 +488,13 @@ impl OutputTrait for Output<File> {
|
||||||
let mut dst = open_dst(Path::new(&fname), &cflags, &oflags)
|
let mut dst = open_dst(Path::new(&fname), &cflags, &oflags)
|
||||||
.map_err_context(|| format!("failed to open {}", fname.quote()))?;
|
.map_err_context(|| format!("failed to open {}", fname.quote()))?;
|
||||||
|
|
||||||
if let Some(amt) = seek {
|
let i = seek.unwrap_or(0).try_into().unwrap();
|
||||||
let amt: u64 = amt
|
if !cflags.notrunc {
|
||||||
.try_into()
|
dst.set_len(i)
|
||||||
.map_err(|_| USimpleError::new(1, "failed to parse seek amount"))?;
|
.map_err_context(|| "failed to truncate output file".to_string())?;
|
||||||
dst.seek(io::SeekFrom::Start(amt))
|
|
||||||
.map_err_context(|| "failed to seek in output file".to_string())?;
|
|
||||||
}
|
}
|
||||||
|
dst.seek(io::SeekFrom::Start(i))
|
||||||
|
.map_err_context(|| "failed to seek in output file".to_string())?;
|
||||||
|
|
||||||
Ok(Self { dst, obs, cflags })
|
Ok(Self { dst, obs, cflags })
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -604,5 +604,27 @@ fn test_seek_bytes() {
|
||||||
.stdout_is("\0\0\0\0\0\0\0\0abcdefghijklm\n");
|
.stdout_is("\0\0\0\0\0\0\0\0abcdefghijklm\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_seek_do_not_overwrite() {
|
||||||
|
let (at, mut ucmd) = at_and_ucmd!();
|
||||||
|
let mut outfile = at.make_file("outfile");
|
||||||
|
outfile.write_all(b"abc").unwrap();
|
||||||
|
// Skip the first byte of the input, seek past the first byte of
|
||||||
|
// the output, and write only one byte to the output.
|
||||||
|
ucmd.args(&[
|
||||||
|
"bs=1",
|
||||||
|
"skip=1",
|
||||||
|
"seek=1",
|
||||||
|
"count=1",
|
||||||
|
"status=noxfer",
|
||||||
|
"of=outfile",
|
||||||
|
])
|
||||||
|
.pipe_in("123")
|
||||||
|
.succeeds()
|
||||||
|
.stderr_is("1+0 records in\n1+0 records out\n")
|
||||||
|
.no_stdout();
|
||||||
|
assert_eq!(at.read("outfile"), "a2");
|
||||||
|
}
|
||||||
|
|
||||||
// conv=[ascii,ebcdic,ibm], conv=[ucase,lcase], conv=[block,unblock], conv=sync
|
// conv=[ascii,ebcdic,ibm], conv=[ucase,lcase], conv=[block,unblock], conv=sync
|
||||||
// TODO: Move conv tests from unit test module
|
// TODO: Move conv tests from unit test module
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue