diff --git a/src/uu/cat/src/cat.rs b/src/uu/cat/src/cat.rs index f9916ef40..89d1ec59a 100644 --- a/src/uu/cat/src/cat.rs +++ b/src/uu/cat/src/cat.rs @@ -479,10 +479,12 @@ fn get_input_type(path: &OsString) -> CatResult { fn write_fast(handle: &mut InputHandle) -> CatResult<()> { let stdout = io::stdout(); #[cfg(any(target_os = "linux", target_os = "android"))] + let mut stdout = stdout; + #[cfg(any(target_os = "linux", target_os = "android"))] { // If we're on Linux or Android, try to use the splice() system call // for faster writing. If it works, we're done. - if !splice::write_fast_using_splice(handle, &stdout)? { + if !splice::write_fast_using_splice(handle, &mut stdout)? { return Ok(()); } } diff --git a/src/uu/cat/src/splice.rs b/src/uu/cat/src/splice.rs index 37df79b95..f9082ff26 100644 --- a/src/uu/cat/src/splice.rs +++ b/src/uu/cat/src/splice.rs @@ -4,13 +4,11 @@ // file that was distributed with this source code. use super::{CatResult, FdReadable, InputHandle}; -use rustix::io::{read, write}; +use std::io::{Read, Write}; use std::os::{fd::AsFd, unix::io::AsRawFd}; use uucore::pipes::{MAX_ROOTLESS_PIPE_SIZE, might_fuse, pipe, splice, splice_exact}; -const BUF_SIZE: usize = 1024 * 16; - /// This function is called from `write_fast()` on Linux and Android. The /// function `splice()` is used to move data between two file descriptors /// without copying between kernel and user spaces. This results in a large @@ -19,14 +17,14 @@ const BUF_SIZE: usize = 1024 * 16; /// The `bool` in the result value indicates if we need to fall back to normal /// copying or not. False means we don't have to. #[inline] -pub(super) fn write_fast_using_splice( +pub(super) fn write_fast_using_splice( handle: &InputHandle, - write_fd: &S, + write_fd: &mut S, ) -> CatResult { if splice(&handle.reader, &write_fd, MAX_ROOTLESS_PIPE_SIZE).is_ok() { // fcntl improves throughput // todo: avoid fcntl overhead for small input, but don't fcntl inside of the loop - let _ = rustix::pipe::fcntl_setpipe_size(write_fd, MAX_ROOTLESS_PIPE_SIZE); + let _ = rustix::pipe::fcntl_setpipe_size(&mut *write_fd, MAX_ROOTLESS_PIPE_SIZE); loop { match splice(&handle.reader, &write_fd, MAX_ROOTLESS_PIPE_SIZE) { Ok(1..) => {} @@ -46,7 +44,9 @@ pub(super) fn write_fast_using_splice( // we can recover by copying the data that we have from the // intermediate pipe to stdout using normal read/write. Then // we tell the caller to fall back. - copy_exact(&pipe_rd, write_fd, n)?; + let mut drain = Vec::with_capacity(n); // bounded by pipe size + pipe_rd.take(n as u64).read_to_end(&mut drain)?; + write_fd.write_all(&drain)?; return Ok(true); } } @@ -57,24 +57,3 @@ pub(super) fn write_fast_using_splice( Ok(true) } } - -/// Move exactly `num_bytes` bytes from `read_fd` to `write_fd`. -/// -/// Panics if not enough bytes can be read. -fn copy_exact(read_fd: &impl AsFd, write_fd: &impl AsFd, num_bytes: usize) -> std::io::Result<()> { - let mut left = num_bytes; - let mut buf = [0; BUF_SIZE]; - while left > 0 { - let n = read(read_fd, &mut buf)?; - assert_ne!(n, 0, "unexpected end of pipe"); - let mut written = 0; - while written < n { - match write(write_fd, &buf[written..n])? { - 0 => unreachable!("fd should be writable"), - w => written += w, - } - } - left -= n; - } - Ok(()) -}