1use crate::{Category, MessageBuf, ErrorCode};
2use crate::utils::write_fallback_code;
3use crate::types::c_int;
4
5use core::{ptr, str};
6
7pub 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(any(target_env = "newlib", not(any(target_os = "unknown", target_os = "hermit", target_os = "vxworks", target_os = "dragonfly"))))]
26pub(crate) fn get_last_error() -> c_int {
27 extern "C" {
28 #[cfg_attr(
29 any(
30 target_os = "linux",
31 target_os = "emscripten",
32 target_os = "fuchsia",
33 target_os = "l4re",
34 target_os = "hurd",
35 target_os = "teeos",
36 target_os = "wasi"
37 ),
38 link_name = "__errno_location"
39 )]
40 #[cfg_attr(
41 any(
42 target_os = "netbsd",
43 target_os = "openbsd",
44 target_os = "cygwin",
45 target_os = "android",
46 target_os = "redox",
47 target_os = "nuttx",
48 target_env = "newlib"
49 ),
50 link_name = "__errno"
51 )]
52 #[cfg_attr(any(target_os = "solaris", target_os = "illumos"), link_name = "___errno")]
53 #[cfg_attr(target_os = "nto", link_name = "__get_errno_ptr")]
54 #[cfg_attr(target_os = "qnx", link_name = "__get_errno_ptr")]
55 #[cfg_attr(any(target_os = "freebsd", target_vendor = "apple"), link_name = "__error")]
56 #[cfg_attr(target_os = "haiku", link_name = "_errnop")]
57 #[cfg_attr(target_os = "aix", link_name = "_Errno")]
58 #[cfg_attr(target_os = "windows", link_name = "_errno")]
59 fn errno_location() -> *mut c_int;
60 }
61
62 unsafe {
63 *(errno_location())
64 }
65}
66
67#[cfg(target_os = "dragonfly")]
68pub(crate) fn get_last_error() -> c_int {
69 extern "C" {
72 #[thread_local]
73 static errno: c_int;
74 }
75
76 errno
77}
78
79#[cfg(target_os = "vxworks")]
80pub(crate) fn get_last_error() -> c_int {
81 extern "C" {
82 pub fn errnoGet() -> c_int;
83 }
84
85 unsafe {
86 errnoGet()
87 }
88}
89
90#[cfg(target_os = "hermit")]
91pub(crate) fn get_last_error() -> c_int {
92 extern "C" {
93 #[link_name = "sys_get_errno"]
94 pub fn get_errno() -> c_int;
95 }
96
97 unsafe {
98 get_errno()
99 }
100}
101
102#[cfg(all(target_os = "unknown", not(target_env = "newlib")))]
103pub(crate) fn get_last_error() -> c_int {
104 0
105}
106
107pub(crate) fn message(_code: c_int, out: &mut MessageBuf) -> &str {
108 #[cfg(any(windows, target_os = "wasi", all(unix, not(target_env = "gnu"))))]
109 extern "C" {
110 fn strerror(code: c_int) -> *const i8;
112 fn strlen(text: *const i8) -> usize;
113 }
114
115 #[cfg(all(unix, target_env = "gnu"))]
116 extern "C" {
117 fn strerror_l(code: c_int, locale: *mut i8) -> *const i8;
118 fn strlen(text: *const i8) -> usize;
119 }
120
121 #[cfg(all(unix, target_env = "gnu"))]
122 #[inline]
123 unsafe fn strerror(code: c_int) -> *const i8 {
124 strerror_l(code, ptr::null_mut())
125 }
126
127 #[cfg(any(windows, unix, target_os = "wasi"))]
128 {
129 let err = unsafe {
130 strerror(_code)
131 };
132
133 if !err.is_null() {
134 let err_len = unsafe {
135 core::cmp::min(out.len(), strlen(err) as _)
136 };
137
138 let err_slice = unsafe {
139 ptr::copy_nonoverlapping(err as *const u8, out.as_mut_ptr() as *mut u8, err_len);
140 core::slice::from_raw_parts(out.as_ptr() as *const u8, err_len)
141 };
142
143 if let Ok(msg) = str::from_utf8(err_slice) {
144 return msg
145 }
146 }
147 }
148
149 write_fallback_code(out, _code)
150}
151
152#[cfg(not(any(windows, unix, target_os = "wasi")))]
153pub(crate) fn is_would_block(_: c_int) -> bool {
154 false
155}
156
157#[cfg(any(windows, unix, target_os = "wasi"))]
158pub(crate) fn is_would_block(code: c_int) -> bool {
159 code == crate::defs::EWOULDBLOCK || code == crate::defs::EAGAIN
160}