summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/fcntl.rs9
-rw-r--r--src/sys/stat.rs16
-rw-r--r--src/unistd.rs69
3 files changed, 74 insertions, 20 deletions
diff --git a/src/fcntl.rs b/src/fcntl.rs
index 58de3b31..5942506b 100644
--- a/src/fcntl.rs
+++ b/src/fcntl.rs
@@ -2,6 +2,7 @@ use {Error, Result, NixPath};
use errno::Errno;
use libc::{self, c_int, c_uint, c_char, size_t, ssize_t};
use sys::stat::Mode;
+use std::os::raw;
use std::os::unix::io::RawFd;
use std::ffi::OsStr;
use std::os::unix::ffi::OsStrExt;
@@ -182,6 +183,14 @@ pub fn readlinkat<'a, P: ?Sized + NixPath>(dirfd: RawFd, path: &P, buffer: &'a m
wrap_readlink_result(buffer, res)
}
+/// Computes the raw fd consumed by a function of the form `*at`.
+pub(crate) fn at_rawfd(fd: Option<RawFd>) -> raw::c_int {
+ match fd {
+ None => libc::AT_FDCWD,
+ Some(fd) => fd,
+ }
+}
+
#[cfg(any(target_os = "android", target_os = "linux"))]
libc_bitflags!(
/// Additional flags for file sealing, which allows for limiting operations on a file.
diff --git a/src/sys/stat.rs b/src/sys/stat.rs
index d0f0f8d9..a0b3aafc 100644
--- a/src/sys/stat.rs
+++ b/src/sys/stat.rs
@@ -3,10 +3,9 @@ pub use libc::stat as FileStat;
use {Result, NixPath};
use errno::Errno;
-use fcntl::AtFlags;
+use fcntl::{AtFlags, at_rawfd};
use libc;
use std::mem;
-use std::os::raw;
use std::os::unix::io::RawFd;
use sys::time::{TimeSpec, TimeVal};
@@ -135,15 +134,6 @@ pub fn fchmod(fd: RawFd, mode: Mode) -> Result<()> {
Errno::result(res).map(|_| ())
}
-/// Computes the raw fd consumed by a function of the form `*at`.
-#[inline]
-fn actual_atfd(fd: Option<RawFd>) -> raw::c_int {
- match fd {
- None => libc::AT_FDCWD,
- Some(fd) => fd,
- }
-}
-
/// Flags for `fchmodat` function.
#[derive(Clone, Copy, Debug)]
pub enum FchmodatFlags {
@@ -180,7 +170,7 @@ pub fn fchmodat<P: ?Sized + NixPath>(
};
let res = path.with_nix_path(|cstr| unsafe {
libc::fchmodat(
- actual_atfd(dirfd),
+ at_rawfd(dirfd),
cstr.as_ptr(),
mode.bits() as mode_t,
atflag.bits() as libc::c_int,
@@ -260,7 +250,7 @@ pub fn utimensat<P: ?Sized + NixPath>(
let times: [libc::timespec; 2] = [*atime.as_ref(), *mtime.as_ref()];
let res = path.with_nix_path(|cstr| unsafe {
libc::utimensat(
- actual_atfd(dirfd),
+ at_rawfd(dirfd),
cstr.as_ptr(),
&times[0],
atflag.bits() as libc::c_int,
diff --git a/src/unistd.rs b/src/unistd.rs
index 70882604..d5192977 100644
--- a/src/unistd.rs
+++ b/src/unistd.rs
@@ -2,7 +2,7 @@
use errno::{self, Errno};
use {Error, Result, NixPath};
-use fcntl::{fcntl, FdFlag, OFlag};
+use fcntl::{AtFlags, at_rawfd, fcntl, FdFlag, OFlag};
use fcntl::FcntlArg::F_SETFD;
use libc::{self, c_char, c_void, c_int, c_long, c_uint, size_t, pid_t, off_t,
uid_t, gid_t, mode_t};
@@ -557,6 +557,16 @@ pub fn getcwd() -> Result<PathBuf> {
}
}
+/// Computes the raw UID and GID values to pass to a `*chown` call.
+fn chown_raw_ids(owner: Option<Uid>, group: Option<Gid>) -> (libc::uid_t, libc::gid_t) {
+ // According to the POSIX specification, -1 is used to indicate that owner and group
+ // are not to be changed. Since uid_t and gid_t are unsigned types, we have to wrap
+ // around to get -1.
+ let uid = owner.map(Into::into).unwrap_or((0 as uid_t).wrapping_sub(1));
+ let gid = group.map(Into::into).unwrap_or((0 as gid_t).wrapping_sub(1));
+ (uid, gid)
+}
+
/// Change the ownership of the file at `path` to be owned by the specified
/// `owner` (user) and `group` (see
/// [chown(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/chown.html)).
@@ -567,17 +577,62 @@ pub fn getcwd() -> Result<PathBuf> {
#[inline]
pub fn chown<P: ?Sized + NixPath>(path: &P, owner: Option<Uid>, group: Option<Gid>) -> Result<()> {
let res = try!(path.with_nix_path(|cstr| {
- // According to the POSIX specification, -1 is used to indicate that
- // owner and group, respectively, are not to be changed. Since uid_t and
- // gid_t are unsigned types, we use wrapping_sub to get '-1'.
- unsafe { libc::chown(cstr.as_ptr(),
- owner.map(Into::into).unwrap_or((0 as uid_t).wrapping_sub(1)),
- group.map(Into::into).unwrap_or((0 as gid_t).wrapping_sub(1))) }
+ let (uid, gid) = chown_raw_ids(owner, group);
+ unsafe { libc::chown(cstr.as_ptr(), uid, gid) }
}));
Errno::result(res).map(drop)
}
+/// Flags for `fchownat` function.
+#[derive(Clone, Copy, Debug)]
+pub enum FchownatFlags {
+ FollowSymlink,
+ NoFollowSymlink,
+}
+
+/// Change the ownership of the file at `path` to be owned by the specified
+/// `owner` (user) and `group`.
+///
+/// The owner/group for the provided path name will not be modified if `None` is
+/// provided for that argument. Ownership change will be attempted for the path
+/// only if `Some` owner/group is provided.
+///
+/// The file to be changed is determined relative to the directory associated
+/// with the file descriptor `dirfd` or the current working directory
+/// if `dirfd` is `None`.
+///
+/// If `flag` is `FchownatFlags::NoFollowSymlink` and `path` names a symbolic link,
+/// then the mode of the symbolic link is changed.
+///
+/// `fchownat(None, path, mode, FchownatFlags::NoFollowSymlink)` is identical to
+/// a call `libc::lchown(path, mode)`. That's why `lchmod` is unimplemented in
+/// the `nix` crate.
+///
+/// # References
+///
+/// [fchownat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchownat.html).
+pub fn fchownat<P: ?Sized + NixPath>(
+ dirfd: Option<RawFd>,
+ path: &P,
+ owner: Option<Uid>,
+ group: Option<Gid>,
+ flag: FchownatFlags,
+) -> Result<()> {
+ let atflag =
+ match flag {
+ FchownatFlags::FollowSymlink => AtFlags::empty(),
+ FchownatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW,
+ };
+ let res = path.with_nix_path(|cstr| unsafe {
+ let (uid, gid) = chown_raw_ids(owner, group);
+ libc::fchownat(at_rawfd(dirfd), cstr.as_ptr(), uid, gid,
+ atflag.bits() as libc::c_int)
+ })?;
+
+ Errno::result(res).map(|_| ())
+}
+
fn to_exec_array(args: &[CString]) -> Vec<*const c_char> {
let mut args_p: Vec<*const c_char> = args.iter().map(|s| s.as_ptr()).collect();
args_p.push(ptr::null());