diff options
author | oblique <psyberbits@gmail.com> | 2018-12-11 23:32:09 +0200 |
---|---|---|
committer | oblique <psyberbits@gmail.com> | 2018-12-12 00:49:15 +0200 |
commit | 98ac44103601cdf0578f868e12f3090051dabe5f (patch) | |
tree | 575126a951c965eb43e78256dedfb4357938cec3 | |
parent | f1b12d6b1b8bf6d8ad41e7b2967b95c6f876745c (diff) | |
download | nix-98ac44103601cdf0578f868e12f3090051dabe5f.zip |
Implement symlinkat
-rw-r--r-- | CHANGELOG.md | 2 | ||||
-rw-r--r-- | src/unistd.rs | 28 | ||||
-rw-r--r-- | test/test_unistd.rs | 28 |
3 files changed, 57 insertions, 1 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index f89e4998..8e8135b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ This project adheres to [Semantic Versioning](http://semver.org/). ([#972](https://github.com/nix-rust/nix/pull/972)) - Added option `TCP_CONGESTION` in `setsockopt`. ([#972](https://github.com/nix-rust/nix/pull/972)) +- Added `symlinkat` wrapper. + ([#997](https://github.com/nix-rust/nix/pull/997)) ### Changed ### Fixed diff --git a/src/unistd.rs b/src/unistd.rs index f2ad55b2..2c00f7f0 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -506,6 +506,34 @@ pub fn mkfifo<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> { 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 +/// with the file descriptor. +/// +/// If `dirfd` is `None`, then `path2` is relative to the current working +/// directory. This is identical to `libc::symlink(path1, path2)`. +/// +/// See also [symlinkat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/symlinkat.html). +pub fn symlinkat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>( + path1: &P1, + dirfd: Option<RawFd>, + path2: &P2) -> Result<()> { + let res = + path1.with_nix_path(|path1| { + path2.with_nix_path(|path2| { + unsafe { + libc::symlinkat( + path1.as_ptr(), + dirfd.unwrap_or(libc::AT_FDCWD), + path2.as_ptr() + ) + } + }) + })??; + Errno::result(res).map(drop) +} + /// Returns the current directory as a `PathBuf` /// /// Err is returned if the current user doesn't have the permission to read or search a component diff --git a/test/test_unistd.rs b/test/test_unistd.rs index a4bb92eb..8b373278 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -1,4 +1,4 @@ -use nix::fcntl::{fcntl, FcntlArg, FdFlag, open, OFlag}; +use nix::fcntl::{fcntl, FcntlArg, FdFlag, open, OFlag, readlink}; use nix::unistd::*; use nix::unistd::ForkResult::*; use nix::sys::signal::{SaFlags, SigAction, SigHandler, SigSet, Signal, sigaction}; @@ -543,3 +543,29 @@ fn test_canceling_alarm() { assert_eq!(alarm::set(60), None); assert_eq!(alarm::cancel(), Some(60)); } + +#[test] +fn test_symlinkat() { + let mut buf = [0; 1024]; + let tempdir = tempfile::tempdir().unwrap(); + + let target = tempdir.path().join("a"); + let linkpath = tempdir.path().join("b"); + symlinkat(&target, None, &linkpath).unwrap(); + assert_eq!( + readlink(&linkpath, &mut buf).unwrap().to_str().unwrap(), + target.to_str().unwrap() + ); + + let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap(); + let target = "c"; + let linkpath = "d"; + symlinkat(target, Some(dirfd), linkpath).unwrap(); + assert_eq!( + readlink(&tempdir.path().join(linkpath), &mut buf) + .unwrap() + .to_str() + .unwrap(), + target + ); +} |