From 607bf3ca4d34db62f4ecb655ce51c310928fb834 Mon Sep 17 00:00:00 2001 From: Ed Smith Date: Sat, 25 Jun 2022 23:19:30 +0100 Subject: [PATCH] Terminate on elimination of all writers in tee tee is supposed to exit when there is nothing left to write to. For finite inputs, it can be hard to determine whether this functions correctly, but for tee of infinite streams, it is very important to exit when there is nothing more to write to. --- src/uu/tee/src/tee.rs | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/uu/tee/src/tee.rs b/src/uu/tee/src/tee.rs index 319fab9e9..5096e47f0 100644 --- a/src/uu/tee/src/tee.rs +++ b/src/uu/tee/src/tee.rs @@ -199,10 +199,18 @@ fn tee(options: &Options) -> Result<()> { inner: Box::new(stdin()) as Box, }; - // TODO: replaced generic 'copy' call to be able to stop copying - // if all outputs are closed (due to errors) - if copy(input, &mut output).is_err() || output.flush().is_err() || output.error_occurred() { - Err(Error::new(ErrorKind::Other, "")) + let res = match copy(input, &mut output) { + // ErrorKind::Other is raised by MultiWriter when all writers + // have exited, so that copy will abort. It's equivalent to + // success of this part (if there was an error that should + // cause a failure from any writer, that error would have been + // returned instead). + Err(e) if e.kind() != ErrorKind::Other => Err(e), + _ => Ok(()), + }; + + if res.is_err() || output.flush().is_err() || output.error_occurred() { + Err(Error::from(ErrorKind::Other)) } else { Ok(()) } @@ -313,6 +321,11 @@ impl Write for MultiWriter { self.ignored_errors += errors; if let Some(e) = aborted { Err(e) + } else if self.writers.is_empty() { + // This error kind will never be raised by the standard + // library, so we can use it for early termination of + // `copy` + Err(Error::from(ErrorKind::Other)) } else { Ok(buf.len()) }