Skip to content

Commit

Permalink
add support readlink|readlinkat
Browse files Browse the repository at this point in the history
  • Loading branch information
Mic92 committed Mar 22, 2017
1 parent b6a8a3c commit 55d7b5c
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 6 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased]

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

### Changed
Expand Down
38 changes: 35 additions & 3 deletions src/fcntl.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use {Errno, Result, NixPath};
use libc::{self, c_int, c_uint};
use {Error, Errno, Result, NixPath};
use libc::{self, c_int, c_uint, c_char, size_t, ssize_t};
use sys::stat::Mode;
use std::os::unix::io::RawFd;
use std::ffi::OsStr;
use std::os::unix::ffi::OsStrExt;

#[cfg(any(target_os = "linux", target_os = "android"))]
use sys::uio::IoVec; // For vmsplice
Expand Down Expand Up @@ -49,10 +51,40 @@ pub fn openat<P: ?Sized + NixPath>(dirfd: RawFd, path: &P, oflag: OFlag, mode: M
let fd = try!(path.with_nix_path(|cstr| {
unsafe { libc::openat(dirfd, cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint) }
}));

Errno::result(fd)
}

fn wrap_readlink_result<'a>(buffer: &'a mut[u8], res: ssize_t)
-> Result<&'a OsStr> {
match Errno::result(res) {
Err(err) => Err(err),
Ok(len) => {
if (len as usize) >= buffer.len() {
Err(Error::Sys(Errno::ENAMETOOLONG))
} else {
Ok(OsStr::from_bytes(&buffer[..(len as usize)]))
}
}
}
}

pub fn readlink<'a, P: ?Sized + NixPath>(path: &P, buffer: &'a mut [u8]) -> Result<&'a OsStr> {
let res = try!(path.with_nix_path(|cstr| {
unsafe { libc::readlink(cstr.as_ptr(), buffer.as_mut_ptr() as *mut c_char, buffer.len() as size_t) }
}));

wrap_readlink_result(buffer, res)
}


pub fn readlinkat<'a, P: ?Sized + NixPath>(dirfd: RawFd, path: &P, buffer: &'a mut [u8]) -> Result<&'a OsStr> {
let res = try!(path.with_nix_path(|cstr| {
unsafe { libc::readlinkat(dirfd, cstr.as_ptr(), buffer.as_mut_ptr() as *mut c_char, buffer.len() as size_t) }
}));

wrap_readlink_result(buffer, res)
}

pub enum FcntlArg<'a> {
F_DUPFD(RawFd),
F_DUPFD_CLOEXEC(RawFd),
Expand Down
25 changes: 23 additions & 2 deletions test/test_fcntl.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use nix::fcntl::{openat, open, O_PATH, O_RDONLY};
use nix::fcntl::{openat, open, OFlag, O_RDONLY, readlink, readlinkat};
use nix::sys::stat::Mode;
use nix::unistd::{close, read};
use tempdir::TempDir;
use tempfile::NamedTempFile;
use std::io::prelude::*;
use std::os::unix::fs;

#[test]
fn test_openat() {
Expand All @@ -11,7 +13,7 @@ fn test_openat() {
tmp.write(CONTENTS).unwrap();

let dirfd = open(tmp.path().parent().unwrap(),
O_PATH,
OFlag::empty(),
Mode::empty()).unwrap();
let fd = openat(dirfd,
tmp.path().file_name().unwrap(),
Expand All @@ -26,6 +28,25 @@ fn test_openat() {
close(dirfd).unwrap();
}

#[test]
fn test_readlink() {
let tempdir = TempDir::new("nix-test_readdir")
.unwrap_or_else(|e| panic!("tempdir failed: {}", e));
let src = tempdir.path().join("a");
let dst = tempdir.path().join("b");
println!("a: {:?}, b: {:?}", &src, &dst);
fs::symlink(&src.as_path(), &dst.as_path()).unwrap();
let dirfd = open(tempdir.path(),
OFlag::empty(),
Mode::empty()).unwrap();

let mut buf = vec![0; src.to_str().unwrap().len() + 1];
assert_eq!(readlink(&dst, &mut buf).unwrap().to_str().unwrap(),
src.to_str().unwrap());
assert_eq!(readlinkat(dirfd, "b", &mut buf).unwrap().to_str().unwrap(),
src.to_str().unwrap());
}

#[cfg(any(target_os = "linux", target_os = "android"))]
mod linux_android {
use std::io::prelude::*;
Expand Down

0 comments on commit 55d7b5c

Please sign in to comment.