1#![allow(unsafe_code)]
7#![allow(clippy::undocumented_unsafe_blocks)]
8
9#[cfg(target_pointer_width = "64")]
10use crate::backend::conv::loff_t_from_u64;
11#[cfg(all(
12 target_pointer_width = "32",
13 any(target_arch = "arm", target_arch = "mips", target_arch = "mips32r6"),
14))]
15use crate::backend::conv::zero;
16use crate::backend::conv::{
17 c_uint, pass_usize, raw_fd, ret, ret_c_int, ret_c_uint, ret_discarded_fd, ret_owned_fd,
18 ret_usize, slice,
19};
20#[cfg(target_pointer_width = "32")]
21use crate::backend::conv::{hi, lo};
22use crate::backend::{c, MAX_IOV};
23use crate::fd::{AsFd, BorrowedFd, OwnedFd, RawFd};
24use crate::io::{self, DupFlags, FdFlags, IoSlice, IoSliceMut, ReadWriteFlags};
25use crate::ioctl::{IoctlOutput, RawOpcode};
26#[cfg(all(feature = "fs", feature = "net"))]
27use crate::net::{RecvFlags, SendFlags};
28use core::cmp;
29use linux_raw_sys::general::{F_DUPFD_CLOEXEC, F_GETFD, F_SETFD};
30
31#[inline]
32pub(crate) unsafe fn read(fd: BorrowedFd<'_>, buf: *mut u8, len: usize) -> io::Result<usize> {
33 ret_usize(syscall!(__NR_read, fd, buf, pass_usize(len)))
34}
35
36#[inline]
37pub(crate) unsafe fn pread(
38 fd: BorrowedFd<'_>,
39 buf: *mut u8,
40 len: usize,
41 pos: u64,
42) -> io::Result<usize> {
43 #[cfg(all(
45 target_pointer_width = "32",
46 any(target_arch = "arm", target_arch = "mips", target_arch = "mips32r6"),
47 ))]
48 {
49 ret_usize(syscall!(
50 __NR_pread64,
51 fd,
52 buf,
53 pass_usize(len),
54 zero(),
55 hi(pos),
56 lo(pos)
57 ))
58 }
59 #[cfg(all(
60 target_pointer_width = "32",
61 not(any(target_arch = "arm", target_arch = "mips", target_arch = "mips32r6")),
62 ))]
63 {
64 ret_usize(syscall!(
65 __NR_pread64,
66 fd,
67 buf,
68 pass_usize(len),
69 hi(pos),
70 lo(pos)
71 ))
72 }
73 #[cfg(target_pointer_width = "64")]
74 ret_usize(syscall!(
75 __NR_pread64,
76 fd,
77 buf,
78 pass_usize(len),
79 loff_t_from_u64(pos)
80 ))
81}
82
83#[inline]
84pub(crate) fn readv(fd: BorrowedFd<'_>, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
85 let (bufs_addr, bufs_len) = slice(&bufs[..cmp::min(bufs.len(), MAX_IOV)]);
86
87 unsafe { ret_usize(syscall!(__NR_readv, fd, bufs_addr, bufs_len)) }
88}
89
90#[inline]
91pub(crate) fn preadv(
92 fd: BorrowedFd<'_>,
93 bufs: &mut [IoSliceMut<'_>],
94 pos: u64,
95) -> io::Result<usize> {
96 let (bufs_addr, bufs_len) = slice(&bufs[..cmp::min(bufs.len(), MAX_IOV)]);
97
98 unsafe {
101 ret_usize(syscall!(
102 __NR_preadv,
103 fd,
104 bufs_addr,
105 bufs_len,
106 pass_usize(pos as usize),
107 pass_usize((pos >> 32) as usize)
108 ))
109 }
110}
111
112#[inline]
113pub(crate) fn preadv2(
114 fd: BorrowedFd<'_>,
115 bufs: &mut [IoSliceMut<'_>],
116 pos: u64,
117 flags: ReadWriteFlags,
118) -> io::Result<usize> {
119 let (bufs_addr, bufs_len) = slice(&bufs[..cmp::min(bufs.len(), MAX_IOV)]);
120
121 unsafe {
124 ret_usize(syscall!(
125 __NR_preadv2,
126 fd,
127 bufs_addr,
128 bufs_len,
129 pass_usize(pos as usize),
130 pass_usize((pos >> 32) as usize),
131 flags
132 ))
133 }
134}
135
136#[inline]
137pub(crate) fn write(fd: BorrowedFd<'_>, buf: &[u8]) -> io::Result<usize> {
138 let (buf_addr, buf_len) = slice(buf);
139
140 unsafe { ret_usize(syscall_readonly!(__NR_write, fd, buf_addr, buf_len)) }
141}
142
143#[inline]
144pub(crate) fn pwrite(fd: BorrowedFd<'_>, buf: &[u8], pos: u64) -> io::Result<usize> {
145 let (buf_addr, buf_len) = slice(buf);
146
147 #[cfg(all(
149 target_pointer_width = "32",
150 any(target_arch = "arm", target_arch = "mips", target_arch = "mips32r6"),
151 ))]
152 unsafe {
153 ret_usize(syscall_readonly!(
154 __NR_pwrite64,
155 fd,
156 buf_addr,
157 buf_len,
158 zero(),
159 hi(pos),
160 lo(pos)
161 ))
162 }
163 #[cfg(all(
164 target_pointer_width = "32",
165 not(any(target_arch = "arm", target_arch = "mips", target_arch = "mips32r6")),
166 ))]
167 unsafe {
168 ret_usize(syscall_readonly!(
169 __NR_pwrite64,
170 fd,
171 buf_addr,
172 buf_len,
173 hi(pos),
174 lo(pos)
175 ))
176 }
177 #[cfg(target_pointer_width = "64")]
178 unsafe {
179 ret_usize(syscall_readonly!(
180 __NR_pwrite64,
181 fd,
182 buf_addr,
183 buf_len,
184 loff_t_from_u64(pos)
185 ))
186 }
187}
188
189#[inline]
190pub(crate) fn writev(fd: BorrowedFd<'_>, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
191 let (bufs_addr, bufs_len) = slice(&bufs[..cmp::min(bufs.len(), MAX_IOV)]);
192
193 unsafe { ret_usize(syscall_readonly!(__NR_writev, fd, bufs_addr, bufs_len)) }
194}
195
196#[inline]
197pub(crate) fn pwritev(fd: BorrowedFd<'_>, bufs: &[IoSlice<'_>], pos: u64) -> io::Result<usize> {
198 let (bufs_addr, bufs_len) = slice(&bufs[..cmp::min(bufs.len(), MAX_IOV)]);
199
200 unsafe {
203 ret_usize(syscall_readonly!(
204 __NR_pwritev,
205 fd,
206 bufs_addr,
207 bufs_len,
208 pass_usize(pos as usize),
209 pass_usize((pos >> 32) as usize)
210 ))
211 }
212}
213
214#[inline]
215pub(crate) fn pwritev2(
216 fd: BorrowedFd<'_>,
217 bufs: &[IoSlice<'_>],
218 pos: u64,
219 flags: ReadWriteFlags,
220) -> io::Result<usize> {
221 let (bufs_addr, bufs_len) = slice(&bufs[..cmp::min(bufs.len(), MAX_IOV)]);
222
223 unsafe {
226 ret_usize(syscall_readonly!(
227 __NR_pwritev2,
228 fd,
229 bufs_addr,
230 bufs_len,
231 pass_usize(pos as usize),
232 pass_usize((pos >> 32) as usize),
233 flags
234 ))
235 }
236}
237
238#[inline]
239pub(crate) unsafe fn close(fd: RawFd) {
240 syscall_readonly!(__NR_close, raw_fd(fd)).decode_void();
242}
243
244#[cfg(feature = "try_close")]
245#[inline]
246pub(crate) unsafe fn try_close(fd: RawFd) -> io::Result<()> {
247 ret(syscall_readonly!(__NR_close, raw_fd(fd)))
248}
249
250#[inline]
251pub(crate) unsafe fn ioctl(
252 fd: BorrowedFd<'_>,
253 request: RawOpcode,
254 arg: *mut c::c_void,
255) -> io::Result<IoctlOutput> {
256 ret_c_int(syscall!(__NR_ioctl, fd, c_uint(request), arg))
257}
258
259#[inline]
260pub(crate) unsafe fn ioctl_readonly(
261 fd: BorrowedFd<'_>,
262 request: RawOpcode,
263 arg: *mut c::c_void,
264) -> io::Result<IoctlOutput> {
265 ret_c_int(syscall_readonly!(__NR_ioctl, fd, c_uint(request), arg))
266}
267
268#[cfg(all(feature = "fs", feature = "net"))]
269pub(crate) fn is_read_write(fd: BorrowedFd<'_>) -> io::Result<(bool, bool)> {
270 let (mut read, mut write) = crate::fs::fd::_is_file_read_write(fd)?;
271 let mut not_socket = false;
272 if read {
273 let mut buf = [core::mem::MaybeUninit::<u8>::uninit()];
277 match unsafe {
278 crate::backend::net::syscalls::recv(
279 fd,
280 buf.as_mut_ptr().cast::<u8>(),
281 1,
282 RecvFlags::PEEK | RecvFlags::DONTWAIT,
283 )
284 } {
285 Ok(0) => read = false,
286 Err(err) => {
287 #[allow(unreachable_patterns)] match err {
289 io::Errno::AGAIN | io::Errno::WOULDBLOCK => (),
290 io::Errno::NOTSOCK => not_socket = true,
291 _ => return Err(err),
292 }
293 }
294 Ok(_) => (),
295 }
296 }
297 if write && !not_socket {
298 #[allow(unreachable_patterns)] match crate::backend::net::syscalls::send(fd, &[], SendFlags::DONTWAIT) {
302 Err(io::Errno::AGAIN | io::Errno::WOULDBLOCK | io::Errno::NOTSOCK) => (),
303 Err(io::Errno::PIPE) => write = false,
304 Err(err) => return Err(err),
305 Ok(_) => (),
306 }
307 }
308 Ok((read, write))
309}
310
311#[inline]
312pub(crate) fn dup(fd: BorrowedFd<'_>) -> io::Result<OwnedFd> {
313 unsafe { ret_owned_fd(syscall_readonly!(__NR_dup, fd)) }
314}
315
316#[allow(clippy::needless_pass_by_ref_mut)]
317#[inline]
318pub(crate) fn dup2(fd: BorrowedFd<'_>, new: &mut OwnedFd) -> io::Result<()> {
319 #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
320 {
321 dup3(fd, new, DupFlags::empty())
325 }
326
327 #[cfg(not(any(target_arch = "aarch64", target_arch = "riscv64")))]
328 unsafe {
329 ret_discarded_fd(syscall_readonly!(__NR_dup2, fd, new.as_fd()))
330 }
331}
332
333#[allow(clippy::needless_pass_by_ref_mut)]
334#[inline]
335pub(crate) fn dup3(fd: BorrowedFd<'_>, new: &mut OwnedFd, flags: DupFlags) -> io::Result<()> {
336 unsafe { ret_discarded_fd(syscall_readonly!(__NR_dup3, fd, new.as_fd(), flags)) }
337}
338
339#[inline]
340pub(crate) fn fcntl_getfd(fd: BorrowedFd<'_>) -> io::Result<FdFlags> {
341 #[cfg(target_pointer_width = "32")]
342 unsafe {
343 ret_c_uint(syscall_readonly!(__NR_fcntl64, fd, c_uint(F_GETFD)))
344 .map(FdFlags::from_bits_retain)
345 }
346 #[cfg(target_pointer_width = "64")]
347 unsafe {
348 ret_c_uint(syscall_readonly!(__NR_fcntl, fd, c_uint(F_GETFD)))
349 .map(FdFlags::from_bits_retain)
350 }
351}
352
353#[inline]
354pub(crate) fn fcntl_setfd(fd: BorrowedFd<'_>, flags: FdFlags) -> io::Result<()> {
355 #[cfg(target_pointer_width = "32")]
356 unsafe {
357 ret(syscall_readonly!(__NR_fcntl64, fd, c_uint(F_SETFD), flags))
358 }
359 #[cfg(target_pointer_width = "64")]
360 unsafe {
361 ret(syscall_readonly!(__NR_fcntl, fd, c_uint(F_SETFD), flags))
362 }
363}
364
365#[inline]
366pub(crate) fn fcntl_dupfd_cloexec(fd: BorrowedFd<'_>, min: RawFd) -> io::Result<OwnedFd> {
367 #[cfg(target_pointer_width = "32")]
368 unsafe {
369 ret_owned_fd(syscall_readonly!(
370 __NR_fcntl64,
371 fd,
372 c_uint(F_DUPFD_CLOEXEC),
373 raw_fd(min)
374 ))
375 }
376 #[cfg(target_pointer_width = "64")]
377 unsafe {
378 ret_owned_fd(syscall_readonly!(
379 __NR_fcntl,
380 fd,
381 c_uint(F_DUPFD_CLOEXEC),
382 raw_fd(min)
383 ))
384 }
385}