diff --git a/.vscode/cspell.dictionaries/workspace.wordlist.txt b/.vscode/cspell.dictionaries/workspace.wordlist.txt index 3845e4d0411..a9829a23c39 100644 --- a/.vscode/cspell.dictionaries/workspace.wordlist.txt +++ b/.vscode/cspell.dictionaries/workspace.wordlist.txt @@ -367,6 +367,7 @@ uutils # * function names execfn +fstatfs getcwd setpipe diff --git a/src/uu/cat/src/splice.rs b/src/uu/cat/src/splice.rs index 87cbff81a3e..37df79b9506 100644 --- a/src/uu/cat/src/splice.rs +++ b/src/uu/cat/src/splice.rs @@ -7,7 +7,7 @@ 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}; +use uucore::pipes::{MAX_ROOTLESS_PIPE_SIZE, might_fuse, pipe, splice, splice_exact}; const BUF_SIZE: usize = 1024 * 16; @@ -30,7 +30,7 @@ pub(super) fn write_fast_using_splice( loop { match splice(&handle.reader, &write_fd, MAX_ROOTLESS_PIPE_SIZE) { Ok(1..) => {} - Ok(0) => return Ok(false), + Ok(0) => return Ok(might_fuse(&handle.reader)), Err(_) => return Ok(true), } } @@ -38,7 +38,7 @@ pub(super) fn write_fast_using_splice( // both of in/output are not pipe. needs broker to use splice() with additional costs loop { match splice(&handle.reader, &pipe_wr, MAX_ROOTLESS_PIPE_SIZE) { - Ok(0) => return Ok(false), + Ok(0) => return Ok(might_fuse(&handle.reader)), Ok(n) => { if splice_exact(&pipe_rd, write_fd, n).is_err() { // If the first splice manages to copy to the intermediate diff --git a/src/uucore/src/lib/features/pipes.rs b/src/uucore/src/lib/features/pipes.rs index 8d5800cf961..1336fde6c7c 100644 --- a/src/uucore/src/lib/features/pipes.rs +++ b/src/uucore/src/lib/features/pipes.rs @@ -62,6 +62,16 @@ pub fn splice_exact(source: &impl AsFd, target: &impl AsFd, len: usize) -> std:: Ok(()) } +/// check that source is FUSE +/// we fallback to read() at FUSE +#[inline] +#[cfg(any(target_os = "linux", target_os = "android"))] +pub fn might_fuse(source: &impl AsFd) -> bool { + rustix::fs::fstatfs(source) + .map(|stats| stats.f_type == 0x6573_5546) // FUSE magic number, too many platform specific clippy warning with const + .unwrap_or(true) +} + /// Return verified /dev/null /// /// `splice` to /dev/null is faster than `read` when we skip or count the input which is not able to seek