Skip to content

Commit

Permalink
sys/stat: implement mkdirat
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinwern committed Jun 10, 2019
1 parent 83407c5 commit 515bee4
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 3 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
### Added
- Added `MSG_WAITALL` to `MsgFlags` in `sys::socket`.
([#1079](https://github.com/nix-rust/nix/pull/1079))
- 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)
}
40 changes: 37 additions & 3 deletions test/test_stat.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
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::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 +261,36 @@ 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]
#[should_panic="EACCES"]
fn test_mkdirat_fail() {
let tempdir = tempfile::tempdir().unwrap();
let filename = "example_subdir";
let mut perms = fs::metadata(tempdir.path()).unwrap().permissions();
perms.set_readonly(true);
fs::set_permissions(tempdir.path(), perms).unwrap();
let dirfd = fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty()).unwrap();
let result = mkdirat(dirfd, filename, Mode::S_IRWXU).unwrap();
}

0 comments on commit 515bee4

Please sign in to comment.