diff --git a/CHANGELOG.md b/CHANGELOG.md index 777b4d98d9..9a5ad80f7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ([#1084](https://github.com/nix-rust/nix/pull/1084)) - Add `posix_fadvise`. ([#1089](https://github.com/nix-rust/nix/pull/1089)) +- Add `renameat` and `AT_FDCWD`. + ([#1097](https://github.com/nix-rust/nix/pull/1097)) ### Changed - Support for `ifaddrs` now present when building for Android. diff --git a/src/fcntl.rs b/src/fcntl.rs index 2201873a63..2d9a077021 100644 --- a/src/fcntl.rs +++ b/src/fcntl.rs @@ -21,6 +21,8 @@ use sys::uio::IoVec; // For vmsplice target_env = "freebsd"))] pub use self::posix_fadvise::*; +pub const AT_FDCWD: RawFd = libc::AT_FDCWD as RawFd; + libc_bitflags!{ pub struct AtFlags: c_int { AT_SYMLINK_NOFOLLOW; @@ -164,6 +166,17 @@ pub fn openat(dirfd: RawFd, path: &P, oflag: OFlag, mode: M Errno::result(fd) } +pub fn renameat(old_dirfd: RawFd, old_path: &P1, + new_dirfd: RawFd, new_path: &P2) + -> Result<()> { + let res = old_path.with_nix_path(|old_cstr| { + new_path.with_nix_path(|new_cstr| unsafe { + libc::renameat(old_dirfd, old_cstr.as_ptr(), new_dirfd, new_cstr.as_ptr()) + }) + })??; + Errno::result(res).map(drop) +} + fn wrap_readlink_result(buffer: &mut[u8], res: ssize_t) -> Result<&OsStr> { match Errno::result(res) { Err(err) => Err(err), diff --git a/test/test_fcntl.rs b/test/test_fcntl.rs index 058518288d..dee20ad25d 100644 --- a/test/test_fcntl.rs +++ b/test/test_fcntl.rs @@ -1,7 +1,10 @@ -use nix::fcntl::{openat, open, OFlag, readlink, readlinkat}; +use nix::Error; +use nix::errno::*; +use nix::fcntl::{openat, open, OFlag, readlink, readlinkat, renameat}; use nix::sys::stat::Mode; use nix::unistd::{close, read}; use tempfile::{self, NamedTempFile}; +use std::fs::File; use std::io::prelude::*; use std::os::unix::fs; @@ -27,6 +30,23 @@ fn test_openat() { close(dirfd).unwrap(); } +#[test] +fn test_renameat() { + let old_dir = tempfile::tempdir().unwrap(); + let old_dirfd = open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); + let old_path = old_dir.path().join("old"); + File::create(&old_path).unwrap(); + let new_dir = tempfile::tempdir().unwrap(); + let new_dirfd = open(new_dir.path(), OFlag::empty(), Mode::empty()).unwrap(); + renameat(old_dirfd, "old", new_dirfd, "new").unwrap(); + assert_eq!(renameat(old_dirfd, "old", new_dirfd, "new").unwrap_err(), + Error::Sys(Errno::ENOENT)); + close(old_dirfd).unwrap(); + close(new_dirfd).unwrap(); + assert!(!old_path.exists()); + assert!(new_dir.path().join("new").exists()); +} + #[test] fn test_readlink() { let tempdir = tempfile::tempdir().unwrap();