Skip to content
Closed
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
50 changes: 35 additions & 15 deletions src/uu/cp/src/cp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1383,26 +1383,28 @@ fn parse_path_args(
Ok((paths, target))
}

/// Check if an error is ENOTSUP/EOPNOTSUPP (operation not supported).
/// This is used to suppress xattr errors on filesystems that don't support them.
fn is_enotsup_error(error: &CpError) -> bool {
#[cfg(unix)]
const EOPNOTSUPP: i32 = libc::EOPNOTSUPP;
#[cfg(not(unix))]
const EOPNOTSUPP: i32 = 95;

match error {
CpError::IoErr(e) | CpError::IoErrContext(e, _) | CpError::SelinuxContextIoErr(e, _) => {
let raw = e.raw_os_error();
// WASI's sandbox has no chmod/chown syscalls at all (not merely an
// unsupported combination of flags), so `fs::set_permissions` and
// friends always fail with ENOSYS there. Treat that the same as
// EOPNOTSUPP for optional preservation.
if e.kind() == io::ErrorKind::Unsupported {
return true;
}
#[cfg(unix)]
if matches!(
e.raw_os_error(),
Some(code) if code == libc::ENOTSUP || code == libc::EOPNOTSUPP || code == libc::ENOSYS
) {
return true;
}
#[cfg(target_os = "wasi")]
if raw == Some(libc::ENOSYS) {
if e.raw_os_error() == Some(libc::ENOSYS) {
return true;
}
#[cfg(not(any(unix, target_os = "wasi")))]
if matches!(e.raw_os_error(), Some(95)) {
return true;
}
raw == Some(EOPNOTSUPP)
false
}
_ => false,
}
Expand Down Expand Up @@ -3169,7 +3171,7 @@ fn disk_usage_directory(p: &Path) -> io::Result<u64> {
#[cfg(test)]
mod tests {

use crate::{Attributes, Preserve, aligned_ancestors, localize_to_target};
use super::*;
use std::path::Path;

#[test]
Expand Down Expand Up @@ -3261,4 +3263,22 @@ mod tests {
assert_eq!(unioned.mode, Preserve::No { explicit: true });
assert_eq!(unioned.timestamps, Preserve::Yes { required: true });
}

#[test]
fn test_is_enotsup_error() {
let unsupported_err =
CpError::IoErr(io::Error::new(io::ErrorKind::Unsupported, "unsupported"));
assert!(is_enotsup_error(&unsupported_err));

let other_err = CpError::IoErr(io::Error::new(io::ErrorKind::NotFound, "not found"));
assert!(!is_enotsup_error(&other_err));

#[cfg(unix)]
{
for errno in [libc::ENOTSUP, libc::EOPNOTSUPP, libc::ENOSYS] {
let err = CpError::IoErr(io::Error::from_raw_os_error(errno));
assert!(is_enotsup_error(&err));
}
}
}
}
35 changes: 26 additions & 9 deletions src/uucore/src/lib/features/fsxattr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore getxattr posix_acl_default posix_acl_access ENOTSUP EOPNOTSUPP renamer
// spell-checker:ignore getxattr posix_acl_default posix_acl_access ENOTSUP EOPNOTSUPP ENOSYS renamer

//! Set of functions to manage xattr on files and dirs
use itertools::Itertools;
Expand All @@ -13,19 +13,18 @@ use std::ffi::{OsStr, OsString};
use std::os::unix::ffi::OsStrExt;
use std::path::Path;

/// True if the error is `ENOTSUP` / `EOPNOTSUPP` (same errno on Linux,
/// distinct on the BSDs).
#[cfg(unix)]
fn is_xattr_unsupported(err: &std::io::Error) -> bool {
matches!(
err.raw_os_error(),
Some(e) if e == libc::ENOTSUP || e == libc::EOPNOTSUPP
)
err.kind() == std::io::ErrorKind::Unsupported
|| matches!(
err.raw_os_error(),
Some(e) if e == libc::ENOTSUP || e == libc::EOPNOTSUPP || e == libc::ENOSYS
)
}

#[cfg(not(unix))]
fn is_xattr_unsupported(_err: &std::io::Error) -> bool {
false
fn is_xattr_unsupported(err: &std::io::Error) -> bool {
err.kind() == std::io::ErrorKind::Unsupported
}

/// Copies extended attributes (xattrs) from one path to another.
Expand Down Expand Up @@ -499,4 +498,22 @@ mod tests {
test_value
);
}

#[test]
fn test_is_xattr_unsupported() {
let unsupported =
std::io::Error::new(std::io::ErrorKind::Unsupported, "unsupported platform");
assert!(is_xattr_unsupported(&unsupported));

let other = std::io::Error::new(std::io::ErrorKind::NotFound, "not found");
assert!(!is_xattr_unsupported(&other));

#[cfg(unix)]
{
for errno in [libc::ENOTSUP, libc::EOPNOTSUPP, libc::ENOSYS] {
let err = std::io::Error::from_raw_os_error(errno);
assert!(is_xattr_unsupported(&err));
}
}
}
}
Loading