1use core::str::Utf8Error;
5use std::{io, process::ExitCode};
6
7pub fn exit_code(code: u32) -> ExitCode {
12 #[cfg(windows)]
13 {
14 if code > u8::MAX as u32 {
19 std::process::exit(code as i32)
20 }
21 }
22 ExitCode::from(code as u8)
23}
24
25pub trait ErrorExt {
26 fn posix_errno(&self) -> i32;
27}
28
29impl ErrorExt for io::Error {
30 #[cfg(not(windows))]
31 fn posix_errno(&self) -> i32 {
32 self.raw_os_error().unwrap_or(0)
33 }
34 #[cfg(windows)]
35 fn posix_errno(&self) -> i32 {
36 let winerror = self.raw_os_error().unwrap_or(0);
37 winerror_to_errno(winerror)
38 }
39}
40
41#[cfg(windows)]
44pub fn errno_io_error() -> io::Error {
45 let errno: i32 = get_errno();
46 let winerror = errno_to_winerror(errno);
47 io::Error::from_raw_os_error(winerror)
48}
49
50#[cfg(not(windows))]
51pub fn errno_io_error() -> io::Error {
52 std::io::Error::last_os_error()
53}
54
55#[cfg(windows)]
56pub fn get_errno() -> i32 {
57 unsafe extern "C" {
58 fn _get_errno(pValue: *mut i32) -> i32;
59 }
60 let mut errno = 0;
61 unsafe { suppress_iph!(_get_errno(&mut errno)) };
62 errno
63}
64
65#[cfg(not(windows))]
66pub fn get_errno() -> i32 {
67 std::io::Error::last_os_error().posix_errno()
68}
69
70#[cfg(windows)]
72pub fn set_errno(value: i32) {
73 unsafe extern "C" {
74 fn _set_errno(value: i32) -> i32;
75 }
76 unsafe { suppress_iph!(_set_errno(value)) };
77}
78
79#[cfg(unix)]
80pub fn set_errno(value: i32) {
81 nix::errno::Errno::from_raw(value).set();
82}
83
84#[cfg(unix)]
85pub fn bytes_as_os_str(b: &[u8]) -> Result<&std::ffi::OsStr, Utf8Error> {
86 use std::os::unix::ffi::OsStrExt;
87 Ok(std::ffi::OsStr::from_bytes(b))
88}
89
90#[cfg(not(unix))]
91pub fn bytes_as_os_str(b: &[u8]) -> Result<&std::ffi::OsStr, Utf8Error> {
92 Ok(core::str::from_utf8(b)?.as_ref())
93}
94
95#[cfg(unix)]
96pub use std::os::unix::ffi;
97
98#[cfg(all(target_os = "wasi", not(target_env = "p2")))]
100pub use std::os::wasi::ffi;
101
102#[cfg(all(target_os = "wasi", target_env = "p2"))]
105pub mod ffi {
106 use std::ffi::{OsStr, OsString};
107
108 pub trait OsStrExt: sealed::Sealed {
109 fn as_bytes(&self) -> &[u8];
110 fn from_bytes(slice: &[u8]) -> &Self;
111 }
112
113 impl OsStrExt for OsStr {
114 fn as_bytes(&self) -> &[u8] {
115 self.to_str().expect("wasip2 strings are UTF-8").as_bytes()
117 }
118
119 fn from_bytes(slice: &[u8]) -> &OsStr {
120 OsStr::new(core::str::from_utf8(slice).expect("wasip2 strings are UTF-8"))
122 }
123 }
124
125 pub trait OsStringExt: sealed::Sealed {
126 fn from_vec(vec: Vec<u8>) -> Self;
127 fn into_vec(self) -> Vec<u8>;
128 }
129
130 impl OsStringExt for OsString {
131 fn from_vec(vec: Vec<u8>) -> OsString {
132 OsString::from(String::from_utf8(vec).expect("wasip2 strings are UTF-8"))
134 }
135
136 fn into_vec(self) -> Vec<u8> {
137 self.to_str()
139 .expect("wasip2 strings are UTF-8")
140 .as_bytes()
141 .to_vec()
142 }
143 }
144
145 mod sealed {
146 pub trait Sealed {}
147 impl Sealed for std::ffi::OsStr {}
148 impl Sealed for std::ffi::OsString {}
149 }
150}
151
152#[cfg(windows)]
153pub fn errno_to_winerror(errno: i32) -> i32 {
154 use libc::*;
155 use windows_sys::Win32::Foundation::*;
156 let winerror = match errno {
157 ENOENT => ERROR_FILE_NOT_FOUND,
158 E2BIG => ERROR_BAD_ENVIRONMENT,
159 ENOEXEC => ERROR_BAD_FORMAT,
160 EBADF => ERROR_INVALID_HANDLE,
161 ECHILD => ERROR_WAIT_NO_CHILDREN,
162 EAGAIN => ERROR_NO_PROC_SLOTS,
163 ENOMEM => ERROR_NOT_ENOUGH_MEMORY,
164 EACCES => ERROR_ACCESS_DENIED,
165 EEXIST => ERROR_FILE_EXISTS,
166 EXDEV => ERROR_NOT_SAME_DEVICE,
167 ENOTDIR => ERROR_DIRECTORY,
168 EMFILE => ERROR_TOO_MANY_OPEN_FILES,
169 ENOSPC => ERROR_DISK_FULL,
170 EPIPE => ERROR_BROKEN_PIPE,
171 ENOTEMPTY => ERROR_DIR_NOT_EMPTY,
172 EILSEQ => ERROR_NO_UNICODE_TRANSLATION,
173 EINVAL => ERROR_INVALID_FUNCTION,
174 _ => ERROR_INVALID_FUNCTION,
175 };
176 winerror as _
177}
178
179#[cfg(windows)]
182pub fn winerror_to_errno(winerror: i32) -> i32 {
183 use libc::*;
184 use windows_sys::Win32::{
185 Foundation::*,
186 Networking::WinSock::{
187 WSAEACCES, WSAEBADF, WSAECONNABORTED, WSAECONNREFUSED, WSAECONNRESET, WSAEFAULT,
188 WSAEINTR, WSAEINVAL, WSAEMFILE,
189 },
190 };
191 if (10000..12000).contains(&winerror) {
198 match winerror {
199 WSAEINTR | WSAEBADF | WSAEACCES | WSAEFAULT | WSAEINVAL | WSAEMFILE => {
200 return winerror - 10000;
202 }
203 _ => return winerror as _,
204 }
205 }
206
207 #[allow(non_upper_case_globals)]
208 match winerror as u32 {
209 ERROR_FILE_NOT_FOUND
210 | ERROR_PATH_NOT_FOUND
211 | ERROR_INVALID_DRIVE
212 | ERROR_NO_MORE_FILES
213 | ERROR_BAD_NETPATH
214 | ERROR_BAD_NET_NAME
215 | ERROR_BAD_PATHNAME
216 | ERROR_FILENAME_EXCED_RANGE => ENOENT,
217 ERROR_BAD_ENVIRONMENT => E2BIG,
218 ERROR_BAD_FORMAT
219 | ERROR_INVALID_STARTING_CODESEG
220 | ERROR_INVALID_STACKSEG
221 | ERROR_INVALID_MODULETYPE
222 | ERROR_INVALID_EXE_SIGNATURE
223 | ERROR_EXE_MARKED_INVALID
224 | ERROR_BAD_EXE_FORMAT
225 | ERROR_ITERATED_DATA_EXCEEDS_64k
226 | ERROR_INVALID_MINALLOCSIZE
227 | ERROR_DYNLINK_FROM_INVALID_RING
228 | ERROR_IOPL_NOT_ENABLED
229 | ERROR_INVALID_SEGDPL
230 | ERROR_AUTODATASEG_EXCEEDS_64k
231 | ERROR_RING2SEG_MUST_BE_MOVABLE
232 | ERROR_RELOC_CHAIN_XEEDS_SEGLIM
233 | ERROR_INFLOOP_IN_RELOC_CHAIN => ENOEXEC,
234 ERROR_INVALID_HANDLE | ERROR_INVALID_TARGET_HANDLE | ERROR_DIRECT_ACCESS_HANDLE => EBADF,
235 ERROR_WAIT_NO_CHILDREN | ERROR_CHILD_NOT_COMPLETE => ECHILD,
236 ERROR_NO_PROC_SLOTS | ERROR_MAX_THRDS_REACHED | ERROR_NESTING_NOT_ALLOWED => EAGAIN,
237 ERROR_ARENA_TRASHED
238 | ERROR_NOT_ENOUGH_MEMORY
239 | ERROR_INVALID_BLOCK
240 | ERROR_NOT_ENOUGH_QUOTA => ENOMEM,
241 ERROR_ACCESS_DENIED
242 | ERROR_CURRENT_DIRECTORY
243 | ERROR_WRITE_PROTECT
244 | ERROR_BAD_UNIT
245 | ERROR_NOT_READY
246 | ERROR_BAD_COMMAND
247 | ERROR_CRC
248 | ERROR_BAD_LENGTH
249 | ERROR_SEEK
250 | ERROR_NOT_DOS_DISK
251 | ERROR_SECTOR_NOT_FOUND
252 | ERROR_OUT_OF_PAPER
253 | ERROR_WRITE_FAULT
254 | ERROR_READ_FAULT
255 | ERROR_GEN_FAILURE
256 | ERROR_SHARING_VIOLATION
257 | ERROR_LOCK_VIOLATION
258 | ERROR_WRONG_DISK
259 | ERROR_SHARING_BUFFER_EXCEEDED
260 | ERROR_NETWORK_ACCESS_DENIED
261 | ERROR_CANNOT_MAKE
262 | ERROR_FAIL_I24
263 | ERROR_DRIVE_LOCKED
264 | ERROR_SEEK_ON_DEVICE
265 | ERROR_NOT_LOCKED
266 | ERROR_LOCK_FAILED
267 | 35 => EACCES,
268 ERROR_FILE_EXISTS | ERROR_ALREADY_EXISTS => EEXIST,
269 ERROR_NOT_SAME_DEVICE => EXDEV,
270 ERROR_DIRECTORY => ENOTDIR,
271 ERROR_TOO_MANY_OPEN_FILES => EMFILE,
272 ERROR_DISK_FULL => ENOSPC,
273 ERROR_BROKEN_PIPE | ERROR_NO_DATA => EPIPE,
274 ERROR_DIR_NOT_EMPTY => ENOTEMPTY,
275 ERROR_NO_UNICODE_TRANSLATION => EILSEQ,
276 ERROR_CONNECTION_REFUSED => WSAECONNREFUSED,
279 ERROR_CONNECTION_ABORTED => WSAECONNABORTED,
280 ERROR_NETNAME_DELETED => WSAECONNRESET,
281 ERROR_INVALID_FUNCTION
282 | ERROR_INVALID_ACCESS
283 | ERROR_INVALID_DATA
284 | ERROR_INVALID_PARAMETER
285 | ERROR_NEGATIVE_SEEK => EINVAL,
286 _ => EINVAL,
287 }
288}