Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement faccessat #1780

Merged
merged 1 commit into from Aug 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -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
Expand Down
21 changes: 21 additions & 0 deletions src/unistd.rs
Expand Up @@ -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! {
Expand Down
68 changes: 68 additions & 0 deletions test/test_unistd.rs
Expand Up @@ -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());
}