From 2139c90bb70c4cb4692ece14a45a653b9747df56 Mon Sep 17 00:00:00 2001 From: Philipp Matthias Schaefer Date: Wed, 4 May 2016 19:31:22 +0200 Subject: Use Wrapping for intended underflow of unsigned integer value. --- src/unistd.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src/unistd.rs') diff --git a/src/unistd.rs b/src/unistd.rs index 71448248..89ba3db9 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -114,8 +114,12 @@ pub fn chdir(path: &P) -> Result<()> { #[inline] pub fn chown(path: &P, owner: Option, group: Option) -> Result<()> { let res = try!(path.with_nix_path(|cstr| { - // We use `0 - 1` to get `-1 : {u,g}id_t` which is specified as the no-op value for chown(3). - unsafe { libc::chown(cstr.as_ptr(), owner.unwrap_or(0 - 1), group.unwrap_or(0 - 1)) } + // According to the POSIX specification, -1 is used to indicate that + // owner and group, respectively, are not to be changed. Since uid_t and + // gid_t are unsigned types, we use wrapping_sub to get '-1'. + unsafe { libc::chown(cstr.as_ptr(), + owner.unwrap_or((0 as uid_t).wrapping_sub(1)), + group.unwrap_or((0 as gid_t).wrapping_sub(1))) } })); Errno::result(res).map(drop) -- cgit v1.2.3 From 0eb8b4b365fa362c0abd2a5b9da4257e6f2989a3 Mon Sep 17 00:00:00 2001 From: Andrei Oprisan Date: Wed, 8 Jun 2016 15:52:26 +0300 Subject: Added lseek to unistd llseek and lseek64 impl Whence fixed formatting awful typo when refactoring no llseek wrong test name using off64_t got rid of offset Added SeekHole/Data; formatted test; SeekCur/Set/End use libc constants --- src/unistd.rs | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) (limited to 'src/unistd.rs') diff --git a/src/unistd.rs b/src/unistd.rs index 89ba3db9..6ab1d920 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -214,6 +214,40 @@ pub fn write(fd: RawFd, buf: &[u8]) -> Result { Errno::result(res).map(|r| r as usize) } +pub enum Whence { + SeekSet, + SeekCur, + SeekEnd, + SeekData, + SeekHole +} + +impl Whence { + fn to_libc_type(&self) -> c_int { + match self { + &Whence::SeekSet => libc::SEEK_SET, + &Whence::SeekCur => libc::SEEK_CUR, + &Whence::SeekEnd => libc::SEEK_END, + &Whence::SeekData => 3, + &Whence::SeekHole => 4 + } + } + +} + +pub fn lseek(fd: RawFd, offset: libc::off_t, whence: Whence) -> Result { + let res = unsafe { libc::lseek(fd, offset, whence.to_libc_type()) }; + + Errno::result(res).map(|r| r as libc::off_t) +} + +#[cfg(any(target_os = "linux", target_os = "android"))] +pub fn lseek64(fd: RawFd, offset: libc::off64_t, whence: Whence) -> Result { + let res = unsafe { libc::lseek64(fd, offset, whence.to_libc_type()) }; + + Errno::result(res).map(|r| r as libc::off64_t) +} + pub fn pipe() -> Result<(RawFd, RawFd)> { unsafe { let mut fds: [c_int; 2] = mem::uninitialized(); @@ -292,7 +326,6 @@ pub fn unlink(path: &P) -> Result<()> { libc::unlink(cstr.as_ptr()) } })); - Errno::result(res).map(drop) } -- cgit v1.2.3 From bae5a373391eced579c7574fda942b9db4a55c3f Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Mon, 25 Jul 2016 02:41:24 +0000 Subject: Fix the sethostname binding on FreeBSD and DragonflyBSD --- src/unistd.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/unistd.rs') diff --git a/src/unistd.rs b/src/unistd.rs index 6ab1d920..d4da60da 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -176,7 +176,10 @@ pub fn daemon(nochdir: bool, noclose: bool) -> Result<()> { pub fn sethostname(name: &[u8]) -> Result<()> { // Handle some differences in type of the len arg across platforms. cfg_if! { - if #[cfg(any(target_os = "macos", target_os = "ios"))] { + if #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", ))] { type sethostname_len_t = c_int; } else { type sethostname_len_t = size_t; -- cgit v1.2.3 From ac642737967525226dc36f43e6e99d58328d5c6c Mon Sep 17 00:00:00 2001 From: Philipp Keller Date: Fri, 2 Sep 2016 22:57:39 +0200 Subject: implemented getcwd (returning Result, reconciling all calls to expect into proper try handling), needs testing still --- src/unistd.rs | 42 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) (limited to 'src/unistd.rs') 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(path: &P) -> Result<()> { Errno::result(res).map(drop) } +// #[inline] +// pub fn mkdir(path: &P) -> Result<()> { +// Errno::result(0) +// } + +#[inline] +pub fn getcwd() -> Result { + 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(path: &P, owner: Option, group: Option) -> Result<()> { let res = try!(path.with_nix_path(|cstr| { -- cgit v1.2.3 From 8b1828a5cd7c133156fc2bac703136e6d5abd31d Mon Sep 17 00:00:00 2001 From: Philipp Keller Date: Mon, 5 Sep 2016 21:50:06 +0200 Subject: implemented mkdir, extended getcwd test to include long path names --- src/unistd.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'src/unistd.rs') diff --git a/src/unistd.rs b/src/unistd.rs index 34e9b6a9..f8e17153 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -3,12 +3,13 @@ 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,CStr}; +use std::path::PathBuf; use std::os::unix::io::RawFd; use void::Void; -use std::path::PathBuf; +use sys::stat::Mode; #[cfg(any(target_os = "linux", target_os = "android"))] pub use self::linux::*; @@ -112,10 +113,14 @@ pub fn chdir(path: &P) -> Result<()> { Errno::result(res).map(drop) } -// #[inline] -// pub fn mkdir(path: &P) -> Result<()> { -// Errno::result(0) -// } +#[inline] +pub fn mkdir(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) +} #[inline] pub fn getcwd() -> Result { @@ -137,7 +142,8 @@ pub fn getcwd() -> Result { return Ok(PathBuf::from(&s)); } else { let error = Errno::last(); - if error == Errno::ERANGE { + // ERANGE means buffer was too small to store directory name + if error != Errno::ERANGE { return Err(Error::Sys(error)); } } -- cgit v1.2.3 From 8fbd8e91ff9ef518287bb4f2a012d3f62332f1ca Mon Sep 17 00:00:00 2001 From: Philipp Keller Date: Tue, 6 Sep 2016 17:17:21 +0200 Subject: made it running with rust 1.2.0: the code for getcwd is now an exact copy of the implementation in std --- src/unistd.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'src/unistd.rs') diff --git a/src/unistd.rs b/src/unistd.rs index f8e17153..6c3a1ebf 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -5,7 +5,8 @@ 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, mode_t}; use std::mem; -use std::ffi::{CString,CStr}; +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; @@ -134,12 +135,10 @@ pub fn getcwd() -> Result { // 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(); + let len = CStr::from_ptr(buf.as_ptr() as *const libc::c_char).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)); + return Ok(PathBuf::from(OsString::from_vec(buf))); } else { let error = Errno::last(); // ERANGE means buffer was too small to store directory name -- cgit v1.2.3 From c0a578539a4ad6b1f8ad48b8e26fbacc0d55852d Mon Sep 17 00:00:00 2001 From: Philipp Keller Date: Tue, 6 Sep 2016 17:19:07 +0200 Subject: fixed the trailing whitespaces --- src/unistd.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/unistd.rs') diff --git a/src/unistd.rs b/src/unistd.rs index 6c3a1ebf..900be379 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -144,7 +144,7 @@ pub fn getcwd() -> Result { // 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 @@ -153,7 +153,7 @@ pub fn getcwd() -> Result { buf.set_len(cap); buf.reserve(1); } - } + } } #[inline] -- cgit v1.2.3 From 50693c11b02f11e13687ee48f5a1e0131542d7f8 Mon Sep 17 00:00:00 2001 From: Philipp Keller Date: Tue, 6 Sep 2016 22:18:19 +0200 Subject: added documentation for getcwd and mkdir, changed test so that it compares against std::env::current_dir --- src/unistd.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'src/unistd.rs') diff --git a/src/unistd.rs b/src/unistd.rs index 900be379..52add2cd 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -114,6 +114,35 @@ pub fn chdir(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. +/// For a full list consult `man mkdir(2)` +/// +/// - 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"); +/// +/// // owner has read, write and execute rights on the new directory +/// unistd::mkdir(&tmp_dir, stat::S_IRWXU).expect("couldn't create directory"); +/// } +/// ``` #[inline] pub fn mkdir(path: &P, mode: Mode) -> Result<()> { let res = try!(path.with_nix_path(|cstr| { @@ -123,6 +152,18 @@ pub fn mkdir(path: &P, mode: Mode) -> Result<()> { 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; +/// +/// let dir = unistd::getcwd().expect("not allowed to get current directory"); +/// println!("The current directory is {:?}", dir.display()); +/// ``` #[inline] pub fn getcwd() -> Result { let mut buf = Vec::with_capacity(512); -- cgit v1.2.3 From 37e4f9756d7181e6b95f9b812874d582bfc2eec5 Mon Sep 17 00:00:00 2001 From: Philipp Keller Date: Tue, 6 Sep 2016 22:28:13 +0200 Subject: rust 1.2.0 doesn't support expect, switched to proper match block --- src/unistd.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src/unistd.rs') diff --git a/src/unistd.rs b/src/unistd.rs index 52add2cd..d7bd3b91 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -139,8 +139,11 @@ pub fn chdir(path: &P) -> Result<()> { /// let mut tmp_dir = TempDir::new("test_mkdir").unwrap().into_path(); /// tmp_dir.push("new_dir"); /// -/// // owner has read, write and execute rights on the new directory -/// unistd::mkdir(&tmp_dir, stat::S_IRWXU).expect("couldn't create directory"); +/// // 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()), +/// Err(err) => println!("Error creating directory: {}", err), +/// } /// } /// ``` #[inline] -- cgit v1.2.3 From 5f1e144de965d10b61fbd2c8e3ac50c12099690a Mon Sep 17 00:00:00 2001 From: Philipp Keller Date: Wed, 7 Sep 2016 07:17:36 +0200 Subject: resolving all remarks by @posborne, fixed max line length=99, fixed rust 1.2.0 error in doc-test --- src/unistd.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) (limited to 'src/unistd.rs') diff --git a/src/unistd.rs b/src/unistd.rs index d7bd3b91..74d74c9c 100644 --- a/src/unistd.rs +++ b/src/unistd.rs @@ -5,7 +5,7 @@ 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, mode_t}; use std::mem; -use std::ffi::{CString,CStr,OsString}; +use std::ffi::{CString, CStr, OsString}; use std::os::unix::ffi::OsStringExt; use std::path::PathBuf; use std::os::unix::io::RawFd; @@ -118,13 +118,15 @@ pub fn chdir(path: &P) -> Result<()> { /// /// # Errors /// -/// `Err` is returned in case of an error. There are several situations where mkdir might fail. -/// For a full list consult `man mkdir(2)` +/// There are several situations where mkdir might fail: /// /// - 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) /// +/// For a full list consult +/// [man mkdir(2)](http://man7.org/linux/man-pages/man2/mkdir.2.html#ERRORS) +/// /// # Example /// /// ```rust @@ -141,7 +143,7 @@ pub fn chdir(path: &P) -> Result<()> { /// /// // 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()), +/// Ok(_) => println!("created {:?}", tmp_dir), /// Err(err) => println!("Error creating directory: {}", err), /// } /// } @@ -157,15 +159,21 @@ pub fn mkdir(path: &P, mode: Mode) -> Result<()> { /// 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. +/// Err is returned if the current user doesn't have the permission to read or search a component +/// of the current path. /// /// # Example /// /// ```rust +/// extern crate nix; +/// /// use nix::unistd; /// -/// let dir = unistd::getcwd().expect("not allowed to get current directory"); -/// println!("The current directory is {:?}", dir.display()); +/// fn main() { +/// // assume that we are allowed to get current directory +/// let dir = unistd::getcwd().unwrap(); +/// println!("The current directory is {:?}", dir); +/// } /// ``` #[inline] pub fn getcwd() -> Result { -- cgit v1.2.3