Skip to content

Commit 173223c

Browse files
committed
add support readlink|readlinkat
1 parent 1e268ed commit 173223c

File tree

3 files changed

+43
-3
lines changed

3 files changed

+43
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
66
## [Unreleased]
77

88
<!--### Added-->
9-
- Added `openat`, `fstatat` in `::nix::unistd`
9+
- Added `nix::unistd::{openat, fstatat, readlink, readlinkat}`
1010
([#497](https://github.com/nix-rust/nix/pull/551))
1111

1212
### Changed

src/fcntl.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use {Errno, Result, NixPath};
2-
use libc::{self, c_int, c_uint};
2+
use libc::{self, c_int, c_uint, c_char, size_t};
33
use sys::stat::Mode;
44
use std::os::unix::io::RawFd;
5+
use std::ffi::OsStr;
6+
use std::os::unix::ffi::OsStrExt;
57

68
#[cfg(any(target_os = "linux", target_os = "android"))]
79
use sys::uio::IoVec; // For vmsplice
@@ -34,6 +36,23 @@ pub fn openat<P: ?Sized + NixPath>(dirfd: RawFd, path: &P, oflag: OFlag, mode: M
3436
Errno::result(fd)
3537
}
3638

39+
pub fn readlink<'a, P: ?Sized + NixPath>(path: &P, buffer: &'a mut [u8]) -> Result<&'a OsStr> {
40+
let res = try!(path.with_nix_path(|cstr| {
41+
unsafe { libc::readlink(cstr.as_ptr(), buffer.as_mut_ptr() as *mut c_char, buffer.len() as size_t) }
42+
}));
43+
44+
Errno::result(res).map(move |len| OsStr::from_bytes(&buffer[..(len as usize)]))
45+
}
46+
47+
48+
pub fn readlinkat<'a, P: ?Sized + NixPath>(dirfd: RawFd, path: &P, buffer: &'a mut [u8]) -> Result<&'a OsStr> {
49+
let res = try!(path.with_nix_path(|cstr| {
50+
unsafe { libc::readlinkat(dirfd, cstr.as_ptr(), buffer.as_mut_ptr() as *mut c_char, buffer.len() as size_t) }
51+
}));
52+
53+
Errno::result(res).map(move |len| OsStr::from_bytes(&buffer[..(len as usize)]))
54+
}
55+
3756
pub enum FcntlArg<'a> {
3857
F_DUPFD(RawFd),
3958
F_DUPFD_CLOEXEC(RawFd),

test/test_fcntl.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
use nix::fcntl::{openat, open, O_PATH, O_RDONLY};
1+
use nix::fcntl::{openat, open, O_PATH, O_RDONLY, readlink, readlinkat};
22
use nix::sys::stat::Mode;
33
use nix::unistd::{close, read};
4+
use tempdir::TempDir;
45
use tempfile::NamedTempFile;
56
use std::io::prelude::*;
7+
use std::os::unix::fs;
68

79
#[test]
810
fn test_openat() {
@@ -26,6 +28,25 @@ fn test_openat() {
2628
close(dirfd).unwrap();
2729
}
2830

31+
#[test]
32+
fn test_readlink() {
33+
let tempdir = TempDir::new("nix-test_readdir")
34+
.unwrap_or_else(|e| panic!("tempdir failed: {}", e));
35+
let src = tempdir.path().join("a");
36+
let dst = tempdir.path().join("b");
37+
println!("a: {:?}, b: {:?}", &src, &dst);
38+
fs::symlink(&src.as_path(), &dst.as_path()).unwrap();
39+
let dirfd = open(tempdir.path(),
40+
O_PATH,
41+
Mode::empty()).unwrap();
42+
43+
let mut buf = vec![0; src.to_str().unwrap().len()];
44+
assert_eq!(readlink(&dst, &mut buf).unwrap().to_str().unwrap(),
45+
src.to_str().unwrap());
46+
assert_eq!(readlinkat(dirfd, "b", &mut buf).unwrap().to_str().unwrap(),
47+
src.to_str().unwrap());
48+
}
49+
2950
#[cfg(any(target_os = "linux", target_os = "android"))]
3051
mod linux_android {
3152
use std::io::prelude::*;

0 commit comments

Comments
 (0)