Skip to content

Commit

Permalink
Add rename, renameat, AT_FDCWD
Browse files Browse the repository at this point in the history
These syscalls are (somewhat oddly, imho) in stdio.h. I put them in
nix::fcntl because there's no nix::stdio and all their friends
(including the AT_* constants) are in nix::fcntl.
  • Loading branch information
scottlamb committed Jul 11, 2019
1 parent 5e463aa commit 09a9198
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ 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))
- Added wrappers for `rename` and `renameat`.

### Changed
- Support for `ifaddrs` now present when building for Android.
Expand Down
22 changes: 22 additions & 0 deletions src/fcntl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -164,6 +166,26 @@ pub fn openat<P: ?Sized + NixPath>(dirfd: RawFd, path: &P, oflag: OFlag, mode: M
Errno::result(fd)
}

pub fn rename<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(old: &P1, new: &P2) -> Result<()> {
let res = try!(try!(old.with_nix_path(|old_cstr| {
new.with_nix_path(|new_cstr| {
unsafe { libc::rename(old_cstr.as_ptr(), new_cstr.as_ptr()) }
})
})));
Errno::result(res).map(drop)
}

pub fn renameat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(old_dirfd: RawFd, old_path: &P1,
new_dirfd: RawFd, new_path: &P2)
-> Result<()> {
let res = try!(try!(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),
Expand Down
29 changes: 28 additions & 1 deletion test/test_fcntl.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use nix::fcntl::{openat, open, OFlag, readlink, readlinkat};
use nix::Error;
use nix::errno::*;
use nix::fcntl::{openat, open, OFlag, readlink, readlinkat, rename, renameat};
use nix::sys::stat::Mode;
use nix::unistd::{close, read};
use tempfile::{self, NamedTempFile};
Expand Down Expand Up @@ -27,6 +29,31 @@ fn test_openat() {
close(dirfd).unwrap();
}

#[test]
fn test_rename() {
let old_dir = tempfile::tempdir().unwrap();
let old_path = old_dir.path().join("old");
std::fs::File::create(&old_path).unwrap();
let new_dir = tempfile::tempdir().unwrap();
let new_path = new_dir.path().join("new");
rename(&old_path, &new_path).unwrap();
assert_eq!(rename(&old_path, &new_path).unwrap_err(), Error::Sys(Errno::ENOENT));
}

#[test]
fn test_renameat() {
let old_dir = tempfile::tempdir().unwrap();
let old_dirfd = open(old_dir.path(), OFlag::empty(), Mode::empty()).unwrap();
std::fs::File::create(&old_dir.path().join("old")).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();
}

#[test]
fn test_readlink() {
let tempdir = tempfile::tempdir().unwrap();
Expand Down

0 comments on commit 09a9198

Please sign in to comment.