summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuca BRUNO <luca.bruno@coreos.com>2021-07-22 07:49:59 +0000
committerLuca BRUNO <luca.bruno@coreos.com>2021-07-28 12:36:59 +0000
commit6e2158bc7126510890351d67400d53de9fa9629e (patch)
treedd3b5ab5d5c6a4ff49771c90477b2499a95dbc80
parent8519d9f8c8e3b1cdf211774d309f8f21cf450528 (diff)
downloadnix-6e2158bc7126510890351d67400d53de9fa9629e.zip
sys/stat: add a safe wrapper for mknodat(2)
This introduces a new `mknodat` helper. Ref: https://pubs.opengroup.org/onlinepubs/9699919799/functions/mknod.html
-rw-r--r--CHANGELOG.md2
-rw-r--r--src/sys/stat.rs25
-rw-r--r--test/test_stat.rs42
3 files changed, 65 insertions, 4 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 97268ef2..dce18009 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,8 @@ This project adheres to [Semantic Versioning](https://semver.org/).
(#[1471](https://github.com/nix-rust/nix/pull/1471))
- Added `pthread_kill`.
(#[1472](https://github.com/nix-rust/nix/pull/1472))
+- Added `mknodat`.
+ (#[1473](https://github.com/nix-rust/nix/pull/1473))
### Changed
diff --git a/src/sys/stat.rs b/src/sys/stat.rs
index 15451e78..c797576e 100644
--- a/src/sys/stat.rs
+++ b/src/sys/stat.rs
@@ -9,6 +9,7 @@ use std::os::unix::io::RawFd;
use crate::sys::time::{TimeSpec, TimeVal};
libc_bitflags!(
+ /// "File type" flags for `mknod` and related functions.
pub struct SFlag: mode_t {
S_IFIFO;
S_IFCHR;
@@ -22,6 +23,7 @@ libc_bitflags!(
);
libc_bitflags! {
+ /// "File mode / permissions" flags.
pub struct Mode: mode_t {
S_IRWXU;
S_IRUSR;
@@ -41,11 +43,26 @@ libc_bitflags! {
}
}
+/// Create a special or ordinary file, by pathname.
pub fn mknod<P: ?Sized + NixPath>(path: &P, kind: SFlag, perm: Mode, dev: dev_t) -> Result<()> {
- let res = path.with_nix_path(|cstr| {
- unsafe {
- libc::mknod(cstr.as_ptr(), kind.bits | perm.bits() as mode_t, dev)
- }
+ let res = path.with_nix_path(|cstr| unsafe {
+ libc::mknod(cstr.as_ptr(), kind.bits | perm.bits() as mode_t, dev)
+ })?;
+
+ Errno::result(res).map(drop)
+}
+
+/// Create a special or ordinary file, relative to a given directory.
+#[cfg(not(any(target_os = "ios", target_os = "macos", target_os = "redox")))]
+pub fn mknodat<P: ?Sized + NixPath>(
+ dirfd: RawFd,
+ path: &P,
+ kind: SFlag,
+ perm: Mode,
+ dev: dev_t,
+) -> Result<()> {
+ let res = path.with_nix_path(|cstr| unsafe {
+ libc::mknodat(dirfd, cstr.as_ptr(), kind.bits | perm.bits() as mode_t, dev)
})?;
Errno::result(res).map(drop)
diff --git a/test/test_stat.rs b/test/test_stat.rs
index 424371fa..42c536a8 100644
--- a/test/test_stat.rs
+++ b/test/test_stat.rs
@@ -306,3 +306,45 @@ fn test_mkdirat_fail() {
let result = mkdirat(dirfd, filename, Mode::S_IRWXU).unwrap_err();
assert_eq!(result, Errno::ENOTDIR);
}
+
+#[test]
+#[cfg(not(any(target_os = "freebsd",
+ target_os = "ios",
+ target_os = "macos",
+ target_os = "redox")))]
+fn test_mknod_family() {
+ use fcntl::{AtFlags, OFlag};
+ use nix::dir::Dir;
+ use stat::{fstatat, lstat, mknod, mknodat, SFlag};
+
+ let file_name = "test_file";
+ {
+ let tempdir = tempfile::tempdir().unwrap();
+ let target = tempdir.path().join(file_name);
+ mknod(&target, SFlag::S_IFREG, Mode::S_IRWXU, 0).unwrap();
+ let mode = lstat(&target).unwrap().st_mode as mode_t;
+ assert!(mode & libc::S_IFREG == libc::S_IFREG);
+ assert!(mode & libc::S_IRWXU == libc::S_IRWXU);
+ }
+ {
+ let tempdir = tempfile::tempdir().unwrap();
+ let target_dir = Dir::open(tempdir.path(), OFlag::O_DIRECTORY, Mode::S_IRWXU).unwrap();
+ mknodat(
+ target_dir.as_raw_fd(),
+ file_name,
+ SFlag::S_IFREG,
+ Mode::S_IRWXU,
+ 0,
+ )
+ .unwrap();
+ let mode = fstatat(
+ target_dir.as_raw_fd(),
+ file_name,
+ AtFlags::AT_SYMLINK_NOFOLLOW,
+ )
+ .unwrap()
+ .st_mode as mode_t;
+ assert!(mode & libc::S_IFREG == libc::S_IFREG);
+ assert!(mode & libc::S_IRWXU == libc::S_IRWXU);
+ }
+}