1use crate::backend::c;
4#[cfg(not(target_os = "wasi"))]
5use crate::backend::conv::ret_discarded_fd;
6use crate::backend::conv::{borrowed_fd, ret, ret_c_int, ret_owned_fd, ret_usize};
7use crate::fd::{AsFd as _, BorrowedFd, OwnedFd, RawFd};
8#[cfg(not(any(
9 target_os = "aix",
10 target_os = "espidf",
11 target_os = "nto",
12 target_os = "vita",
13 target_os = "wasi"
14)))]
15use crate::io::DupFlags;
16#[cfg(all(linux_kernel, not(target_os = "android")))]
17use crate::io::ReadWriteFlags;
18use crate::io::{self, FdFlags};
19use crate::ioctl::{IoctlOutput, Opcode};
20use core::cmp::min;
21#[cfg(not(any(target_os = "espidf", target_os = "horizon")))]
22use {
23 crate::backend::MAX_IOV,
24 crate::io::{IoSlice, IoSliceMut},
25};
26
27pub(crate) unsafe fn read(fd: BorrowedFd<'_>, buf: (*mut u8, usize)) -> io::Result<usize> {
28 ret_usize(c::read(
29 borrowed_fd(fd),
30 buf.0.cast(),
31 min(buf.1, READ_LIMIT),
32 ))
33}
34
35pub(crate) fn write(fd: BorrowedFd<'_>, buf: &[u8]) -> io::Result<usize> {
36 unsafe {
37 ret_usize(c::write(
38 borrowed_fd(fd),
39 buf.as_ptr().cast(),
40 min(buf.len(), READ_LIMIT),
41 ))
42 }
43}
44
45pub(crate) unsafe fn pread(
46 fd: BorrowedFd<'_>,
47 buf: (*mut u8, usize),
48 offset: u64,
49) -> io::Result<usize> {
50 let len = min(buf.1, READ_LIMIT);
51
52 let offset = offset as i64;
54
55 let offset = offset.try_into().map_err(|_| io::Errno::OVERFLOW)?;
57
58 ret_usize(c::pread(borrowed_fd(fd), buf.0.cast(), len, offset))
59}
60
61pub(crate) fn pwrite(fd: BorrowedFd<'_>, buf: &[u8], offset: u64) -> io::Result<usize> {
62 let len = min(buf.len(), READ_LIMIT);
63
64 let offset = offset as i64;
66
67 let offset = offset.try_into().map_err(|_| io::Errno::OVERFLOW)?;
69
70 unsafe { ret_usize(c::pwrite(borrowed_fd(fd), buf.as_ptr().cast(), len, offset)) }
71}
72
73#[cfg(not(any(target_os = "espidf", target_os = "horizon")))]
74pub(crate) fn readv(fd: BorrowedFd<'_>, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
75 unsafe {
76 ret_usize(c::readv(
77 borrowed_fd(fd),
78 bufs.as_ptr().cast::<c::iovec>(),
79 min(bufs.len(), MAX_IOV) as c::c_int,
80 ))
81 }
82}
83
84#[cfg(not(any(target_os = "espidf", target_os = "horizon")))]
85pub(crate) fn writev(fd: BorrowedFd<'_>, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
86 unsafe {
87 ret_usize(c::writev(
88 borrowed_fd(fd),
89 bufs.as_ptr().cast::<c::iovec>(),
90 min(bufs.len(), MAX_IOV) as c::c_int,
91 ))
92 }
93}
94
95#[cfg(not(any(
96 target_os = "cygwin",
97 target_os = "espidf",
98 target_os = "haiku",
99 target_os = "horizon",
100 target_os = "nto",
101 target_os = "redox",
102 target_os = "solaris",
103 target_os = "vita",
104)))]
105pub(crate) fn preadv(
106 fd: BorrowedFd<'_>,
107 bufs: &mut [IoSliceMut<'_>],
108 offset: u64,
109) -> io::Result<usize> {
110 let offset = offset as i64;
112
113 let offset = offset.try_into().map_err(|_| io::Errno::OVERFLOW)?;
115
116 unsafe {
117 ret_usize(c::preadv(
118 borrowed_fd(fd),
119 bufs.as_ptr().cast::<c::iovec>(),
120 min(bufs.len(), MAX_IOV) as c::c_int,
121 offset,
122 ))
123 }
124}
125
126#[cfg(not(any(
127 target_os = "cygwin",
128 target_os = "espidf",
129 target_os = "haiku",
130 target_os = "nto",
131 target_os = "horizon",
132 target_os = "redox",
133 target_os = "solaris",
134 target_os = "vita",
135)))]
136pub(crate) fn pwritev(fd: BorrowedFd<'_>, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
137 let offset = offset as i64;
139
140 let offset = offset.try_into().map_err(|_| io::Errno::OVERFLOW)?;
142
143 unsafe {
144 ret_usize(c::pwritev(
145 borrowed_fd(fd),
146 bufs.as_ptr().cast::<c::iovec>(),
147 min(bufs.len(), MAX_IOV) as c::c_int,
148 offset,
149 ))
150 }
151}
152
153#[cfg(all(linux_kernel, not(target_os = "android")))]
154pub(crate) fn preadv2(
155 fd: BorrowedFd<'_>,
156 bufs: &mut [IoSliceMut<'_>],
157 offset: u64,
158 flags: ReadWriteFlags,
159) -> io::Result<usize> {
160 let offset = offset as i64;
162 unsafe {
163 ret_usize(c::preadv2(
164 borrowed_fd(fd),
165 bufs.as_ptr().cast::<c::iovec>(),
166 min(bufs.len(), MAX_IOV) as c::c_int,
167 offset,
168 bitflags_bits!(flags),
169 ))
170 }
171}
172
173#[cfg(all(linux_kernel, not(target_os = "android")))]
174pub(crate) fn pwritev2(
175 fd: BorrowedFd<'_>,
176 bufs: &[IoSlice<'_>],
177 offset: u64,
178 flags: ReadWriteFlags,
179) -> io::Result<usize> {
180 let offset = offset as i64;
182 unsafe {
183 ret_usize(c::pwritev2(
184 borrowed_fd(fd),
185 bufs.as_ptr().cast::<c::iovec>(),
186 min(bufs.len(), MAX_IOV) as c::c_int,
187 offset,
188 bitflags_bits!(flags),
189 ))
190 }
191}
192
193#[cfg(target_os = "macos")]
205const READ_LIMIT: usize = c::c_int::MAX as usize - 1;
206#[cfg(not(target_os = "macos"))]
207const READ_LIMIT: usize = c::ssize_t::MAX as usize;
208
209pub(crate) unsafe fn close(raw_fd: RawFd) {
210 let _ = c::close(raw_fd as c::c_int);
211}
212
213#[cfg(feature = "try_close")]
214pub(crate) unsafe fn try_close(raw_fd: RawFd) -> io::Result<()> {
215 ret(c::close(raw_fd as c::c_int))
216}
217
218#[inline]
219pub(crate) unsafe fn ioctl(
220 fd: BorrowedFd<'_>,
221 request: Opcode,
222 arg: *mut c::c_void,
223) -> io::Result<IoctlOutput> {
224 ret_c_int(c::ioctl(borrowed_fd(fd), request, arg))
225}
226
227#[inline]
228pub(crate) unsafe fn ioctl_readonly(
229 fd: BorrowedFd<'_>,
230 request: Opcode,
231 arg: *mut c::c_void,
232) -> io::Result<IoctlOutput> {
233 ioctl(fd, request, arg)
234}
235
236pub(crate) fn fcntl_getfd(fd: BorrowedFd<'_>) -> io::Result<FdFlags> {
237 let flags = unsafe { ret_c_int(c::fcntl(borrowed_fd(fd), c::F_GETFD))? };
238 Ok(FdFlags::from_bits_retain(bitcast!(flags)))
239}
240
241pub(crate) fn fcntl_setfd(fd: BorrowedFd<'_>, flags: FdFlags) -> io::Result<()> {
242 unsafe { ret(c::fcntl(borrowed_fd(fd), c::F_SETFD, flags.bits())) }
243}
244
245#[cfg(not(any(target_os = "espidf", target_os = "wasi")))]
246pub(crate) fn fcntl_dupfd_cloexec(fd: BorrowedFd<'_>, min: RawFd) -> io::Result<OwnedFd> {
247 unsafe { ret_owned_fd(c::fcntl(borrowed_fd(fd), c::F_DUPFD_CLOEXEC, min)) }
248}
249
250#[cfg(target_os = "espidf")]
251pub(crate) fn fcntl_dupfd(fd: BorrowedFd<'_>, min: RawFd) -> io::Result<OwnedFd> {
252 unsafe { ret_owned_fd(c::fcntl(borrowed_fd(fd), c::F_DUPFD, min)) }
253}
254
255#[cfg(not(target_os = "wasi"))]
256pub(crate) fn dup(fd: BorrowedFd<'_>) -> io::Result<OwnedFd> {
257 unsafe { ret_owned_fd(c::dup(borrowed_fd(fd))) }
258}
259
260#[allow(clippy::needless_pass_by_ref_mut)]
261#[cfg(not(target_os = "wasi"))]
262pub(crate) fn dup2(fd: BorrowedFd<'_>, new: &mut OwnedFd) -> io::Result<()> {
263 unsafe { ret_discarded_fd(c::dup2(borrowed_fd(fd), borrowed_fd(new.as_fd()))) }
264}
265
266#[allow(clippy::needless_pass_by_ref_mut)]
267#[cfg(not(any(
268 apple,
269 target_os = "aix",
270 target_os = "android",
271 target_os = "dragonfly",
272 target_os = "espidf",
273 target_os = "haiku",
274 target_os = "horizon",
275 target_os = "nto",
276 target_os = "redox",
277 target_os = "vita",
278 target_os = "wasi",
279)))]
280pub(crate) fn dup3(fd: BorrowedFd<'_>, new: &mut OwnedFd, flags: DupFlags) -> io::Result<()> {
281 unsafe {
282 ret_discarded_fd(c::dup3(
283 borrowed_fd(fd),
284 borrowed_fd(new.as_fd()),
285 bitflags_bits!(flags),
286 ))
287 }
288}
289
290#[cfg(any(
291 apple,
292 target_os = "android",
293 target_os = "dragonfly",
294 target_os = "haiku",
295 target_os = "redox",
296))]
297pub(crate) fn dup3(fd: BorrowedFd<'_>, new: &mut OwnedFd, _flags: DupFlags) -> io::Result<()> {
298 dup2(fd, new)
303}