use IntoInner;
use io::FileDesc;
use libc::{self, c_void, size_t};
use sys::cvt_r;
use std::fs::File;
use std::io::{Result, SeekFrom};
use std::mem;
use std::os::unix::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd};
use std::process::Stdio;
mod fd_ext;
pub use self::fd_ext::{EventedFileDesc, FileDescExt, MaybeEventedFd};
#[derive(Debug, Eq)]
pub struct RawIo {
fd: RawFd,
}
impl PartialEq<RawIo> for RawIo {
fn eq(&self, other: &RawIo) -> bool {
self.fd == other.fd
}
}
impl Into<Stdio> for RawIo {
fn into(self) -> Stdio {
unsafe { FromRawFd::from_raw_fd(self.into_inner()) }
}
}
impl FromRawFd for FileDesc {
unsafe fn from_raw_fd(fd: RawFd) -> Self {
Self::new(fd)
}
}
impl AsRawFd for FileDesc {
fn as_raw_fd(&self) -> RawFd { self.inner().inner() }
}
impl IntoRawFd for FileDesc {
fn into_raw_fd(self) -> RawFd { unsafe { self.into_inner().into_inner() } }
}
impl From<File> for FileDesc {
fn from(file: File) -> Self {
unsafe { FromRawFd::from_raw_fd(file.into_raw_fd()) }
}
}
impl RawIo {
pub unsafe fn new(fd: RawFd) -> Self {
RawIo {
fd: fd,
}
}
pub unsafe fn into_inner(self) -> RawFd {
let fd = self.fd;
mem::forget(self);
fd
}
pub fn inner(&self) -> RawFd { self.fd }
pub fn duplicate(&self) -> Result<Self> {
unsafe {
Ok(RawIo::new(try!(cvt_r(|| { libc::dup(self.fd) }))))
}
}
pub fn read_inner(&self, buf: &mut [u8]) -> Result<usize> {
let ret = try!(cvt_r(|| unsafe {
libc::read(self.fd,
buf.as_mut_ptr() as *mut c_void,
buf.len() as size_t)
}));
Ok(ret as usize)
}
pub fn write_inner(&self, buf: &[u8]) -> Result<usize> {
let ret = try!(cvt_r(|| unsafe {
libc::write(self.fd,
buf.as_ptr() as *const c_void,
buf.len() as size_t)
}));
Ok(ret as usize)
}
pub fn flush_inner(&self) -> Result<()> {
Ok(())
}
pub fn seek(&self, pos: SeekFrom) -> Result<u64> {
let (whence, pos) = match pos {
SeekFrom::Start(off) => (libc::SEEK_SET, off as libc::off_t),
SeekFrom::End(off) => (libc::SEEK_END, off as libc::off_t),
SeekFrom::Current(off) => (libc::SEEK_CUR, off as libc::off_t),
};
let n = try!(cvt_r(|| unsafe { libc::lseek(self.fd, pos, whence) }));
Ok(n as u64)
}
pub fn set_cloexec(&self, set: bool) -> Result<()> {
unsafe {
let flags = try!(cvt_r(|| libc::fcntl(self.fd, libc::F_GETFD)));
let new_flags = if set {
flags | libc::FD_CLOEXEC
} else {
flags & !libc::FD_CLOEXEC
};
cvt_r(|| libc::fcntl(self.fd, libc::F_SETFD, new_flags)).map(|_| ())
}
}
pub fn set_nonblock(&self, set: bool) -> Result<()> {
unsafe {
let flags = try!(cvt_r(|| libc::fcntl(self.fd, libc::F_GETFL)));
let new_flags = if set {
flags | libc::O_NONBLOCK
} else {
flags & !libc::O_NONBLOCK
};
cvt_r(|| libc::fcntl(self.fd, libc::F_SETFL, new_flags)).map(|_| ())
}
}
}
impl Drop for RawIo {
fn drop(&mut self) {
let _ = unsafe { libc::close(self.fd) };
}
}
unsafe fn dup_fd_cloexec(fd: RawFd) -> Result<RawIo> {
let min_fd = libc::STDERR_FILENO + 1;
Ok(RawIo::new(try!(cvt_r(|| { libc::fcntl(fd, libc::F_DUPFD_CLOEXEC, min_fd) }))))
}
#[cfg(any(target_os = "linux", target_os = "android", target_os = "emscripten"))]
pub fn pipe() -> Result<(RawIo, RawIo)> {
unsafe {
let mut fds = [0; 2];
try!(cvt_r(|| {
libc::pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC)
}));
let reader = RawIo::new(fds[0]);
let writer = RawIo::new(fds[1]);
Ok((reader, writer))
}
}
#[cfg(not(any(target_os = "linux", target_os = "android", target_os = "emscripten")))]
pub fn pipe() -> Result<(RawIo, RawIo)> {
unsafe {
let mut fds = [0; 2];
try!(cvt_r(|| {
libc::pipe(fds.as_mut_ptr())
}));
let reader = RawIo::new(fds[0]);
let writer = RawIo::new(fds[1]);
try!(reader.set_cloexec(true));
try!(writer.set_cloexec(true));
Ok((reader, writer))
}
}
pub fn dup_stdio() -> Result<(RawIo, RawIo, RawIo)> {
unsafe {
Ok((
try!(dup_fd_cloexec(libc::STDIN_FILENO)),
try!(dup_fd_cloexec(libc::STDOUT_FILENO)),
try!(dup_fd_cloexec(libc::STDERR_FILENO))
))
}
}
pub fn getpid() -> libc::pid_t {
unsafe {
libc::getpid()
}
}