Skip to content

Commit 41d3ba7

Browse files
committed
Implement symlink and symlinkat
1 parent f1b12d6 commit 41d3ba7

File tree

2 files changed

+65
-1
lines changed

2 files changed

+65
-1
lines changed

src/unistd.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,45 @@ 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 directory.
515+
/// This is identical to `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+
537+
/// Creates a symbolic link at `path2` which points to `path1`.
538+
///
539+
/// This is same as calling `symlinkat(path1, None, path2)`.
540+
///
541+
/// See also [symlink(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/symlink.html)
542+
pub fn symlink<P1: ?Sized + NixPath, P2: ?Sized + NixPath>(
543+
path1: &P1,
544+
path2: &P2) -> Result<()> {
545+
symlinkat(path1, None, path2)
546+
}
547+
509548
/// Returns the current directory as a `PathBuf`
510549
///
511550
/// Err is returned if the current user doesn't have the permission to read or search a component

test/test_unistd.rs

Lines changed: 26 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,28 @@ 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_symlink() {
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+
symlink(&target, &linkpath).unwrap();
555+
assert_eq!(readlink(&linkpath, &mut buf).unwrap().to_str().unwrap(),
556+
target.to_str().unwrap());
557+
558+
let target = tempdir.path().join("c");
559+
let linkpath = tempdir.path().join("d");
560+
symlinkat(&target, None, &linkpath).unwrap();
561+
assert_eq!(readlink(&linkpath, &mut buf).unwrap().to_str().unwrap(),
562+
target.to_str().unwrap());
563+
564+
let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap();
565+
let target = "e";
566+
let linkpath = "f";
567+
symlinkat(target, Some(dirfd), linkpath).unwrap();
568+
assert_eq!(readlink(&tempdir.path().join(linkpath), &mut buf).unwrap().to_str().unwrap(),
569+
target);
570+
}

0 commit comments

Comments
 (0)