1
1
mirror of https://github.com/wez/wezterm.git synced 2025-01-03 19:21:57 +03:00

filedescriptor: remove anyhow from public interface

Use thiserror instead
This commit is contained in:
Wez Furlong 2021-05-23 14:24:01 -07:00
parent ed331542ee
commit f78190ec9c
17 changed files with 203 additions and 178 deletions

4
Cargo.lock generated
View File

@ -1234,10 +1234,10 @@ dependencies = [
[[package]]
name = "filedescriptor"
version = "0.7.3"
version = "0.8.0"
dependencies = [
"anyhow",
"libc",
"thiserror",
"winapi 0.3.9",
]

View File

@ -1,6 +1,6 @@
[package]
name = "filedescriptor"
version = "0.7.3"
version = "0.8.0"
authors = ["Wez Furlong"]
edition = "2018"
repository = "https://github.com/wez/wezterm"
@ -11,7 +11,7 @@ readme = "README.md"
keywords = ["socketpair", "pipe", "poll", "filedescriptor"]
[dependencies]
anyhow = "1.0"
thiserror = "1.0"
libc = "0.2"
[target."cfg(windows)".dependencies]

View File

@ -14,16 +14,16 @@ the conditional code that would otherwise be required to deal with
calling `as_raw_fd` and `as_raw_handle`:
```
use filedescriptor::{FileDescriptor, FromRawFileDescriptor};
use filedescriptor::{FileDescriptor, FromRawFileDescriptor, Result};
use std::io::Write;
fn get_stdout() -> anyhow::Result<FileDescriptor> {
fn get_stdout() -> Result<FileDescriptor> {
let stdout = std::io::stdout();
let handle = stdout.lock();
FileDescriptor::dup(&handle)
}
fn print_something() -> anyhow::Result<()> {
fn print_something() -> Result<()> {
get_stdout()?.write(b"hello")?;
Ok(())
}
@ -36,7 +36,6 @@ the lifetime of both the read and write ends of that pipe.
```
use filedescriptor::Pipe;
use std::io::{Read, Write};
use anyhow::Error;
let mut pipe = Pipe::new()?;
pipe.write.write(b"hello")?;
@ -53,7 +52,6 @@ sockets and functions both on posix and windows systems.
```
use std::io::{Read, Write};
use anyhow::Error;
let (mut a, mut b) = filedescriptor::socketpair()?;
a.write(b"hello")?;
@ -75,7 +73,6 @@ function is used instead.
```
use filedescriptor::*;
use anyhow::Error;
use std::time::Duration;
use std::io::{Read, Write};

View File

@ -12,16 +12,16 @@
//! calling `as_raw_fd` and `as_raw_handle`:
//!
//! ```
//! use filedescriptor::{FileDescriptor, FromRawFileDescriptor};
//! use filedescriptor::{FileDescriptor, FromRawFileDescriptor, Result};
//! use std::io::Write;
//!
//! fn get_stdout() -> anyhow::Result<FileDescriptor> {
//! fn get_stdout() -> Result<FileDescriptor> {
//! let stdout = std::io::stdout();
//! let handle = stdout.lock();
//! FileDescriptor::dup(&handle)
//! }
//!
//! fn print_something() -> anyhow::Result<()> {
//! fn print_something() -> Result<()> {
//! get_stdout()?.write(b"hello")?;
//! Ok(())
//! }
@ -32,9 +32,8 @@
//! the lifetime of both the read and write ends of that pipe.
//!
//! ```
//! use filedescriptor::Pipe;
//! use filedescriptor::{Pipe, Error};
//! use std::io::{Read, Write};
//! use anyhow::Error;
//!
//! let mut pipe = Pipe::new()?;
//! pipe.write.write(b"hello")?;
@ -52,7 +51,7 @@
//!
//! ```
//! use std::io::{Read, Write};
//! use anyhow::Error;
//! use filedescriptor::Error;
//!
//! let (mut a, mut b) = filedescriptor::socketpair()?;
//! a.write(b"hello")?;
@ -75,7 +74,6 @@
//!
//! ```
//! use filedescriptor::*;
//! use anyhow::Error;
//! use std::time::Duration;
//! use std::io::{Read, Write};
//!
@ -106,6 +104,57 @@ mod windows;
#[cfg(windows)]
pub use crate::windows::*;
use thiserror::Error;
#[derive(Error, Debug)]
#[non_exhaustive]
pub enum Error {
#[error("failed to create a pipe")]
Pipe(#[source] std::io::Error),
#[error("failed to create a socketpair")]
Socketpair(#[source] std::io::Error),
#[error("failed to create a socket")]
Socket(#[source] std::io::Error),
#[error("failed to bind a socket")]
Bind(#[source] std::io::Error),
#[error("failed to fetch socket name")]
Getsockname(#[source] std::io::Error),
#[error("failed to set socket to listen mode")]
Listen(#[source] std::io::Error),
#[error("failed to connect socket")]
Connect(#[source] std::io::Error),
#[error("failed to accept socket")]
Accept(#[source] std::io::Error),
#[error("fcntl read failed")]
Fcntl(#[source] std::io::Error),
#[error("failed to set cloexec")]
Cloexec(#[source] std::io::Error),
#[error("failed to change non-blocking mode")]
FionBio(#[source] std::io::Error),
#[error("poll failed")]
Poll(#[source] std::io::Error),
#[error("dup of fd {fd} failed")]
Dup { fd: i64, source: std::io::Error },
#[error("dup of fd {src_fd} to fd {dest_fd} failed")]
Dup2 {
src_fd: i64,
dest_fd: i64,
source: std::io::Error,
},
#[error("Illegal fd value {0}")]
IllegalFdValue(i64),
#[error("fd value {0} too large to use with select(2)")]
FdValueOutsideFdSetSize(i64),
#[error("Only socket descriptors can change their non-blocking mode on Windows")]
OnlySocketsNonBlocking,
#[error("SetStdHandle failed")]
SetStdHandle(#[source] std::io::Error),
#[error("IoError")]
Io(#[from] std::io::Error),
}
pub type Result<T> = std::result::Result<T, Error>;
/// `AsRawFileDescriptor` is a platform independent trait for returning
/// a non-owning reference to the underlying platform file descriptor
/// type.
@ -167,7 +216,7 @@ impl OwnedHandle {
/// potentially fallible operation.
/// The returned handle has a separate lifetime from the source, but
/// references the same object at the kernel level.
pub fn try_clone(&self) -> anyhow::Result<Self> {
pub fn try_clone(&self) -> Result<Self> {
Self::dup_impl(self, self.handle_type)
}
@ -178,7 +227,7 @@ impl OwnedHandle {
/// potentially fallible operation.
/// The returned handle has a separate lifetime from the source, but
/// references the same object at the kernel level.
pub fn dup<F: AsRawFileDescriptor>(f: &F) -> anyhow::Result<Self> {
pub fn dup<F: AsRawFileDescriptor>(f: &F) -> Result<Self> {
Self::dup_impl(f, Default::default())
}
}
@ -191,16 +240,16 @@ impl OwnedHandle {
/// calling `as_raw_fd` and `as_raw_handle`:
///
/// ```
/// use filedescriptor::{FileDescriptor, FromRawFileDescriptor};
/// use filedescriptor::{FileDescriptor, FromRawFileDescriptor, Result};
/// use std::io::Write;
///
/// fn get_stdout() -> anyhow::Result<FileDescriptor> {
/// fn get_stdout() -> Result<FileDescriptor> {
/// let stdout = std::io::stdout();
/// let handle = stdout.lock();
/// FileDescriptor::dup(&handle)
/// }
///
/// fn print_something() -> anyhow::Result<()> {
/// fn print_something() -> Result<()> {
/// get_stdout()?.write(b"hello")?;
/// Ok(())
/// }
@ -233,7 +282,7 @@ impl FileDescriptor {
/// potentially fallible operation.
/// The returned handle has a separate lifetime from the source, but
/// references the same object at the kernel level.
pub fn dup<F: AsRawFileDescriptor>(f: &F) -> anyhow::Result<Self> {
pub fn dup<F: AsRawFileDescriptor>(f: &F) -> Result<Self> {
OwnedHandle::dup(f).map(|handle| Self { handle })
}
@ -243,7 +292,7 @@ impl FileDescriptor {
/// potentially fallible operation.
/// The returned handle has a separate lifetime from the source, but
/// references the same object at the kernel level.
pub fn try_clone(&self) -> anyhow::Result<Self> {
pub fn try_clone(&self) -> Result<Self> {
self.handle.try_clone().map(|handle| Self { handle })
}
@ -251,7 +300,7 @@ impl FileDescriptor {
/// to be used for eg: redirecting the stdio streams of a child
/// process. The `Stdio` is created using a duplicated handle so
/// that the source handle remains alive.
pub fn as_stdio(&self) -> anyhow::Result<std::process::Stdio> {
pub fn as_stdio(&self) -> Result<std::process::Stdio> {
self.as_stdio_impl()
}
@ -261,7 +310,7 @@ impl FileDescriptor {
/// non-blocking mode but it will have no effect.
/// File descriptors based on sockets are the most portable type
/// that can be successfully made non-blocking.
pub fn set_non_blocking(&mut self, non_blocking: bool) -> anyhow::Result<()> {
pub fn set_non_blocking(&mut self, non_blocking: bool) -> Result<()> {
self.set_non_blocking_impl(non_blocking)
}
@ -270,10 +319,7 @@ impl FileDescriptor {
/// Since the redirection requires kernel resources that may not be
/// available, this is a potentially fallible operation.
/// Supports stdin, stdout, and stderr redirections.
pub fn redirect_stdio<F: AsRawFileDescriptor>(
f: &F,
stdio: StdioDescriptor,
) -> anyhow::Result<Self> {
pub fn redirect_stdio<F: AsRawFileDescriptor>(f: &F, stdio: StdioDescriptor) -> Result<Self> {
Self::redirect_stdio_impl(f, stdio)
}
}
@ -282,9 +328,8 @@ impl FileDescriptor {
/// connected via a kernel pipe.
///
/// ```
/// use filedescriptor::Pipe;
/// use filedescriptor::{Pipe, Error};
/// use std::io::{Read,Write};
/// use anyhow::Error;
///
/// let mut pipe = Pipe::new()?;
/// pipe.write.write(b"hello")?;
@ -331,13 +376,13 @@ use std::time::Duration;
///
/// The `pfd` array is mutated and the `revents` field is updated to indicate
/// which of the events were received.
pub fn poll(pfd: &mut [pollfd], duration: Option<Duration>) -> anyhow::Result<usize> {
pub fn poll(pfd: &mut [pollfd], duration: Option<Duration>) -> Result<usize> {
poll_impl(pfd, duration)
}
/// Create a pair of connected sockets
///
/// This implementation creates a pair of SOCK_STREAM sockets.
pub fn socketpair() -> anyhow::Result<(FileDescriptor, FileDescriptor)> {
pub fn socketpair() -> Result<(FileDescriptor, FileDescriptor)> {
socketpair_impl()
}

View File

@ -1,9 +1,8 @@
use crate::{
AsRawFileDescriptor, AsRawSocketDescriptor, FileDescriptor, FromRawFileDescriptor,
AsRawFileDescriptor, AsRawSocketDescriptor, Error, FileDescriptor, FromRawFileDescriptor,
FromRawSocketDescriptor, IntoRawFileDescriptor, IntoRawSocketDescriptor, OwnedHandle, Pipe,
StdioDescriptor,
Result, StdioDescriptor,
};
use anyhow::bail;
use std::os::unix::prelude::*;
pub(crate) type HandleType = ();
@ -87,32 +86,26 @@ impl FromRawFd for OwnedHandle {
impl OwnedHandle {
/// Helper function to set the close-on-exec flag for a raw descriptor
fn cloexec(&mut self) -> anyhow::Result<()> {
fn cloexec(&mut self) -> Result<()> {
let flags = unsafe { libc::fcntl(self.handle, libc::F_GETFD) };
if flags == -1 {
bail!(
"fcntl to read flags failed: {:?}",
std::io::Error::last_os_error()
);
return Err(Error::Fcntl(std::io::Error::last_os_error()));
}
let result = unsafe { libc::fcntl(self.handle, libc::F_SETFD, flags | libc::FD_CLOEXEC) };
if result == -1 {
bail!(
"fcntl to set CLOEXEC failed: {:?}",
std::io::Error::last_os_error()
);
Err(Error::Cloexec(std::io::Error::last_os_error()))
} else {
Ok(())
}
Ok(())
}
fn non_atomic_dup(fd: RawFd) -> anyhow::Result<Self> {
fn non_atomic_dup(fd: RawFd) -> Result<Self> {
let duped = unsafe { libc::dup(fd) };
if duped == -1 {
bail!(
"dup of fd {} failed: {:?}",
fd,
std::io::Error::last_os_error()
)
Err(Error::Dup {
fd: fd.into(),
source: std::io::Error::last_os_error(),
})
} else {
let mut owned = OwnedHandle {
handle: duped,
@ -123,15 +116,14 @@ impl OwnedHandle {
}
}
fn non_atomic_dup2(fd: RawFd, dest_fd: RawFd) -> anyhow::Result<Self> {
fn non_atomic_dup2(fd: RawFd, dest_fd: RawFd) -> Result<Self> {
let duped = unsafe { libc::dup2(fd, dest_fd) };
if duped == -1 {
bail!(
"dup2 of fd {} and dest_fd {} failed: {:?}",
fd,
dest_fd,
std::io::Error::last_os_error()
)
Err(Error::Dup2 {
src_fd: fd.into(),
dest_fd: dest_fd.into(),
source: std::io::Error::last_os_error(),
})
} else {
let mut owned = OwnedHandle {
handle: duped,
@ -146,7 +138,7 @@ impl OwnedHandle {
pub(crate) fn dup_impl<F: AsRawFileDescriptor>(
fd: &F,
handle_type: HandleType,
) -> anyhow::Result<Self> {
) -> Result<Self> {
let fd = fd.as_raw_file_descriptor();
let duped = unsafe { libc::fcntl(fd, libc::F_DUPFD_CLOEXEC, 0) };
if duped == -1 {
@ -154,9 +146,12 @@ impl OwnedHandle {
if let Some(libc::EINVAL) = err.raw_os_error() {
// We may be running on eg: WSL or an old kernel that
// doesn't support F_DUPFD_CLOEXEC; fall back.
return Self::non_atomic_dup(fd);
Self::non_atomic_dup(fd)
} else {
bail!("dup of fd {} failed: {:?}", fd, err)
Err(Error::Dup {
fd: fd.into(),
source: err,
})
}
} else {
Ok(OwnedHandle {
@ -167,10 +162,7 @@ impl OwnedHandle {
}
#[inline]
pub(crate) unsafe fn dup2_impl<F: AsRawFileDescriptor>(
fd: &F,
dest_fd: RawFd,
) -> anyhow::Result<Self> {
pub(crate) unsafe fn dup2_impl<F: AsRawFileDescriptor>(fd: &F, dest_fd: RawFd) -> Result<Self> {
let fd = fd.as_raw_file_descriptor();
#[cfg(not(target_os = "linux"))]
@ -185,20 +177,19 @@ impl OwnedHandle {
if let Some(libc::EINVAL) = err.raw_os_error() {
// We may be running on eg: WSL or an old kernel that
// doesn't support O_CLOEXEC; fall back.
return Self::non_atomic_dup2(fd, dest_fd);
Self::non_atomic_dup2(fd, dest_fd)
} else {
bail!(
"dup2 of fd {} and dest_fd {} failed: {:?}",
fd,
dest_fd,
err
)
Err(Error::Dup2 {
src_fd: fd.into(),
dest_fd: dest_fd.into(),
source: err,
})
}
} else {
return Ok(OwnedHandle {
Ok(OwnedHandle {
handle: duped,
handle_type: (),
});
})
}
}
}
@ -209,7 +200,7 @@ impl OwnedHandle {
}
impl std::io::Read for FileDescriptor {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, std::io::Error> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
let size = unsafe { libc::read(self.handle.handle, buf.as_mut_ptr() as *mut _, buf.len()) };
if size == -1 {
Err(std::io::Error::last_os_error())
@ -220,7 +211,7 @@ impl std::io::Read for FileDescriptor {
}
impl std::io::Write for FileDescriptor {
fn write(&mut self, buf: &[u8]) -> Result<usize, std::io::Error> {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
let size = unsafe { libc::write(self.handle.handle, buf.as_ptr() as *const _, buf.len()) };
if size == -1 {
Err(std::io::Error::last_os_error())
@ -228,7 +219,7 @@ impl std::io::Write for FileDescriptor {
Ok(size as usize)
}
}
fn flush(&mut self) -> Result<(), std::io::Error> {
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
@ -255,7 +246,7 @@ impl FromRawFd for FileDescriptor {
impl FileDescriptor {
#[inline]
pub(crate) fn as_stdio_impl(&self) -> anyhow::Result<std::process::Stdio> {
pub(crate) fn as_stdio_impl(&self) -> Result<std::process::Stdio> {
let duped = OwnedHandle::dup(self)?;
let fd = duped.into_raw_fd();
let stdio = unsafe { std::process::Stdio::from_raw_fd(fd) };
@ -263,16 +254,14 @@ impl FileDescriptor {
}
#[inline]
pub(crate) fn set_non_blocking_impl(&mut self, non_blocking: bool) -> anyhow::Result<()> {
pub(crate) fn set_non_blocking_impl(&mut self, non_blocking: bool) -> Result<()> {
let on = if non_blocking { 1 } else { 0 };
let res = unsafe { libc::ioctl(self.handle.as_raw_file_descriptor(), libc::FIONBIO, &on) };
if res != 0 {
bail!(
"failed to change non-blocking mode: {:?}",
std::io::Error::last_os_error()
);
Err(Error::FionBio(std::io::Error::last_os_error()))
} else {
Ok(())
}
Ok(())
}
/// Attempt to duplicate the underlying handle from an object that is
@ -282,14 +271,14 @@ impl FileDescriptor {
/// resources that may not be available, this is a potentially fallible operation.
/// The returned handle has a separate lifetime from the source, but
/// references the same object at the kernel level.
pub unsafe fn dup2<F: AsRawFileDescriptor>(f: &F, dest_fd: RawFd) -> anyhow::Result<Self> {
pub unsafe fn dup2<F: AsRawFileDescriptor>(f: &F, dest_fd: RawFd) -> Result<Self> {
OwnedHandle::dup2_impl(f, dest_fd).map(|handle| Self { handle })
}
pub(crate) fn redirect_stdio_impl<F: AsRawFileDescriptor>(
f: &F,
stdio: StdioDescriptor,
) -> anyhow::Result<Self> {
) -> Result<Self> {
let std_descriptor = match stdio {
StdioDescriptor::Stdin => libc::STDIN_FILENO,
StdioDescriptor::Stdout => libc::STDOUT_FILENO,
@ -305,14 +294,11 @@ impl FileDescriptor {
impl Pipe {
#[cfg(target_os = "linux")]
pub fn new() -> anyhow::Result<Pipe> {
pub fn new() -> Result<Pipe> {
let mut fds = [-1i32; 2];
let res = unsafe { libc::pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC) };
if res == -1 {
bail!(
"failed to create a pipe: {:?}",
std::io::Error::last_os_error()
)
Err(Error::Pipe(std::io::Error::last_os_error()))
} else {
let read = FileDescriptor {
handle: OwnedHandle {
@ -331,7 +317,7 @@ impl Pipe {
}
#[cfg(not(target_os = "linux"))]
pub fn new() -> anyhow::Result<Pipe> {
pub fn new() -> Result<Pipe> {
let mut fds = [-1i32; 2];
let res = unsafe { libc::pipe(fds.as_mut_ptr()) };
if res == -1 {
@ -361,7 +347,7 @@ impl Pipe {
#[cfg(target_os = "linux")]
#[doc(hidden)]
pub fn socketpair_impl() -> anyhow::Result<(FileDescriptor, FileDescriptor)> {
pub fn socketpair_impl() -> Result<(FileDescriptor, FileDescriptor)> {
let mut fds = [-1i32; 2];
let res = unsafe {
libc::socketpair(
@ -372,10 +358,7 @@ pub fn socketpair_impl() -> anyhow::Result<(FileDescriptor, FileDescriptor)> {
)
};
if res == -1 {
bail!(
"failed to create a socketpair: {:?}",
std::io::Error::last_os_error()
)
Err(Error::Socketpair(std::io::Error::last_os_error()))
} else {
let read = FileDescriptor {
handle: OwnedHandle {
@ -395,7 +378,7 @@ pub fn socketpair_impl() -> anyhow::Result<(FileDescriptor, FileDescriptor)> {
#[cfg(not(target_os = "linux"))]
#[doc(hidden)]
pub fn socketpair_impl() -> anyhow::Result<(FileDescriptor, FileDescriptor)> {
pub fn socketpair_impl() -> Result<(FileDescriptor, FileDescriptor)> {
let mut fds = [-1i32; 2];
let res = unsafe { libc::socketpair(libc::PF_LOCAL, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) };
if res == -1 {
@ -427,7 +410,7 @@ use std::time::Duration;
#[cfg(not(target_os = "macos"))]
#[doc(hidden)]
pub fn poll_impl(pfd: &mut [pollfd], duration: Option<Duration>) -> anyhow::Result<usize> {
pub fn poll_impl(pfd: &mut [pollfd], duration: Option<Duration>) -> Result<usize> {
let poll_result = unsafe {
libc::poll(
pfd.as_mut_ptr(),
@ -438,7 +421,7 @@ pub fn poll_impl(pfd: &mut [pollfd], duration: Option<Duration>) -> anyhow::Resu
)
};
if poll_result < 0 {
Err(std::io::Error::last_os_error().into())
Err(Error::Poll(std::io::Error::last_os_error()))
} else {
Ok(poll_result as usize)
}
@ -456,12 +439,13 @@ mod macos {
}
#[inline]
fn check_fd(fd: RawFd) -> anyhow::Result<()> {
anyhow::ensure!(fd >= 0, "illegal fd value");
anyhow::ensure!(
(fd as usize) < FD_SETSIZE,
"fd value is too large to use with select(2) on macos"
);
fn check_fd(fd: RawFd) -> Result<()> {
if fd < 0 {
return Err(Error::IllegalFdValue(fd.into()));
}
if fd >= FD_SETSIZE {
return Err(Error::FdValueOutsideFdSetSize(fd.into()));
}
Ok(())
}
@ -474,7 +458,7 @@ mod macos {
}
}
pub fn add(&mut self, fd: RawFd) -> anyhow::Result<()> {
pub fn add(&mut self, fd: RawFd) -> Result<()> {
check_fd(fd)?;
unsafe {
FD_SET(fd, &mut self.set);
@ -502,7 +486,7 @@ mod macos {
set.as_mut().map(|s| s.contains(fd)).unwrap_or(false)
}
pub fn poll_impl(pfd: &mut [pollfd], duration: Option<Duration>) -> anyhow::Result<usize> {
pub fn poll_impl(pfd: &mut [pollfd], duration: Option<Duration>) -> Result<usize> {
let mut read_set = None;
let mut write_set = None;
let mut exception_set = None;

View File

@ -3,7 +3,6 @@ use crate::{
FromRawSocketDescriptor, IntoRawFileDescriptor, IntoRawSocketDescriptor, OwnedHandle, Pipe,
StdioDescriptor,
};
use anyhow::bail;
use std::io::{self, Error as IoError};
use std::os::windows::prelude::*;
use std::ptr;
@ -178,10 +177,7 @@ impl FromRawHandle for OwnedHandle {
impl OwnedHandle {
#[inline]
pub(crate) fn dup_impl<F: AsRawFileDescriptor>(
f: &F,
handle_type: HandleType,
) -> anyhow::Result<Self> {
pub(crate) fn dup_impl<F: AsRawFileDescriptor>(f: &F, handle_type: HandleType) -> Result<Self> {
let handle = f.as_raw_file_descriptor();
if handle == INVALID_HANDLE_VALUE as _ || handle.is_null() {
return Ok(OwnedHandle {
@ -232,7 +228,7 @@ impl IntoRawHandle for OwnedHandle {
impl FileDescriptor {
#[inline]
pub(crate) fn as_stdio_impl(&self) -> anyhow::Result<std::process::Stdio> {
pub(crate) fn as_stdio_impl(&self) -> Result<std::process::Stdio> {
let duped = self.handle.try_clone()?;
let handle = duped.into_raw_handle();
let stdio = unsafe { std::process::Stdio::from_raw_handle(handle) };
@ -240,9 +236,9 @@ impl FileDescriptor {
}
#[inline]
pub(crate) fn set_non_blocking_impl(&mut self, non_blocking: bool) -> anyhow::Result<()> {
pub(crate) fn set_non_blocking_impl(&mut self, non_blocking: bool) -> Result<()> {
if !self.handle.is_socket_handle() {
bail!("only socket descriptors can change their non-blocking mode on windows");
return Err(Error::OnlySocketsNonBlocking);
}
let mut on = if non_blocking { 1 } else { 0 };
@ -254,18 +250,16 @@ impl FileDescriptor {
)
};
if res != 0 {
bail!(
"failed to change non-blocking mode: {:?}",
std::io::Error::last_os_error()
);
Err(Error::FionBio(std::io::Error::last_os_error()))
} else {
Ok(())
}
Ok(())
}
pub(crate) fn redirect_stdio_impl<F: AsRawFileDescriptor>(
f: &F,
stdio: StdioDescriptor,
) -> anyhow::Result<Self> {
) -> Result<Self> {
let std_handle = match stdio {
StdioDescriptor::Stdin => STD_INPUT_HANDLE,
StdioDescriptor::Stdout => STD_OUTPUT_HANDLE,
@ -277,13 +271,10 @@ impl FileDescriptor {
let cloned_handle = OwnedHandle::dup(f)?;
if unsafe { SetStdHandle(std_handle, cloned_handle.into_raw_handle() as *mut _) } == 0 {
bail!(
"failed to redirect stdio to file handle: {:?}",
std::io::Error::last_os_error()
);
Err(Error::SetStdHandle(std::io::Error::last_os_error()))
} else {
Ok(std_original)
}
Ok(std_original)
}
}
@ -415,7 +406,7 @@ impl io::Write for FileDescriptor {
}
impl Pipe {
pub fn new() -> anyhow::Result<Pipe> {
pub fn new() -> Result<Pipe> {
let mut sa = SECURITY_ATTRIBUTES {
nLength: std::mem::size_of::<SECURITY_ATTRIBUTES>() as u32,
lpSecurityDescriptor: ptr::null_mut(),
@ -424,22 +415,23 @@ impl Pipe {
let mut read: HANDLE = INVALID_HANDLE_VALUE as _;
let mut write: HANDLE = INVALID_HANDLE_VALUE as _;
if unsafe { CreatePipe(&mut read, &mut write, &mut sa, 0) } == 0 {
bail!("CreatePipe failed: {}", IoError::last_os_error());
Err(Error::Pipe(IoError::last_os_error()))
} else {
Ok(Pipe {
read: FileDescriptor {
handle: OwnedHandle {
handle: read as _,
handle_type: HandleType::Pipe,
},
},
write: FileDescriptor {
handle: OwnedHandle {
handle: write as _,
handle_type: HandleType::Pipe,
},
},
})
}
Ok(Pipe {
read: FileDescriptor {
handle: OwnedHandle {
handle: read as _,
handle_type: HandleType::Pipe,
},
},
write: FileDescriptor {
handle: OwnedHandle {
handle: write as _,
handle_type: HandleType::Pipe,
},
},
})
}
}
@ -455,7 +447,7 @@ fn init_winsock() {
});
}
fn socket(af: i32, sock_type: i32, proto: i32) -> anyhow::Result<FileDescriptor> {
fn socket(af: i32, sock_type: i32, proto: i32) -> Result<FileDescriptor> {
let s = unsafe {
WSASocketW(
af,
@ -467,18 +459,19 @@ fn socket(af: i32, sock_type: i32, proto: i32) -> anyhow::Result<FileDescriptor>
)
};
if s == INVALID_SOCKET {
bail!("socket failed: {}", IoError::last_os_error());
Err(Error::Socket(IoError::last_os_error()))
} else {
Ok(FileDescriptor {
handle: OwnedHandle {
handle: s as _,
handle_type: HandleType::Socket,
},
})
}
Ok(FileDescriptor {
handle: OwnedHandle {
handle: s as _,
handle_type: HandleType::Socket,
},
})
}
#[doc(hidden)]
pub fn socketpair_impl() -> anyhow::Result<(FileDescriptor, FileDescriptor)> {
pub fn socketpair_impl() -> Result<(FileDescriptor, FileDescriptor)> {
init_winsock();
let s = socket(AF_INET, SOCK_STREAM, 0)?;
@ -496,7 +489,7 @@ pub fn socketpair_impl() -> anyhow::Result<(FileDescriptor, FileDescriptor)> {
std::mem::size_of_val(&in_addr) as _,
) != 0
{
bail!("bind failed: {}", IoError::last_os_error());
return Err(Error::Bind(IoError::last_os_error()));
}
}
@ -509,13 +502,13 @@ pub fn socketpair_impl() -> anyhow::Result<(FileDescriptor, FileDescriptor)> {
&mut addr_len,
) != 0
{
bail!("getsockname failed: {}", IoError::last_os_error());
return Err(Error::Getsockname(IoError::last_os_error()));
}
}
unsafe {
if listen(s.as_raw_handle() as _, 1) != 0 {
bail!("listen failed: {}", IoError::last_os_error());
return Err(Error::Listen(IoError::last_os_error()));
}
}
@ -528,13 +521,13 @@ pub fn socketpair_impl() -> anyhow::Result<(FileDescriptor, FileDescriptor)> {
addr_len,
) != 0
{
bail!("connect failed: {}", IoError::last_os_error());
return Err(Error::Connect(IoError::last_os_error()));
}
}
let server = unsafe { accept(s.as_raw_handle() as _, ptr::null_mut(), ptr::null_mut()) };
if server == INVALID_SOCKET {
bail!("socket failed: {}", IoError::last_os_error());
return Err(Error::Accept(IoError::last_os_error()));
}
let server = FileDescriptor {
handle: OwnedHandle {
@ -547,7 +540,7 @@ pub fn socketpair_impl() -> anyhow::Result<(FileDescriptor, FileDescriptor)> {
}
#[doc(hidden)]
pub fn poll_impl(pfd: &mut [pollfd], duration: Option<Duration>) -> anyhow::Result<usize> {
pub fn poll_impl(pfd: &mut [pollfd], duration: Option<Duration>) -> Result<usize> {
let poll_result = unsafe {
WSAPoll(
pfd.as_mut_ptr(),

View File

@ -14,7 +14,7 @@ bintree = { path = "../bintree" }
config = { path = "../config" }
crossbeam = "0.8"
downcast-rs = "1.0"
filedescriptor = { version="0.7", path = "../filedescriptor" }
filedescriptor = { version="0.8", path = "../filedescriptor" }
lazy_static = "1.4"
libc = "0.2"
log = "0.4"

View File

@ -10,7 +10,7 @@ documentation = "https://docs.rs/portable-pty"
[dependencies]
anyhow = "1.0"
filedescriptor = { version="0.7", path = "../filedescriptor" }
filedescriptor = { version="0.8", path = "../filedescriptor" }
log = "0.4"
libc = "0.2"
shell-words = "1.0"

View File

@ -16,7 +16,7 @@ bitflags = "1.0"
cassowary = {version="0.3", optional=true}
cfg-if = "1.0"
anyhow = "1.0"
filedescriptor = { version="0.7", path = "../filedescriptor" }
filedescriptor = { version="0.8", path = "../filedescriptor" }
fnv = {version="1.0", optional=true}
lazy_static = "1.4"
libc = "0.2"

View File

@ -69,6 +69,9 @@ pub enum InternalError {
#[error(transparent)]
Terminfo(#[from] terminfo::Error),
#[error(transparent)]
FileDescriptor(#[from] filedescriptor::Error),
#[error("{}", .context)]
Context {
context: String,

View File

@ -4,6 +4,7 @@ use filedescriptor::{poll, pollfd, FileDescriptor, POLLIN};
use libc::{self, winsize};
use signal_hook::{self, SigId};
use std::collections::VecDeque;
use std::error::Error as _;
use std::fs::OpenOptions;
use std::io::{stdin, stdout, Error as IoError, ErrorKind, Read, Write};
use std::mem;
@ -422,8 +423,12 @@ impl Terminal for UnixTerminal {
];
if let Err(err) = poll(&mut pfd, wait) {
return match err.downcast::<std::io::Error>() {
Ok(err) => {
return match err
.source()
.ok_or_else(|| anyhow::anyhow!("error has no source! {:#}", err))?
.downcast_ref::<std::io::Error>()
{
Some(err) => {
if err.kind() == ErrorKind::Interrupted {
// SIGWINCH may have been the source of the interrupt.
// Check for that now so that we reduce the latency of
@ -437,7 +442,7 @@ impl Terminal for UnixTerminal {
bail!("poll(2) error: {}", err)
}
}
Err(err) => bail!("poll(2) error: {}", err),
None => bail!("poll(2) error: {}", err),
};
};

View File

@ -12,7 +12,7 @@ async-trait = "0.1"
async_ossl = { path = "../async_ossl" }
codec = { path = "../codec" }
config = { path = "../config" }
filedescriptor = { version="0.7", path = "../filedescriptor" }
filedescriptor = { version="0.8", path = "../filedescriptor" }
futures = "0.3"
log = "0.4"
lru = "0.6"

View File

@ -25,7 +25,7 @@ config = { path = "../config" }
downcast-rs = "1.0"
env-bootstrap = { path = "../env-bootstrap" }
euclid = "0.22"
filedescriptor = { version="0.7", path = "../filedescriptor" }
filedescriptor = { version="0.8", path = "../filedescriptor" }
hdrhistogram = "7.1"
http_req = {version="0.7", default-features=false, features=["rust-tls"]}
image = "0.23"

View File

@ -14,7 +14,7 @@ documentation = "https://docs.rs/wezterm-ssh"
anyhow = "1.0"
base64 = "0.13"
dirs-next = "2.0"
filedescriptor = { version="0.7", path = "../filedescriptor" }
filedescriptor = { version="0.8", path = "../filedescriptor" }
log = "0.4"
portable-pty = { version="0.4", path = "../pty" }
regex = "1"

View File

@ -64,15 +64,13 @@ impl portable_pty::MasterPty for SshPty {
}
fn try_clone_reader(&self) -> anyhow::Result<Box<(dyn Read + Send + 'static)>> {
self.reader
.try_clone()
.map(|f| -> Box<(dyn Read + Send + 'static)> { Box::new(f) })
let reader = self.reader.try_clone()?;
Ok(Box::new(reader))
}
fn try_clone_writer(&self) -> anyhow::Result<Box<(dyn Write + Send + 'static)>> {
self.writer
.try_clone()
.map(|f| -> Box<(dyn Write + Send + 'static)> { Box::new(f) })
let writer = self.writer.try_clone()?;
Ok(Box::new(writer))
}
#[cfg(unix)]

View File

@ -14,7 +14,7 @@ anyhow = "1.0"
codec = { path = "../codec" }
config = { path = "../config" }
env-bootstrap = { path = "../env-bootstrap" }
filedescriptor = { version="0.7", path = "../filedescriptor" }
filedescriptor = { version="0.8", path = "../filedescriptor" }
hostname = "0.3"
log = "0.4"
mux = { path = "../mux" }

View File

@ -53,7 +53,7 @@ shared_library = "0.1"
[target.'cfg(all(unix, not(target_os = "macos")))'.dependencies]
dirs-next = "2.0"
filedescriptor = { version="0.7", path = "../filedescriptor" }
filedescriptor = { version="0.8", path = "../filedescriptor" }
x11 = {version ="2.18", features = ["xlib_xcb"]}
xcb = {version="0.9", features=["render", "xkb", "xlib_xcb"]}
xcb-util = { features = [ "cursor", "image", "icccm", "ewmh", "keysyms"], version = "0.3" }