summaryrefslogtreecommitdiff
path: root/vendor/rustix/src/backend/libc/io/syscalls.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/rustix/src/backend/libc/io/syscalls.rs')
-rw-r--r--vendor/rustix/src/backend/libc/io/syscalls.rs303
1 files changed, 303 insertions, 0 deletions
diff --git a/vendor/rustix/src/backend/libc/io/syscalls.rs b/vendor/rustix/src/backend/libc/io/syscalls.rs
new file mode 100644
index 00000000..f1231aaf
--- /dev/null
+++ b/vendor/rustix/src/backend/libc/io/syscalls.rs
@@ -0,0 +1,303 @@
+//! libc syscalls supporting `rustix::io`.
+
+use crate::backend::c;
+#[cfg(not(target_os = "wasi"))]
+use crate::backend::conv::ret_discarded_fd;
+use crate::backend::conv::{borrowed_fd, ret, ret_c_int, ret_owned_fd, ret_usize};
+use crate::fd::{AsFd as _, BorrowedFd, OwnedFd, RawFd};
+#[cfg(not(any(
+ target_os = "aix",
+ target_os = "espidf",
+ target_os = "nto",
+ target_os = "vita",
+ target_os = "wasi"
+)))]
+use crate::io::DupFlags;
+#[cfg(linux_kernel)]
+use crate::io::ReadWriteFlags;
+use crate::io::{self, FdFlags};
+use crate::ioctl::{IoctlOutput, Opcode};
+use core::cmp::min;
+#[cfg(not(any(target_os = "espidf", target_os = "horizon")))]
+use {
+ crate::backend::MAX_IOV,
+ crate::io::{IoSlice, IoSliceMut},
+};
+
+pub(crate) unsafe fn read(fd: BorrowedFd<'_>, buf: (*mut u8, usize)) -> io::Result<usize> {
+ ret_usize(c::read(
+ borrowed_fd(fd),
+ buf.0.cast(),
+ min(buf.1, READ_LIMIT),
+ ))
+}
+
+pub(crate) fn write(fd: BorrowedFd<'_>, buf: &[u8]) -> io::Result<usize> {
+ unsafe {
+ ret_usize(c::write(
+ borrowed_fd(fd),
+ buf.as_ptr().cast(),
+ min(buf.len(), READ_LIMIT),
+ ))
+ }
+}
+
+pub(crate) unsafe fn pread(
+ fd: BorrowedFd<'_>,
+ buf: (*mut u8, usize),
+ offset: u64,
+) -> io::Result<usize> {
+ let len = min(buf.1, READ_LIMIT);
+
+ // Silently cast; we'll get `EINVAL` if the value is negative.
+ let offset = offset as i64;
+
+ // ESP-IDF and Vita don't support 64-bit offsets, for example.
+ let offset = offset.try_into().map_err(|_| io::Errno::OVERFLOW)?;
+
+ ret_usize(c::pread(borrowed_fd(fd), buf.0.cast(), len, offset))
+}
+
+pub(crate) fn pwrite(fd: BorrowedFd<'_>, buf: &[u8], offset: u64) -> io::Result<usize> {
+ let len = min(buf.len(), READ_LIMIT);
+
+ // Silently cast; we'll get `EINVAL` if the value is negative.
+ let offset = offset as i64;
+
+ // ESP-IDF and Vita don't support 64-bit offsets, for example.
+ let offset = offset.try_into().map_err(|_| io::Errno::OVERFLOW)?;
+
+ unsafe { ret_usize(c::pwrite(borrowed_fd(fd), buf.as_ptr().cast(), len, offset)) }
+}
+
+#[cfg(not(any(target_os = "espidf", target_os = "horizon")))]
+pub(crate) fn readv(fd: BorrowedFd<'_>, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+ unsafe {
+ ret_usize(c::readv(
+ borrowed_fd(fd),
+ bufs.as_ptr().cast::<c::iovec>(),
+ min(bufs.len(), MAX_IOV) as c::c_int,
+ ))
+ }
+}
+
+#[cfg(not(any(target_os = "espidf", target_os = "horizon")))]
+pub(crate) fn writev(fd: BorrowedFd<'_>, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+ unsafe {
+ ret_usize(c::writev(
+ borrowed_fd(fd),
+ bufs.as_ptr().cast::<c::iovec>(),
+ min(bufs.len(), MAX_IOV) as c::c_int,
+ ))
+ }
+}
+
+#[cfg(not(any(
+ target_os = "cygwin",
+ target_os = "espidf",
+ target_os = "haiku",
+ target_os = "horizon",
+ target_os = "nto",
+ target_os = "redox",
+ target_os = "solaris",
+ target_os = "vita",
+)))]
+pub(crate) fn preadv(
+ fd: BorrowedFd<'_>,
+ bufs: &mut [IoSliceMut<'_>],
+ offset: u64,
+) -> io::Result<usize> {
+ // Silently cast; we'll get `EINVAL` if the value is negative.
+ let offset = offset as i64;
+
+ // ESP-IDF and Vita don't support 64-bit offsets, for example.
+ let offset = offset.try_into().map_err(|_| io::Errno::OVERFLOW)?;
+
+ unsafe {
+ ret_usize(c::preadv(
+ borrowed_fd(fd),
+ bufs.as_ptr().cast::<c::iovec>(),
+ min(bufs.len(), MAX_IOV) as c::c_int,
+ offset,
+ ))
+ }
+}
+
+#[cfg(not(any(
+ target_os = "cygwin",
+ target_os = "espidf",
+ target_os = "haiku",
+ target_os = "nto",
+ target_os = "horizon",
+ target_os = "redox",
+ target_os = "solaris",
+ target_os = "vita",
+)))]
+pub(crate) fn pwritev(fd: BorrowedFd<'_>, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
+ // Silently cast; we'll get `EINVAL` if the value is negative.
+ let offset = offset as i64;
+
+ // ESP-IDF and Vita don't support 64-bit offsets, for example.
+ let offset = offset.try_into().map_err(|_| io::Errno::OVERFLOW)?;
+
+ unsafe {
+ ret_usize(c::pwritev(
+ borrowed_fd(fd),
+ bufs.as_ptr().cast::<c::iovec>(),
+ min(bufs.len(), MAX_IOV) as c::c_int,
+ offset,
+ ))
+ }
+}
+
+#[cfg(linux_kernel)]
+pub(crate) fn preadv2(
+ fd: BorrowedFd<'_>,
+ bufs: &mut [IoSliceMut<'_>],
+ offset: u64,
+ flags: ReadWriteFlags,
+) -> io::Result<usize> {
+ // Silently cast; we'll get `EINVAL` if the value is negative.
+ let offset = offset as i64;
+ unsafe {
+ ret_usize(c::preadv2(
+ borrowed_fd(fd),
+ bufs.as_ptr().cast::<c::iovec>(),
+ min(bufs.len(), MAX_IOV) as c::c_int,
+ offset,
+ bitflags_bits!(flags),
+ ))
+ }
+}
+
+#[cfg(linux_kernel)]
+pub(crate) fn pwritev2(
+ fd: BorrowedFd<'_>,
+ bufs: &[IoSlice<'_>],
+ offset: u64,
+ flags: ReadWriteFlags,
+) -> io::Result<usize> {
+ // Silently cast; we'll get `EINVAL` if the value is negative.
+ let offset = offset as i64;
+ unsafe {
+ ret_usize(c::pwritev2(
+ borrowed_fd(fd),
+ bufs.as_ptr().cast::<c::iovec>(),
+ min(bufs.len(), MAX_IOV) as c::c_int,
+ offset,
+ bitflags_bits!(flags),
+ ))
+ }
+}
+
+// These functions are derived from Rust's library/std/src/sys/unix/fd.rs at
+// revision 326ef470a8b379a180d6dc4bbef08990698a737a.
+
+// The maximum read limit on most POSIX-like systems is `SSIZE_MAX`, with the
+// manual page quoting that if the count of bytes to read is greater than
+// `SSIZE_MAX` the result is “unspecified”.
+//
+// On macOS, however, apparently the 64-bit libc is either buggy or
+// intentionally showing odd behavior by rejecting any read with a size larger
+// than or equal to `INT_MAX`. To handle both of these the read size is capped
+// on both platforms.
+#[cfg(target_os = "macos")]
+const READ_LIMIT: usize = c::c_int::MAX as usize - 1;
+#[cfg(not(target_os = "macos"))]
+const READ_LIMIT: usize = c::ssize_t::MAX as usize;
+
+pub(crate) unsafe fn close(raw_fd: RawFd) {
+ let _ = c::close(raw_fd as c::c_int);
+}
+
+#[cfg(feature = "try_close")]
+pub(crate) unsafe fn try_close(raw_fd: RawFd) -> io::Result<()> {
+ ret(c::close(raw_fd as c::c_int))
+}
+
+#[inline]
+pub(crate) unsafe fn ioctl(
+ fd: BorrowedFd<'_>,
+ request: Opcode,
+ arg: *mut c::c_void,
+) -> io::Result<IoctlOutput> {
+ ret_c_int(c::ioctl(borrowed_fd(fd), request, arg))
+}
+
+#[inline]
+pub(crate) unsafe fn ioctl_readonly(
+ fd: BorrowedFd<'_>,
+ request: Opcode,
+ arg: *mut c::c_void,
+) -> io::Result<IoctlOutput> {
+ ioctl(fd, request, arg)
+}
+
+pub(crate) fn fcntl_getfd(fd: BorrowedFd<'_>) -> io::Result<FdFlags> {
+ let flags = unsafe { ret_c_int(c::fcntl(borrowed_fd(fd), c::F_GETFD))? };
+ Ok(FdFlags::from_bits_retain(bitcast!(flags)))
+}
+
+pub(crate) fn fcntl_setfd(fd: BorrowedFd<'_>, flags: FdFlags) -> io::Result<()> {
+ unsafe { ret(c::fcntl(borrowed_fd(fd), c::F_SETFD, flags.bits())) }
+}
+
+#[cfg(not(any(target_os = "espidf", target_os = "wasi")))]
+pub(crate) fn fcntl_dupfd_cloexec(fd: BorrowedFd<'_>, min: RawFd) -> io::Result<OwnedFd> {
+ unsafe { ret_owned_fd(c::fcntl(borrowed_fd(fd), c::F_DUPFD_CLOEXEC, min)) }
+}
+
+#[cfg(target_os = "espidf")]
+pub(crate) fn fcntl_dupfd(fd: BorrowedFd<'_>, min: RawFd) -> io::Result<OwnedFd> {
+ unsafe { ret_owned_fd(c::fcntl(borrowed_fd(fd), c::F_DUPFD, min)) }
+}
+
+#[cfg(not(target_os = "wasi"))]
+pub(crate) fn dup(fd: BorrowedFd<'_>) -> io::Result<OwnedFd> {
+ unsafe { ret_owned_fd(c::dup(borrowed_fd(fd))) }
+}
+
+#[allow(clippy::needless_pass_by_ref_mut)]
+#[cfg(not(target_os = "wasi"))]
+pub(crate) fn dup2(fd: BorrowedFd<'_>, new: &mut OwnedFd) -> io::Result<()> {
+ unsafe { ret_discarded_fd(c::dup2(borrowed_fd(fd), borrowed_fd(new.as_fd()))) }
+}
+
+#[allow(clippy::needless_pass_by_ref_mut)]
+#[cfg(not(any(
+ apple,
+ target_os = "aix",
+ target_os = "android",
+ target_os = "dragonfly",
+ target_os = "espidf",
+ target_os = "haiku",
+ target_os = "horizon",
+ target_os = "nto",
+ target_os = "redox",
+ target_os = "vita",
+ target_os = "wasi",
+)))]
+pub(crate) fn dup3(fd: BorrowedFd<'_>, new: &mut OwnedFd, flags: DupFlags) -> io::Result<()> {
+ unsafe {
+ ret_discarded_fd(c::dup3(
+ borrowed_fd(fd),
+ borrowed_fd(new.as_fd()),
+ bitflags_bits!(flags),
+ ))
+ }
+}
+
+#[cfg(any(
+ apple,
+ target_os = "android",
+ target_os = "dragonfly",
+ target_os = "haiku",
+ target_os = "redox",
+))]
+pub(crate) fn dup3(fd: BorrowedFd<'_>, new: &mut OwnedFd, _flags: DupFlags) -> io::Result<()> {
+ // Android 5.0 has `dup3`, but libc doesn't have bindings. Emulate it
+ // using `dup2`. We don't need to worry about the difference between
+ // `dup2` and `dup3` when the file descriptors are equal because we
+ // have an `&mut OwnedFd` which means `fd` doesn't alias it.
+ dup2(fd, new)
+}