Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 1 addition & 14 deletions src/uu/wc/src/count_fast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ use uucore::hardware::SimdPolicy;

use super::WordCountable;

#[cfg(any(target_os = "linux", target_os = "android"))]
use std::fs::OpenOptions;
use std::io::{self, ErrorKind, Read};

#[cfg(unix)]
Expand Down Expand Up @@ -41,18 +39,7 @@ const BUF_SIZE: usize = 256 * 1024;
#[inline]
#[cfg(any(target_os = "linux", target_os = "android"))]
fn count_bytes_using_splice(fd: &impl AsFd) -> Result<usize, usize> {
let null_file = OpenOptions::new()
.write(true)
.open("/dev/null")
.map_err(|_| 0_usize)?;
let null_rdev = rustix::fs::fstat(null_file.as_fd())
.map_err(|_| 0_usize)?
.st_rdev as libc::dev_t;
if (libc::major(null_rdev), libc::minor(null_rdev)) != (1, 3) {
// This is not a proper /dev/null, writing to it is probably bad
// Bit of an edge case, but it has been known to happen
return Err(0);
}
let null_file = uucore::pipes::dev_null().ok_or(0_usize)?;
// todo: avoid generating broker if input is pipe (fcntl_setpipe_size succeed) and directly splice() to /dev/null to save RAM usage
let (pipe_rd, pipe_wr) = pipe().map_err(|_| 0_usize)?;

Expand Down
22 changes: 22 additions & 0 deletions src/uucore/src/lib/features/pipes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub const MAX_ROOTLESS_PIPE_SIZE: usize = 1024 * 1024;
/// Returns two `File` objects: everything written to the second can be read
/// from the first.
/// This is used only for resolving the limitation for splice: one of a input or output should be pipe
#[inline]
#[cfg(any(target_os = "linux", target_os = "android"))]
pub fn pipe() -> std::io::Result<(File, File)> {
let (read, write) = rustix::pipe::pipe()?;
Expand All @@ -36,6 +37,7 @@ pub fn pipe() -> std::io::Result<(File, File)> {
/// To get around this requirement, consider splicing from your source into
/// a [`pipe`] and then from the pipe into your target (with `splice_exact`):
/// this is still very efficient.
#[inline]
#[cfg(any(target_os = "linux", target_os = "android"))]
pub fn splice(source: &impl AsFd, target: &impl AsFd, len: usize) -> std::io::Result<usize> {
Ok(rustix::pipe::splice(
Expand All @@ -53,6 +55,7 @@ pub fn splice(source: &impl AsFd, target: &impl AsFd, len: usize) -> std::io::Re
/// Exactly `len` bytes are moved from `source` into `target`.
///
/// Panics if `source` runs out of data before `len` bytes have been moved.
#[inline]
#[cfg(any(target_os = "linux", target_os = "android"))]
pub fn splice_exact(source: &impl AsFd, target: &impl AsFd, len: usize) -> std::io::Result<()> {
let mut left = len;
Expand All @@ -63,3 +66,22 @@ pub fn splice_exact(source: &impl AsFd, target: &impl AsFd, len: usize) -> std::
}
Ok(())
}

/// 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
#[inline]
#[cfg(any(target_os = "linux", target_os = "android"))]
pub fn dev_null() -> Option<File> {
let null = std::fs::OpenOptions::new()
.write(true)
.open("/dev/null")
.ok()?;
let stat = rustix::fs::fstat(&null).ok()?;
let dev = stat.st_rdev;
if (rustix::fs::major(dev), rustix::fs::minor(dev)) == (1, 3) {
Some(null)
} else {
None
}
}
Loading