mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 19:47:45 +00:00
Remove usage of vmsplice from yes
Addresses issue #7625 Remove the usage of vmsplice from `yes` utility since it can cause errors.
This commit is contained in:
parent
349e56897c
commit
d1f84cdc41
2 changed files with 0 additions and 90 deletions
|
@ -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(),
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -9,14 +9,10 @@ use clap::{Arg, ArgAction, Command, builder::ValueParser};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
|
||||||
use std::os::fd::AsFd;
|
|
||||||
use uucore::error::{UResult, USimpleError};
|
use uucore::error::{UResult, USimpleError};
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use uucore::signals::enable_pipe_errors;
|
use uucore::signals::enable_pipe_errors;
|
||||||
use uucore::{format_usage, help_about, help_usage};
|
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 ABOUT: &str = help_about!("yes.md");
|
||||||
const USAGE: &str = help_usage!("yes.md");
|
const USAGE: &str = help_usage!("yes.md");
|
||||||
|
@ -118,15 +114,6 @@ pub fn exec(bytes: &[u8]) -> io::Result<()> {
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
enable_pipe_errors()?;
|
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 {
|
loop {
|
||||||
stdout.write_all(bytes)?;
|
stdout.write_all(bytes)?;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue