diff --git a/CHANGELOG.md b/CHANGELOG.md index 36b528ca91..3317261b22 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::{symlink,symlinkat}. + ([#757](https://github.com/nix-rust/nix/pull/757)) ### Changed - Renamed existing `ptrace` wrappers to encourage namespacing ([#692](https://github.com/nix-rust/nix/pull/692)) diff --git a/src/unistd.rs b/src/unistd.rs index fad51272e0..03300f7b52 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -812,6 +812,39 @@ pub fn lseek64(fd: RawFd, offset: libc::off64_t, whence: Whence) -> Result(target: &P1, + linkpath: &P2) -> Result<()> { + let res = try!(try!(target.with_nix_path(|t| + linkpath.with_nix_path(|l| + unsafe { + libc::symlink(t.as_ptr() as *const c_char, l.as_ptr() as *const c_char) + } + ) + ))); + + Errno::result(res).map(drop) +} + +/// Make a new name for a file +/// ([posix specification](http://pubs.opengroup.org/onlinepubs/9699919799/functions/symlinkat.html)). +pub fn symlinkat(target: &P1, + newdirfd: RawFd, + linkpath: &P2) -> Result<()> { + let res = try!(try!(target.with_nix_path(|t| + linkpath.with_nix_path(|l| + unsafe { + libc::symlinkat(t.as_ptr() as *const c_char, + newdirfd, + l.as_ptr() as *const c_char) + } + ) + ))); + + Errno::result(res).map(drop) +} + pub fn pipe() -> Result<(RawFd, RawFd)> { unsafe { let mut fds: [c_int; 2] = mem::uninitialized(); diff --git a/test/test_fcntl.rs b/test/test_fcntl.rs index 43bfc09162..32cfc5a279 100644 --- a/test/test_fcntl.rs +++ b/test/test_fcntl.rs @@ -1,10 +1,9 @@ use nix::fcntl::{openat, open, OFlag, O_RDONLY, readlink, readlinkat}; use nix::sys::stat::Mode; -use nix::unistd::{close, read}; +use nix::unistd::{close, read, symlink, symlinkat}; use tempdir::TempDir; use tempfile::NamedTempFile; use std::io::prelude::*; -use std::os::unix::fs; #[test] fn test_openat() { @@ -30,19 +29,29 @@ fn test_openat() { #[test] fn test_readlink() { - let tempdir = TempDir::new("nix-test_readdir") + let tempdir = TempDir::new("nix-test_readdlink") + .unwrap_or_else(|e| panic!("tempdir failed: {}", e)); + let src = tempdir.path().join("a"); + let dst = tempdir.path().join("b"); + symlink(src.as_path(), dst.as_path()).unwrap(); + + let mut buf = vec![0; src.to_str().unwrap().len() + 1]; + assert_eq!(readlink(&dst, &mut buf).unwrap().to_str().unwrap(), + src.to_str().unwrap()); +} + +#[test] +fn test_readlinkat() { + let tempdir = TempDir::new("nix-test_readlinkat") .unwrap_or_else(|e| panic!("tempdir failed: {}", e)); let src = tempdir.path().join("a"); let dst = tempdir.path().join("b"); - println!("a: {:?}, b: {:?}", &src, &dst); - fs::symlink(&src.as_path(), &dst.as_path()).unwrap(); let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); + symlinkat(src.as_path(), dirfd, dst.file_name().unwrap()).unwrap(); let mut buf = vec![0; src.to_str().unwrap().len() + 1]; - assert_eq!(readlink(&dst, &mut buf).unwrap().to_str().unwrap(), - src.to_str().unwrap()); assert_eq!(readlinkat(dirfd, "b", &mut buf).unwrap().to_str().unwrap(), src.to_str().unwrap()); }