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