-
Notifications
You must be signed in to change notification settings - Fork 681
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add unistd::getcwd and unistd::mkdir #416
Changes from 7 commits
ac64273
b03d4e5
8b1828a
8fbd8e9
c0a5785
50693c1
37e4f97
5f1e144
7dd12c6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,11 +3,14 @@ | |
use {Errno, Error, Result, NixPath}; | ||
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 libc::{self, c_char, c_void, c_int, c_uint, size_t, pid_t, off_t, uid_t, gid_t, mode_t}; | ||
use std::mem; | ||
use std::ffi::CString; | ||
use std::ffi::{CString,CStr,OsString}; | ||
use std::os::unix::ffi::OsStringExt; | ||
use std::path::PathBuf; | ||
use std::os::unix::io::RawFd; | ||
use void::Void; | ||
use sys::stat::Mode; | ||
|
||
#[cfg(any(target_os = "linux", target_os = "android"))] | ||
pub use self::linux::*; | ||
|
@@ -111,6 +114,92 @@ pub fn chdir<P: ?Sized + NixPath>(path: &P) -> Result<()> { | |
Errno::result(res).map(drop) | ||
} | ||
|
||
/// Creates new directory `path` with access rights `mode`. | ||
/// | ||
/// # Errors | ||
/// | ||
/// `Err` is returned in case of an error. There are several situations where mkdir might fail. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. First sentence does not need to be stated, drop it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you're right. Resolved |
||
/// For a full list consult `man mkdir(2)` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I would prefer a link to the man pages from man7.org, in this case http://man7.org/linux/man-pages/man2/mkdir.2.html There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. resolved, also added anchor to errors |
||
/// | ||
/// - current user has insufficient rights in the parent directory | ||
/// - the path already exists | ||
/// - the path name is too long (longer than `PATH_MAX`, usually 4096 on linux, 1024 on OS X) | ||
/// | ||
/// # Example | ||
/// | ||
/// ```rust | ||
/// extern crate tempdir; | ||
/// extern crate nix; | ||
/// | ||
/// use nix::unistd; | ||
/// use nix::sys::stat; | ||
/// use tempdir::TempDir; | ||
/// | ||
/// fn main() { | ||
/// let mut tmp_dir = TempDir::new("test_mkdir").unwrap().into_path(); | ||
/// tmp_dir.push("new_dir"); | ||
/// | ||
/// // create new directory and give read, write and execute rights to the owner | ||
/// match unistd::mkdir(&tmp_dir, stat::S_IRWXU) { | ||
/// Ok(_) => println!("created {:?}", tmp_dir.display()), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Explicitly calling There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. resolved, thanks for the hint |
||
/// Err(err) => println!("Error creating directory: {}", err), | ||
/// } | ||
/// } | ||
/// ``` | ||
#[inline] | ||
pub fn mkdir<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> { | ||
let res = try!(path.with_nix_path(|cstr| { | ||
unsafe { libc::mkdir(cstr.as_ptr(), mode.bits() as mode_t) } | ||
})); | ||
|
||
Errno::result(res).map(drop) | ||
} | ||
|
||
/// Returns the current directory as a PathBuf | ||
/// | ||
/// Err is returned if the current user doesn't have the permission to read or search a component of the current path. | ||
/// | ||
/// # Example | ||
/// | ||
/// ```rust | ||
/// use nix::unistd; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The previous example included There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, this is required. The doc says:
Since I need to do a I think you want to hint that all examples should have the same style, that's why I now changed the doc of |
||
/// | ||
/// let dir = unistd::getcwd().expect("not allowed to get current directory"); | ||
/// println!("The current directory is {:?}", dir.display()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto on There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. resolved |
||
/// ``` | ||
#[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(buf.as_ptr() as *const libc::c_char).to_bytes().len(); | ||
buf.set_len(len); | ||
buf.shrink_to_fit(); | ||
return Ok(PathBuf::from(OsString::from_vec(buf))); | ||
} else { | ||
let error = Errno::last(); | ||
// ERANGE means buffer was too small to store directory name | ||
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| { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,17 @@ | ||
extern crate tempdir; | ||
|
||
use nix::unistd::*; | ||
use nix::unistd::ForkResult::*; | ||
use nix::sys::wait::*; | ||
use nix::sys::stat; | ||
use std::iter; | ||
use std::ffi::CString; | ||
|
||
use std::io::{Write, Read}; | ||
use std::os::unix::prelude::*; | ||
use std::env::current_dir; | ||
use tempfile::tempfile; | ||
use tempdir::TempDir; | ||
use libc::off_t; | ||
use std::os::unix::prelude::*; | ||
|
||
|
||
|
||
#[test] | ||
fn test_fork_and_waitpid() { | ||
|
@@ -119,6 +122,24 @@ macro_rules! execve_test_factory( | |
) | ||
); | ||
|
||
#[test] | ||
fn test_getcwd() { | ||
let mut tmp_dir = TempDir::new("test_getcwd").unwrap().into_path(); | ||
assert!(chdir(tmp_dir.as_path()).is_ok()); | ||
assert_eq!(getcwd().unwrap(), current_dir().unwrap()); | ||
|
||
// make path 500 chars longer so that buffer doubling in getcwd kicks in. | ||
// Note: One path cannot be longer than 255 bytes (NAME_MAX) | ||
// whole path cannot be longer than PATH_MAX (usually 4096 on linux, 1024 on macos) | ||
for _ in 0..5 { | ||
let newdir = iter::repeat("a").take(100).collect::<String>(); | ||
tmp_dir.push(newdir); | ||
assert!(mkdir(tmp_dir.as_path(), stat::S_IRWXU).is_ok()); | ||
} | ||
assert!(chdir(tmp_dir.as_path()).is_ok()); | ||
assert_eq!(getcwd().unwrap(), current_dir().unwrap()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just noticed that this code is indented with 2-spaces for some reason. Should be 4. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Running |
||
} | ||
|
||
#[test] | ||
fn test_lseek() { | ||
const CONTENTS: &'static [u8] = b"abcdef123456"; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: spaces after comma.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolved