diff options
author | Philipp Keller <philipp.keller@gmail.com> | 2016-09-02 22:57:39 +0200 |
---|---|---|
committer | Philipp Keller <philipp.keller@gmail.com> | 2016-09-02 22:57:39 +0200 |
commit | ac642737967525226dc36f43e6e99d58328d5c6c (patch) | |
tree | 8883b813e519ef1bf208b876bb8d0ccd80a8a3ed | |
parent | 07039357d8d519ab1fe3591b9f9b05fd49ab4195 (diff) | |
download | nix-ac642737967525226dc36f43e6e99d58328d5c6c.zip |
implemented getcwd (returning Result<PathBuf>, reconciling all calls to expect into proper try handling), needs testing still
-rw-r--r-- | src/unistd.rs | 42 | ||||
-rw-r--r-- | test/test_unistd.rs | 5 |
2 files changed, 46 insertions, 1 deletions
diff --git a/src/unistd.rs b/src/unistd.rs index d4da60da..34e9b6a9 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -5,9 +5,10 @@ use fcntl::{fcntl, OFlag, O_NONBLOCK, O_CLOEXEC, FD_CLOEXEC}; use fcntl::FcntlArg::{F_SETFD, F_SETFL}; use libc::{self, c_char, c_void, c_int, c_uint, size_t, pid_t, off_t, uid_t, gid_t}; use std::mem; -use std::ffi::CString; +use std::ffi::{CString,CStr}; use std::os::unix::io::RawFd; use void::Void; +use std::path::PathBuf; #[cfg(any(target_os = "linux", target_os = "android"))] pub use self::linux::*; @@ -111,6 +112,45 @@ pub fn chdir<P: ?Sized + NixPath>(path: &P) -> Result<()> { Errno::result(res).map(drop) } +// #[inline] +// pub fn mkdir<P: ?Sized + NixPath>(path: &P) -> Result<()> { +// Errno::result(0) +// } + +#[inline] +pub fn getcwd() -> Result<PathBuf> { + let mut buf = Vec::with_capacity(512); + loop { + unsafe { + let ptr = buf.as_mut_ptr() as *mut libc::c_char; + + // The buffer must be large enough to store the absolute pathname plus + // a terminating null byte, or else null is returned. + // To safely handle this we start with a reasonable size (512 bytes) + // and double the buffer size upon every error + if !libc::getcwd(ptr, buf.capacity()).is_null() { + let len = CStr::from_ptr(ptr).to_bytes().len(); + buf.set_len(len); + buf.shrink_to_fit(); + let s = try!(CString::new(buf).map_err(|_| Error::Sys(Errno::EILSEQ))); + let s = try!(s.into_string().map_err(|_| Error::Sys(Errno::EILSEQ))); + return Ok(PathBuf::from(&s)); + } else { + let error = Errno::last(); + if error == Errno::ERANGE { + return Err(Error::Sys(error)); + } + } + + // Trigger the internal buffer resizing logic of `Vec` by requiring + // more space than the current capacity. + let cap = buf.capacity(); + buf.set_len(cap); + buf.reserve(1); + } + } +} + #[inline] pub fn chown<P: ?Sized + NixPath>(path: &P, owner: Option<uid_t>, group: Option<gid_t>) -> Result<()> { let res = try!(path.with_nix_path(|cstr| { diff --git a/test/test_unistd.rs b/test/test_unistd.rs index 188bfbeb..48891bc3 100644 --- a/test/test_unistd.rs +++ b/test/test_unistd.rs @@ -120,6 +120,11 @@ macro_rules! execve_test_factory( ); #[test] +fn test_getcwd() { + println!("{}", getcwd().unwrap().display()); +} + +#[test] fn test_lseek() { const CONTENTS: &'static [u8] = b"abcdef123456"; let mut tmp = tempfile().unwrap(); |