use core::str::Utf8Error;
use std::{io, process::ExitCode};
pub fn exit_code(code: u32) -> ExitCode {
#[cfg(windows)]
{
if code > u8::MAX as u32 {
std::process::exit(code as i32)
}
}
ExitCode::from(code as u8)
}
pub trait ErrorExt {
fn posix_errno(&self) -> i32;
}
impl ErrorExt for io::Error {
#[cfg(not(windows))]
fn posix_errno(&self) -> i32 {
self.raw_os_error().unwrap_or(0)
}
#[cfg(windows)]
fn posix_errno(&self) -> i32 {
let winerror = self.raw_os_error().unwrap_or(0);
winerror_to_errno(winerror)
}
}
#[cfg(windows)]
pub fn errno_io_error() -> io::Error {
let errno: i32 = get_errno();
let winerror = errno_to_winerror(errno);
io::Error::from_raw_os_error(winerror)
}
#[cfg(not(windows))]
pub fn errno_io_error() -> io::Error {
std::io::Error::last_os_error()
}
#[cfg(windows)]
pub fn get_errno() -> i32 {
unsafe extern "C" {
fn _get_errno(pValue: *mut i32) -> i32;
}
let mut errno = 0;
unsafe { suppress_iph!(_get_errno(&mut errno)) };
errno
}
#[cfg(not(windows))]
pub fn get_errno() -> i32 {
std::io::Error::last_os_error().posix_errno()
}
#[cfg(windows)]
pub fn set_errno(value: i32) {
unsafe extern "C" {
fn _set_errno(value: i32) -> i32;
}
unsafe { suppress_iph!(_set_errno(value)) };
}
#[cfg(unix)]
pub fn set_errno(value: i32) {
nix::errno::Errno::from_raw(value).set();
}
#[cfg(unix)]
pub fn bytes_as_os_str(b: &[u8]) -> Result<&std::ffi::OsStr, Utf8Error> {
use std::os::unix::ffi::OsStrExt;
Ok(std::ffi::OsStr::from_bytes(b))
}
#[cfg(not(unix))]
pub fn bytes_as_os_str(b: &[u8]) -> Result<&std::ffi::OsStr, Utf8Error> {
Ok(core::str::from_utf8(b)?.as_ref())
}
#[cfg(unix)]
pub use std::os::unix::ffi;
#[cfg(all(target_os = "wasi", not(target_env = "p2")))]
pub use std::os::wasi::ffi;
#[cfg(all(target_os = "wasi", target_env = "p2"))]
pub mod ffi {
use std::ffi::{OsStr, OsString};
pub trait OsStrExt: sealed::Sealed {
fn as_bytes(&self) -> &[u8];
fn from_bytes(slice: &[u8]) -> &Self;
}
impl OsStrExt for OsStr {
fn as_bytes(&self) -> &[u8] {
self.to_str().expect("wasip2 strings are UTF-8").as_bytes()
}
fn from_bytes(slice: &[u8]) -> &OsStr {
OsStr::new(core::str::from_utf8(slice).expect("wasip2 strings are UTF-8"))
}
}
pub trait OsStringExt: sealed::Sealed {
fn from_vec(vec: Vec<u8>) -> Self;
fn into_vec(self) -> Vec<u8>;
}
impl OsStringExt for OsString {
fn from_vec(vec: Vec<u8>) -> OsString {
OsString::from(String::from_utf8(vec).expect("wasip2 strings are UTF-8"))
}
fn into_vec(self) -> Vec<u8> {
self.to_str()
.expect("wasip2 strings are UTF-8")
.as_bytes()
.to_vec()
}
}
mod sealed {
pub trait Sealed {}
impl Sealed for std::ffi::OsStr {}
impl Sealed for std::ffi::OsString {}
}
}
#[cfg(windows)]
pub fn errno_to_winerror(errno: i32) -> i32 {
use libc::*;
use windows_sys::Win32::Foundation::*;
let winerror = match errno {
ENOENT => ERROR_FILE_NOT_FOUND,
E2BIG => ERROR_BAD_ENVIRONMENT,
ENOEXEC => ERROR_BAD_FORMAT,
EBADF => ERROR_INVALID_HANDLE,
ECHILD => ERROR_WAIT_NO_CHILDREN,
EAGAIN => ERROR_NO_PROC_SLOTS,
ENOMEM => ERROR_NOT_ENOUGH_MEMORY,
EACCES => ERROR_ACCESS_DENIED,
EEXIST => ERROR_FILE_EXISTS,
EXDEV => ERROR_NOT_SAME_DEVICE,
ENOTDIR => ERROR_DIRECTORY,
EMFILE => ERROR_TOO_MANY_OPEN_FILES,
ENOSPC => ERROR_DISK_FULL,
EPIPE => ERROR_BROKEN_PIPE,
ENOTEMPTY => ERROR_DIR_NOT_EMPTY,
EILSEQ => ERROR_NO_UNICODE_TRANSLATION,
EINVAL => ERROR_INVALID_FUNCTION,
_ => ERROR_INVALID_FUNCTION,
};
winerror as _
}
#[cfg(windows)]
pub fn winerror_to_errno(winerror: i32) -> i32 {
use libc::*;
use windows_sys::Win32::{
Foundation::*,
Networking::WinSock::{
WSAEACCES, WSAEBADF, WSAECONNABORTED, WSAECONNREFUSED, WSAECONNRESET, WSAEFAULT,
WSAEINTR, WSAEINVAL, WSAEMFILE,
},
};
if (10000..12000).contains(&winerror) {
match winerror {
WSAEINTR | WSAEBADF | WSAEACCES | WSAEFAULT | WSAEINVAL | WSAEMFILE => {
return winerror - 10000;
}
_ => return winerror as _,
}
}
#[allow(non_upper_case_globals)]
match winerror as u32 {
ERROR_FILE_NOT_FOUND
| ERROR_PATH_NOT_FOUND
| ERROR_INVALID_DRIVE
| ERROR_NO_MORE_FILES
| ERROR_BAD_NETPATH
| ERROR_BAD_NET_NAME
| ERROR_BAD_PATHNAME
| ERROR_FILENAME_EXCED_RANGE => ENOENT,
ERROR_BAD_ENVIRONMENT => E2BIG,
ERROR_BAD_FORMAT
| ERROR_INVALID_STARTING_CODESEG
| ERROR_INVALID_STACKSEG
| ERROR_INVALID_MODULETYPE
| ERROR_INVALID_EXE_SIGNATURE
| ERROR_EXE_MARKED_INVALID
| ERROR_BAD_EXE_FORMAT
| ERROR_ITERATED_DATA_EXCEEDS_64k
| ERROR_INVALID_MINALLOCSIZE
| ERROR_DYNLINK_FROM_INVALID_RING
| ERROR_IOPL_NOT_ENABLED
| ERROR_INVALID_SEGDPL
| ERROR_AUTODATASEG_EXCEEDS_64k
| ERROR_RING2SEG_MUST_BE_MOVABLE
| ERROR_RELOC_CHAIN_XEEDS_SEGLIM
| ERROR_INFLOOP_IN_RELOC_CHAIN => ENOEXEC,
ERROR_INVALID_HANDLE | ERROR_INVALID_TARGET_HANDLE | ERROR_DIRECT_ACCESS_HANDLE => EBADF,
ERROR_WAIT_NO_CHILDREN | ERROR_CHILD_NOT_COMPLETE => ECHILD,
ERROR_NO_PROC_SLOTS | ERROR_MAX_THRDS_REACHED | ERROR_NESTING_NOT_ALLOWED => EAGAIN,
ERROR_ARENA_TRASHED
| ERROR_NOT_ENOUGH_MEMORY
| ERROR_INVALID_BLOCK
| ERROR_NOT_ENOUGH_QUOTA => ENOMEM,
ERROR_ACCESS_DENIED
| ERROR_CURRENT_DIRECTORY
| ERROR_WRITE_PROTECT
| ERROR_BAD_UNIT
| ERROR_NOT_READY
| ERROR_BAD_COMMAND
| ERROR_CRC
| ERROR_BAD_LENGTH
| ERROR_SEEK
| ERROR_NOT_DOS_DISK
| ERROR_SECTOR_NOT_FOUND
| ERROR_OUT_OF_PAPER
| ERROR_WRITE_FAULT
| ERROR_READ_FAULT
| ERROR_GEN_FAILURE
| ERROR_SHARING_VIOLATION
| ERROR_LOCK_VIOLATION
| ERROR_WRONG_DISK
| ERROR_SHARING_BUFFER_EXCEEDED
| ERROR_NETWORK_ACCESS_DENIED
| ERROR_CANNOT_MAKE
| ERROR_FAIL_I24
| ERROR_DRIVE_LOCKED
| ERROR_SEEK_ON_DEVICE
| ERROR_NOT_LOCKED
| ERROR_LOCK_FAILED
| 35 => EACCES,
ERROR_FILE_EXISTS | ERROR_ALREADY_EXISTS => EEXIST,
ERROR_NOT_SAME_DEVICE => EXDEV,
ERROR_DIRECTORY => ENOTDIR,
ERROR_TOO_MANY_OPEN_FILES => EMFILE,
ERROR_DISK_FULL => ENOSPC,
ERROR_BROKEN_PIPE | ERROR_NO_DATA => EPIPE,
ERROR_DIR_NOT_EMPTY => ENOTEMPTY,
ERROR_NO_UNICODE_TRANSLATION => EILSEQ,
ERROR_CONNECTION_REFUSED => WSAECONNREFUSED,
ERROR_CONNECTION_ABORTED => WSAECONNABORTED,
ERROR_NETNAME_DELETED => WSAECONNRESET,
ERROR_INVALID_FUNCTION
| ERROR_INVALID_ACCESS
| ERROR_INVALID_DATA
| ERROR_INVALID_PARAMETER
| ERROR_NEGATIVE_SEEK => EINVAL,
_ => EINVAL,
}
}