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