diff --git a/src/uu/tee/Cargo.toml b/src/uu/tee/Cargo.toml index d57156545a8..5bd8f3438c1 100644 --- a/src/uu/tee/Cargo.toml +++ b/src/uu/tee/Cargo.toml @@ -22,7 +22,7 @@ doctest = false [dependencies] clap = { workspace = true } rustix = { workspace = true, features = ["stdio", "fs"] } -uucore = { workspace = true, features = ["parser", "signals"] } +uucore = { workspace = true, features = ["fs", "parser", "signals"] } fluent = { workspace = true } [dev-dependencies] diff --git a/src/uu/tee/src/tee.rs b/src/uu/tee/src/tee.rs index f4a5876ee4f..3ba565fe4f3 100644 --- a/src/uu/tee/src/tee.rs +++ b/src/uu/tee/src/tee.rs @@ -7,7 +7,7 @@ use std::ffi::OsString; use std::fs::OpenOptions; -use std::io::{Error, ErrorKind, Read, Result, Write, stderr, stdin, stdout}; +use std::io::{Error, ErrorKind, Read, Result, Write, stderr, stdin}; use std::path::PathBuf; use uucore::display::Quotable; use uucore::error::{UResult, strip_errno}; @@ -80,7 +80,10 @@ fn tee(options: &Options) -> Result<()> { 0, NamedWriter { name: translate!("tee-standard-output").into(), - inner: Writer::Stdout(stdout()), + #[cfg(any(unix, target_os = "wasi"))] + inner: Writer::Stdout(uucore::io::RawWriter(rustix::stdio::stdout())), + #[cfg(not(any(unix, target_os = "wasi")))] + inner: Writer::Stdout(std::io::stdout()), }, ); @@ -197,12 +200,8 @@ impl MultiWriter { fn write_flush(&mut self, buf: &[u8]) -> Result<()> { let mode = self.output_error_mode; - self.writers.retain_mut(|writer| { - let res = (|| { - writer.inner.write_all(buf)?; - writer.inner.flush() - })(); - match res { + self.writers + .retain_mut(|writer| match writer.inner.write_all(buf) { Ok(()) => true, Err(e) => { if let Err(e) = process_error(mode, e, writer, &mut self.ignored_errors) { @@ -210,8 +209,7 @@ impl MultiWriter { } false } - } - }); + }); self.aborted.take().map_or( if self.writers.is_empty() { // This error kind will never be raised by the standard @@ -251,21 +249,26 @@ fn process_error( enum Writer { File(std::fs::File), + // remove buffering for posix requirement and improve throughput + #[cfg(any(unix, target_os = "wasi"))] + Stdout(uucore::io::RawWriter>), + #[cfg(not(any(unix, target_os = "wasi")))] Stdout(std::io::Stdout), } -impl Write for Writer { - fn write(&mut self, buf: &[u8]) -> Result { - match self { - Self::File(f) => f.write(buf), - Self::Stdout(s) => s.write(buf), - } - } - - fn flush(&mut self) -> Result<()> { +impl Writer { + pub fn write_all(&mut self, buf: &[u8]) -> Result<()> { match self { - Self::File(f) => f.flush(), - Self::Stdout(s) => s.flush(), + // File does not have line buffering + Self::File(f) => f.write_all(buf), + #[cfg(any(unix, target_os = "wasi"))] + Self::Stdout(s) => s.write_all(buf), + #[cfg(not(any(unix, target_os = "wasi")))] + Self::Stdout(s) => { + s.write_all(buf)?; + // needs unsafe to remove buffering... flush after write_all to keep overhead minimal + s.flush() + } } } }