1
1
mirror of https://github.com/wez/wezterm.git synced 2024-11-27 02:25:28 +03:00

make filedescriptor crate compile on windows

This commit is contained in:
Wez Furlong 2019-05-18 10:30:28 -07:00
parent 8a38ab6cb1
commit 9271c130c5
4 changed files with 275 additions and 133 deletions

View File

@ -9,3 +9,10 @@ failure = "0.1"
failure_derive = "0.1"
libc = "0.2"
[target."cfg(windows)".dependencies]
winapi = { version = "0.3", features = [
"winuser",
"handleapi",
"fileapi",
"namedpipeapi",
]}

View File

@ -1,143 +1,14 @@
use failure::{bail, Fallible};
use std::os::unix::prelude::*;
#[cfg(unix)]
pub trait AsRawFileDescriptor: AsRawFd {}
mod unix;
#[cfg(unix)]
impl<T: AsRawFd> AsRawFileDescriptor for T {}
pub use crate::unix::*;
#[cfg(windows)]
pub trait AsRawFileDescriptor: AsRawHandle {}
mod windows;
#[cfg(windows)]
impl<T: AsRawHandle> AsRawFileDescriptor for T {}
#[derive(Debug)]
pub struct FileDescriptor {
fd: RawFd,
}
impl std::io::Read for FileDescriptor {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, std::io::Error> {
let size = unsafe { libc::read(self.fd, buf.as_mut_ptr() as *mut _, buf.len()) };
if size == -1 {
Err(std::io::Error::last_os_error())
} else {
Ok(size as usize)
}
}
}
impl std::io::Write for FileDescriptor {
fn write(&mut self, buf: &[u8]) -> Result<usize, std::io::Error> {
let size = unsafe { libc::write(self.fd, buf.as_ptr() as *const _, buf.len()) };
if size == -1 {
Err(std::io::Error::last_os_error())
} else {
Ok(size as usize)
}
}
fn flush(&mut self) -> Result<(), std::io::Error> {
Ok(())
}
}
impl Drop for FileDescriptor {
fn drop(&mut self) {
unsafe {
libc::close(self.fd);
}
}
}
impl AsRawFd for FileDescriptor {
fn as_raw_fd(&self) -> RawFd {
self.fd
}
}
impl AsRawFd for &FileDescriptor {
fn as_raw_fd(&self) -> RawFd {
self.fd
}
}
fn dup_fd(fd: RawFd) -> Fallible<FileDescriptor> {
let duped = unsafe { libc::dup(fd) };
if duped == -1 {
bail!(
"dup of fd {} failed: {:?}",
fd,
std::io::Error::last_os_error()
)
} else {
let mut owned = FileDescriptor { fd: duped };
owned.cloexec()?;
Ok(owned)
}
}
pub use crate::windows::*;
pub struct Pipes {
pub read: FileDescriptor,
pub write: FileDescriptor,
}
pub fn dup<F: AsRawFileDescriptor>(f: F) -> Fallible<FileDescriptor> {
#[cfg(unix)]
dup_fd(f.as_raw_fd())
}
impl FileDescriptor {
pub fn dup<F: AsRawFileDescriptor>(f: F) -> Fallible<Self> {
dup(f)
}
pub fn clone(&self) -> Fallible<FileDescriptor> {
dup(self)
}
pub fn pipe() -> Fallible<Pipes> {
let mut fds = [-1i32; 2];
let res = unsafe { libc::pipe(fds.as_mut_ptr()) };
if res == -1 {
bail!(
"failed to create a pipe: {:?}",
std::io::Error::last_os_error()
)
} else {
let mut read = FileDescriptor { fd: fds[0] };
let mut write = FileDescriptor { fd: fds[1] };
read.cloexec()?;
write.cloexec()?;
Ok(Pipes { read, write })
}
}
/// Helper function to set the close-on-exec flag for a raw descriptor
fn cloexec(&mut self) -> Fallible<()> {
let flags = unsafe { libc::fcntl(self.fd, libc::F_GETFD) };
if flags == -1 {
bail!(
"fcntl to read flags failed: {:?}",
std::io::Error::last_os_error()
);
}
let result = unsafe { libc::fcntl(self.fd, libc::F_SETFD, flags | libc::FD_CLOEXEC) };
if result == -1 {
bail!(
"fcntl to set CLOEXEC failed: {:?}",
std::io::Error::last_os_error()
);
}
Ok(())
}
pub fn as_stdio(&self) -> Fallible<std::process::Stdio> {
let duped = dup_fd(self.fd)?;
let fd = duped.fd;
let stdio = unsafe { std::process::Stdio::from_raw_fd(fd) };
std::mem::forget(duped); // don't drop; stdio now owns it
Ok(stdio)
}
}

