Skip to content

Commit 51bd085

Browse files
bors[bot]oblique
andcommitted
Merge #997
997: Implement symlinkat r=asomers a=oblique Co-authored-by: oblique <psyberbits@gmail.com>
2 parents f1b12d6 + 98ac441 commit 51bd085

File tree

3 files changed

+57
-1
lines changed

3 files changed

+57
-1
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
99
([#972](https://github.com/nix-rust/nix/pull/972))
1010
- Added option `TCP_CONGESTION` in `setsockopt`.
1111
([#972](https://github.com/nix-rust/nix/pull/972))
12+
- Added `symlinkat` wrapper.
13+
([#997](https://github.com/nix-rust/nix/pull/997))
1214

1315
### Changed
1416
### Fixed

src/unistd.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,34 @@ pub fn mkfifo<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> {
506506
Errno::result(res).map(drop)
507507
}
508508

509+
/// Creates a symbolic link at `path2` which points to `path1`.
510+
///
511+
/// If `dirfd` has a value, then `path2` is relative to directory associated
512+
/// with the file descriptor.
513+
///
514+
/// If `dirfd` is `None`, then `path2` is relative to the current working
515+
/// directory. This is identical to `libc::symlink(path1, path2)`.
516+
///
517+
/// See also [symlinkat(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/symlinkat.html).
518+
pub fn symlinkat<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
519+
path1: &P1,
520+
dirfd: Option<RawFd>,
521+
path2: &P2) -> Result<()> {
522+
let res =
523+
path1.with_nix_path(|path1| {
524+
path2.with_nix_path(|path2| {
525+
unsafe {
526+
libc::symlinkat(
527+
path1.as_ptr(),
528+
dirfd.unwrap_or(libc::AT_FDCWD),
529+
path2.as_ptr()
530+
)
531+
}
532+
})
533+
})??;
534+
Errno::result(res).map(drop)
535+
}
536+
509537
/// Returns the current directory as a `PathBuf`
510538
///
511539
/// Err is returned if the current user doesn't have the permission to read or search a component

test/test_unistd.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use nix::fcntl::{fcntl, FcntlArg, FdFlag, open, OFlag};
1+
use nix::fcntl::{fcntl, FcntlArg, FdFlag, open, OFlag, readlink};
22
use nix::unistd::*;
33
use nix::unistd::ForkResult::*;
44
use nix::sys::signal::{SaFlags, SigAction, SigHandler, SigSet, Signal, sigaction};
@@ -543,3 +543,29 @@ fn test_canceling_alarm() {
543543
assert_eq!(alarm::set(60), None);
544544
assert_eq!(alarm::cancel(), Some(60));
545545
}
546+
547+
#[test]
548+
fn test_symlinkat() {
549+
let mut buf = [0; 1024];
550+
let tempdir = tempfile::tempdir().unwrap();
551+
552+
let target = tempdir.path().join("a");
553+
let linkpath = tempdir.path().join("b");
554+
symlinkat(&target, None, &linkpath).unwrap();
555+
assert_eq!(
556+
readlink(&linkpath, &mut buf).unwrap().to_str().unwrap(),
557+
target.to_str().unwrap()
558+
);
559+
560+
let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap();
561+
let target = "c";
562+
let linkpath = "d";
563+
symlinkat(target, Some(dirfd), linkpath).unwrap();
564+
assert_eq!(
565+
readlink(&tempdir.path().join(linkpath), &mut buf)
566+
.unwrap()
567+
.to_str()
568+
.unwrap(),
569+
target
570+
);
571+
}

0 commit comments

Comments
 (0)