diff --git a/Cargo.toml b/Cargo.toml index 704e42337..d0396eec8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,7 @@ once_cell = { version = "1.5.2", optional = true } [target.'cfg(all(not(rustix_use_libc), not(miri), target_os = "linux", target_endian = "little", any(target_arch = "arm", all(target_arch = "aarch64", target_pointer_width = "64"), target_arch = "riscv64", all(rustix_use_experimental_asm, target_arch = "powerpc64"), all(rustix_use_experimental_asm, target_arch = "mips"), all(rustix_use_experimental_asm, target_arch = "mips32r6"), all(rustix_use_experimental_asm, target_arch = "mips64"), all(rustix_use_experimental_asm, target_arch = "mips64r6"), target_arch = "x86", all(target_arch = "x86_64", target_pointer_width = "64"))))'.dependencies] linux-raw-sys = { version = "0.4.11", default-features = false, features = ["general", "errno", "ioctl", "no_std", "elf"] } libc_errno = { package = "errno", version = "0.3.8", default-features = false, optional = true } -libc = { version = "0.2.150", default-features = false, features = ["extra_traits"], optional = true } +libc = { version = "0.2.151", default-features = false, features = ["extra_traits"], optional = true } # Dependencies for platforms where only libc is supported: # diff --git a/src/backend/libc/fs/syscalls.rs b/src/backend/libc/fs/syscalls.rs index 70e86cf70..a098e2b80 100644 --- a/src/backend/libc/fs/syscalls.rs +++ b/src/backend/libc/fs/syscalls.rs @@ -2272,15 +2272,24 @@ pub(crate) fn lgetxattr(path: &CStr, name: &CStr, value: &mut [u8]) -> io::Resul } #[cfg(apple)] - unsafe { - ret_usize(c::getxattr( - path.as_ptr(), - name.as_ptr(), - value_ptr.cast::(), - value.len(), - 0, - c::XATTR_NOFOLLOW, - )) + { + // Passing an empty to slice to getxattr leads to ERANGE on macOS. Pass null instead. + let ptr = if value.is_empty() { + core::ptr::null_mut() + } else { + value_ptr.cast::() + }; + + unsafe { + ret_usize(c::getxattr( + path.as_ptr(), + name.as_ptr(), + ptr, + value.len(), + 0, + c::XATTR_NOFOLLOW, + )) + } } } diff --git a/src/backend/linux_raw/c.rs b/src/backend/linux_raw/c.rs index edc9eb862..54174bb0c 100644 --- a/src/backend/linux_raw/c.rs +++ b/src/backend/linux_raw/c.rs @@ -42,6 +42,10 @@ pub(crate) use linux_raw_sys::general::{ }; pub(crate) use linux_raw_sys::ioctl::{BLKPBSZGET, BLKSSZGET, FICLONE}; +#[cfg(target_pointer_width = "32")] +pub(crate) use linux_raw_sys::ioctl::{FS_IOC32_GETFLAGS, FS_IOC32_SETFLAGS}; +#[cfg(target_pointer_width = "64")] +pub(crate) use linux_raw_sys::ioctl::{FS_IOC_GETFLAGS, FS_IOC_SETFLAGS}; #[cfg(feature = "io_uring")] pub(crate) use linux_raw_sys::{general::open_how, io_uring::*}; diff --git a/src/fs/ioctl.rs b/src/fs/ioctl.rs index 75222752f..490f183ff 100644 --- a/src/fs/ioctl.rs +++ b/src/fs/ioctl.rs @@ -9,6 +9,8 @@ use { backend::c, }; +use bitflags::bitflags; + #[cfg(all(linux_kernel, not(any(target_arch = "sparc", target_arch = "sparc64"))))] use crate::fd::{AsRawFd, BorrowedFd}; @@ -90,3 +92,74 @@ unsafe impl ioctl::Ioctl for Ficlone<'_> { Ok(()) } } + +#[cfg(linux_kernel)] +bitflags! { + /// `FS_*` constants for use with [`ioctl_getflags`][crate::io::ioctl::ioctl_getflags]. + pub struct IFlags: c::c_uint { + /// `FS_APPEND_FL` + const APPEND = linux_raw_sys::general::FS_APPEND_FL; + /// `FS_COMPR_FL` + const COMPRESSED = linux_raw_sys::general::FS_COMPR_FL; + /// `FS_DIRSYNC_FL` + const DIRSYNC = linux_raw_sys::general::FS_DIRSYNC_FL; + /// `FS_IMMUTABLE_FL` + const IMMUTABLE = linux_raw_sys::general::FS_IMMUTABLE_FL; + /// `FS_JOURNAL_DATA_FL` + const JOURNALING = linux_raw_sys::general::FS_JOURNAL_DATA_FL; + /// `FS_NOATIME_FL` + const NOATIME = linux_raw_sys::general::FS_NOATIME_FL; + /// `FS_NOCOW_FL` + const NOCOW = linux_raw_sys::general::FS_NOCOW_FL; + /// `FS_NODUMP_FL` + const NODUMP = linux_raw_sys::general::FS_NODUMP_FL; + /// `FS_NOTAIL_FL` + const NOTAIL = linux_raw_sys::general::FS_NOTAIL_FL; + /// `FS_PROJINHERIT_FL` + const PROJECT_INHERIT = linux_raw_sys::general::FS_PROJINHERIT_FL; + /// `FS_SECRM_FL` + const SECURE_REMOVAL = linux_raw_sys::general::FS_SECRM_FL; + /// `FS_SYNC_FL` + const SYNC = linux_raw_sys::general::FS_SYNC_FL; + /// `FS_TOPDIR_FL` + const TOPDIR = linux_raw_sys::general::FS_TOPDIR_FL; + /// `FS_UNRM_FL` + const UNRM = linux_raw_sys::general::FS_UNRM_FL; + } +} + +/// `ioctl(fd, FS_IOC_GETFLAGS)`—Returns the [inode flags] attributes +/// +/// [inode flags]: https://man7.org/linux/man-pages/man2/ioctl_iflags.2.html +#[cfg(linux_kernel)] +#[inline] +#[doc(alias = "FS_IOC_GETFLAGS")] +pub fn ioctl_getflags(fd: Fd) -> io::Result { + unsafe { + #[cfg(target_pointer_width = "32")] + let ctl = ioctl::Getter::, u32>::new(); + #[cfg(target_pointer_width = "64")] + let ctl = ioctl::Getter::, u32>::new(); + + ioctl::ioctl(fd, ctl).map(IFlags::from_bits_retain) + } +} + +/// `ioctl(fd, FS_IOC_SETFLAGS)`—Modify the [inode flags] attributes +/// +/// [inode flags]: https://man7.org/linux/man-pages/man2/ioctl_iflags.2.html +#[cfg(linux_kernel)] +#[inline] +#[doc(alias = "FS_IOC_SETFLAGS")] +pub fn ioctl_setflags(fd: Fd, flags: IFlags) -> io::Result<()> { + unsafe { + #[cfg(target_pointer_width = "32")] + let ctl = + ioctl::Setter::, u32>::new(flags.bits()); + + #[cfg(target_pointer_width = "64")] + let ctl = ioctl::Setter::, u32>::new(flags.bits()); + + ioctl::ioctl(fd, ctl) + } +}