diff --git a/src/backend/libc/io/syscalls.rs b/src/backend/libc/io/syscalls.rs index d083fc520..dbdb332a5 100644 --- a/src/backend/libc/io/syscalls.rs +++ b/src/backend/libc/io/syscalls.rs @@ -14,6 +14,8 @@ use super::super::offset::{libc_preadv2, libc_pwritev2}; use crate::fd::{AsFd, BorrowedFd, OwnedFd, RawFd}; #[cfg(not(any(target_os = "aix", target_os = "wasi")))] use crate::io::DupFlags; +#[cfg(any(target_os = "android", target_os = "linux"))] +use crate::io::IFlags; #[cfg(not(any( target_os = "aix", target_os = "haiku", @@ -324,6 +326,47 @@ pub(crate) fn ioctl_blkpbszget(fd: BorrowedFd) -> io::Result { } } +#[cfg(any(target_os = "android", target_os = "linux"))] +#[inline] +pub(crate) fn ioctl_get_flags(fd: BorrowedFd) -> io::Result { + let mut result = MaybeUninit::::uninit(); + #[cfg(target_pointer_width = "32")] + unsafe { + ret(c::ioctl( + borrowed_fd(fd), + c::FS_IOC32_GETFLAGS, + result.as_mut_ptr(), + ))?; + Ok(result.assume_init() as IFlags) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret(c::ioctl( + borrowed_fd(fd), + c::FS_IOC_GETFLAGS, + result.as_mut_ptr(), + ))?; + Ok(result.assume_init() as IFlags) + } +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +#[inline] +pub(crate) fn ioctl_set_flags(fd: BorrowedFd, flags: IFlags) -> io::Result<()> { + #[cfg(target_pointer_width = "32")] + unsafe { + ret(c::ioctl( + borrowed_fd(fd), + c::FS_IOC32_SETFLAGS, + flags.bits(), + )) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret(c::ioctl(borrowed_fd(fd), c::FS_IOC_SETFLAGS, flags.bits())) + } +} + #[cfg(not(target_os = "redox"))] pub(crate) fn ioctl_fionread(fd: BorrowedFd<'_>) -> io::Result { let mut nread = MaybeUninit::::uninit(); diff --git a/src/backend/libc/io/types.rs b/src/backend/libc/io/types.rs index 9716b27df..af9476db7 100644 --- a/src/backend/libc/io/types.rs +++ b/src/backend/libc/io/types.rs @@ -157,3 +157,38 @@ impl<'a> IoSliceRaw<'a> { } } } + +#[cfg(any(target_os = "android", target_os = "linux"))] +bitflags! { + /// `FS_*` constants for use with [`ioctl_getflags`][crate::io::ioctl::ioctl_getflags]. + pub struct IFlags: c::c_uint { + /// `FS_APPEND_FL` + const APPEND = c::FS_APPEND_FL; + /// `FS_COMPR_FL` + const COMPRESSED = c::FS_COMPR_FL; + /// `FS_DIRSYNC_FL` + const DIRSYNC = c::FS_DIRSYNC_FL; + /// `FS_IMMUTABLE_FL` + const IMMUTABLE = c::FS_IMMUTABLE_FL; + /// `FS_JOURNAL_DATA_FL` + const JOURNALING = c::FS_JOURNAL_DATA_FL; + /// `FS_NOATIME_FL` + const NOATIME = c::FS_NOATIME_FL; + /// `FS_NOCOW_FL` + const NOCOW = c::FS_NOCOW_FL; + /// `FS_NODUMP_FL` + const NODUMP = c::FS_NODUMP_FL; + /// `FS_NOTAIL_FL` + const NOTAIL = c::FS_NOTAIL_FL; + /// `FS_PROJINHERIT_FL` + const PROJECT_INHERIT = c::FS_PROJINHERIT_FL; + /// `FS_SECRM_FL` + const SECURE_REMOVAL = c::FS_SECRM_FL; + /// `FS_SYNC_FL` + const SYNC = c::FS_SYNC_FL; + /// `FS_TOPDIR_FL` + const TOPDIR = c::FS_TOPDIR_FL; + /// `FS_UNRM_FL` + const UNRM = c::FS_UNRM_FL; + } +} diff --git a/src/backend/linux_raw/io/syscalls.rs b/src/backend/linux_raw/io/syscalls.rs index 2cc7898af..810114b6e 100644 --- a/src/backend/linux_raw/io/syscalls.rs +++ b/src/backend/linux_raw/io/syscalls.rs @@ -15,6 +15,8 @@ use super::super::conv::{ }; #[cfg(target_pointer_width = "32")] use super::super::conv::{hi, lo}; +#[cfg(any(target_os = "android", target_os = "linux"))] +use crate::backend::io::types::IFlags; use crate::fd::{AsFd, BorrowedFd, OwnedFd, RawFd}; #[cfg(any(target_os = "android", target_os = "linux"))] use crate::io::SpliceFlags; @@ -33,6 +35,10 @@ use linux_raw_sys::general::{ UIO_MAXIOV, }; use linux_raw_sys::ioctl::{BLKPBSZGET, BLKSSZGET, FIONBIO, FIONREAD, TIOCEXCL, TIOCNXCL}; +#[cfg(target_pointer_width = "32")] +use linux_raw_sys::ioctl::{FS_IOC32_GETFLAGS, FS_IOC32_SETFLAGS}; +#[cfg(target_pointer_width = "64")] +use linux_raw_sys::ioctl::{FS_IOC_GETFLAGS, FS_IOC_SETFLAGS}; #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] use { super::super::conv::{opt_ref, size_of}, @@ -352,6 +358,55 @@ pub(crate) fn ioctl_blkpbszget(fd: BorrowedFd) -> io::Result { } } +#[inline] +pub(crate) fn ioctl_get_flags(fd: BorrowedFd) -> io::Result { + let mut result = MaybeUninit::::uninit(); + #[cfg(target_pointer_width = "32")] + unsafe { + ret(syscall!( + __NR_ioctl, + fd, + c_uint(FS_IOC32_GETFLAGS), + &mut result + ))?; + Ok(result.assume_init() as IFlags) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret(syscall!( + __NR_ioctl, + fd, + c_uint(FS_IOC_GETFLAGS), + &mut result + ))?; + Ok(result.assume_init() as IFlags) + } +} + +#[inline] +pub(crate) fn ioctl_set_flags(fd: BorrowedFd, flags: IFlags) -> io::Result<()> { + // ioctl expect a *const c_uint, we thus need to convert it and pass it by reference + let attr = flags.bits(); + #[cfg(target_pointer_width = "32")] + unsafe { + ret(syscall_readonly!( + __NR_ioctl, + fd, + c_uint(FS_IOC32_SETFLAGS), + by_ref(&attr) + )) + } + #[cfg(target_pointer_width = "64")] + unsafe { + ret(syscall_readonly!( + __NR_ioctl, + fd, + c_uint(FS_IOC_SETFLAGS), + by_ref(&attr) + )) + } +} + #[cfg(all(feature = "fs", feature = "net"))] pub(crate) fn is_read_write(fd: BorrowedFd<'_>) -> io::Result<(bool, bool)> { let (mut read, mut write) = crate::fs::fd::_is_file_read_write(fd)?; diff --git a/src/backend/linux_raw/io/types.rs b/src/backend/linux_raw/io/types.rs index 51ab61d94..220a20582 100644 --- a/src/backend/linux_raw/io/types.rs +++ b/src/backend/linux_raw/io/types.rs @@ -126,3 +126,37 @@ impl<'a> IoSliceRaw<'a> { } } } + +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; + } +} diff --git a/src/io/ioctl.rs b/src/io/ioctl.rs index 01ded2e12..327c8036a 100644 --- a/src/io/ioctl.rs +++ b/src/io/ioctl.rs @@ -5,6 +5,8 @@ use crate::{backend, io}; use backend::fd::AsFd; +#[cfg(any(target_os = "android", target_os = "linux"))] +pub use backend::io::types::IFlags; /// `ioctl(fd, TIOCEXCL)`—Enables exclusive mode on a terminal. /// @@ -97,3 +99,23 @@ pub fn ioctl_blksszget(fd: Fd) -> io::Result { pub fn ioctl_blkpbszget(fd: Fd) -> io::Result { backend::io::syscalls::ioctl_blkpbszget(fd.as_fd()) } + +/// `ioctl(fd, FS_IOC_GETFLAGS)`—Returns the [inode flags] attributes +/// +/// [inode flags]: https://man7.org/linux/man-pages/man2/ioctl_iflags.2.html +#[cfg(any(target_os = "android", target_os = "linux"))] +#[inline] +#[doc(alias = "FS_IOC_GETFLAGS")] +pub fn ioctl_getflags(fd: Fd) -> io::Result { + backend::io::syscalls::ioctl_get_flags(fd.as_fd()) +} + +/// `ioctl(fd, FS_IOC_SETFLAGS)`—Modify the [inode flags] attributes +/// +/// [inode flags]: https://man7.org/linux/man-pages/man2/ioctl_iflags.2.html +#[cfg(any(target_os = "android", target_os = "linux"))] +#[inline] +#[doc(alias = "FS_IOC_GETFLAGS")] +pub fn ioctl_setflags(fd: Fd, flags: IFlags) -> io::Result<()> { + backend::io::syscalls::ioctl_set_flags(fd.as_fd(), flags) +} diff --git a/src/io/mod.rs b/src/io/mod.rs index 78106ab7d..6b38d2ab7 100644 --- a/src/io/mod.rs +++ b/src/io/mod.rs @@ -42,7 +42,9 @@ pub use ioctl::ioctl_fionbio; #[cfg(not(target_os = "redox"))] pub use ioctl::ioctl_fionread; #[cfg(any(target_os = "android", target_os = "linux"))] -pub use ioctl::{ioctl_blkpbszget, ioctl_blksszget}; +pub use ioctl::IFlags; +#[cfg(any(target_os = "android", target_os = "linux"))] +pub use ioctl::{ioctl_blkpbszget, ioctl_blksszget, ioctl_getflags, ioctl_setflags}; #[cfg(not(any(windows, target_os = "haiku", target_os = "redox", target_os = "wasi")))] pub use ioctl::{ioctl_tiocexcl, ioctl_tiocnxcl}; #[cfg(not(any(windows, target_os = "redox")))]