diff --git a/src/uu/csplit/src/csplit.rs b/src/uu/csplit/src/csplit.rs index d654c9271..501f97582 100644 --- a/src/uu/csplit/src/csplit.rs +++ b/src/uu/csplit/src/csplit.rs @@ -87,7 +87,11 @@ pub fn csplit(options: &CsplitOptions, patterns: &[String], input: T) -> Resu where T: BufRead, { - let mut input_iter = InputSplitter::new(input.lines().enumerate()); + let enumerated_input_lines = input + .lines() + .map(|line| line.map_err_context(|| "read error".to_string())) + .enumerate(); + let mut input_iter = InputSplitter::new(enumerated_input_lines); let mut split_writer = SplitWriter::new(options); let patterns: Vec = patterns::get_patterns(patterns)?; let ret = do_csplit(&mut split_writer, patterns, &mut input_iter); @@ -117,7 +121,7 @@ fn do_csplit( input_iter: &mut InputSplitter, ) -> Result<(), CsplitError> where - I: Iterator)>, + I: Iterator)>, { // split the file based on patterns for pattern in patterns { @@ -305,7 +309,7 @@ impl SplitWriter<'_> { input_iter: &mut InputSplitter, ) -> Result<(), CsplitError> where - I: Iterator)>, + I: Iterator)>, { input_iter.rewind_buffer(); input_iter.set_size_of_buffer(1); @@ -358,7 +362,7 @@ impl SplitWriter<'_> { input_iter: &mut InputSplitter, ) -> Result<(), CsplitError> where - I: Iterator)>, + I: Iterator)>, { if offset >= 0 { // The offset is zero or positive, no need for a buffer on the lines read. @@ -470,7 +474,7 @@ impl SplitWriter<'_> { /// This is used to pass matching lines to the next split and to support patterns with a negative offset. struct InputSplitter where - I: Iterator)>, + I: Iterator)>, { iter: I, buffer: Vec<::Item>, @@ -483,7 +487,7 @@ where impl InputSplitter where - I: Iterator)>, + I: Iterator)>, { fn new(iter: I) -> Self { Self { @@ -547,7 +551,7 @@ where impl Iterator for InputSplitter where - I: Iterator)>, + I: Iterator)>, { type Item = ::Item; @@ -581,13 +585,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { Ok(csplit(&options, &patterns, stdin.lock())?) } else { let file = File::open(file_name) - .map_err_context(|| format!("cannot access {}", file_name.quote()))?; - let file_metadata = file - .metadata() - .map_err_context(|| format!("cannot access {}", file_name.quote()))?; - if !file_metadata.is_file() { - return Err(CsplitError::NotRegularFile(file_name.to_string()).into()); - } + .map_err_context(|| format!("cannot open {} for reading", file_name.quote()))?; Ok(csplit(&options, &patterns, BufReader::new(file))?) } } diff --git a/src/uu/csplit/src/csplit_error.rs b/src/uu/csplit/src/csplit_error.rs index 4a83b637b..ac1c8d01c 100644 --- a/src/uu/csplit/src/csplit_error.rs +++ b/src/uu/csplit/src/csplit_error.rs @@ -35,6 +35,8 @@ pub enum CsplitError { SuffixFormatTooManyPercents, #[error("{} is not a regular file", ._0.quote())] NotRegularFile(String), + #[error("{}", _0)] + UError(Box), } impl From for CsplitError { @@ -43,8 +45,17 @@ impl From for CsplitError { } } -impl UError for CsplitError { - fn code(&self) -> i32 { - 1 +impl From> for CsplitError { + fn from(error: Box) -> Self { + Self::UError(error) + } +} + +impl UError for CsplitError { + fn code(&self) -> i32 { + match self { + Self::UError(e) => e.code(), + _ => 1, + } } } diff --git a/tests/by-util/test_csplit.rs b/tests/by-util/test_csplit.rs index 9323b9851..38f5c97bf 100644 --- a/tests/by-util/test_csplit.rs +++ b/tests/by-util/test_csplit.rs @@ -1379,7 +1379,7 @@ fn no_such_file() { let (_, mut ucmd) = at_and_ucmd!(); ucmd.args(&["in", "0"]) .fails() - .stderr_contains("cannot access 'in': No such file or directory"); + .stderr_contains("cannot open 'in' for reading: No such file or directory"); } #[test] @@ -1417,3 +1417,52 @@ fn repeat_everything() { assert_eq!(at.read("xxz_004"), generate(37, 44 + 1)); assert_eq!(at.read("xxz_005"), generate(46, 50 + 1)); } + +#[cfg(unix)] +#[test] +fn test_named_pipe_input_file() { + let (at, mut ucmd) = at_and_ucmd!(); + + let mut fifo_writer = + create_named_pipe_with_writer(&at.plus_as_string("fifo"), &generate(1, 51)); + + let result = ucmd.args(&["fifo", "10"]).succeeds(); + fifo_writer.kill().unwrap(); + fifo_writer.wait().unwrap(); + result.stdout_only("18\n123\n"); + + let count = glob(&at.plus_as_string("xx*")) + .expect("there should be splits created") + .count(); + assert_eq!(count, 2); + assert_eq!(at.read("xx00"), generate(1, 10)); + assert_eq!(at.read("xx01"), generate(10, 51)); +} + +#[cfg(unix)] +fn create_named_pipe_with_writer(path: &str, data: &str) -> std::process::Child { + // cSpell:ignore IRWXU + nix::unistd::mkfifo(path, nix::sys::stat::Mode::S_IRWXU).unwrap(); + std::process::Command::new("sh") + .arg("-c") + .arg(format!("printf '{}' > {path}", data)) + .spawn() + .unwrap() +} + +#[test] +fn test_directory_input_file() { + let (at, mut ucmd) = at_and_ucmd!(); + at.mkdir("test_directory"); + + #[cfg(unix)] + ucmd.args(&["test_directory", "1"]) + .fails() + .code_is(1) + .stderr_only("csplit: read error: Is a directory\n"); + #[cfg(windows)] + ucmd.args(&["test_directory", "1"]) + .fails() + .code_is(1) + .stderr_only("csplit: cannot open 'test_directory' for reading: Permission denied\n"); +}