1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 03:27:44 +00:00

Merge pull request #7770 from karlmcdowall/yes_splice

yes: Remove usage of vmsplice
This commit is contained in:
Sylvestre Ledru 2025-04-19 11:41:17 +02:00 committed by GitHub
commit c76467896a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 0 additions and 90 deletions

View file

@ -1,77 +0,0 @@
// This file is part of the uutils coreutils package.
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
//! On Linux we can use vmsplice() to write data more efficiently.
//!
//! This does not always work. We're not allowed to splice to some targets,
//! and on some systems (notably WSL 1) it isn't supported at all.
//!
//! If we get an error code that suggests splicing isn't supported then we
//! tell that to the caller so it can fall back to a robust naïve method. If
//! we get another kind of error we bubble it up as normal.
//!
//! vmsplice() can only splice into a pipe, so if the output is not a pipe
//! we make our own and use splice() to bridge the gap from the pipe to the
//! output.
//!
//! We assume that an "unsupported" error will only ever happen before any
//! data was successfully written to the output. That way we don't have to
//! make any effort to rescue data from the pipe if splice() fails, we can
//! just fall back and start over from the beginning.
use std::{
io,
os::fd::{AsFd, AsRawFd},
};
use nix::{errno::Errno, libc::S_IFIFO, sys::stat::fstat};
use uucore::pipes::{pipe, splice_exact, vmsplice};
pub(crate) fn splice_data<T>(bytes: &[u8], out: &T) -> Result<()>
where
T: AsRawFd + AsFd,
{
let is_pipe = fstat(out.as_raw_fd())?.st_mode as nix::libc::mode_t & S_IFIFO != 0;
if is_pipe {
loop {
let mut bytes = bytes;
while !bytes.is_empty() {
let len = vmsplice(out, bytes).map_err(maybe_unsupported)?;
bytes = &bytes[len..];
}
}
} else {
let (read, write) = pipe()?;
loop {
let mut bytes = bytes;
while !bytes.is_empty() {
let len = vmsplice(&write, bytes).map_err(maybe_unsupported)?;
splice_exact(&read, out, len).map_err(maybe_unsupported)?;
bytes = &bytes[len..];
}
}
}
}
pub(crate) enum Error {
Unsupported,
Io(io::Error),
}
type Result<T> = std::result::Result<T, Error>;
impl From<nix::Error> for Error {
fn from(error: nix::Error) -> Self {
Self::Io(io::Error::from_raw_os_error(error as i32))
}
}
fn maybe_unsupported(error: nix::Error) -> Error {
match error {
Errno::EINVAL | Errno::ENOSYS | Errno::EBADF => Error::Unsupported,
_ => error.into(),
}
}

View file

@ -9,14 +9,10 @@ use clap::{Arg, ArgAction, Command, builder::ValueParser};
use std::error::Error;
use std::ffi::OsString;
use std::io::{self, Write};
#[cfg(any(target_os = "linux", target_os = "android"))]
use std::os::fd::AsFd;
use uucore::error::{UResult, USimpleError};
#[cfg(unix)]
use uucore::signals::enable_pipe_errors;
use uucore::{format_usage, help_about, help_usage};
#[cfg(any(target_os = "linux", target_os = "android"))]
mod splice;
const ABOUT: &str = help_about!("yes.md");
const USAGE: &str = help_usage!("yes.md");
@ -118,15 +114,6 @@ pub fn exec(bytes: &[u8]) -> io::Result<()> {
#[cfg(unix)]
enable_pipe_errors()?;
#[cfg(any(target_os = "linux", target_os = "android"))]
{
match splice::splice_data(bytes, &stdout.as_fd()) {
Ok(_) => return Ok(()),
Err(splice::Error::Io(err)) => return Err(err),
Err(splice::Error::Unsupported) => (),
}
}
loop {
stdout.write_all(bytes)?;
}