error_code/
posix.rs

1use crate::{Category, MessageBuf, ErrorCode};
2use crate::utils::write_fallback_code;
3use crate::types::c_int;
4
5use core::{ptr, str};
6
7/// Posix error category, suitable for all environments.
8///
9/// In presence of OS, it means it identifies POSIX error codes.
10pub static POSIX_CATEGORY: Category = Category {
11    name: "PosixError",
12    message,
13    equivalent,
14    is_would_block,
15};
16
17fn equivalent(code: c_int, other: &ErrorCode) -> bool {
18    ptr::eq(&POSIX_CATEGORY, other.category()) && code == other.raw_code()
19}
20
21#[cfg(not(any(target_os = "cloudabi", target_os = "unknown")))]
22pub(crate) fn get_last_error() -> c_int {
23    //Reference:
24    //https://github.com/rust-lang/rust/blob/2ae1bb671183a072b54ed8ed39abfcd72990a3e7/library/std/src/sys/pal/unix/os.rs#L42
25    extern {
26        #[cfg(not(any(target_os = "dragonfly", target_os = "vxworks")))]
27        #[cfg_attr(
28            any(
29                target_os = "linux",
30                target_os = "emscripten",
31                target_os = "fuchsia",
32                target_os = "l4re",
33                target_os = "hurd",
34                target_os = "teeos",
35                target_os = "wasi"
36            ),
37            link_name = "__errno_location"
38        )]
39        #[cfg_attr(
40            any(
41                target_os = "netbsd",
42                target_os = "openbsd",
43                target_os = "android",
44                target_os = "redox",
45                target_env = "newlib"
46            ),
47            link_name = "__errno"
48        )]
49        #[cfg_attr(any(target_os = "solaris", target_os = "illumos"), link_name = "___errno")]
50        #[cfg_attr(target_os = "nto", link_name = "__get_errno_ptr")]
51        #[cfg_attr(
52            any(
53                target_os = "macos",
54                target_os = "ios",
55                target_os = "tvos",
56                target_os = "freebsd",
57                target_os = "watchos"
58            ),
59            link_name = "__error"
60        )]
61        #[cfg_attr(target_os = "haiku", link_name = "_errnop")]
62        #[cfg_attr(target_os = "aix", link_name = "_Errno")]
63        #[cfg_attr(target_os = "windows", link_name = "_errno")]
64        fn errno_location() -> *mut c_int;
65    }
66
67    unsafe {
68        *(errno_location())
69    }
70}
71
72#[cfg(any(target_os = "cloudabi", target_os = "dragonfly"))]
73pub(crate) fn get_last_error() -> c_int {
74    //WASI implements it as thread local, but thread local are not stable :(
75    extern {
76        #[thread_local]
77        static errno: c_int;
78    }
79
80    errno
81}
82
83#[cfg(target_os = "vxworks")]
84pub(crate) fn get_last_error() -> c_int {
85    extern "C" {
86        pub fn errnoGet() -> c_int;
87    }
88
89    unsafe {
90        errnoGet()
91    }
92}
93
94#[cfg(all(target_os = "unknown", not(target_env = "newlib")))]
95pub(crate) fn get_last_error() -> c_int {
96    0
97}
98
99pub(crate) fn message(_code: c_int, out: &mut MessageBuf) -> &str {
100    #[cfg(any(windows, target_os = "wasi", all(unix, not(target_env = "gnu"))))]
101    extern "C" {
102        ///Only GNU impl is thread unsafe
103        fn strerror(code: c_int) -> *const i8;
104        fn strlen(text: *const i8) -> usize;
105    }
106
107    #[cfg(all(unix, target_env = "gnu"))]
108    extern "C" {
109        fn strerror_l(code: c_int, locale: *mut i8) -> *const i8;
110        fn strlen(text: *const i8) -> usize;
111    }
112
113    #[cfg(all(unix, target_env = "gnu"))]
114    #[inline]
115    unsafe fn strerror(code: c_int) -> *const i8 {
116        strerror_l(code, ptr::null_mut())
117    }
118
119    #[cfg(any(windows, unix, target_os = "wasi"))]
120    {
121        let err = unsafe {
122            strerror(_code)
123        };
124
125        if !err.is_null() {
126            let err_len = unsafe {
127                core::cmp::min(out.len(), strlen(err) as usize)
128            };
129
130            let err_slice = unsafe {
131                ptr::copy_nonoverlapping(err as *const u8, out.as_mut_ptr() as *mut u8, err_len);
132                core::slice::from_raw_parts(out.as_ptr() as *const u8, err_len)
133            };
134
135            if let Ok(msg) = str::from_utf8(err_slice) {
136                return msg
137            }
138        }
139    }
140
141    write_fallback_code(out, _code)
142}
143
144#[cfg(not(any(windows, unix, target_os = "wasi")))]
145pub(crate) fn is_would_block(_: c_int) -> bool {
146    false
147}
148
149#[cfg(any(windows, unix, target_os = "wasi"))]
150pub(crate) fn is_would_block(code: c_int) -> bool {
151    code == crate::defs::EWOULDBLOCK || code == crate::defs::EAGAIN
152}