mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 03:27:44 +00:00
dd: add support for skipping in input FIFO
For example, `dd skip=1 if=fifo` will now work.
This commit is contained in:
parent
9c3f810f97
commit
c52647a632
2 changed files with 57 additions and 0 deletions
|
@ -99,6 +99,10 @@ enum Source {
|
||||||
|
|
||||||
/// Input from a file.
|
/// Input from a file.
|
||||||
File(File),
|
File(File),
|
||||||
|
|
||||||
|
/// Input from a named pipe, also known as a FIFO.
|
||||||
|
#[cfg(unix)]
|
||||||
|
Fifo(File),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Source {
|
impl Source {
|
||||||
|
@ -113,6 +117,8 @@ impl Source {
|
||||||
Err(e) => Err(e),
|
Err(e) => Err(e),
|
||||||
},
|
},
|
||||||
Self::File(f) => f.seek(io::SeekFrom::Start(n)),
|
Self::File(f) => f.seek(io::SeekFrom::Start(n)),
|
||||||
|
#[cfg(unix)]
|
||||||
|
Self::Fifo(f) => io::copy(&mut f.take(n), &mut io::sink()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,6 +128,8 @@ impl Read for Source {
|
||||||
match self {
|
match self {
|
||||||
Self::Stdin(stdin) => stdin.read(buf),
|
Self::Stdin(stdin) => stdin.read(buf),
|
||||||
Self::File(f) => f.read(buf),
|
Self::File(f) => f.read(buf),
|
||||||
|
#[cfg(unix)]
|
||||||
|
Self::Fifo(f) => f.read(buf),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,6 +179,20 @@ impl<'a> Input<'a> {
|
||||||
}
|
}
|
||||||
Ok(Self { src, settings })
|
Ok(Self { src, settings })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Instantiate this struct with the named pipe as a source.
|
||||||
|
#[cfg(unix)]
|
||||||
|
fn new_fifo(filename: &Path, settings: &'a Settings) -> UResult<Self> {
|
||||||
|
let mut opts = OpenOptions::new();
|
||||||
|
opts.read(true);
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||||
|
opts.custom_flags(make_linux_iflags(&settings.iflags).unwrap_or(0));
|
||||||
|
let mut src = Source::Fifo(opts.open(filename)?);
|
||||||
|
if settings.skip > 0 {
|
||||||
|
src.skip(settings.skip)?;
|
||||||
|
}
|
||||||
|
Ok(Self { src, settings })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||||
|
@ -889,6 +911,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let i = match settings.infile {
|
let i = match settings.infile {
|
||||||
|
#[cfg(unix)]
|
||||||
|
Some(ref infile) if is_fifo(infile) => Input::new_fifo(Path::new(&infile), &settings)?,
|
||||||
Some(ref infile) => Input::new_file(Path::new(&infile), &settings)?,
|
Some(ref infile) => Input::new_file(Path::new(&infile), &settings)?,
|
||||||
None => Input::new_stdin(&settings)?,
|
None => Input::new_stdin(&settings)?,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1481,3 +1481,36 @@ fn test_seek_output_fifo() {
|
||||||
assert!(output.stdout.is_empty());
|
assert!(output.stdout.is_empty());
|
||||||
assert_eq!(&output.stderr, b"1+0 records in\n1+0 records out\n");
|
assert_eq!(&output.stderr, b"1+0 records in\n1+0 records out\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Test that a skip on an input FIFO results in a read.
|
||||||
|
#[test]
|
||||||
|
#[cfg(all(unix, not(target_os = "macos"), not(target_os = "freebsd")))]
|
||||||
|
fn test_skip_input_fifo() {
|
||||||
|
let ts = TestScenario::new(util_name!());
|
||||||
|
let at = &ts.fixtures;
|
||||||
|
at.mkfifo("fifo");
|
||||||
|
|
||||||
|
// TODO When `dd` is a bit more advanced, we could use the uutils
|
||||||
|
// version of dd here as well.
|
||||||
|
let child = Command::new("dd")
|
||||||
|
.current_dir(&at.subdir)
|
||||||
|
.args([
|
||||||
|
"count=1",
|
||||||
|
"if=/dev/zero",
|
||||||
|
&format!("of={}", at.plus_as_string("fifo")),
|
||||||
|
"status=noxfer",
|
||||||
|
])
|
||||||
|
.stderr(Stdio::piped())
|
||||||
|
.spawn()
|
||||||
|
.expect("failed to execute child process");
|
||||||
|
|
||||||
|
ts.ucmd()
|
||||||
|
.args(&["count=0", "skip=1", "if=fifo", "status=noxfer"])
|
||||||
|
.succeeds()
|
||||||
|
.stderr_only("0+0 records in\n0+0 records out\n");
|
||||||
|
|
||||||
|
let output = child.wait_with_output().unwrap();
|
||||||
|
assert!(output.status.success());
|
||||||
|
assert!(output.stdout.is_empty());
|
||||||
|
assert_eq!(&output.stderr, b"1+0 records in\n1+0 records out\n");
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue