summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHomu <homu@barosl.com>2017-03-26 12:14:02 +0900
committerHomu <homu@barosl.com>2017-03-26 12:14:02 +0900
commitc086d23997ca1c887377bc78fd3fa79000a810d7 (patch)
treeceed3cfad4b87db2e817129ea16c74ef5704ae77 /src
parent0eef6515f265428e522eea3e2aa3dd936398c4e0 (diff)
parent55d7b5cef30e525c2b04c02ef4eedf7098505700 (diff)
downloadnix-c086d23997ca1c887377bc78fd3fa79000a810d7.zip
Auto merge of #552 - Mic92:fstatat, r=posborne
add support for openat, fstatat, readlink, readlinkat
Diffstat (limited to 'src')
-rw-r--r--src/fcntl.rs63
-rw-r--r--src/sys/stat.rs13
2 files changed, 74 insertions, 2 deletions
diff --git a/src/fcntl.rs b/src/fcntl.rs
index e224d3b1..a295de3a 100644
--- a/src/fcntl.rs
+++ b/src/fcntl.rs
@@ -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
@@ -18,6 +20,25 @@ mod ffi {
pub const F_GET_SEALS: c_int = 1034;
}
+#[cfg(not(any(target_os = "ios", target_os = "macos")))]
+libc_bitflags!{
+ pub flags AtFlags: c_int {
+ AT_SYMLINK_NOFOLLOW,
+ #[cfg(any(target_os = "linux", target_os = "android"))]
+ AT_NO_AUTOMOUNT,
+ #[cfg(any(target_os = "linux", target_os = "android"))]
+ AT_EMPTY_PATH
+ }
+}
+
+#[cfg(any(target_os = "ios", target_os = "macos"))]
+bitflags!(
+ pub flags AtFlags: c_int {
+ // hack because bitflags require one entry
+ const EMPTY = 0x0
+ }
+);
+
pub fn open<P: ?Sized + NixPath>(path: &P, oflag: OFlag, mode: Mode) -> Result<RawFd> {
let fd = try!(path.with_nix_path(|cstr| {
unsafe { libc::open(cstr.as_ptr(), oflag.bits(), mode.bits() as c_uint) }
@@ -26,6 +47,44 @@ pub fn open<P: ?Sized + NixPath>(path: &P, oflag: OFlag, mode: Mode) -> Result<R
Errno::result(fd)
}
+pub fn openat<P: ?Sized + NixPath>(dirfd: RawFd, path: &P, oflag: OFlag, mode: Mode) -> Result<RawFd> {
+ 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),
diff --git a/src/sys/stat.rs b/src/sys/stat.rs
index 1ff35923..054aedc1 100644
--- a/src/sys/stat.rs
+++ b/src/sys/stat.rs
@@ -2,6 +2,7 @@ pub use libc::dev_t;
pub use libc::stat as FileStat;
use {Errno, Result, NixPath};
+use fcntl::AtFlags;
use libc::{self, mode_t};
use std::mem;
use std::os::unix::io::RawFd;
@@ -121,3 +122,15 @@ pub fn fstat(fd: RawFd) -> Result<FileStat> {
Ok(dst)
}
+
+pub fn fstatat<P: ?Sized + NixPath>(dirfd: RawFd, pathname: &P, f: AtFlags) -> Result<FileStat> {
+ let mut dst = unsafe { mem::uninitialized() };
+ let res = try!(pathname.with_nix_path(|cstr| {
+ unsafe { libc::fstatat(dirfd, cstr.as_ptr(), &mut dst as *mut FileStat, f.bits() as libc::c_int) }
+ }));
+
+ try!(Errno::result(res));
+
+ Ok(dst)
+}
+