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
2 changes: 1 addition & 1 deletion src/uu/od/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ byteorder = { workspace = true }
clap = { workspace = true }
half = { workspace = true }
rustix = { workspace = true, features = ["stdio"] }
uucore = { workspace = true, features = ["fs", "parser-size"] }
uucore = { workspace = true, features = ["fs", "parser-size", "pipes"] }
fluent = { workspace = true }
libc.workspace = true

Expand Down
23 changes: 21 additions & 2 deletions src/uu/od/src/multifile_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@ impl io::Read for CurrentReader {
}
}

#[cfg(any(target_os = "linux", target_os = "android"))]
impl rustix::fd::AsFd for CurrentReader {
fn as_fd(&self) -> rustix::fd::BorrowedFd<'_> {
match self {
Self::File(f) => f.as_fd(),
Self::Stdin(s) => s.0,
}
}
}

// MultifileReader - concatenate all our input, file or stdin.
pub struct MultifileReader<'a> {
ni: Vec<InputSource<'a>>,
Expand Down Expand Up @@ -186,8 +196,17 @@ fn skip_in_file(curr: &mut CurrentReader, n_skip: u64) -> io::Result<u64> {
}
}
}
let read = uucore::io::read_and_discard(curr, n_skip, SKIP_BUFFER_SIZE)?;
Ok(n_skip - read)
#[cfg(any(target_os = "linux", target_os = "android"))]
match uucore::pipes::discard_n_bytes(&curr, n_skip as usize) {
Ok(spliced) => Ok(n_skip - spliced as u64),
Err(spliced) => {
let read =
uucore::io::read_and_discard(curr, n_skip - spliced as u64, SKIP_BUFFER_SIZE)?;
Ok(n_skip - spliced as u64 - read)
}
}
#[cfg(not(any(target_os = "linux", target_os = "android")))]
Ok(n_skip - uucore::io::read_and_discard(curr, n_skip, SKIP_BUFFER_SIZE)?)
}

/// Seek `f` forward by `n` bytes. Returns `Ok(true)` if the seek happened, or
Expand Down
29 changes: 29 additions & 0 deletions src/uucore/src/lib/features/pipes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,35 @@ pub fn send_n_bytes(input: impl AsFd, target: impl AsFd, n: u64) -> std::io::Res
Ok(bytes_written)
}

/// discard `n` bytes by splice
/// return actually discarded bytes
/// Err(b) means we discarded b bytes, but we should try to discarding remaining bytes by read
#[inline]
pub fn discard_n_bytes(fd: impl AsFd, n: usize) -> Result<usize, usize> {
let mut discarded = 0;
let dev_null = dev_null().ok_or(0_usize)?;
while discarded < n
&& let Ok(s) = splice(&fd, &dev_null, n - discarded)
{
if s == 0 {
return Ok(discarded);
}
discarded += s;
}
// else, input is not a pipe
let (pipe_read, pipe_write) = pipe::<false>().map_err(|_| discarded)?;
while discarded < n
&& let Ok(s @ 1..) = splice(&fd, &pipe_write, n - discarded)
{
discarded += s;
// pipe to null is not blocked. So this returns the same length at most cases
// next splice does not hang if we discarded 1+ pages
splice(&pipe_read, &dev_null, s).map_err(|_| discarded)?;
}

Ok(discarded)
}

/// Return verified /dev/null
///
/// `splice` to /dev/null is faster than `read` when we skip or count the non-seekable input
Expand Down
Loading