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