Skip to content
Draft
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
21 changes: 10 additions & 11 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion src/uu/cp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ fluent = { workspace = true }

[target.'cfg(unix)'.dependencies]
exacl = { workspace = true, optional = true }
nix = { workspace = true, features = ["fs"] }

[[bin]]
name = "cp"
Expand Down
31 changes: 24 additions & 7 deletions src/uu/cp/src/cp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use clap::{Arg, ArgAction, ArgMatches, Command, builder::ValueParser, value_pars
use filetime::FileTime;
use indicatif::{ProgressBar, ProgressStyle};
#[cfg(unix)]
use nix::sys::stat::{Mode, SFlag, dev_t, mknod as nix_mknod, mode_t};
use libc::{dev_t, mode_t};
use thiserror::Error;

use platform::copy_on_write;
Expand Down Expand Up @@ -2809,14 +2809,31 @@ fn copy_node(
overwrite.verify(dest, debug)?;
fs::remove_file(dest)?;
}
let sflag = if source_metadata.file_type().is_char_device() {
SFlag::S_IFCHR
let sflag: mode_t = if source_metadata.file_type().is_char_device() {
libc::S_IFCHR
} else {
SFlag::S_IFBLK
libc::S_IFBLK
};
let mode = Mode::from_bits_truncate(source_metadata.mode() as mode_t);
nix_mknod(dest, sflag, mode, source_metadata.rdev() as dev_t)
.map_err(|e| translate!("cp-error-cannot-create-special-file", "path" => dest.quote(), "error" => e.desc()).into())
let mode = (source_metadata.mode() as mode_t) & 0o7777;
use std::io;
let c_path = std::ffi::CString::new(dest.as_os_str().as_encoded_bytes())
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "path contains null byte"))?;
// SAFETY: c_path is a valid null-terminated C string
let ret = unsafe {
libc::mknod(
c_path.as_ptr(),
sflag | mode,
source_metadata.rdev() as dev_t,
)
};
if ret != 0 {
let e = io::Error::last_os_error();
return Err(
translate!("cp-error-cannot-create-special-file", "path" => dest.quote(), "error" => uucore::error::strip_errno(&e))
.into(),
);
}
Ok(())
}

