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(not(any(target_os = "cloudabi", target_os = "unknown")))]
22pub(crate) fn get_last_error() -> c_int {
23 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 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 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}