diff --git a/src/uu/cat/src/cat.rs b/src/uu/cat/src/cat.rs index 9aeb3ca150..544af3138f 100644 --- a/src/uu/cat/src/cat.rs +++ b/src/uu/cat/src/cat.rs @@ -467,6 +467,13 @@ fn write_fast(handle: &mut InputHandle) -> CatResult<()> { } stdout_lock.write_all(&buf[..n])?; } + + // If the splice() call failed and there has been some data written to + // stdout via while loop above AND there will be second splice() call + // that will succeed, data pushed through splice will be output before + // the data buffered in stdout.lock. Therefore additional explicit flush + // is required here. + stdout_lock.flush()?; Ok(()) } diff --git a/tests/by-util/test_cat.rs b/tests/by-util/test_cat.rs index 8983251873..d9be694365 100644 --- a/tests/by-util/test_cat.rs +++ b/tests/by-util/test_cat.rs @@ -2,7 +2,7 @@ // // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -// spell-checker:ignore NOFILE nonewline +// spell-checker:ignore NOFILE nonewline cmdline #[cfg(not(windows))] use crate::common::util::vec_of_size; @@ -529,6 +529,21 @@ fn test_dev_full_show_all() { proc.kill(); } +// For some reason splice() on first of those files fails, resulting in +// fallback inside `write_fast`, the other splice succeeds, in effect +// without additional flush output gets reversed. +#[test] +#[cfg(target_os = "linux")] +fn test_write_fast_fallthrough_uses_flush() { + const PROC_INIT_CMDLINE: &str = "/proc/1/cmdline"; + let cmdline = std::fs::read_to_string(PROC_INIT_CMDLINE).unwrap(); + + new_ucmd!() + .args(&[PROC_INIT_CMDLINE, "alpha.txt"]) + .succeeds() + .stdout_only(format!("{cmdline}abcde\nfghij\nklmno\npqrst\nuvwxyz\n")); // spell-checker:disable-line +} + #[test] #[cfg(unix)] #[ignore]