fn copy_link(
Expand Down
2 changes: 1 addition & 1 deletion src/uu/dd/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ thiserror = { workspace = true }
fluent = { workspace = true }

[target.'cfg(any(target_os = "linux", target_os = "android"))'.dependencies]
nix = { workspace = true, features = ["fs", "signal"] }
rustix = { workspace = true, features = ["fs"] }

[[bin]]
name = "dd"
Expand Down
61 changes: 31 additions & 30 deletions src/uu/dd/src/dd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,13 @@ mod progress;
use crate::bufferedoutput::BufferedOutput;
use blocks::conv_block_unblock_helper;
use datastructures::{ConversionMode, IConvFlags, IFlags, OConvFlags, OFlags, options};
#[cfg(any(target_os = "linux", target_os = "android"))]
use nix::fcntl::FcntlArg;
#[cfg(any(target_os = "linux", target_os = "android"))]
use nix::fcntl::OFlag;
use parseargs::Parser;
use progress::ProgUpdateType;
use progress::{ProgUpdate, ReadStat, StatusLevel, WriteStat, gen_prog_updater};
#[cfg(target_os = "linux")]
use progress::{check_and_reset_sigusr1, install_sigusr1_handler};
#[cfg(any(target_os = "linux", target_os = "android"))]
use rustix::fs::OFlags as RustixOFlags;
use uucore::io::OwnedFileDescriptorOrHandle;
use uucore::translate;

Expand Down Expand Up @@ -55,10 +53,7 @@ use std::time::{Duration, Instant};
use clap::{Arg, Command};
use gcd::Gcd;
#[cfg(target_os = "linux")]
use nix::{
errno::Errno,
fcntl::{PosixFadviseAdvice, posix_fadvise},
};
use rustix::fs::{Advice as PosixFadviseAdvice, fadvise};
use uucore::display::Quotable;
use uucore::error::{FromIo, UResult};
#[cfg(unix)]
Expand Down Expand Up @@ -316,14 +311,16 @@ impl Source {
/// portion of the source is no longer needed. If not possible,
/// then this function returns an error.
#[cfg(target_os = "linux")]
fn discard_cache(&self, offset: libc::off_t, len: libc::off_t) -> nix::Result<()> {
fn discard_cache(&self, offset: libc::off_t, len: libc::off_t) -> io::Result<()> {
#[allow(clippy::match_wildcard_for_single_variants)]
match self {
Self::File(f) => {
let advice = PosixFadviseAdvice::POSIX_FADV_DONTNEED;
posix_fadvise(f.as_fd(), offset, len, advice)
let advice = PosixFadviseAdvice::DontNeed;
let len = std::num::NonZeroU64::new(len as u64);
fadvise(f.as_fd(), offset as u64, len, advice)?;
Ok(())
}
_ => Err(Errno::ESPIPE), // "Illegal seek"
_ => Err(io::Error::from_raw_os_error(libc::ESPIPE)), // "Illegal seek"
}
}
}
Expand Down Expand Up @@ -698,13 +695,15 @@ impl Dest {
/// specified portion of the destination is no longer needed. If
/// not possible, then this function returns an error.
#[cfg(target_os = "linux")]
fn discard_cache(&self, offset: libc::off_t, len: libc::off_t) -> nix::Result<()> {
fn discard_cache(&self, offset: libc::off_t, len: libc::off_t) -> io::Result<()> {
match self {
Self::File(f, _) => {
let advice = PosixFadviseAdvice::POSIX_FADV_DONTNEED;
posix_fadvise(f.as_fd(), offset, len, advice)
let advice = PosixFadviseAdvice::DontNeed;
let len = std::num::NonZeroU64::new(len as u64);
fadvise(f.as_fd(), offset as u64, len, advice)?;
Ok(())
}
_ => Err(Errno::ESPIPE), // "Illegal seek"
_ => Err(io::Error::from_raw_os_error(libc::ESPIPE)), // "Illegal seek"
}
}
}
Expand All @@ -718,31 +717,33 @@ fn is_sparse(buf: &[u8]) -> bool {
/// This follows GNU dd behavior for partial block writes with O_DIRECT.
#[cfg(any(target_os = "linux", target_os = "android"))]
fn handle_o_direct_write(f: &mut File, buf: &[u8], original_error: io::Error) -> io::Result<usize> {
use nix::fcntl::{FcntlArg, OFlag, fcntl};
use rustix::fs::{OFlags, fcntl_getfl, fcntl_setfl};

// Get current flags using nix
let oflags = match fcntl(&mut *f, FcntlArg::F_GETFL) {
Ok(flags) => OFlag::from_bits_retain(flags),
Err(_) => return Err(original_error),
// Get current flags
let Ok(oflags) = fcntl_getfl(&*f) else {
return Err(original_error);
};

// If O_DIRECT is set, try removing it temporarily
if oflags.contains(OFlag::O_DIRECT) {
let flags_without_direct = oflags - OFlag::O_DIRECT;
if oflags.contains(OFlags::DIRECT) {
let flags_without_direct = oflags & !OFlags::DIRECT;

// Remove O_DIRECT flag using nix
if fcntl(&mut *f, FcntlArg::F_SETFL(flags_without_direct)).is_err() {
// Remove O_DIRECT flag
if fcntl_setfl(&*f, flags_without_direct).is_err() {
return Err(original_error);
}

// Retry the write without O_DIRECT
let write_result = f.write(buf);

// Restore O_DIRECT flag using nix (GNU doesn't restore it, but we'll be safer)
// Restore O_DIRECT flag (GNU doesn't restore it, but we'll be safer)
// Log any restoration errors without failing the operation
if let Err(os_err) = fcntl(&mut *f, FcntlArg::F_SETFL(oflags)) {
if let Err(os_err) = fcntl_setfl(&*f, oflags) {
// Just log the error, don't fail the whole operation
show_error!("Failed to restore O_DIRECT flag: {os_err}");
show_error!(
"Failed to restore O_DIRECT flag: {}",
io::Error::from(os_err)
);
}

write_result
Expand Down Expand Up @@ -889,9 +890,9 @@ impl<'a> Output<'a> {
let fx = OwnedFileDescriptorOrHandle::from(io::stdout())?;
#[cfg(any(target_os = "linux", target_os = "android"))]
if let Some(libc_flags) = make_linux_oflags(&settings.oflags) {
nix::fcntl::fcntl(
rustix::fs::fcntl_setfl(
fx.as_raw().as_fd(),
FcntlArg::F_SETFL(OFlag::from_bits_retain(libc_flags)),
RustixOFlags::from_bits_retain(libc_flags as _),
)?;
}

Expand Down
4 changes: 2 additions & 2 deletions src/uu/dd/src/progress.rs
Original file line number Diff line number Diff line change
Expand Up @@ -459,8 +459,8 @@ extern "C" fn sigusr1_handler(_: std::os::raw::c_int) {
}

#[cfg(target_os = "linux")]
pub(crate) fn install_sigusr1_handler() -> Result<(), nix::errno::Errno> {
uucore::signals::install_signal_handler(nix::sys::signal::Signal::SIGUSR1, sigusr1_handler)
pub(crate) fn install_sigusr1_handler() -> std::io::Result<()> {
uucore::signals::install_signal_handler(libc::SIGUSR1, sigusr1_handler)
}

/// Return a closure that can be used in its own thread to print progress info.
Expand Down
2 changes: 1 addition & 1 deletion src/uu/env/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ uucore = { workspace = true, features = ["signals"] }
fluent = { workspace = true }

[target.'cfg(unix)'.dependencies]
nix = { workspace = true, features = ["signal"] }
libc = { workspace = true }

[[bin]]
name = "env"
Expand Down
Loading
Loading