From 4840f67fcbe02fe6428a0a29bcf329401242b739 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Tue, 14 Sep 2021 18:29:38 -0700 Subject: [PATCH 1/2] Add chown functions to std::os::unix::fs to change the owner and group of files This is a straightforward wrapper that uses the existing helpers for C string handling and errno handling. Having this available is convenient for UNIX utility programs written in Rust, and avoids having to call unsafe functions like `libc::chown` directly and handle errors manually, in a program that may otherwise be entirely safe code. In addition, these functions provide a more Rustic interface by accepting appropriate traits and using `None` rather than `-1`. --- library/std/src/os/unix/fs.rs | 70 ++++++++++++++++++++++++++++++++++ library/std/src/sys/unix/fs.rs | 17 +++++++++ 2 files changed, 87 insertions(+) diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs index 6cf37f23c574d..c26f6a182b74f 100644 --- a/library/std/src/os/unix/fs.rs +++ b/library/std/src/os/unix/fs.rs @@ -5,6 +5,7 @@ use super::platform::fs::MetadataExt as _; use crate::fs::{self, OpenOptions, Permissions}; use crate::io; +use crate::os::unix::io::{AsFd, AsRawFd}; use crate::path::Path; use crate::sys; use crate::sys_common::{AsInner, AsInnerMut, FromInner}; @@ -924,6 +925,75 @@ impl DirBuilderExt for fs::DirBuilder { } } +/// Change the owner and group of the specified path. +/// +/// Specifying either the uid or gid as `None` will leave it unchanged. +/// +/// Changing the owner typically requires privileges, such as root or a specific capability. +/// Changing the group typically requires either being the owner and a member of the group, or +/// having privileges. +/// +/// If called on a symbolic link, this will change the owner and group of the link target. To +/// change the owner and group of the link itself, see [`lchown`]. +/// +/// # Examples +/// +/// ```no_run +/// #![feature(unix_chown)] +/// use std::os::unix::fs; +/// +/// fn main() -> std::io::Result<()> { +/// fs::chown("/sandbox", Some(0), Some(0))?; +/// Ok(()) +/// } +/// ``` +#[unstable(feature = "unix_chown", issue = "none")] +pub fn chown>(dir: P, uid: Option, gid: Option) -> io::Result<()> { + sys::fs::chown(dir.as_ref(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX)) +} + +/// Change the owner and group of the file referenced by the specified open file descriptor. +/// +/// For semantics and required privileges, see [`chown`]. +/// +/// # Examples +/// +/// ```no_run +/// #![feature(unix_chown)] +/// use std::os::unix::fs; +/// +/// fn main() -> std::io::Result<()> { +/// let f = std::fs::File::open("/file")?; +/// fs::fchown(f, Some(0), Some(0))?; +/// Ok(()) +/// } +/// ``` +#[unstable(feature = "unix_chown", issue = "none")] +pub fn fchown(fd: F, uid: Option, gid: Option) -> io::Result<()> { + sys::fs::fchown(fd.as_fd().as_raw_fd(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX)) +} + +/// Change the owner and group of the specified path, without dereferencing symbolic links. +/// +/// Identical to [`chown`], except that if called on a symbolic link, this will change the owner +/// and group of the link itself rather than the owner and group of the link target. +/// +/// # Examples +/// +/// ```no_run +/// #![feature(unix_chown)] +/// use std::os::unix::fs; +/// +/// fn main() -> std::io::Result<()> { +/// fs::lchown("/symlink", Some(0), Some(0))?; +/// Ok(()) +/// } +/// ``` +#[unstable(feature = "unix_chown", issue = "none")] +pub fn lchown>(dir: P, uid: Option, gid: Option) -> io::Result<()> { + sys::fs::lchown(dir.as_ref(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX)) +} + /// Change the root directory of the current process to the specified path. /// /// This typically requires privileges, such as root or a specific capability. diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 6d7524a733afd..a4fff9b2e6473 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -1416,6 +1416,23 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { Ok(bytes_copied as u64) } +pub fn chown(path: &Path, uid: u32, gid: u32) -> io::Result<()> { + let path = cstr(path)?; + cvt(unsafe { libc::chown(path.as_ptr(), uid as libc::uid_t, gid as libc::gid_t) })?; + Ok(()) +} + +pub fn fchown(fd: c_int, uid: u32, gid: u32) -> io::Result<()> { + cvt(unsafe { libc::fchown(fd, uid as libc::uid_t, gid as libc::gid_t) })?; + Ok(()) +} + +pub fn lchown(path: &Path, uid: u32, gid: u32) -> io::Result<()> { + let path = cstr(path)?; + cvt(unsafe { libc::lchown(path.as_ptr(), uid as libc::uid_t, gid as libc::gid_t) })?; + Ok(()) +} + #[cfg(not(any(target_os = "fuchsia", target_os = "vxworks")))] pub fn chroot(dir: &Path) -> io::Result<()> { let dir = cstr(dir)?; From 862d89e3b5ba092d95586fc2a33b23d1c8672087 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 15 Sep 2021 13:09:54 -0700 Subject: [PATCH 2/2] Add tracking issue for unix_chown --- library/std/src/os/unix/fs.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs index c26f6a182b74f..30eead9b05901 100644 --- a/library/std/src/os/unix/fs.rs +++ b/library/std/src/os/unix/fs.rs @@ -947,7 +947,7 @@ impl DirBuilderExt for fs::DirBuilder { /// Ok(()) /// } /// ``` -#[unstable(feature = "unix_chown", issue = "none")] +#[unstable(feature = "unix_chown", issue = "88989")] pub fn chown>(dir: P, uid: Option, gid: Option) -> io::Result<()> { sys::fs::chown(dir.as_ref(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX)) } @@ -968,7 +968,7 @@ pub fn chown>(dir: P, uid: Option, gid: Option) -> io:: /// Ok(()) /// } /// ``` -#[unstable(feature = "unix_chown", issue = "none")] +#[unstable(feature = "unix_chown", issue = "88989")] pub fn fchown(fd: F, uid: Option, gid: Option) -> io::Result<()> { sys::fs::fchown(fd.as_fd().as_raw_fd(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX)) } @@ -989,7 +989,7 @@ pub fn fchown(fd: F, uid: Option, gid: Option) -> io::Result< /// Ok(()) /// } /// ``` -#[unstable(feature = "unix_chown", issue = "none")] +#[unstable(feature = "unix_chown", issue = "88989")] pub fn lchown>(dir: P, uid: Option, gid: Option) -> io::Result<()> { sys::fs::lchown(dir.as_ref(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX)) }