use super::{CatResult, FdReadable, InputHandle};
use rustix::io::{read, write};
use std::os::{fd::AsFd, unix::io::AsRawFd};
use uucore::pipes::{MAX_ROOTLESS_PIPE_SIZE, pipe, splice, splice_exact};
const BUF_SIZE: usize = 1024 * 16;
#[inline]
pub(super) fn write_fast_using_splice<R: FdReadable, S: AsRawFd + AsFd>(
handle: &InputHandle<R>,
write_fd: &S,
) -> CatResult<bool> {
if splice(&handle.reader, &write_fd, MAX_ROOTLESS_PIPE_SIZE).is_ok() {
let _ = rustix::pipe::fcntl_setpipe_size(write_fd, MAX_ROOTLESS_PIPE_SIZE);
loop {
match splice(&handle.reader, &write_fd, MAX_ROOTLESS_PIPE_SIZE) {
Ok(1..) => {}
Ok(0) => return Ok(false),
Err(_) => return Ok(true),
}
}
} else if let Ok((pipe_rd, pipe_wr)) = pipe() {
loop {
match splice(&handle.reader, &pipe_wr, MAX_ROOTLESS_PIPE_SIZE) {
Ok(0) => return Ok(false),
Ok(n) => {
if splice_exact(&pipe_rd, write_fd, n).is_err() {
copy_exact(&pipe_rd, write_fd, n)?;
return Ok(true);
}
}
Err(_) => return Ok(true),
}
}
} else {
Ok(true)
}
}
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(())
}