@@ -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
191149impl 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