diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2018-03-24 15:47:05 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2018-03-24 15:47:05 +0000 |
commit | 868fd3ca29d1b3a4e7947568c3d4a9d936b3e1e5 (patch) | |
tree | 0cf7c2f61c17073bdde5fc574d2e765ee201bdcc | |
parent | 0418d346c5343d4b55d580dc9fd66cd2a150a0c3 (diff) | |
parent | d315804a1f69977ab2332b41d81668a5da0ee71b (diff) | |
download | nix-868fd3ca29d1b3a4e7947568c3d4a9d936b3e1e5.zip |
Merge #857
857: Add chmod, fchmod, fchmodat functions r=asomers a=antage
-rw-r--r-- | CHANGELOG.md | 2 | ||||
-rw-r--r-- | src/sys/stat.rs | 61 | ||||
-rw-r--r-- | test/test_stat.rs | 54 |
3 files changed, 115 insertions, 2 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c7b9d24..d594974f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ([#825](https://github.com/nix-rust/nix/pull/825)) - Exposed `MSG_CMSG_CLOEXEC` on *BSD. ([#825](https://github.com/nix-rust/nix/pull/825)) +- Added `fchmod`, `fchmodat`. + ([#857](https://github.com/nix-rust/nix/pull/857)) ### Changed - Display and Debug for SysControlAddr now includes all fields. diff --git a/src/sys/stat.rs b/src/sys/stat.rs index 1f0d728a..7bcf1fce 100644 --- a/src/sys/stat.rs +++ b/src/sys/stat.rs @@ -122,3 +122,64 @@ pub fn fstatat<P: ?Sized + NixPath>(dirfd: RawFd, pathname: &P, f: AtFlags) -> R Ok(dst) } +/// Change the file permission bits of the file specified by a file descriptor. +/// +/// # References +/// +/// [fchmod(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmod.html). +pub fn fchmod(fd: RawFd, mode: Mode) -> Result<()> { + let res = unsafe { libc::fchmod(fd, mode.bits() as mode_t) }; + + Errno::result(res).map(|_| ()) +} + +/// Flags for `fchmodat` function. +#[derive(Clone, Copy, Debug)] +pub enum FchmodatFlags { + FollowSymlink, + NoFollowSymlink, +} + +/// Change the file permission bits. +/// +/// 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 `FchmodatFlags::NoFollowSymlink` and `path` names a symbolic link, +/// then the mode of the symbolic link is changed. +/// +/// `fchmod(None, path, mode, FchmodatFlags::FollowSymlink)` is identical to +/// a call `libc::chmod(path, mode)`. That's why `chmod` is unimplemented +/// in the `nix` crate. +/// +/// # References +/// +/// [fchmodat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchmodat.html). +pub fn fchmodat<P: ?Sized + NixPath>( + dirfd: Option<RawFd>, + path: &P, + mode: Mode, + flag: FchmodatFlags, +) -> Result<()> { + let actual_dirfd = + match dirfd { + None => libc::AT_FDCWD, + Some(fd) => fd, + }; + let atflag = + match flag { + FchmodatFlags::FollowSymlink => AtFlags::empty(), + FchmodatFlags::NoFollowSymlink => AtFlags::AT_SYMLINK_NOFOLLOW, + }; + let res = path.with_nix_path(|cstr| unsafe { + libc::fchmodat( + actual_dirfd, + cstr.as_ptr(), + mode.bits() as mode_t, + atflag.bits() as libc::c_int, + ) + })?; + + Errno::result(res).map(|_| ()) +} diff --git a/test/test_stat.rs b/test/test_stat.rs index a65778ea..c042ce19 100644 --- a/test/test_stat.rs +++ b/test/test_stat.rs @@ -5,8 +5,9 @@ use std::os::unix::prelude::AsRawFd; use libc::{S_IFMT, S_IFLNK}; use nix::fcntl; -use nix::sys::stat::{self, stat, fstat, lstat}; -use nix::sys::stat::FileStat; +use nix::sys::stat::{self, fchmod, fchmodat, fstat, lstat, stat}; +use nix::sys::stat::{FileStat, Mode, FchmodatFlags}; +use nix::unistd::chdir; use nix::Result; use tempdir::TempDir; @@ -102,3 +103,52 @@ fn test_stat_fstat_lstat() { let fstat_result = fstat(link.as_raw_fd()); assert_stat_results(fstat_result); } + +#[test] +fn test_fchmod() { + let tempdir = TempDir::new("nix-test_fchmod").unwrap(); + let filename = tempdir.path().join("foo.txt"); + let file = File::create(&filename).unwrap(); + + let mut mode1 = Mode::empty(); + mode1.insert(Mode::S_IRUSR); + mode1.insert(Mode::S_IWUSR); + fchmod(file.as_raw_fd(), mode1).unwrap(); + + let file_stat1 = stat(&filename).unwrap(); + assert_eq!(file_stat1.st_mode & 0o7777, mode1.bits()); + + let mut mode2 = Mode::empty(); + mode2.insert(Mode::S_IROTH); + fchmod(file.as_raw_fd(), mode2).unwrap(); + + let file_stat2 = stat(&filename).unwrap(); + assert_eq!(file_stat2.st_mode & 0o7777, mode2.bits()); +} + +#[test] +fn test_fchmodat() { + let tempdir = TempDir::new("nix-test_fchmodat").unwrap(); + let filename = "foo.txt"; + let fullpath = tempdir.path().join(filename); + File::create(&fullpath).unwrap(); + + let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap(); + + let mut mode1 = Mode::empty(); + mode1.insert(Mode::S_IRUSR); + mode1.insert(Mode::S_IWUSR); + fchmodat(Some(dirfd), filename, mode1, FchmodatFlags::FollowSymlink).unwrap(); + + let file_stat1 = stat(&fullpath).unwrap(); + assert_eq!(file_stat1.st_mode & 0o7777, mode1.bits()); + + chdir(tempdir.path()).unwrap(); + + let mut mode2 = Mode::empty(); + mode2.insert(Mode::S_IROTH); + fchmodat(None, filename, mode2, FchmodatFlags::FollowSymlink).unwrap(); + + let file_stat2 = stat(&fullpath).unwrap(); + assert_eq!(file_stat2.st_mode & 0o7777, mode2.bits()); +} |