]>
Commit | Line | Data |
---|---|---|
fe692bf9 FG |
1 | //! libc syscalls supporting `rustix::io`. |
2 | ||
3 | use super::super::c; | |
4 | #[cfg(any( | |
5 | target_os = "android", | |
6 | all(target_os = "linux", not(target_env = "gnu")), | |
7 | ))] | |
8 | use super::super::conv::syscall_ret_usize; | |
9 | use super::super::conv::{borrowed_fd, ret, ret_c_int, ret_discarded_fd, ret_owned_fd, ret_usize}; | |
10 | use super::super::offset::{libc_pread, libc_pwrite}; | |
11 | #[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "solaris")))] | |
12 | use super::super::offset::{libc_preadv, libc_pwritev}; | |
13 | #[cfg(all(target_os = "linux", target_env = "gnu"))] | |
14 | use super::super::offset::{libc_preadv2, libc_pwritev2}; | |
15 | use crate::fd::{AsFd, BorrowedFd, OwnedFd, RawFd}; | |
16 | #[cfg(not(any(target_os = "aix", target_os = "wasi")))] | |
17 | use crate::io::DupFlags; | |
18 | #[cfg(any(linux_kernel, target_os = "freebsd", target_os = "illumos"))] | |
19 | use crate::io::EventfdFlags; | |
20 | #[cfg(not(any(apple, target_os = "aix", target_os = "haiku", target_os = "wasi")))] | |
21 | use crate::io::PipeFlags; | |
22 | use crate::io::{self, FdFlags, IoSlice, IoSliceMut, PollFd}; | |
23 | use core::cmp::min; | |
24 | use core::convert::TryInto; | |
25 | use core::mem::MaybeUninit; | |
26 | #[cfg(all(feature = "fs", feature = "net"))] | |
27 | use libc_errno::errno; | |
28 | #[cfg(linux_kernel)] | |
29 | use { | |
30 | super::super::conv::syscall_ret_owned_fd, | |
31 | crate::io::{IoSliceRaw, ReadWriteFlags, SpliceFlags}, | |
32 | crate::utils::optional_as_mut_ptr, | |
33 | }; | |
34 | #[cfg(bsd)] | |
35 | use {crate::io::kqueue::Event, crate::utils::as_ptr, core::ptr::null}; | |
36 | #[cfg(solarish)] | |
37 | use {crate::io::port::Event, crate::utils::as_mut_ptr, core::ptr::null_mut}; | |
38 | ||
39 | pub(crate) fn read(fd: BorrowedFd<'_>, buf: &mut [u8]) -> io::Result<usize> { | |
40 | unsafe { | |
41 | ret_usize(c::read( | |
42 | borrowed_fd(fd), | |
43 | buf.as_mut_ptr().cast(), | |
44 | min(buf.len(), READ_LIMIT), | |
45 | )) | |
46 | } | |
47 | } | |
48 | ||
49 | pub(crate) fn write(fd: BorrowedFd<'_>, buf: &[u8]) -> io::Result<usize> { | |
50 | unsafe { | |
51 | ret_usize(c::write( | |
52 | borrowed_fd(fd), | |
53 | buf.as_ptr().cast(), | |
54 | min(buf.len(), READ_LIMIT), | |
55 | )) | |
56 | } | |
57 | } | |
58 | ||
59 | pub(crate) fn pread(fd: BorrowedFd<'_>, buf: &mut [u8], offset: u64) -> io::Result<usize> { | |
60 | let len = min(buf.len(), READ_LIMIT); | |
61 | ||
62 | // Silently cast; we'll get `EINVAL` if the value is negative. | |
63 | let offset = offset as i64; | |
64 | ||
65 | unsafe { | |
66 | ret_usize(libc_pread( | |
67 | borrowed_fd(fd), | |
68 | buf.as_mut_ptr().cast(), | |
69 | len, | |
70 | offset, | |
71 | )) | |
72 | } | |
73 | } | |
74 | ||
75 | pub(crate) fn pwrite(fd: BorrowedFd<'_>, buf: &[u8], offset: u64) -> io::Result<usize> { | |
76 | let len = min(buf.len(), READ_LIMIT); | |
77 | ||
78 | // Silently cast; we'll get `EINVAL` if the value is negative. | |
79 | let offset = offset as i64; | |
80 | ||
81 | unsafe { | |
82 | ret_usize(libc_pwrite( | |
83 | borrowed_fd(fd), | |
84 | buf.as_ptr().cast(), | |
85 | len, | |
86 | offset, | |
87 | )) | |
88 | } | |
89 | } | |
90 | ||
91 | pub(crate) fn readv(fd: BorrowedFd<'_>, bufs: &mut [IoSliceMut]) -> io::Result<usize> { | |
92 | unsafe { | |
93 | ret_usize(c::readv( | |
94 | borrowed_fd(fd), | |
95 | bufs.as_ptr().cast::<c::iovec>(), | |
96 | min(bufs.len(), max_iov()) as c::c_int, | |
97 | )) | |
98 | } | |
99 | } | |
100 | ||
101 | pub(crate) fn writev(fd: BorrowedFd<'_>, bufs: &[IoSlice]) -> io::Result<usize> { | |
102 | unsafe { | |
103 | ret_usize(c::writev( | |
104 | borrowed_fd(fd), | |
105 | bufs.as_ptr().cast::<c::iovec>(), | |
106 | min(bufs.len(), max_iov()) as c::c_int, | |
107 | )) | |
108 | } | |
109 | } | |
110 | ||
111 | #[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "solaris")))] | |
112 | pub(crate) fn preadv( | |
113 | fd: BorrowedFd<'_>, | |
114 | bufs: &mut [IoSliceMut], | |
115 | offset: u64, | |
116 | ) -> io::Result<usize> { | |
117 | // Silently cast; we'll get `EINVAL` if the value is negative. | |
118 | let offset = offset as i64; | |
119 | unsafe { | |
120 | ret_usize(libc_preadv( | |
121 | borrowed_fd(fd), | |
122 | bufs.as_ptr().cast::<c::iovec>(), | |
123 | min(bufs.len(), max_iov()) as c::c_int, | |
124 | offset, | |
125 | )) | |
126 | } | |
127 | } | |
128 | ||
129 | #[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "solaris")))] | |
130 | pub(crate) fn pwritev(fd: BorrowedFd<'_>, bufs: &[IoSlice], offset: u64) -> io::Result<usize> { | |
131 | // Silently cast; we'll get `EINVAL` if the value is negative. | |
132 | let offset = offset as i64; | |
133 | unsafe { | |
134 | ret_usize(libc_pwritev( | |
135 | borrowed_fd(fd), | |
136 | bufs.as_ptr().cast::<c::iovec>(), | |
137 | min(bufs.len(), max_iov()) as c::c_int, | |
138 | offset, | |
139 | )) | |
140 | } | |
141 | } | |
142 | ||
143 | #[cfg(all(target_os = "linux", target_env = "gnu"))] | |
144 | pub(crate) fn preadv2( | |
145 | fd: BorrowedFd<'_>, | |
146 | bufs: &mut [IoSliceMut], | |
147 | offset: u64, | |
148 | flags: ReadWriteFlags, | |
149 | ) -> io::Result<usize> { | |
150 | // Silently cast; we'll get `EINVAL` if the value is negative. | |
151 | let offset = offset as i64; | |
152 | unsafe { | |
153 | ret_usize(libc_preadv2( | |
154 | borrowed_fd(fd), | |
155 | bufs.as_ptr().cast::<c::iovec>(), | |
156 | min(bufs.len(), max_iov()) as c::c_int, | |
157 | offset, | |
158 | flags.bits(), | |
159 | )) | |
160 | } | |
161 | } | |
162 | ||
163 | /// At present, `libc` only has `preadv2` defined for glibc. On other | |
164 | /// ABIs, use `c::syscall`. | |
165 | #[cfg(any( | |
166 | target_os = "android", | |
167 | all(target_os = "linux", not(target_env = "gnu")), | |
168 | ))] | |
169 | #[inline] | |
170 | pub(crate) fn preadv2( | |
171 | fd: BorrowedFd<'_>, | |
172 | bufs: &mut [IoSliceMut], | |
173 | offset: u64, | |
174 | flags: ReadWriteFlags, | |
175 | ) -> io::Result<usize> { | |
176 | // Silently cast; we'll get `EINVAL` if the value is negative. | |
177 | let offset = offset as i64; | |
178 | unsafe { | |
179 | syscall_ret_usize(c::syscall( | |
180 | c::SYS_preadv2, | |
181 | borrowed_fd(fd), | |
182 | bufs.as_ptr().cast::<c::iovec>(), | |
183 | min(bufs.len(), max_iov()) as c::c_int, | |
184 | offset, | |
185 | flags.bits(), | |
186 | )) | |
187 | } | |
188 | } | |
189 | ||
190 | #[cfg(all(target_os = "linux", target_env = "gnu"))] | |
191 | pub(crate) fn pwritev2( | |
192 | fd: BorrowedFd<'_>, | |
193 | bufs: &[IoSlice], | |
194 | offset: u64, | |
195 | flags: ReadWriteFlags, | |
196 | ) -> io::Result<usize> { | |
197 | // Silently cast; we'll get `EINVAL` if the value is negative. | |
198 | let offset = offset as i64; | |
199 | unsafe { | |
200 | ret_usize(libc_pwritev2( | |
201 | borrowed_fd(fd), | |
202 | bufs.as_ptr().cast::<c::iovec>(), | |
203 | min(bufs.len(), max_iov()) as c::c_int, | |
204 | offset, | |
205 | flags.bits(), | |
206 | )) | |
207 | } | |
208 | } | |
209 | ||
210 | /// At present, `libc` only has `pwritev2` defined for glibc. On other | |
211 | /// ABIs, use `c::syscall`. | |
212 | #[cfg(any( | |
213 | target_os = "android", | |
214 | all(target_os = "linux", not(target_env = "gnu")), | |
215 | ))] | |
216 | #[inline] | |
217 | pub(crate) fn pwritev2( | |
218 | fd: BorrowedFd<'_>, | |
219 | bufs: &[IoSlice], | |
220 | offset: u64, | |
221 | flags: ReadWriteFlags, | |
222 | ) -> io::Result<usize> { | |
223 | // Silently cast; we'll get `EINVAL` if the value is negative. | |
224 | let offset = offset as i64; | |
225 | unsafe { | |
226 | syscall_ret_usize(c::syscall( | |
227 | c::SYS_pwritev2, | |
228 | borrowed_fd(fd), | |
229 | bufs.as_ptr().cast::<c::iovec>(), | |
230 | min(bufs.len(), max_iov()) as c::c_int, | |
231 | offset, | |
232 | flags.bits(), | |
233 | )) | |
234 | } | |
235 | } | |
236 | ||
237 | // These functions are derived from Rust's library/std/src/sys/unix/fd.rs at | |
238 | // revision 326ef470a8b379a180d6dc4bbef08990698a737a. | |
239 | ||
240 | // The maximum read limit on most POSIX-like systems is `SSIZE_MAX`, with the | |
241 | // manual page quoting that if the count of bytes to read is greater than | |
242 | // `SSIZE_MAX` the result is “unspecified”. | |
243 | // | |
244 | // On macOS, however, apparently the 64-bit libc is either buggy or | |
245 | // intentionally showing odd behavior by rejecting any read with a size larger | |
246 | // than or equal to `INT_MAX`. To handle both of these the read size is capped | |
247 | // on both platforms. | |
248 | #[cfg(target_os = "macos")] | |
249 | const READ_LIMIT: usize = c::c_int::MAX as usize - 1; | |
250 | #[cfg(not(target_os = "macos"))] | |
251 | const READ_LIMIT: usize = c::ssize_t::MAX as usize; | |
252 | ||
253 | #[cfg(bsd)] | |
254 | const fn max_iov() -> usize { | |
255 | c::IOV_MAX as usize | |
256 | } | |
257 | ||
258 | #[cfg(any(linux_kernel, target_os = "emscripten", target_os = "nto"))] | |
259 | const fn max_iov() -> usize { | |
260 | c::UIO_MAXIOV as usize | |
261 | } | |
262 | ||
263 | #[cfg(not(any( | |
264 | bsd, | |
265 | linux_kernel, | |
266 | target_os = "emscripten", | |
267 | target_os = "nto", | |
268 | target_os = "horizon", | |
269 | )))] | |
270 | const fn max_iov() -> usize { | |
271 | 16 // The minimum value required by POSIX. | |
272 | } | |
273 | ||
274 | pub(crate) unsafe fn close(raw_fd: RawFd) { | |
275 | let _ = c::close(raw_fd as c::c_int); | |
276 | } | |
277 | ||
278 | #[cfg(linux_kernel)] | |
279 | pub(crate) fn eventfd(initval: u32, flags: EventfdFlags) -> io::Result<OwnedFd> { | |
280 | unsafe { syscall_ret_owned_fd(c::syscall(c::SYS_eventfd2, initval, flags.bits())) } | |
281 | } | |
282 | ||
283 | #[cfg(any(target_os = "freebsd", target_os = "illumos"))] | |
284 | pub(crate) fn eventfd(initval: u32, flags: EventfdFlags) -> io::Result<OwnedFd> { | |
add651ee FG |
285 | // `eventfd` was added in FreeBSD 13, so it isn't available on FreeBSD 12. |
286 | #[cfg(target_os = "freebsd")] | |
287 | unsafe { | |
288 | weakcall! { | |
289 | fn eventfd( | |
290 | initval: c::c_uint, | |
291 | flags: c::c_int | |
292 | ) -> c::c_int | |
293 | } | |
294 | ret_owned_fd(eventfd(initval, flags.bits())) | |
295 | } | |
296 | ||
297 | #[cfg(target_os = "illumos")] | |
298 | unsafe { | |
299 | ret_owned_fd(c::eventfd(initval, flags.bits())) | |
300 | } | |
fe692bf9 FG |
301 | } |
302 | ||
303 | #[cfg(linux_kernel)] | |
304 | #[inline] | |
305 | pub(crate) fn ioctl_blksszget(fd: BorrowedFd) -> io::Result<u32> { | |
306 | let mut result = MaybeUninit::<c::c_uint>::uninit(); | |
307 | unsafe { | |
308 | ret(c::ioctl(borrowed_fd(fd), c::BLKSSZGET, result.as_mut_ptr()))?; | |
309 | Ok(result.assume_init() as u32) | |
310 | } | |
311 | } | |
312 | ||
313 | #[cfg(linux_kernel)] | |
314 | #[inline] | |
315 | pub(crate) fn ioctl_blkpbszget(fd: BorrowedFd) -> io::Result<u32> { | |
316 | let mut result = MaybeUninit::<c::c_uint>::uninit(); | |
317 | unsafe { | |
318 | ret(c::ioctl( | |
319 | borrowed_fd(fd), | |
320 | c::BLKPBSZGET, | |
321 | result.as_mut_ptr(), | |
322 | ))?; | |
323 | Ok(result.assume_init() as u32) | |
324 | } | |
325 | } | |
326 | ||
327 | #[cfg(not(target_os = "redox"))] | |
328 | pub(crate) fn ioctl_fionread(fd: BorrowedFd<'_>) -> io::Result<u64> { | |
329 | let mut nread = MaybeUninit::<c::c_int>::uninit(); | |
330 | unsafe { | |
331 | ret(c::ioctl(borrowed_fd(fd), c::FIONREAD, nread.as_mut_ptr()))?; | |
332 | // `FIONREAD` returns the number of bytes silently casted to a `c_int`, | |
333 | // even when this is lossy. The best we can do is convert it back to a | |
334 | // `u64` without sign-extending it back first. | |
335 | Ok(u64::from(nread.assume_init() as c::c_uint)) | |
336 | } | |
337 | } | |
338 | ||
339 | pub(crate) fn ioctl_fionbio(fd: BorrowedFd<'_>, value: bool) -> io::Result<()> { | |
340 | unsafe { | |
341 | let data = value as c::c_int; | |
342 | ret(c::ioctl(borrowed_fd(fd), c::FIONBIO, &data)) | |
343 | } | |
344 | } | |
345 | ||
346 | // Sparc lacks `FICLONE`. | |
347 | #[cfg(all(linux_kernel, not(any(target_arch = "sparc", target_arch = "sparc64"))))] | |
348 | pub(crate) fn ioctl_ficlone(fd: BorrowedFd<'_>, src_fd: BorrowedFd<'_>) -> io::Result<()> { | |
349 | unsafe { | |
350 | ret(c::ioctl( | |
351 | borrowed_fd(fd), | |
352 | c::FICLONE as _, | |
353 | borrowed_fd(src_fd), | |
354 | )) | |
355 | } | |
356 | } | |
357 | ||
358 | #[cfg(linux_kernel)] | |
359 | #[inline] | |
360 | pub(crate) fn ext4_ioc_resize_fs(fd: BorrowedFd<'_>, blocks: u64) -> io::Result<()> { | |
361 | // TODO: Fix linux-raw-sys to define ioctl codes for sparc. | |
362 | #[cfg(any(target_arch = "sparc", target_arch = "sparc64"))] | |
363 | const EXT4_IOC_RESIZE_FS: u32 = 0x8008_6610; | |
364 | ||
365 | #[cfg(not(any(target_arch = "sparc", target_arch = "sparc64")))] | |
366 | use linux_raw_sys::ioctl::EXT4_IOC_RESIZE_FS; | |
367 | ||
368 | unsafe { ret(c::ioctl(borrowed_fd(fd), EXT4_IOC_RESIZE_FS as _, &blocks)) } | |
369 | } | |
370 | ||
371 | #[cfg(not(any(target_os = "redox", target_os = "wasi")))] | |
372 | #[cfg(all(feature = "fs", feature = "net"))] | |
373 | pub(crate) fn is_read_write(fd: BorrowedFd<'_>) -> io::Result<(bool, bool)> { | |
374 | let (mut read, mut write) = crate::fs::fd::_is_file_read_write(fd)?; | |
375 | let mut not_socket = false; | |
376 | if read { | |
377 | // Do a `recv` with `PEEK` and `DONTWAIT` for 1 byte. A 0 indicates | |
378 | // the read side is shut down; an `EWOULDBLOCK` indicates the read | |
379 | // side is still open. | |
380 | match unsafe { | |
381 | c::recv( | |
382 | borrowed_fd(fd), | |
383 | MaybeUninit::<[u8; 1]>::uninit() | |
384 | .as_mut_ptr() | |
385 | .cast::<c::c_void>(), | |
386 | 1, | |
387 | c::MSG_PEEK | c::MSG_DONTWAIT, | |
388 | ) | |
389 | } { | |
390 | 0 => read = false, | |
391 | -1 => { | |
392 | #[allow(unreachable_patterns)] // `EAGAIN` may equal `EWOULDBLOCK` | |
393 | match errno().0 { | |
394 | c::EAGAIN | c::EWOULDBLOCK => (), | |
395 | c::ENOTSOCK => not_socket = true, | |
396 | err => return Err(io::Errno(err)), | |
397 | } | |
398 | } | |
399 | _ => (), | |
400 | } | |
401 | } | |
402 | if write && !not_socket { | |
403 | // Do a `send` with `DONTWAIT` for 0 bytes. An `EPIPE` indicates | |
404 | // the write side is shut down. | |
405 | if unsafe { c::send(borrowed_fd(fd), [].as_ptr(), 0, c::MSG_DONTWAIT) } == -1 { | |
406 | #[allow(unreachable_patterns)] // `EAGAIN` may equal `EWOULDBLOCK` | |
407 | match errno().0 { | |
408 | c::EAGAIN | c::EWOULDBLOCK => (), | |
409 | c::ENOTSOCK => (), | |
410 | c::EPIPE => write = false, | |
411 | err => return Err(io::Errno(err)), | |
412 | } | |
413 | } | |
414 | } | |
415 | Ok((read, write)) | |
416 | } | |
417 | ||
418 | #[cfg(target_os = "wasi")] | |
419 | #[cfg(all(feature = "fs", feature = "net"))] | |
420 | pub(crate) fn is_read_write(_fd: BorrowedFd<'_>) -> io::Result<(bool, bool)> { | |
421 | todo!("Implement is_read_write for WASI in terms of fd_fdstat_get"); | |
422 | } | |
423 | ||
424 | pub(crate) fn fcntl_getfd(fd: BorrowedFd<'_>) -> io::Result<FdFlags> { | |
425 | unsafe { ret_c_int(c::fcntl(borrowed_fd(fd), c::F_GETFD)).map(FdFlags::from_bits_truncate) } | |
426 | } | |
427 | ||
428 | pub(crate) fn fcntl_setfd(fd: BorrowedFd<'_>, flags: FdFlags) -> io::Result<()> { | |
429 | unsafe { ret(c::fcntl(borrowed_fd(fd), c::F_SETFD, flags.bits())) } | |
430 | } | |
431 | ||
432 | #[cfg(not(target_os = "wasi"))] | |
433 | pub(crate) fn fcntl_dupfd_cloexec(fd: BorrowedFd<'_>, min: RawFd) -> io::Result<OwnedFd> { | |
434 | unsafe { ret_owned_fd(c::fcntl(borrowed_fd(fd), c::F_DUPFD_CLOEXEC, min)) } | |
435 | } | |
436 | ||
437 | #[cfg(not(target_os = "wasi"))] | |
438 | pub(crate) fn dup(fd: BorrowedFd<'_>) -> io::Result<OwnedFd> { | |
439 | unsafe { ret_owned_fd(c::dup(borrowed_fd(fd))) } | |
440 | } | |
441 | ||
442 | #[cfg(not(target_os = "wasi"))] | |
443 | pub(crate) fn dup2(fd: BorrowedFd<'_>, new: &mut OwnedFd) -> io::Result<()> { | |
444 | unsafe { ret_discarded_fd(c::dup2(borrowed_fd(fd), borrowed_fd(new.as_fd()))) } | |
445 | } | |
446 | ||
447 | #[cfg(not(any( | |
448 | apple, | |
449 | target_os = "aix", | |
450 | target_os = "android", | |
451 | target_os = "dragonfly", | |
452 | target_os = "haiku", | |
453 | target_os = "redox", | |
454 | target_os = "wasi", | |
455 | )))] | |
456 | pub(crate) fn dup3(fd: BorrowedFd<'_>, new: &mut OwnedFd, flags: DupFlags) -> io::Result<()> { | |
457 | unsafe { | |
458 | ret_discarded_fd(c::dup3( | |
459 | borrowed_fd(fd), | |
460 | borrowed_fd(new.as_fd()), | |
461 | flags.bits(), | |
462 | )) | |
463 | } | |
464 | } | |
465 | ||
466 | #[cfg(any( | |
467 | apple, | |
468 | target_os = "android", | |
469 | target_os = "dragonfly", | |
470 | target_os = "haiku", | |
471 | target_os = "redox", | |
472 | ))] | |
473 | pub(crate) fn dup3(fd: BorrowedFd<'_>, new: &mut OwnedFd, _flags: DupFlags) -> io::Result<()> { | |
474 | // Android 5.0 has `dup3`, but libc doesn't have bindings. Emulate it | |
475 | // using `dup2`. We don't need to worry about the difference between | |
476 | // `dup2` and `dup3` when the file descriptors are equal because we | |
477 | // have an `&mut OwnedFd` which means `fd` doesn't alias it. | |
478 | dup2(fd, new) | |
479 | } | |
480 | ||
481 | #[cfg(apple)] | |
482 | pub(crate) fn ioctl_fioclex(fd: BorrowedFd<'_>) -> io::Result<()> { | |
483 | unsafe { | |
484 | ret(c::ioctl( | |
485 | borrowed_fd(fd), | |
486 | c::FIOCLEX, | |
487 | core::ptr::null_mut::<u8>(), | |
488 | )) | |
489 | } | |
490 | } | |
491 | ||
492 | #[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))] | |
493 | pub(crate) fn ioctl_tiocexcl(fd: BorrowedFd) -> io::Result<()> { | |
494 | unsafe { ret(c::ioctl(borrowed_fd(fd), c::TIOCEXCL as _)) } | |
495 | } | |
496 | ||
497 | #[cfg(not(any(target_os = "haiku", target_os = "redox", target_os = "wasi")))] | |
498 | pub(crate) fn ioctl_tiocnxcl(fd: BorrowedFd) -> io::Result<()> { | |
499 | unsafe { ret(c::ioctl(borrowed_fd(fd), c::TIOCNXCL as _)) } | |
500 | } | |
501 | ||
502 | #[cfg(bsd)] | |
503 | pub(crate) fn kqueue() -> io::Result<OwnedFd> { | |
504 | unsafe { ret_owned_fd(c::kqueue()) } | |
505 | } | |
506 | ||
507 | #[cfg(bsd)] | |
508 | pub(crate) unsafe fn kevent( | |
509 | kq: BorrowedFd<'_>, | |
510 | changelist: &[Event], | |
511 | eventlist: &mut [MaybeUninit<Event>], | |
512 | timeout: Option<&c::timespec>, | |
513 | ) -> io::Result<c::c_int> { | |
514 | ret_c_int(c::kevent( | |
515 | borrowed_fd(kq), | |
516 | changelist.as_ptr().cast(), | |
517 | changelist | |
518 | .len() | |
519 | .try_into() | |
520 | .map_err(|_| io::Errno::OVERFLOW)?, | |
521 | eventlist.as_mut_ptr().cast(), | |
522 | eventlist | |
523 | .len() | |
524 | .try_into() | |
525 | .map_err(|_| io::Errno::OVERFLOW)?, | |
526 | timeout.map_or(null(), as_ptr), | |
527 | )) | |
528 | } | |
529 | ||
530 | #[cfg(not(target_os = "wasi"))] | |
531 | pub(crate) fn pipe() -> io::Result<(OwnedFd, OwnedFd)> { | |
532 | unsafe { | |
533 | let mut result = MaybeUninit::<[OwnedFd; 2]>::uninit(); | |
534 | ret(c::pipe(result.as_mut_ptr().cast::<i32>()))?; | |
535 | let [p0, p1] = result.assume_init(); | |
536 | Ok((p0, p1)) | |
537 | } | |
538 | } | |
539 | ||
540 | #[cfg(not(any(apple, target_os = "aix", target_os = "haiku", target_os = "wasi")))] | |
541 | pub(crate) fn pipe_with(flags: PipeFlags) -> io::Result<(OwnedFd, OwnedFd)> { | |
542 | unsafe { | |
543 | let mut result = MaybeUninit::<[OwnedFd; 2]>::uninit(); | |
544 | ret(c::pipe2(result.as_mut_ptr().cast::<i32>(), flags.bits()))?; | |
545 | let [p0, p1] = result.assume_init(); | |
546 | Ok((p0, p1)) | |
547 | } | |
548 | } | |
549 | ||
550 | #[inline] | |
551 | pub(crate) fn poll(fds: &mut [PollFd<'_>], timeout: c::c_int) -> io::Result<usize> { | |
552 | let nfds = fds | |
553 | .len() | |
554 | .try_into() | |
555 | .map_err(|_convert_err| io::Errno::INVAL)?; | |
556 | ||
557 | ret_c_int(unsafe { c::poll(fds.as_mut_ptr().cast(), nfds, timeout) }) | |
558 | .map(|nready| nready as usize) | |
559 | } | |
560 | ||
561 | #[cfg(linux_kernel)] | |
562 | #[inline] | |
563 | pub fn splice( | |
564 | fd_in: BorrowedFd, | |
565 | off_in: Option<&mut u64>, | |
566 | fd_out: BorrowedFd, | |
567 | off_out: Option<&mut u64>, | |
568 | len: usize, | |
569 | flags: SpliceFlags, | |
570 | ) -> io::Result<usize> { | |
571 | let off_in = optional_as_mut_ptr(off_in).cast(); | |
572 | let off_out = optional_as_mut_ptr(off_out).cast(); | |
573 | ||
574 | unsafe { | |
575 | ret_usize(c::splice( | |
576 | borrowed_fd(fd_in), | |
577 | off_in, | |
578 | borrowed_fd(fd_out), | |
579 | off_out, | |
580 | len, | |
581 | flags.bits(), | |
582 | )) | |
583 | } | |
584 | } | |
585 | ||
586 | #[cfg(linux_kernel)] | |
587 | #[inline] | |
588 | pub unsafe fn vmsplice( | |
589 | fd: BorrowedFd, | |
590 | bufs: &[IoSliceRaw], | |
591 | flags: SpliceFlags, | |
592 | ) -> io::Result<usize> { | |
593 | ret_usize(c::vmsplice( | |
594 | borrowed_fd(fd), | |
595 | bufs.as_ptr().cast::<c::iovec>(), | |
596 | min(bufs.len(), max_iov()), | |
597 | flags.bits(), | |
598 | )) | |
599 | } | |
600 | ||
601 | #[cfg(solarish)] | |
602 | pub(crate) fn port_create() -> io::Result<OwnedFd> { | |
603 | unsafe { ret_owned_fd(c::port_create()) } | |
604 | } | |
605 | ||
606 | #[cfg(solarish)] | |
607 | pub(crate) unsafe fn port_associate( | |
608 | port: BorrowedFd<'_>, | |
609 | source: c::c_int, | |
610 | object: c::uintptr_t, | |
611 | events: c::c_int, | |
612 | user: *mut c::c_void, | |
613 | ) -> io::Result<()> { | |
614 | ret(c::port_associate( | |
615 | borrowed_fd(port), | |
616 | source, | |
617 | object, | |
618 | events, | |
619 | user, | |
620 | )) | |
621 | } | |
622 | ||
623 | #[cfg(solarish)] | |
624 | pub(crate) unsafe fn port_dissociate( | |
625 | port: BorrowedFd<'_>, | |
626 | source: c::c_int, | |
627 | object: c::uintptr_t, | |
628 | ) -> io::Result<()> { | |
629 | ret(c::port_dissociate(borrowed_fd(port), source, object)) | |
630 | } | |
631 | ||
632 | #[cfg(solarish)] | |
633 | pub(crate) fn port_get( | |
634 | port: BorrowedFd<'_>, | |
635 | timeout: Option<&mut c::timespec>, | |
636 | ) -> io::Result<Event> { | |
637 | let mut event = MaybeUninit::<c::port_event>::uninit(); | |
638 | let timeout = timeout.map_or(null_mut(), as_mut_ptr); | |
639 | ||
640 | unsafe { | |
641 | ret(c::port_get(borrowed_fd(port), event.as_mut_ptr(), timeout))?; | |
642 | } | |
643 | ||
644 | // If we're done, initialize the event and return it. | |
645 | Ok(Event(unsafe { event.assume_init() })) | |
646 | } | |
647 | ||
648 | #[cfg(solarish)] | |
649 | pub(crate) fn port_getn( | |
650 | port: BorrowedFd<'_>, | |
651 | timeout: Option<&mut c::timespec>, | |
652 | events: &mut Vec<Event>, | |
653 | mut nget: u32, | |
654 | ) -> io::Result<()> { | |
655 | let timeout = timeout.map_or(null_mut(), as_mut_ptr); | |
656 | unsafe { | |
657 | ret(c::port_getn( | |
658 | borrowed_fd(port), | |
659 | events.as_mut_ptr().cast(), | |
660 | events.len().try_into().unwrap(), | |
661 | &mut nget, | |
662 | timeout, | |
663 | ))?; | |
664 | } | |
665 | ||
666 | // Update the vector length. | |
667 | unsafe { | |
668 | events.set_len(nget.try_into().unwrap()); | |
669 | } | |
670 | ||
671 | Ok(()) | |
672 | } | |
673 | ||
674 | #[cfg(solarish)] | |
675 | pub(crate) fn port_send( | |
676 | port: BorrowedFd<'_>, | |
677 | events: c::c_int, | |
678 | userdata: *mut c::c_void, | |
679 | ) -> io::Result<()> { | |
680 | unsafe { ret(c::port_send(borrowed_fd(port), events, userdata)) } | |
681 | } |