rustix/backend/libc/
conv.rs

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
5use super::c;
6#[cfg(all(feature = "alloc", not(any(windows, target_os = "espidf"))))]
7use super::fd::IntoRawFd as _;
8use super::fd::{AsRawFd as _, BorrowedFd, FromRawFd as _, LibcFd, OwnedFd, RawFd};
9#[cfg(not(windows))]
10use crate::ffi::CStr;
11use crate::io;
12
13#[cfg(not(windows))]
14#[inline]
15pub(super) fn c_str(c: &CStr) -> *const c::c_char {
16    c.as_ptr().cast()
17}
18
19#[cfg(not(any(
20    windows,
21    target_os = "espidf",
22    target_os = "horizon",
23    target_os = "vita",
24    target_os = "wasi"
25)))]
26#[inline]
27pub(super) fn no_fd() -> LibcFd {
28    -1
29}
30
31#[inline]
32pub(super) fn borrowed_fd(fd: BorrowedFd<'_>) -> LibcFd {
33    fd.as_raw_fd() as LibcFd
34}
35
36#[cfg(all(
37    feature = "alloc",
38    not(any(windows, target_os = "espidf", target_os = "redox"))
39))]
40#[inline]
41pub(super) fn owned_fd(fd: OwnedFd) -> LibcFd {
42    fd.into_raw_fd() as LibcFd
43}
44
45#[inline]
46pub(super) fn ret(raw: c::c_int) -> io::Result<()> {
47    if raw == 0 {
48        Ok(())
49    } else {
50        Err(io::Errno::last_os_error())
51    }
52}
53
54#[cfg(apple)]
55#[inline]
56pub(super) fn nonnegative_ret(raw: c::c_int) -> io::Result<()> {
57    if raw >= 0 {
58        Ok(())
59    } else {
60        Err(io::Errno::last_os_error())
61    }
62}
63
64#[cfg(not(any(windows, target_os = "wasi")))]
65#[inline]
66pub(super) unsafe fn ret_infallible(raw: c::c_int) {
67    debug_assert_eq!(raw, 0, "unexpected error: {:?}", io::Errno::last_os_error());
68}
69
70#[inline]
71pub(super) fn ret_c_int(raw: c::c_int) -> io::Result<c::c_int> {
72    if raw == -1 {
73        Err(io::Errno::last_os_error())
74    } else {
75        Ok(raw)
76    }
77}
78
79#[cfg(any(
80    linux_kernel,
81    all(target_os = "illumos", feature = "event"),
82    all(target_os = "redox", feature = "event")
83))]
84#[inline]
85pub(super) fn ret_u32(raw: c::c_int) -> io::Result<u32> {
86    if raw == -1 {
87        Err(io::Errno::last_os_error())
88    } else {
89        Ok(raw as u32)
90    }
91}
92
93#[inline]
94pub(super) fn ret_usize(raw: c::ssize_t) -> io::Result<usize> {
95    if raw == -1 {
96        Err(io::Errno::last_os_error())
97    } else {
98        debug_assert!(raw >= 0);
99        Ok(raw as usize)
100    }
101}
102
103#[cfg(not(windows))]
104#[cfg(feature = "fs")]
105#[inline]
106pub(super) fn ret_off_t(raw: c::off_t) -> io::Result<c::off_t> {
107    if raw == -1 {
108        Err(io::Errno::last_os_error())
109    } else {
110        Ok(raw)
111    }
112}
113
114#[cfg(not(any(windows, target_os = "wasi")))]
115#[inline]
116pub(super) fn ret_pid_t(raw: c::pid_t) -> io::Result<c::pid_t> {
117    if raw == -1 {
118        Err(io::Errno::last_os_error())
119    } else {
120        Ok(raw)
121    }
122}
123
124/// Convert a `c_int` returned from a libc function to an `OwnedFd`, if valid.
125///
126/// # Safety
127///
128/// The caller must ensure that this is the return value of a libc function
129/// which returns an owned file descriptor.
130#[inline]
131pub(super) unsafe fn ret_owned_fd(raw: LibcFd) -> io::Result<OwnedFd> {
132    if raw == !0 {
133        Err(io::Errno::last_os_error())
134    } else {
135        Ok(OwnedFd::from_raw_fd(raw as RawFd))
136    }
137}
138
139#[cfg(not(any(windows, target_os = "wasi")))]
140#[inline]
141pub(super) fn ret_discarded_fd(raw: LibcFd) -> io::Result<()> {
142    if raw == !0 {
143        Err(io::Errno::last_os_error())
144    } else {
145        Ok(())
146    }
147}
148
149#[cfg(all(feature = "alloc", not(any(windows, target_os = "wasi"))))]
150#[inline]
151pub(super) fn ret_discarded_char_ptr(raw: *mut c::c_char) -> io::Result<()> {
152    if raw.is_null() {
153        Err(io::Errno::last_os_error())
154    } else {
155        Ok(())
156    }
157}
158
159/// Convert the buffer-length argument value of a `send` or `recv` call.
160#[cfg(not(any(windows, target_os = "wasi")))]
161#[inline]
162pub(super) fn send_recv_len(len: usize) -> usize {
163    len
164}
165
166/// Convert the buffer-length argument value of a `send` or `recv` call.
167#[cfg(windows)]
168#[inline]
169pub(super) fn send_recv_len(len: usize) -> i32 {
170    // On Windows, the length argument has type `i32`; saturate the length,
171    // since `send` and `recv` are allowed to send and recv less data than
172    // requested.
173    len.try_into().unwrap_or(i32::MAX)
174}
175
176/// Convert the return value of a `send` or `recv` call.
177#[cfg(not(any(windows, target_os = "wasi")))]
178#[inline]
179pub(super) fn ret_send_recv(len: isize) -> io::Result<usize> {
180    ret_usize(len)
181}
182
183/// Convert the return value of a `send` or `recv` call.
184#[cfg(windows)]
185#[inline]
186pub(super) fn ret_send_recv(len: i32) -> io::Result<usize> {
187    ret_usize(len as isize)
188}