Skip to content

Commit

Permalink
Merge #1084
Browse files Browse the repository at this point in the history
1084: sys/stat: implement mkdirat r=asomers a=kevinwern

See: https://github.com/CraneStation/wasi-common/issues/16
https://linux.die.net/man/2/mkdirat

My first contribution to this repo. Tests were probably overkill...

Also, out of curiosity, is there any reason why `mkdir` is located in `unistd`? The documentation I read mentioned the function definition also being located in `sys/stat.h`.

Co-authored-by: Kevin Wern <[email protected]>
  • Loading branch information
bors[bot] and kevinwern committed Jun 16, 2019
2 parents 582846e + c006491 commit f926043
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 4 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
types that support them. ([#1035](https://github.com/nix-rust/nix/pull/1035))
- Added `copy_file_range` wrapper
([#1069](https://github.com/nix-rust/nix/pull/1069))
- Add `mkdirat`.
([#1084](https://github.com/nix-rust/nix/pull/1084))

### Changed
- Support for `ifaddrs` now present when building for Android.
Expand Down
8 changes: 8 additions & 0 deletions src/sys/stat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,3 +284,11 @@ pub fn utimensat<P: ?Sized + NixPath>(

Errno::result(res).map(drop)
}

pub fn mkdirat<P: ?Sized + NixPath>(fd: RawFd, path: &P, mode: Mode) -> Result<()> {
let res = path.with_nix_path(|cstr| {
unsafe { libc::mkdirat(fd, cstr.as_ptr(), mode.bits() as mode_t) }
})?;

Errno::result(res).map(drop)
}
42 changes: 38 additions & 4 deletions test/test_stat.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
use std::fs::{self, File};
use std::os::unix::fs::symlink;
use std::os::unix::fs::{symlink, PermissionsExt};
use std::os::unix::prelude::AsRawFd;
use std::time::{Duration, UNIX_EPOCH};
use std::path::Path;

#[cfg(not(any(target_os = "netbsd")))]
use libc::{S_IFMT, S_IFLNK};
use libc::{S_IFMT, S_IFLNK, mode_t};

use nix::fcntl;
use nix::sys::stat::{self, fchmod, fchmodat, futimens, stat, utimes, utimensat};
use nix::{fcntl, Error};
use nix::errno::{Errno};
use nix::sys::stat::{self, fchmod, fchmodat, futimens, stat, utimes, utimensat, mkdirat};
#[cfg(any(target_os = "linux",
target_os = "haiku",
target_os = "ios",
Expand Down Expand Up @@ -260,3 +262,35 @@ fn test_utimensat() {
UtimensatFlags::FollowSymlink).unwrap();
assert_times_eq(500, 800, &fs::metadata(&fullpath).unwrap());
}

#[test]
fn test_mkdirat_success_path() {
let tempdir = tempfile::tempdir().unwrap();
let filename = "example_subdir";
let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap();
assert!((mkdirat(dirfd, filename, Mode::S_IRWXU)).is_ok());
assert!(Path::exists(&tempdir.path().join(filename)));
}

#[test]
fn test_mkdirat_success_mode() {
let expected_bits = stat::SFlag::S_IFDIR.bits() | stat::Mode::S_IRWXU.bits();
let tempdir = tempfile::tempdir().unwrap();
let filename = "example_subdir";
let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap();
assert!((mkdirat(dirfd, filename, Mode::S_IRWXU)).is_ok());
let permissions = fs::metadata(tempdir.path().join(filename)).unwrap().permissions();
let mode = permissions.mode();
assert_eq!(mode as mode_t, expected_bits)
}

#[test]
fn test_mkdirat_fail() {
let tempdir = tempfile::tempdir().unwrap();
let not_dir_filename= "example_not_dir";
let filename = "example_subdir_dir";
let dirfd = fcntl::open(&tempdir.path().join(not_dir_filename), fcntl::OFlag::O_CREAT,
stat::Mode::empty()).unwrap();
let result = mkdirat(dirfd, filename, Mode::S_IRWXU).unwrap_err();
assert_eq!(result, Error::Sys(Errno::ENOTDIR));
}

0 comments on commit f926043

Please sign in to comment.