Skip to content

Commit e829cfb

Browse files
oech3cakebaker
authored andcommitted
tee: move fn copy to MultiWriter & simplify
1 parent d5e84b4 commit e829cfb

1 file changed

Lines changed: 40 additions & 43 deletions

File tree

src/uu/tee/src/tee.rs

Lines changed: 40 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ fn tee(options: &Options) -> Result<()> {
9393
}
9494

9595
// We cannot use std::io::copy here as it doesn't flush the output buffer
96-
let res = match copy(input, &mut output) {
96+
let res = match output.copy_unbuffered(input) {
9797
// ErrorKind::Other is raised by MultiWriter when all writers
9898
// have exited, so that copy will abort. It's equivalent to
9999
// success of this part (if there was an error that should
@@ -110,48 +110,6 @@ fn tee(options: &Options) -> Result<()> {
110110
}
111111
}
112112

113-
/// Copies all bytes from the input buffer to the output buffer.
114-
fn copy(mut input: impl Read, mut output: impl Write) -> Result<()> {
115-
// The implementation for this function is adopted from the generic buffer copy implementation from
116-
// the standard library:
117-
// https://github.com/rust-lang/rust/blob/2feb91181882e525e698c4543063f4d0296fcf91/library/std/src/io/copy.rs#L271-L297
118-
119-
// Use buffer size from std implementation
120-
// https://github.com/rust-lang/rust/blob/2feb91181882e525e698c4543063f4d0296fcf91/library/std/src/sys/io/mod.rs#L44
121-
const BUF_SIZE: usize = 8 * 1024;
122-
let mut buffer = [0u8; BUF_SIZE];
123-
124-
for _ in 0..2 {
125-
match input.read(&mut buffer) {
126-
Ok(0) => return Ok(()), // end of file
127-
Ok(received) => {
128-
output.write_all(&buffer[..received])?;
129-
// flush the buffer to comply with POSIX requirement that
130-
// `tee` does not buffer the input.
131-
output.flush()?;
132-
}
133-
Err(e) if e.kind() != ErrorKind::Interrupted => return Err(e),
134-
_ => {}
135-
}
136-
}
137-
// buffer is too small optimize for large input
138-
//stack array makes code path for smaller file slower
139-
let mut buffer = vec![0u8; 4 * BUF_SIZE];
140-
loop {
141-
match input.read(&mut buffer) {
142-
Ok(0) => return Ok(()), // end of file
143-
Ok(received) => {
144-
output.write_all(&buffer[..received])?;
145-
// flush the buffer to comply with POSIX requirement that
146-
// `tee` does not buffer the input.
147-
output.flush()?;
148-
}
149-
Err(e) if e.kind() != ErrorKind::Interrupted => return Err(e),
150-
_ => {}
151-
}
152-
}
153-
}
154-
155113
/// Tries to open the indicated file and return it. Reports an error if that's not possible.
156114
/// If that error should lead to program termination, this function returns Some(Err()),
157115
/// otherwise it returns None.
@@ -189,6 +147,45 @@ struct MultiWriter {
189147
}
190148

191149
impl MultiWriter {
150+
/// Copies all bytes from the input buffer to the output buffer
151+
/// without buffering which is POSIX requirement.
152+
pub fn copy_unbuffered<R: Read>(&mut self, mut input: R) -> Result<()> {
153+
// todo: support splice() and tee() fast-path at here
154+
// The implementation for this function is adopted from the generic buffer copy implementation from
155+
// the standard library:
156+
// https://github.com/rust-lang/rust/blob/2feb91181882e525e698c4543063f4d0296fcf91/library/std/src/io/copy.rs#L271-L297
157+
158+
// Use buffer size from std implementation
159+
// https://github.com/rust-lang/rust/blob/2feb91181882e525e698c4543063f4d0296fcf91/library/std/src/sys/io/mod.rs#L44
160+
const BUF_SIZE: usize = 8 * 1024;
161+
let mut buffer = [0u8; BUF_SIZE];
162+
// fast-path for small input
163+
match input.read(&mut buffer) {
164+
Ok(0) => return Ok(()), // end of file
165+
Ok(received) => {
166+
self.write_all(&buffer[..received])?;
167+
self.flush()?; // avoid buffering
168+
}
169+
Err(e) if e.kind() != ErrorKind::Interrupted => return Err(e),
170+
_ => {}
171+
}
172+
// buffer is too small optimize for large input
173+
//stack array makes code path for smaller file slower
174+
let mut buffer = vec![0u8; 4 * BUF_SIZE];
175+
loop {
176+
match input.read(&mut buffer) {
177+
Ok(0) => return Ok(()), // end of file
178+
Ok(received) => {
179+
self.write_all(&buffer[..received])?;
180+
// avoid buffering
181+
self.flush()?;
182+
}
183+
Err(e) if e.kind() != ErrorKind::Interrupted => return Err(e),
184+
_ => {}
185+
}
186+
}
187+
}
188+
192189
fn new(writers: Vec<NamedWriter>, output_error_mode: Option<OutputErrorMode>) -> Self {
193190
Self {
194191
writers,

0 commit comments

Comments
 (0)