From 3dcc466666de0eca2386390ef70ff53812138f42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Fri, 24 Mar 2017 08:16:49 +0100 Subject: [PATCH] add support for `link|linkat` --- CHANGELOG.md | 2 ++ src/unistd.rs | 32 +++++++++++++++++++++++++++++++- test/test_unistd.rs | 31 +++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36b528ca91..fb131a144f 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::{link, linkat}` + ([#755](https://github.com/nix-rust/nix/pull/755)) ### 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..3172cb45da 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -2,7 +2,7 @@ use errno; use {Errno, Error, Result, NixPath}; -use fcntl::{fcntl, OFlag, O_CLOEXEC, FD_CLOEXEC}; +use fcntl::{AtFlags, fcntl, OFlag, O_CLOEXEC, FD_CLOEXEC}; use fcntl::FcntlArg::F_SETFD; use libc::{self, c_char, c_void, c_int, c_long, c_uint, size_t, pid_t, off_t, uid_t, gid_t, mode_t}; @@ -812,6 +812,36 @@ pub fn lseek64(fd: RawFd, offset: libc::off64_t, whence: Whence) -> Result(oldpath: &P1, newpath: &P2) -> Result<()> { + let res = try!(try!(oldpath.with_nix_path(|old| + newpath.with_nix_path(|new| + unsafe { + libc::link(old.as_ptr() as *const c_char, new.as_ptr() as *const c_char) + } + ) + ))); + + Errno::result(res).map(drop) +} + +/// Call the link function to create a link to a file +/// ([posix specification](http://pubs.opengroup.org/onlinepubs/9699919799/functions/linkat.html)). +pub fn linkat(olddirfd: RawFd, oldpath: &P1, + newdirfd: RawFd, newpath: &P2, flags: AtFlags) -> Result<()> { + let res = try!(try!(oldpath.with_nix_path(|old| + newpath.with_nix_path(|new| + unsafe { + libc::linkat(olddirfd, old.as_ptr() as *const c_char, + newdirfd, new.as_ptr() as *const c_char, flags.bits()) + } + ) + ))); + + 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_unistd.rs b/test/test_unistd.rs index adf735794e..a60a46e815 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -1,5 +1,6 @@ extern crate tempdir; +use nix::fcntl; use nix::unistd::*; use nix::unistd::ForkResult::*; use nix::sys::wait::*; @@ -250,6 +251,36 @@ fn test_fpathconf_limited() { assert!(path_max.expect("fpathconf failed").expect("PATH_MAX is unlimited") > 0); } +#[test] +fn test_linkat() { + let tempdir = TempDir::new("nix-test_linkat").unwrap(); + let src = tempdir.path().join("foo"); + let dst = tempdir.path().join("bar"); + File::create(&src).unwrap(); + + let dirfd = fcntl::open(tempdir.path(), + fcntl::OFlag::empty(), + stat::Mode::empty()); + linkat(dirfd.unwrap(), + &src.file_name(), + dirfd.unwrap(), + &dst.file_name(), + fcntl::AtFlags::empty()).unwrap(); + assert!(dst.exists()); +} + +#[test] +fn test_link() { + let tempdir = TempDir::new("nix-test_link").unwrap(); + let src = tempdir.path().join("foo"); + let dst = tempdir.path().join("bar"); + File::create(&src).unwrap(); + + link(&src, &dst).unwrap(); + assert!(dst.exists()); +} + + #[test] fn test_pathconf_limited() { // AFAIK, PATH_MAX is limited on all platforms, so it makes a good test