Skip to content
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

Added direct support for fchown and dup3 #957

Closed
wants to merge 9 commits into from
73 changes: 53 additions & 20 deletions src/unistd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

use errno::{self, Errno};
use {Error, Result, NixPath};
use fcntl::{fcntl, FdFlag, OFlag};
use fcntl::FcntlArg::F_SETFD;
use fcntl::OFlag;
use libc::{self, c_char, c_void, c_int, c_long, c_uint, size_t, pid_t, off_t,
uid_t, gid_t, mode_t};
use std::{fmt, mem, ptr};
Expand Down Expand Up @@ -374,26 +373,11 @@ pub fn dup2(oldfd: RawFd, newfd: RawFd) -> Result<RawFd> {
///
/// This function behaves similar to `dup2()` but allows for flags to be
/// specified.
pub fn dup3(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> {
dup3_polyfill(oldfd, newfd, flags)
}

#[inline]
fn dup3_polyfill(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> {
if oldfd == newfd {
return Err(Error::Sys(Errno::EINVAL));
}

let fd = try!(dup2(oldfd, newfd));

if flags.contains(OFlag::O_CLOEXEC) {
if let Err(e) = fcntl(fd, F_SETFD(FdFlag::FD_CLOEXEC)) {
let _ = close(fd);
return Err(e);
}
}
pub fn dup3(oldfd: RawFd, newfd: RawFd, flags: OFlag) -> Result<RawFd> {
koutheir marked this conversation as resolved.
Show resolved Hide resolved
let res = unsafe { libc::dup3(oldfd, newfd, flags.bits()) };

Ok(fd)
Errno::result(res)
}

/// Change the current working directory of the calling process (see
Expand Down Expand Up @@ -578,6 +562,55 @@ pub fn chown<P: ?Sized + NixPath>(path: &P, owner: Option<Uid>, group: Option<Gi
Errno::result(res).map(drop)
}

/// Change the ownership of the file at `path` to be owned by the specified
/// `owner` (user) and `group` (see
/// [lchown(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/lchown.html)).
/// If `path` names a symbolic link, then ownership of the symbolic link file itself is changed.
///
/// The owner/group for the provided path name will not be modified if `None` is
/// provided for that argument. Ownership change will be attempted for the path
/// only if `Some` owner/group is provided.
#[inline]
pub fn lchown<P: ?Sized + NixPath>(path: &P, owner: Option<Uid>, group: Option<Gid>) -> Result<()> {
koutheir marked this conversation as resolved.
Show resolved Hide resolved
let res = try!(path.with_nix_path(|cstr| {
// 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::lchown(cstr.as_ptr(),
owner.map(Into::into).unwrap_or((0 as uid_t).wrapping_sub(1)),
group.map(Into::into).unwrap_or((0 as gid_t).wrapping_sub(1))) }
}));

Errno::result(res).map(drop)
}

/// Change the ownership of the file specified by the file descriptor `fd` to be owned by the
/// specified `owner` (user) and `group` (see
/// [fchown(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fchown.html)).
///
/// The owner/group for the provided path name will not be modified if `None` is
/// provided for that argument. Ownership change will be attempted for the path
/// only if `Some` owner/group is provided.
#[inline]
koutheir marked this conversation as resolved.
Show resolved Hide resolved
pub fn fchown(fd: RawFd, owner: Option<Uid>, group: Option<Gid>) -> Result<()> {
let res = unsafe { libc::fchown(fd,
owner.map(Into::into).unwrap_or((0 as uid_t).wrapping_sub(1)),
koutheir marked this conversation as resolved.
Show resolved Hide resolved
group.map(Into::into).unwrap_or((0 as gid_t).wrapping_sub(1))) };

Errno::result(res).map(drop)
}

/// Change the mode of the file at `path` (see
/// [chmod(2)](http://pubs.opengroup.org/onlinepubs/9699919799/functions/chmod.html)).
#[inline]
pub fn chmod<P: ?Sized + NixPath>(path: &P, mode: Mode) -> Result<()> {
koutheir marked this conversation as resolved.
Show resolved Hide resolved
let res = try!(path.with_nix_path(|cstr| {
unsafe { libc::chmod(cstr.as_ptr(), mode.bits() as mode_t) }
}));

Errno::result(res).map(drop)
}

fn to_exec_array(args: &[CString]) -> Vec<*const c_char> {
let mut args_p: Vec<*const c_char> = args.iter().map(|s| s.as_ptr()).collect();
args_p.push(ptr::null());
Expand Down