summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md2
-rw-r--r--src/unistd.rs21
-rw-r--r--test/test_unistd.rs68
3 files changed, 91 insertions, 0 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bfe81197..f00b801c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,8 @@ This project adheres to [Semantic Versioning](https://semver.org/).
## [Unreleased] - ReleaseDate
### Added
+- Added `faccessat`
+ ([#1780](https://github.com/nix-rust/nix/pull/1780))
- Added `memfd` on Android.
(#[1773](https://github.com/nix-rust/nix/pull/1773))
- Added ETH_P_ALL to SockProtocol enum
diff --git a/src/unistd.rs b/src/unistd.rs
index d3915dcc..70a06b02 100644
--- a/src/unistd.rs
+++ b/src/unistd.rs
@@ -2900,6 +2900,27 @@ pub fn access<P: ?Sized + NixPath>(path: &P, amode: AccessFlags) -> Result<()> {
})?;
Errno::result(res).map(drop)
}
+
+/// Checks the file named by `path` for accessibility according to the flags given by `mode`
+///
+/// If `dirfd` has a value, then `path` is relative to directory associated with the file descriptor.
+///
+/// If `dirfd` is `None`, then `path` is relative to the current working directory.
+///
+/// # References
+///
+/// [faccessat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/faccessat.html)
+// illumos: faccessat(2) appears to be supported, but the libc crate does not provide a binding.
+// redox: does not appear to support the *at family of syscalls.
+#[cfg(not(any(target_os = "illumos", target_os = "redox")))]
+pub fn faccessat<P: ?Sized + NixPath>(dirfd: Option<RawFd>, path: &P, mode: AccessFlags, flags: AtFlags) -> Result<()> {
+ let res = path.with_nix_path(|cstr| {
+ unsafe {
+ libc::faccessat(at_rawfd(dirfd), cstr.as_ptr(), mode.bits(), flags.bits())
+ }
+ })?;
+ Errno::result(res).map(drop)
+}
}
feature! {
diff --git a/test/test_unistd.rs b/test/test_unistd.rs
index 337ebe46..b08ab332 100644
--- a/test/test_unistd.rs
+++ b/test/test_unistd.rs
@@ -1308,3 +1308,71 @@ fn test_getpeereid_invalid_fd() {
// getpeereid is not POSIX, so error codes are inconsistent between different Unices.
getpeereid(-1).expect_err("assertion failed");
}
+
+#[test]
+#[cfg(not(any(target_os = "illumos", target_os = "redox")))]
+fn test_faccessat_none_not_existing() {
+ use nix::fcntl::AtFlags;
+ let tempdir = tempfile::tempdir().unwrap();
+ let dir = tempdir.path().join("does_not_exist.txt");
+ assert_eq!(
+ faccessat(None, &dir, AccessFlags::F_OK, AtFlags::empty())
+ .err()
+ .unwrap(),
+ Errno::ENOENT
+ );
+}
+
+#[test]
+#[cfg(not(any(target_os = "illumos", target_os = "redox")))]
+fn test_faccessat_not_existing() {
+ use nix::fcntl::AtFlags;
+ let tempdir = tempfile::tempdir().unwrap();
+ let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap();
+ let not_exist_file = "does_not_exist.txt";
+ assert_eq!(
+ faccessat(
+ Some(dirfd),
+ not_exist_file,
+ AccessFlags::F_OK,
+ AtFlags::empty()
+ )
+ .err()
+ .unwrap(),
+ Errno::ENOENT
+ );
+}
+
+#[test]
+#[cfg(not(any(target_os = "illumos", target_os = "redox")))]
+fn test_faccessat_none_file_exists() {
+ use nix::fcntl::AtFlags;
+ let tempdir = tempfile::tempdir().unwrap();
+ let path = tempdir.path().join("does_exist.txt");
+ let _file = File::create(path.clone()).unwrap();
+ assert!(faccessat(
+ None,
+ &path,
+ AccessFlags::R_OK | AccessFlags::W_OK,
+ AtFlags::empty()
+ )
+ .is_ok());
+}
+
+#[test]
+#[cfg(not(any(target_os = "illumos", target_os = "redox")))]
+fn test_faccessat_file_exists() {
+ use nix::fcntl::AtFlags;
+ let tempdir = tempfile::tempdir().unwrap();
+ let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap();
+ let exist_file = "does_exist.txt";
+ let path = tempdir.path().join(exist_file);
+ let _file = File::create(path.clone()).unwrap();
+ assert!(faccessat(
+ Some(dirfd),
+ &path,
+ AccessFlags::R_OK | AccessFlags::W_OK,
+ AtFlags::empty()
+ )
+ .is_ok());
+}