diff --git a/CHANGELOG.md b/CHANGELOG.md index 36b528ca91..272554e005 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ([#739](https://github.com/nix-rust/nix/pull/739)) - Added nix::sys::ptrace::detach. ([#749](https://github.com/nix-rust/nix/pull/749)) +- Added `nix::unistd::unlinkat`. + ([#753](https://github.com/nix-rust/nix/pull/753)) ### Changed - Renamed existing `ptrace` wrappers to encourage namespacing ([#692](https://github.com/nix-rust/nix/pull/692)) diff --git a/src/fcntl.rs b/src/fcntl.rs index 003c316c06..1a2591911a 100644 --- a/src/fcntl.rs +++ b/src/fcntl.rs @@ -11,10 +11,12 @@ use sys::uio::IoVec; // For vmsplice libc_bitflags!{ pub struct AtFlags: c_int { AT_SYMLINK_NOFOLLOW; - #[cfg(any(target_os = "android", target_os = "linux"))] + #[cfg(any(target_os = "linux", target_os = "android"))] + AT_REMOVEDIR; + #[cfg(any(target_os = "linux", target_os = "android"))] AT_NO_AUTOMOUNT; - #[cfg(any(target_os = "android", target_os = "linux"))] - AT_EMPTY_PATH; + #[cfg(any(target_os = "linux", target_os = "android"))] + AT_EMPTY_PATH } } diff --git a/src/unistd.rs b/src/unistd.rs index fad51272e0..0b205bf194 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -2,7 +2,7 @@ use errno; use {Errno, Error, Result, NixPath}; -use fcntl::{fcntl, OFlag, O_CLOEXEC, FD_CLOEXEC}; +use fcntl::{AtFlags, fcntl, OFlag, O_CLOEXEC, FD_CLOEXEC}; use fcntl::FcntlArg::F_SETFD; use libc::{self, c_char, c_void, c_int, c_long, c_uint, size_t, pid_t, off_t, uid_t, gid_t, mode_t}; @@ -914,6 +914,17 @@ pub fn unlink(path: &P) -> Result<()> { Errno::result(res).map(drop) } +/// Delete a name and possibly the file it refers to +/// ([posix specification](http://pubs.opengroup.org/onlinepubs/9699919799/functions/unlinkat.html)). +pub fn unlinkat(fd: RawFd, pathname: &P, flags: AtFlags) -> Result<()> { + let res = try!(pathname.with_nix_path(|cstr| { + unsafe { + libc::unlinkat(fd, cstr.as_ptr(), flags.bits()) + } + })); + Errno::result(res).map(drop) +} + #[inline] pub fn chroot(path: &P) -> Result<()> { let res = try!(path.with_nix_path(|cstr| { diff --git a/test/test_unistd.rs b/test/test_unistd.rs index adf735794e..f6b3782e35 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -1,5 +1,6 @@ extern crate tempdir; +use nix::fcntl; use nix::unistd::*; use nix::unistd::ForkResult::*; use nix::sys::wait::*; @@ -225,6 +226,21 @@ fn test_lseek() { close(tmpfd).unwrap(); } +#[test] +fn test_unlinkat() { + let tempdir = TempDir::new("nix-test_unlinkat").unwrap(); + let dirfd = fcntl::open(tempdir.path(), + fcntl::OFlag::empty(), + stat::Mode::empty()); + let file = tempdir.path().join("foo"); + File::create(&file).unwrap(); + + unlinkat(dirfd.unwrap(), + &file.file_name(), + fcntl::AtFlags::empty()).unwrap(); + assert!(!file.exists()); +} + #[cfg(any(target_os = "linux", target_os = "android"))] #[test] fn test_lseek64() {