summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md2
-rw-r--r--src/unistd.rs28
-rw-r--r--test/test_unistd.rs28
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
+ );
+}