1 //! Libc call arguments and return values are often things like `c_int`,
2 //! `c_uint`, or libc-specific pointer types. This module provides functions
3 //! for converting between rustix's types and libc types.
4 
5 use super::c;
6 #[cfg(all(feature = "alloc", not(any(windows, target_os = "espidf"))))]
7 use super::fd::IntoRawFd;
8 use super::fd::{AsRawFd, BorrowedFd, FromRawFd, LibcFd, OwnedFd, RawFd};
9 #[cfg(not(windows))]
10 use crate::ffi::CStr;
11 use crate::io;
12 
13 #[cfg(not(windows))]
14 #[inline]
c_str(c: &CStr) -> *const c::c_char15 pub(super) fn c_str(c: &CStr) -> *const c::c_char {
16     c.as_ptr()
17 }
18 
19 #[cfg(not(any(windows, target_os = "espidf", target_os = "vita", target_os = "wasi")))]
20 #[inline]
no_fd() -> LibcFd21 pub(super) fn no_fd() -> LibcFd {
22     -1
23 }
24 
25 #[inline]
borrowed_fd(fd: BorrowedFd<'_>) -> LibcFd26 pub(super) fn borrowed_fd(fd: BorrowedFd<'_>) -> LibcFd {
27     fd.as_raw_fd() as LibcFd
28 }
29 
30 #[cfg(all(
31     feature = "alloc",
32     not(any(windows, target_os = "espidf", target_os = "redox"))
33 ))]
34 #[inline]
owned_fd(fd: OwnedFd) -> LibcFd35 pub(super) fn owned_fd(fd: OwnedFd) -> LibcFd {
36     fd.into_raw_fd() as LibcFd
37 }
38 
39 #[inline]
ret(raw: c::c_int) -> io::Result<()>40 pub(super) fn ret(raw: c::c_int) -> io::Result<()> {
41     if raw == 0 {
42         Ok(())
43     } else {
44         Err(io::Errno::last_os_error())
45     }
46 }
47 
48 #[cfg(apple)]
49 #[inline]
nonnegative_ret(raw: c::c_int) -> io::Result<()>50 pub(super) fn nonnegative_ret(raw: c::c_int) -> io::Result<()> {
51     if raw >= 0 {
52         Ok(())
53     } else {
54         Err(io::Errno::last_os_error())
55     }
56 }
57 
58 #[cfg(not(any(windows, target_os = "wasi")))]
59 #[inline]
ret_infallible(raw: c::c_int)60 pub(super) unsafe fn ret_infallible(raw: c::c_int) {
61     debug_assert_eq!(raw, 0, "unexpected error: {:?}", io::Errno::last_os_error());
62 }
63 
64 #[inline]
ret_c_int(raw: c::c_int) -> io::Result<c::c_int>65 pub(super) fn ret_c_int(raw: c::c_int) -> io::Result<c::c_int> {
66     if raw == -1 {
67         Err(io::Errno::last_os_error())
68     } else {
69         Ok(raw)
70     }
71 }
72 
73 #[cfg(any(linux_kernel, all(target_os = "redox", feature = "event")))]
74 #[inline]
ret_u32(raw: c::c_int) -> io::Result<u32>75 pub(super) fn ret_u32(raw: c::c_int) -> io::Result<u32> {
76     if raw == -1 {
77         Err(io::Errno::last_os_error())
78     } else {
79         Ok(raw as u32)
80     }
81 }
82 
83 #[inline]
ret_usize(raw: c::ssize_t) -> io::Result<usize>84 pub(super) fn ret_usize(raw: c::ssize_t) -> io::Result<usize> {
85     if raw == -1 {
86         Err(io::Errno::last_os_error())
87     } else {
88         debug_assert!(raw >= 0);
89         Ok(raw as usize)
90     }
91 }
92 
93 #[cfg(not(windows))]
94 #[cfg(feature = "fs")]
95 #[inline]
ret_off_t(raw: c::off_t) -> io::Result<c::off_t>96 pub(super) fn ret_off_t(raw: c::off_t) -> io::Result<c::off_t> {
97     if raw == -1 {
98         Err(io::Errno::last_os_error())
99     } else {
100         Ok(raw)
101     }
102 }
103 
104 #[cfg(not(any(windows, target_os = "wasi")))]
105 #[inline]
ret_pid_t(raw: c::pid_t) -> io::Result<c::pid_t>106 pub(super) fn ret_pid_t(raw: c::pid_t) -> io::Result<c::pid_t> {
107     if raw == -1 {
108         Err(io::Errno::last_os_error())
109     } else {
110         Ok(raw)
111     }
112 }
113 
114 /// Convert a `c_int` returned from a libc function to an `OwnedFd`, if valid.
115 ///
116 /// # Safety
117 ///
118 /// The caller must ensure that this is the return value of a libc function
119 /// which returns an owned file descriptor.
120 #[inline]
ret_owned_fd(raw: LibcFd) -> io::Result<OwnedFd>121 pub(super) unsafe fn ret_owned_fd(raw: LibcFd) -> io::Result<OwnedFd> {
122     if raw == !0 {
123         Err(io::Errno::last_os_error())
124     } else {
125         Ok(OwnedFd::from_raw_fd(raw as RawFd))
126     }
127 }
128 
129 #[cfg(not(any(windows, target_os = "wasi")))]
130 #[inline]
ret_discarded_fd(raw: LibcFd) -> io::Result<()>131 pub(super) fn ret_discarded_fd(raw: LibcFd) -> io::Result<()> {
132     if raw == !0 {
133         Err(io::Errno::last_os_error())
134     } else {
135         Ok(())
136     }
137 }
138 
139 #[cfg(all(feature = "alloc", not(any(windows, target_os = "wasi"))))]
140 #[inline]
ret_discarded_char_ptr(raw: *mut c::c_char) -> io::Result<()>141 pub(super) fn ret_discarded_char_ptr(raw: *mut c::c_char) -> io::Result<()> {
142     if raw.is_null() {
143         Err(io::Errno::last_os_error())
144     } else {
145         Ok(())
146     }
147 }
148 
149 /// Convert the buffer-length argument value of a `send` or `recv` call.
150 #[cfg(not(any(windows, target_os = "redox", target_os = "wasi")))]
151 #[inline]
send_recv_len(len: usize) -> usize152 pub(super) fn send_recv_len(len: usize) -> usize {
153     len
154 }
155 
156 /// Convert the buffer-length argument value of a `send` or `recv` call.
157 #[cfg(windows)]
158 #[inline]
send_recv_len(len: usize) -> i32159 pub(super) fn send_recv_len(len: usize) -> i32 {
160     // On Windows, the length argument has type `i32`; saturate the length,
161     // since `send` and `recv` are allowed to send and recv less data than
162     // requested.
163     len.try_into().unwrap_or(i32::MAX)
164 }
165 
166 /// Convert the return value of a `send` or `recv` call.
167 #[cfg(not(any(windows, target_os = "redox", target_os = "wasi")))]
168 #[inline]
ret_send_recv(len: isize) -> io::Result<usize>169 pub(super) fn ret_send_recv(len: isize) -> io::Result<usize> {
170     ret_usize(len)
171 }
172 
173 /// Convert the return value of a `send` or `recv` call.
174 #[cfg(windows)]
175 #[inline]
ret_send_recv(len: i32) -> io::Result<usize>176 pub(super) fn ret_send_recv(len: i32) -> io::Result<usize> {
177     ret_usize(len as isize)
178 }
179 
180 /// Convert the value to the `msg_iovlen` field of a `msghdr` struct.
181 #[cfg(all(
182     not(any(windows, target_os = "espidf", target_os = "redox", target_os = "wasi")),
183     any(
184         target_os = "android",
185         all(
186             target_os = "linux",
187             not(target_env = "musl"),
188             not(all(target_env = "uclibc", any(target_arch = "arm", target_arch = "mips")))
189         )
190     )
191 ))]
192 #[inline]
msg_iov_len(len: usize) -> c::size_t193 pub(super) fn msg_iov_len(len: usize) -> c::size_t {
194     len
195 }
196 
197 /// Convert the value to the `msg_iovlen` field of a `msghdr` struct.
198 #[cfg(all(
199     not(any(
200         windows,
201         target_os = "espidf",
202         target_os = "redox",
203         target_os = "vita",
204         target_os = "wasi"
205     )),
206     not(any(
207         target_os = "android",
208         all(
209             target_os = "linux",
210             not(target_env = "musl"),
211             not(all(target_env = "uclibc", any(target_arch = "arm", target_arch = "mips")))
212         )
213     ))
214 ))]
215 #[inline]
msg_iov_len(len: usize) -> c::c_int216 pub(crate) fn msg_iov_len(len: usize) -> c::c_int {
217     len.try_into().unwrap_or(c::c_int::MAX)
218 }
219 
220 /// Convert the value to a `socklen_t`.
221 #[cfg(any(
222     bsd,
223     solarish,
224     target_env = "musl",
225     target_os = "aix",
226     target_os = "emscripten",
227     target_os = "fuchsia",
228     target_os = "haiku",
229     target_os = "nto",
230 ))]
231 #[inline]
msg_control_len(len: usize) -> c::socklen_t232 pub(crate) fn msg_control_len(len: usize) -> c::socklen_t {
233     len.try_into().unwrap_or(c::socklen_t::MAX)
234 }
235 
236 /// Convert the value to a `size_t`.
237 #[cfg(not(any(
238     bsd,
239     solarish,
240     windows,
241     target_env = "musl",
242     target_os = "aix",
243     target_os = "emscripten",
244     target_os = "espidf",
245     target_os = "fuchsia",
246     target_os = "haiku",
247     target_os = "nto",
248     target_os = "redox",
249     target_os = "vita",
250     target_os = "wasi",
251 )))]
252 #[inline]
msg_control_len(len: usize) -> c::size_t253 pub(crate) fn msg_control_len(len: usize) -> c::size_t {
254     len
255 }
256