From 93c95474e0ef70ba1c10b163d05dc89ba1b74b2d Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 12 Sep 2023 12:14:05 -0700 Subject: [PATCH] Add a `rustix::fs::chown` function. (#825) * Add a `rustix::fs::chown` function. * Fix compile errors with inferred-type casts. --- src/backend/libc/fs/syscalls.rs | 8 ++++++++ src/backend/linux_raw/fs/syscalls.rs | 24 +++++++++++++++++++++++ src/backend/linux_raw/process/syscalls.rs | 8 ++++---- src/backend/linux_raw/vdso.rs | 2 +- src/fs/abs.rs | 16 +++++++++++++++ tests/fs/file.rs | 4 ++++ 6 files changed, 57 insertions(+), 5 deletions(-) diff --git a/src/backend/libc/fs/syscalls.rs b/src/backend/libc/fs/syscalls.rs index ca5a11df7..3a9a3515e 100644 --- a/src/backend/libc/fs/syscalls.rs +++ b/src/backend/libc/fs/syscalls.rs @@ -1267,6 +1267,14 @@ pub(crate) fn fchmod(fd: BorrowedFd<'_>, mode: Mode) -> io::Result<()> { unsafe { ret(fchmod(borrowed_fd(fd), mode.bits() as c::mode_t)) } } +#[cfg(not(target_os = "wasi"))] +pub(crate) fn chown(path: &CStr, owner: Option, group: Option) -> io::Result<()> { + unsafe { + let (ow, gr) = crate::ugid::translate_fchown_args(owner, group); + ret(c::chown(c_str(path), ow, gr)) + } +} + #[cfg(linux_kernel)] pub(crate) fn fchown(fd: BorrowedFd<'_>, owner: Option, group: Option) -> io::Result<()> { // Use `c::syscall` rather than `c::fchown` because some libc diff --git a/src/backend/linux_raw/fs/syscalls.rs b/src/backend/linux_raw/fs/syscalls.rs index 72ab05cf8..e72afb8ab 100644 --- a/src/backend/linux_raw/fs/syscalls.rs +++ b/src/backend/linux_raw/fs/syscalls.rs @@ -158,6 +158,30 @@ pub(crate) fn chownat( } } +#[inline] +pub(crate) fn chown(path: &CStr, owner: Option, group: Option) -> io::Result<()> { + // Most architectures have a `chown` syscall. + #[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))] + unsafe { + let (ow, gr) = crate::ugid::translate_fchown_args(owner, group); + ret(syscall_readonly!(__NR_chown, path, c_uint(ow), c_uint(gr))) + } + + // Aarch64 and RISC-V don't, so use `fchownat`. + #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] + unsafe { + let (ow, gr) = crate::ugid::translate_fchown_args(owner, group); + ret(syscall_readonly!( + __NR_fchownat, + raw_fd(AT_FDCWD), + path, + c_uint(ow), + c_uint(gr), + zero() + )) + } +} + #[inline] pub(crate) fn fchown(fd: BorrowedFd<'_>, owner: Option, group: Option) -> io::Result<()> { unsafe { diff --git a/src/backend/linux_raw/process/syscalls.rs b/src/backend/linux_raw/process/syscalls.rs index 3fe73b938..d08c6b15d 100644 --- a/src/backend/linux_raw/process/syscalls.rs +++ b/src/backend/linux_raw/process/syscalls.rs @@ -366,12 +366,12 @@ pub(crate) fn prlimit(pid: Option, limit: Resource, new: Rlimit) -> io::Res /// Convert a Rust [`Rlimit`] to a C `rlimit64`. #[inline] fn rlimit_from_linux(lim: rlimit64) -> Rlimit { - let current = if lim.rlim_cur == RLIM64_INFINITY as _ { + let current = if lim.rlim_cur as u64 == RLIM64_INFINITY as u64 { None } else { Some(lim.rlim_cur) }; - let maximum = if lim.rlim_max == RLIM64_INFINITY as _ { + let maximum = if lim.rlim_max as u64 == RLIM64_INFINITY as u64 { None } else { Some(lim.rlim_max) @@ -396,12 +396,12 @@ fn rlimit_to_linux(lim: Rlimit) -> rlimit64 { /// Like `rlimit_from_linux` but uses Linux's old 32-bit `rlimit`. #[allow(clippy::useless_conversion)] fn rlimit_from_linux_old(lim: rlimit) -> Rlimit { - let current = if lim.rlim_cur == RLIM_INFINITY as _ { + let current = if lim.rlim_cur as u32 == RLIM_INFINITY as u32 { None } else { Some(lim.rlim_cur.into()) }; - let maximum = if lim.rlim_max == RLIM_INFINITY as _ { + let maximum = if lim.rlim_max as u32 == RLIM_INFINITY as u32 { None } else { Some(lim.rlim_max.into()) diff --git a/src/backend/linux_raw/vdso.rs b/src/backend/linux_raw/vdso.rs index 2934293a0..1b0ae5375 100644 --- a/src/backend/linux_raw/vdso.rs +++ b/src/backend/linux_raw/vdso.rs @@ -167,7 +167,7 @@ fn init_from_sysinfo_ehdr() -> Option { .as_ptr(); } DT_SYMENT => { - if d.d_un.d_val != size_of::() as _ { + if d.d_un.d_ptr != size_of::() { return None; // Failed } } diff --git a/src/fs/abs.rs b/src/fs/abs.rs index b61224f2c..f57bd00fe 100644 --- a/src/fs/abs.rs +++ b/src/fs/abs.rs @@ -16,6 +16,8 @@ use crate::fs::StatFs; #[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))] use crate::fs::StatVfs; use crate::fs::{Mode, OFlags, Stat}; +#[cfg(not(target_os = "wasi"))] +use crate::ugid::{Gid, Uid}; use crate::{backend, io, path}; #[cfg(feature = "alloc")] use { @@ -280,3 +282,17 @@ pub fn statfs(path: P) -> io::Result { pub fn statvfs(path: P) -> io::Result { path.into_with_c_str(backend::fs::syscalls::statvfs) } + +/// `chown(path, owner, group)`—Sets open file or directory ownership. +/// +/// # References +/// - [POSIX] +/// - [Linux] +/// +/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/chown.html +/// [Linux]: https://man7.org/linux/man-pages/man2/chown.2.html +#[cfg(not(target_os = "wasi"))] +#[inline] +pub fn chown(path: P, owner: Option, group: Option) -> io::Result<()> { + path.into_with_c_str(|path| backend::fs::syscalls::chown(path, owner, group)) +} diff --git a/tests/fs/file.rs b/tests/fs/file.rs index 0be1ffd27..d8ca3e11f 100644 --- a/tests/fs/file.rs +++ b/tests/fs/file.rs @@ -9,6 +9,8 @@ fn test_file() { ) .unwrap(); + rustix::fs::chown("Cargo.toml", None, None).unwrap(); + #[cfg(not(any(target_os = "emscripten", target_os = "android")))] #[allow(unreachable_patterns)] match rustix::fs::accessat( @@ -66,6 +68,8 @@ fn test_file() { ) .unwrap(); + rustix::fs::fchown(&file, None, None).unwrap(); + assert_eq!( rustix::fs::openat( &file,