130
filedescriptor/src/unix.rs Normal file
View File

@ -0,0 +1,130 @@
use crate::Pipes;
use failure::{bail, Fallible};
use std::os::unix::prelude::*;
pub trait AsRawFileDescriptor: AsRawFd {}
impl<T: AsRawFd> AsRawFileDescriptor for T {}
#[derive(Debug)]
pub struct FileDescriptor {
fd: RawFd,
}
impl std::io::Read for FileDescriptor {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, std::io::Error> {
let size = unsafe { libc::read(self.fd, buf.as_mut_ptr() as *mut _, buf.len()) };
if size == -1 {
Err(std::io::Error::last_os_error())
} else {
Ok(size as usize)
}
}
}
impl std::io::Write for FileDescriptor {
fn write(&mut self, buf: &[u8]) -> Result<usize, std::io::Error> {
let size = unsafe { libc::write(self.fd, buf.as_ptr() as *const _, buf.len()) };
if size == -1 {
Err(std::io::Error::last_os_error())
} else {
Ok(size as usize)
}
}
fn flush(&mut self) -> Result<(), std::io::Error> {
Ok(())
}
}
impl Drop for FileDescriptor {
fn drop(&mut self) {
unsafe {
libc::close(self.fd);
}
}
}
impl AsRawFd for FileDescriptor {
fn as_raw_fd(&self) -> RawFd {
self.fd
}
}
impl AsRawFd for &FileDescriptor {
fn as_raw_fd(&self) -> RawFd {
self.fd
}
}
fn dup_fd(fd: RawFd) -> Fallible<FileDescriptor> {
let duped = unsafe { libc::dup(fd) };
if duped == -1 {
bail!(
"dup of fd {} failed: {:?}",
fd,
std::io::Error::last_os_error()
)
} else {
let mut owned = FileDescriptor { fd: duped };
owned.cloexec()?;
Ok(owned)
}
}
pub fn dup<F: AsRawFileDescriptor>(f: F) -> Fallible<FileDescriptor> {
dup_fd(f.as_raw_fd())
}
impl FileDescriptor {
pub fn dup<F: AsRawFileDescriptor>(f: F) -> Fallible<Self> {
dup(f)
}
pub fn try_clone(&self) -> Fallible<Self> {
dup(self)
}
pub fn pipe() -> Fallible<Pipes> {
let mut fds = [-1i32; 2];
let res = unsafe { libc::pipe(fds.as_mut_ptr()) };
if res == -1 {
bail!(
"failed to create a pipe: {:?}",
std::io::Error::last_os_error()
)
} else {
let mut read = FileDescriptor { fd: fds[0] };
let mut write = FileDescriptor { fd: fds[1] };
read.cloexec()?;
write.cloexec()?;
Ok(Pipes { read, write })
}
}
/// Helper function to set the close-on-exec flag for a raw descriptor
fn cloexec(&mut self) -> Fallible<()> {
let flags = unsafe { libc::fcntl(self.fd, libc::F_GETFD) };
if flags == -1 {
bail!(
"fcntl to read flags failed: {:?}",
std::io::Error::last_os_error()
);
}
let result = unsafe { libc::fcntl(self.fd, libc::F_SETFD, flags | libc::FD_CLOEXEC) };
if result == -1 {
bail!(
"fcntl to set CLOEXEC failed: {:?}",
std::io::Error::last_os_error()
);
}
Ok(())
}
pub fn as_stdio(&self) -> Fallible<std::process::Stdio> {
let duped = dup_fd(self.fd)?;
let fd = duped.fd;
let stdio = unsafe { std::process::Stdio::from_raw_fd(fd) };
std::mem::forget(duped); // don't drop; stdio now owns it
Ok(stdio)
}
}

