Skip to content

Commit bfdf580

Browse files
oech3sylvestre
authored andcommitted
cat: do not splice() on FUSE
1 parent efd0f0c commit bfdf580

3 files changed

Lines changed: 14 additions & 3 deletions

File tree

.vscode/cspell.dictionaries/workspace.wordlist.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,7 @@ uutils
367367

368368
# * function names
369369
execfn
370+
fstatfs
370371
getcwd
371372
setpipe
372373

src/uu/cat/src/splice.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use super::{CatResult, FdReadable, InputHandle};
77
use rustix::io::{read, write};
88
use std::os::{fd::AsFd, unix::io::AsRawFd};
99

10-
use uucore::pipes::{MAX_ROOTLESS_PIPE_SIZE, pipe, splice, splice_exact};
10+
use uucore::pipes::{MAX_ROOTLESS_PIPE_SIZE, might_fuse, pipe, splice, splice_exact};
1111

1212
const BUF_SIZE: usize = 1024 * 16;
1313

@@ -30,15 +30,15 @@ pub(super) fn write_fast_using_splice<R: FdReadable, S: AsRawFd + AsFd>(
3030
loop {
3131
match splice(&handle.reader, &write_fd, MAX_ROOTLESS_PIPE_SIZE) {
3232
Ok(1..) => {}
33-
Ok(0) => return Ok(false),
33+
Ok(0) => return Ok(might_fuse(&handle.reader)),
3434
Err(_) => return Ok(true),
3535
}
3636
}
3737
} else if let Ok((pipe_rd, pipe_wr)) = pipe() {
3838
// both of in/output are not pipe. needs broker to use splice() with additional costs
3939
loop {
4040
match splice(&handle.reader, &pipe_wr, MAX_ROOTLESS_PIPE_SIZE) {
41-
Ok(0) => return Ok(false),
41+
Ok(0) => return Ok(might_fuse(&handle.reader)),
4242
Ok(n) => {
4343
if splice_exact(&pipe_rd, write_fd, n).is_err() {
4444
// If the first splice manages to copy to the intermediate

src/uucore/src/lib/features/pipes.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,16 @@ pub fn splice_exact(source: &impl AsFd, target: &impl AsFd, len: usize) -> std::
6262
Ok(())
6363
}
6464

65+
/// check that source is FUSE
66+
/// we fallback to read() at FUSE <https://github.com/uutils/coreutils/issues/9609>
67+
#[inline]
68+
#[cfg(any(target_os = "linux", target_os = "android"))]
69+
pub fn might_fuse(source: &impl AsFd) -> bool {
70+
rustix::fs::fstatfs(source)
71+
.map(|stats| stats.f_type == 0x6573_5546) // FUSE magic number, too many platform specific clippy warning with const
72+
.unwrap_or(true)
73+
}
74+
6575
/// Return verified /dev/null
6676
///
6777
/// `splice` to /dev/null is faster than `read` when we skip or count the non-seekable input

0 commit comments

Comments
 (0)