summaryrefslogtreecommitdiff
path: root/src/unistd.rs
diff options
context:
space:
mode:
authorPhilipp Keller <philipp.keller@gmail.com>2016-09-16 07:14:29 +0200
committerPhilipp Keller <philipp.keller@gmail.com>2016-09-16 07:14:29 +0200
commit631a27a545906f739e50393509e71fb847740c3a (patch)
tree1d3279093084c3f2b650bb3ff8b88c2df9c2d69c /src/unistd.rs
parent23a7ea64938cc73d476e42b80a243fefbe7111b2 (diff)
parent7c0570d3ad3c8e5fdd45c7de745771a6be054c3c (diff)
downloadnix-631a27a545906f739e50393509e71fb847740c3a.zip
made it running with rust 1.2, added documentation to mkstemp
Diffstat (limited to 'src/unistd.rs')
-rw-r--r--src/unistd.rs181
1 files changed, 169 insertions, 12 deletions
diff --git a/src/unistd.rs b/src/unistd.rs
index 8db44163..2eb218b3 100644
--- a/src/unistd.rs
+++ b/src/unistd.rs
@@ -3,13 +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, OsStr};
-use std::os::unix::ffi::OsStrExt;
+use std::ffi::{CString, CStr, OsString, OsStr};
+use std::os::unix::ffi::{OsStringExt, OsStrExt};
use std::os::unix::io::RawFd;
-use std::path::{PathBuf, Path};
+use std::path::{PathBuf};
use void::Void;
+use sys::stat::Mode;
#[cfg(any(target_os = "linux", target_os = "android"))]
pub use self::linux::*;
@@ -113,11 +114,109 @@ pub fn chdir<P: ?Sized + NixPath>(path: &P) -> Result<()> {
Errno::result(res).map(drop)
}
+/// Creates new directory `path` with access rights `mode`.
+///
+/// # Errors
+///
+/// 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
+/// 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),
+/// 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
+/// extern crate nix;
+///
+/// use nix::unistd;
+///
+/// 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<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| {
- // 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)
@@ -174,7 +273,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;
@@ -212,6 +314,40 @@ pub fn write(fd: RawFd, buf: &[u8]) -> Result<usize> {
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<libc::off_t> {
+ 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<libc::off64_t> {
+ 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();
@@ -290,7 +426,6 @@ pub fn unlink<P: ?Sized + NixPath>(path: &P) -> Result<()> {
libc::unlink(cstr.as_ptr())
}
}));
-
Errno::result(res).map(drop)
}
@@ -376,19 +511,41 @@ pub fn sleep(seconds: libc::c_uint) -> c_uint {
unsafe { libc::sleep(seconds) }
}
+/// Creates a regular file which persists even after process termination
+///
+/// * `template`: a path whose 6 rightmost characters must be X, e.g. /tmp/tmpfile_XXXXXX
+/// * returns: tuple of file descriptor and filename
+///
+/// Err is returned either if no temporary filename could be created or the template doesn't
+/// end with XXXXXX
+///
+/// # Example
+///
+/// ```rust
+/// use nix::unistd;
+///
+/// let fd = match unistd::mkstemp("/tmp/tempfile_XXXXXX") {
+/// Ok((fd, path)) => {
+/// unistd::unlink(path.as_path()).unwrap(); // flag file to be deleted at app termination
+/// fd
+/// }
+/// Err(e) => panic!("mkstemp failed: {}", e)
+/// };
+/// // do something with fd
+/// ```
#[inline]
pub fn mkstemp<P: ?Sized + NixPath>(template: &P) -> Result<(RawFd, PathBuf)> {
let res = template.with_nix_path(|path| {
- let owned_path = path.to_owned();
- let path_ptr = owned_path.into_raw();
+ let mut path_copy = path.to_bytes_with_nul().to_owned();
+ let p: *mut i8 = path_copy.as_mut_ptr() as *mut i8;
unsafe {
- (libc::mkstemp(path_ptr), CString::from_raw(path_ptr))
+ (libc::mkstemp(p), OsStr::from_bytes(CStr::from_ptr(p).to_bytes()))
}
});
match res {
Ok((fd, pathname)) => {
try!(Errno::result(fd));
- Ok((fd, Path::new(OsStr::from_bytes(pathname.as_bytes())).to_owned()))
+ Ok((fd, PathBuf::from(pathname).to_owned()))
}
Err(e) => {
Err(e)