View File

@ -0,0 +1,134 @@
use crate::Pipes;
use failure::{bail, Fallible};
use std::io::{self, Error as IoError};
use std::os::windows::prelude::*;
use std::os::windows::raw::HANDLE;
use std::ptr;
use winapi::um::fileapi::*;
use winapi::um::handleapi::*;
use winapi::um::namedpipeapi::CreatePipe;
use winapi::um::processthreadsapi::*;
pub trait AsRawFileDescriptor: AsRawHandle {}
impl<T: AsRawHandle> AsRawFileDescriptor for T {}
#[derive(Debug)]
pub struct FileDescriptor {
pub handle: HANDLE,
}
unsafe impl Send for FileDescriptor {}
impl Drop for FileDescriptor {
fn drop(&mut self) {
if self.handle != INVALID_HANDLE_VALUE && !self.handle.is_null() {
unsafe { CloseHandle(self.handle) };
}
}
}
fn dup_handle(handle: HANDLE) -> Fallible<FileDescriptor> {
if handle == INVALID_HANDLE_VALUE || handle.is_null() {
return Ok(FileDescriptor { handle: handle });
}
let proc = unsafe { GetCurrentProcess() };
let mut duped = INVALID_HANDLE_VALUE;
let ok = unsafe {
DuplicateHandle(
proc,
handle as *mut _,
proc,
&mut duped,
0,
0,
winapi::um::winnt::DUPLICATE_SAME_ACCESS,
)
};
if ok == 0 {
Err(IoError::last_os_error().into())
} else {
Ok(FileDescriptor {
handle: duped as *mut _,
})
}
}
pub fn dup<F: AsRawFileDescriptor>(f: F) -> Fallible<FileDescriptor> {
dup_handle(f.as_raw_handle())
}
impl FileDescriptor {
pub fn new(handle: HANDLE) -> Self {
Self { handle }
}
pub fn try_clone(&self) -> Fallible<Self> {
dup_handle(self.handle)
}
pub fn as_stdio(&self) -> Fallible<std::process::Stdio> {
let duped = dup_handle(self.handle)?;
let handle = duped.handle;
let stdio = unsafe { std::process::Stdio::from_raw_handle(handle) };
std::mem::forget(duped); // don't drop; stdio now owns it
Ok(stdio)
}
pub fn pipe() -> Fallible<Pipes> {
let mut read: HANDLE = INVALID_HANDLE_VALUE;
let mut write: HANDLE = INVALID_HANDLE_VALUE;
if unsafe { CreatePipe(&mut read, &mut write, ptr::null_mut(), 0) } == 0 {
bail!("CreatePipe failed: {}", IoError::last_os_error());
}
Ok(Pipes {
read: FileDescriptor { handle: read },
write: FileDescriptor { handle: write },
})
}
pub fn dup<F: AsRawFileDescriptor>(f: F) -> Fallible<Self> {
dup(f)
}
}
impl io::Read for FileDescriptor {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, io::Error> {
let mut num_read = 0;
let ok = unsafe {
ReadFile(
self.handle as *mut _,
buf.as_mut_ptr() as *mut _,
buf.len() as u32,
&mut num_read,
ptr::null_mut(),
)
};
if ok == 0 {
Err(IoError::last_os_error())
} else {
Ok(num_read as usize)
}
}
}
impl io::Write for FileDescriptor {
fn write(&mut self, buf: &[u8]) -> Result<usize, io::Error> {
let mut num_wrote = 0;
let ok = unsafe {
WriteFile(
self.handle as *mut _,
buf.as_ptr() as *const _,
buf.len() as u32,
&mut num_wrote,
ptr::null_mut(),
)
};
if ok == 0 {
Err(IoError::last_os_error())
} else {
Ok(num_wrote as usize)
}
}
fn flush(&mut self) -> Result<(), io::Error> {
Ok(())
}
}