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