diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a0691d134..e719987d68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,9 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Added `NixPath::is_empty`. ([#1107](https://github.com/nix-rust/nix/pull/1107)) +- Added `mkfifoat` + ([#1133](https://github.com/nix-rust/nix/pull/1133)) + ### Changed - `Signal::from_c_int` has been replaced by `Signal::try_from` ([#1113](https://github.com/nix-rust/nix/pull/1113)) diff --git a/src/unistd.rs b/src/unistd.rs index a269a5c252..886084e8c5 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -506,6 +506,26 @@ pub fn mkfifo(path: &P, mode: Mode) -> Result<()> { Errno::result(res).map(drop) } +/// Creates new fifo special file (named pipe) with path `path` and access rights `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 +/// +/// [mkfifoat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mkfifoat.html). +// mkfifoat is not implemented in OSX or android +#[inline] +#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "android")))] +pub fn mkfifoat(dirfd: Option, path: &P, mode: Mode) -> Result<()> { + let res = path.with_nix_path(|cstr| unsafe { + libc::mkfifoat(at_rawfd(dirfd), cstr.as_ptr(), mode.bits() as mode_t) + })?; + + Errno::result(res).map(drop) +} + /// Creates a symbolic link at `path2` which points to `path1`. /// /// If `dirfd` has a value, then `path2` is relative to directory associated diff --git a/test/test_unistd.rs b/test/test_unistd.rs index 9e45ceeb89..94975049da 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -98,6 +98,58 @@ fn test_mkfifo_directory() { assert!(mkfifo(&env::temp_dir(), Mode::S_IRUSR).is_err()); } +#[test] +#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "android")))] +fn test_mkfifoat_none() { + let tempdir = tempfile::tempdir().unwrap(); + let mkfifoat_fifo = tempdir.path().join("mkfifoat_fifo"); + + mkfifoat(None, &mkfifoat_fifo, Mode::S_IRUSR).unwrap(); + + let stats = stat::stat(&mkfifoat_fifo).unwrap(); + let typ = stat::SFlag::from_bits_truncate(stats.st_mode); + assert_eq!(typ, SFlag::S_IFIFO); +} + +#[test] +#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "android")))] +fn test_mkfifoat() { + let tempdir = tempfile::tempdir().unwrap(); + let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); + let mkfifoat_name = "mkfifoat_name"; + + mkfifoat(Some(dirfd), mkfifoat_name, Mode::S_IRUSR).unwrap(); + + let stats = stat::fstatat(dirfd, mkfifoat_name, fcntl::AtFlags::empty()).unwrap(); + let typ = stat::SFlag::from_bits_truncate(stats.st_mode); + assert_eq!(typ, SFlag::S_IFIFO); +} + +#[test] +#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "android")))] +fn test_mkfifoat_directory_none() { + // mkfifoat should fail if a directory is given + assert_eq!( + mkfifoat(None, &env::temp_dir(), Mode::S_IRUSR).is_ok(), + false + ); +} + +#[test] +#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "android")))] +fn test_mkfifoat_directory() { + // mkfifoat should fail if a directory is given + let tempdir = tempfile::tempdir().unwrap(); + let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); + let mkfifoat_dir = "mkfifoat_dir"; + stat::mkdirat(dirfd, mkfifoat_dir, Mode::S_IRUSR).unwrap(); + + assert_eq!( + mkfifoat(Some(dirfd), mkfifoat_dir, Mode::S_IRUSR).is_ok(), + false + ); +} + #[test] fn test_getpid() { let pid: ::libc::pid_t = getpid().into();