summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md2
-rw-r--r--Cargo.toml2
-rw-r--r--build.rs4
-rw-r--r--src/sys/stat.rs61
-rw-r--r--test/test_stat.rs54
5 files changed, 118 insertions, 5 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d77a7717..5fffab92 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -23,6 +23,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/Cargo.toml b/Cargo.toml
index 651c2184..8b1c90e7 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -23,7 +23,7 @@ version = "0.4.5"
default-features = false
[target.'cfg(target_os = "dragonfly")'.build-dependencies]
-gcc = "0.3"
+cc = "1"
[dev-dependencies]
lazy_static = "1"
diff --git a/build.rs b/build.rs
index d6a9a503..92fd3667 100644
--- a/build.rs
+++ b/build.rs
@@ -1,9 +1,9 @@
#[cfg(target_os = "dragonfly")]
-extern crate gcc;
+extern crate cc;
#[cfg(target_os = "dragonfly")]
fn main() {
- gcc::Build::new()
+ cc::Build::new()
.file("src/errno_dragonfly.c")
.compile("liberrno_dragonfly.a");
}
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());
+}