13da5c369Sopenharmony_ci//! Vectored I/O 23da5c369Sopenharmony_ci 33da5c369Sopenharmony_ciuse crate::errno::Errno; 43da5c369Sopenharmony_ciuse crate::Result; 53da5c369Sopenharmony_ciuse libc::{self, c_int, c_void, off_t, size_t}; 63da5c369Sopenharmony_ciuse std::io::{IoSlice, IoSliceMut}; 73da5c369Sopenharmony_ciuse std::marker::PhantomData; 83da5c369Sopenharmony_ciuse std::os::unix::io::RawFd; 93da5c369Sopenharmony_ci 103da5c369Sopenharmony_ci/// Low-level vectored write to a raw file descriptor 113da5c369Sopenharmony_ci/// 123da5c369Sopenharmony_ci/// See also [writev(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/writev.html) 133da5c369Sopenharmony_cipub fn writev(fd: RawFd, iov: &[IoSlice<'_>]) -> Result<usize> { 143da5c369Sopenharmony_ci // SAFETY: to quote the documentation for `IoSlice`: 153da5c369Sopenharmony_ci // 163da5c369Sopenharmony_ci // [IoSlice] is semantically a wrapper around a &[u8], but is 173da5c369Sopenharmony_ci // guaranteed to be ABI compatible with the iovec type on Unix 183da5c369Sopenharmony_ci // platforms. 193da5c369Sopenharmony_ci // 203da5c369Sopenharmony_ci // Because it is ABI compatible, a pointer cast here is valid 213da5c369Sopenharmony_ci let res = unsafe { 223da5c369Sopenharmony_ci libc::writev(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int) 233da5c369Sopenharmony_ci }; 243da5c369Sopenharmony_ci 253da5c369Sopenharmony_ci Errno::result(res).map(|r| r as usize) 263da5c369Sopenharmony_ci} 273da5c369Sopenharmony_ci 283da5c369Sopenharmony_ci/// Low-level vectored read from a raw file descriptor 293da5c369Sopenharmony_ci/// 303da5c369Sopenharmony_ci/// See also [readv(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/readv.html) 313da5c369Sopenharmony_cipub fn readv(fd: RawFd, iov: &mut [IoSliceMut<'_>]) -> Result<usize> { 323da5c369Sopenharmony_ci // SAFETY: same as in writev(), IoSliceMut is ABI-compatible with iovec 333da5c369Sopenharmony_ci let res = unsafe { 343da5c369Sopenharmony_ci libc::readv(fd, iov.as_ptr() as *const libc::iovec, iov.len() as c_int) 353da5c369Sopenharmony_ci }; 363da5c369Sopenharmony_ci 373da5c369Sopenharmony_ci Errno::result(res).map(|r| r as usize) 383da5c369Sopenharmony_ci} 393da5c369Sopenharmony_ci 403da5c369Sopenharmony_ci/// Write to `fd` at `offset` from buffers in `iov`. 413da5c369Sopenharmony_ci/// 423da5c369Sopenharmony_ci/// Buffers in `iov` will be written in order until all buffers have been written 433da5c369Sopenharmony_ci/// or an error occurs. The file offset is not changed. 443da5c369Sopenharmony_ci/// 453da5c369Sopenharmony_ci/// See also: [`writev`](fn.writev.html) and [`pwrite`](fn.pwrite.html) 463da5c369Sopenharmony_ci#[cfg(not(any(target_os = "redox", target_os = "haiku")))] 473da5c369Sopenharmony_ci#[cfg_attr(docsrs, doc(cfg(all())))] 483da5c369Sopenharmony_cipub fn pwritev(fd: RawFd, iov: &[IoSlice<'_>], offset: off_t) -> Result<usize> { 493da5c369Sopenharmony_ci #[cfg(target_env = "uclibc")] 503da5c369Sopenharmony_ci let offset = offset as libc::off64_t; // uclibc doesn't use off_t 513da5c369Sopenharmony_ci 523da5c369Sopenharmony_ci // SAFETY: same as in writev() 533da5c369Sopenharmony_ci let res = unsafe { 543da5c369Sopenharmony_ci libc::pwritev( 553da5c369Sopenharmony_ci fd, 563da5c369Sopenharmony_ci iov.as_ptr() as *const libc::iovec, 573da5c369Sopenharmony_ci iov.len() as c_int, 583da5c369Sopenharmony_ci offset, 593da5c369Sopenharmony_ci ) 603da5c369Sopenharmony_ci }; 613da5c369Sopenharmony_ci 623da5c369Sopenharmony_ci Errno::result(res).map(|r| r as usize) 633da5c369Sopenharmony_ci} 643da5c369Sopenharmony_ci 653da5c369Sopenharmony_ci/// Read from `fd` at `offset` filling buffers in `iov`. 663da5c369Sopenharmony_ci/// 673da5c369Sopenharmony_ci/// Buffers in `iov` will be filled in order until all buffers have been filled, 683da5c369Sopenharmony_ci/// no more bytes are available, or an error occurs. The file offset is not 693da5c369Sopenharmony_ci/// changed. 703da5c369Sopenharmony_ci/// 713da5c369Sopenharmony_ci/// See also: [`readv`](fn.readv.html) and [`pread`](fn.pread.html) 723da5c369Sopenharmony_ci#[cfg(not(any(target_os = "redox", target_os = "haiku")))] 733da5c369Sopenharmony_ci#[cfg_attr(docsrs, doc(cfg(all())))] 743da5c369Sopenharmony_cipub fn preadv( 753da5c369Sopenharmony_ci fd: RawFd, 763da5c369Sopenharmony_ci iov: &mut [IoSliceMut<'_>], 773da5c369Sopenharmony_ci offset: off_t, 783da5c369Sopenharmony_ci) -> Result<usize> { 793da5c369Sopenharmony_ci #[cfg(target_env = "uclibc")] 803da5c369Sopenharmony_ci let offset = offset as libc::off64_t; // uclibc doesn't use off_t 813da5c369Sopenharmony_ci 823da5c369Sopenharmony_ci // SAFETY: same as in readv() 833da5c369Sopenharmony_ci let res = unsafe { 843da5c369Sopenharmony_ci libc::preadv( 853da5c369Sopenharmony_ci fd, 863da5c369Sopenharmony_ci iov.as_ptr() as *const libc::iovec, 873da5c369Sopenharmony_ci iov.len() as c_int, 883da5c369Sopenharmony_ci offset, 893da5c369Sopenharmony_ci ) 903da5c369Sopenharmony_ci }; 913da5c369Sopenharmony_ci 923da5c369Sopenharmony_ci Errno::result(res).map(|r| r as usize) 933da5c369Sopenharmony_ci} 943da5c369Sopenharmony_ci 953da5c369Sopenharmony_ci/// Low-level write to a file, with specified offset. 963da5c369Sopenharmony_ci/// 973da5c369Sopenharmony_ci/// See also [pwrite(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pwrite.html) 983da5c369Sopenharmony_ci// TODO: move to unistd 993da5c369Sopenharmony_cipub fn pwrite(fd: RawFd, buf: &[u8], offset: off_t) -> Result<usize> { 1003da5c369Sopenharmony_ci let res = unsafe { 1013da5c369Sopenharmony_ci libc::pwrite( 1023da5c369Sopenharmony_ci fd, 1033da5c369Sopenharmony_ci buf.as_ptr() as *const c_void, 1043da5c369Sopenharmony_ci buf.len() as size_t, 1053da5c369Sopenharmony_ci offset, 1063da5c369Sopenharmony_ci ) 1073da5c369Sopenharmony_ci }; 1083da5c369Sopenharmony_ci 1093da5c369Sopenharmony_ci Errno::result(res).map(|r| r as usize) 1103da5c369Sopenharmony_ci} 1113da5c369Sopenharmony_ci 1123da5c369Sopenharmony_ci/// Low-level read from a file, with specified offset. 1133da5c369Sopenharmony_ci/// 1143da5c369Sopenharmony_ci/// See also [pread(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pread.html) 1153da5c369Sopenharmony_ci// TODO: move to unistd 1163da5c369Sopenharmony_cipub fn pread(fd: RawFd, buf: &mut [u8], offset: off_t) -> Result<usize> { 1173da5c369Sopenharmony_ci let res = unsafe { 1183da5c369Sopenharmony_ci libc::pread( 1193da5c369Sopenharmony_ci fd, 1203da5c369Sopenharmony_ci buf.as_mut_ptr() as *mut c_void, 1213da5c369Sopenharmony_ci buf.len() as size_t, 1223da5c369Sopenharmony_ci offset, 1233da5c369Sopenharmony_ci ) 1243da5c369Sopenharmony_ci }; 1253da5c369Sopenharmony_ci 1263da5c369Sopenharmony_ci Errno::result(res).map(|r| r as usize) 1273da5c369Sopenharmony_ci} 1283da5c369Sopenharmony_ci 1293da5c369Sopenharmony_ci/// A slice of memory in a remote process, starting at address `base` 1303da5c369Sopenharmony_ci/// and consisting of `len` bytes. 1313da5c369Sopenharmony_ci/// 1323da5c369Sopenharmony_ci/// This is the same underlying C structure as `IoSlice`, 1333da5c369Sopenharmony_ci/// except that it refers to memory in some other process, and is 1343da5c369Sopenharmony_ci/// therefore not represented in Rust by an actual slice as `IoSlice` is. It 1353da5c369Sopenharmony_ci/// is used with [`process_vm_readv`](fn.process_vm_readv.html) 1363da5c369Sopenharmony_ci/// and [`process_vm_writev`](fn.process_vm_writev.html). 1373da5c369Sopenharmony_ci#[cfg(any(target_os = "linux", target_os = "android"))] 1383da5c369Sopenharmony_ci#[cfg_attr(docsrs, doc(cfg(all())))] 1393da5c369Sopenharmony_ci#[repr(C)] 1403da5c369Sopenharmony_ci#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 1413da5c369Sopenharmony_cipub struct RemoteIoVec { 1423da5c369Sopenharmony_ci /// The starting address of this slice (`iov_base`). 1433da5c369Sopenharmony_ci pub base: usize, 1443da5c369Sopenharmony_ci /// The number of bytes in this slice (`iov_len`). 1453da5c369Sopenharmony_ci pub len: usize, 1463da5c369Sopenharmony_ci} 1473da5c369Sopenharmony_ci 1483da5c369Sopenharmony_ci/// A vector of buffers. 1493da5c369Sopenharmony_ci/// 1503da5c369Sopenharmony_ci/// Vectored I/O methods like [`writev`] and [`readv`] use this structure for 1513da5c369Sopenharmony_ci/// both reading and writing. Each `IoVec` specifies the base address and 1523da5c369Sopenharmony_ci/// length of an area in memory. 1533da5c369Sopenharmony_ci#[deprecated( 1543da5c369Sopenharmony_ci since = "0.24.0", 1553da5c369Sopenharmony_ci note = "`IoVec` is no longer used in the public interface, use `IoSlice` or `IoSliceMut` instead" 1563da5c369Sopenharmony_ci)] 1573da5c369Sopenharmony_ci#[repr(transparent)] 1583da5c369Sopenharmony_ci#[allow(renamed_and_removed_lints)] 1593da5c369Sopenharmony_ci#[allow(clippy::unknown_clippy_lints)] 1603da5c369Sopenharmony_ci// Clippy false positive: https://github.com/rust-lang/rust-clippy/issues/8867 1613da5c369Sopenharmony_ci#[allow(clippy::derive_partial_eq_without_eq)] 1623da5c369Sopenharmony_ci#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 1633da5c369Sopenharmony_cipub struct IoVec<T>(pub(crate) libc::iovec, PhantomData<T>); 1643da5c369Sopenharmony_ci 1653da5c369Sopenharmony_ci#[allow(deprecated)] 1663da5c369Sopenharmony_ciimpl<T> IoVec<T> { 1673da5c369Sopenharmony_ci /// View the `IoVec` as a Rust slice. 1683da5c369Sopenharmony_ci #[deprecated( 1693da5c369Sopenharmony_ci since = "0.24.0", 1703da5c369Sopenharmony_ci note = "Use the `Deref` impl of `IoSlice` or `IoSliceMut` instead" 1713da5c369Sopenharmony_ci )] 1723da5c369Sopenharmony_ci #[inline] 1733da5c369Sopenharmony_ci pub fn as_slice(&self) -> &[u8] { 1743da5c369Sopenharmony_ci use std::slice; 1753da5c369Sopenharmony_ci 1763da5c369Sopenharmony_ci unsafe { 1773da5c369Sopenharmony_ci slice::from_raw_parts(self.0.iov_base as *const u8, self.0.iov_len) 1783da5c369Sopenharmony_ci } 1793da5c369Sopenharmony_ci } 1803da5c369Sopenharmony_ci} 1813da5c369Sopenharmony_ci 1823da5c369Sopenharmony_ci#[allow(deprecated)] 1833da5c369Sopenharmony_ciimpl<'a> IoVec<&'a [u8]> { 1843da5c369Sopenharmony_ci /// Create an `IoVec` from a Rust slice. 1853da5c369Sopenharmony_ci #[deprecated(since = "0.24.0", note = "Use `IoSlice::new` instead")] 1863da5c369Sopenharmony_ci pub fn from_slice(buf: &'a [u8]) -> IoVec<&'a [u8]> { 1873da5c369Sopenharmony_ci IoVec( 1883da5c369Sopenharmony_ci libc::iovec { 1893da5c369Sopenharmony_ci iov_base: buf.as_ptr() as *mut c_void, 1903da5c369Sopenharmony_ci iov_len: buf.len() as size_t, 1913da5c369Sopenharmony_ci }, 1923da5c369Sopenharmony_ci PhantomData, 1933da5c369Sopenharmony_ci ) 1943da5c369Sopenharmony_ci } 1953da5c369Sopenharmony_ci} 1963da5c369Sopenharmony_ci 1973da5c369Sopenharmony_ci#[allow(deprecated)] 1983da5c369Sopenharmony_ciimpl<'a> IoVec<&'a mut [u8]> { 1993da5c369Sopenharmony_ci /// Create an `IoVec` from a mutable Rust slice. 2003da5c369Sopenharmony_ci #[deprecated(since = "0.24.0", note = "Use `IoSliceMut::new` instead")] 2013da5c369Sopenharmony_ci pub fn from_mut_slice(buf: &'a mut [u8]) -> IoVec<&'a mut [u8]> { 2023da5c369Sopenharmony_ci IoVec( 2033da5c369Sopenharmony_ci libc::iovec { 2043da5c369Sopenharmony_ci iov_base: buf.as_ptr() as *mut c_void, 2053da5c369Sopenharmony_ci iov_len: buf.len() as size_t, 2063da5c369Sopenharmony_ci }, 2073da5c369Sopenharmony_ci PhantomData, 2083da5c369Sopenharmony_ci ) 2093da5c369Sopenharmony_ci } 2103da5c369Sopenharmony_ci} 2113da5c369Sopenharmony_ci 2123da5c369Sopenharmony_ci// The only reason IoVec isn't automatically Send+Sync is because libc::iovec 2133da5c369Sopenharmony_ci// contains raw pointers. 2143da5c369Sopenharmony_ci#[allow(deprecated)] 2153da5c369Sopenharmony_ciunsafe impl<T> Send for IoVec<T> where T: Send {} 2163da5c369Sopenharmony_ci#[allow(deprecated)] 2173da5c369Sopenharmony_ciunsafe impl<T> Sync for IoVec<T> where T: Sync {} 2183da5c369Sopenharmony_ci 2193da5c369Sopenharmony_cifeature! { 2203da5c369Sopenharmony_ci#![feature = "process"] 2213da5c369Sopenharmony_ci 2223da5c369Sopenharmony_ci/// Write data directly to another process's virtual memory 2233da5c369Sopenharmony_ci/// (see [`process_vm_writev`(2)]). 2243da5c369Sopenharmony_ci/// 2253da5c369Sopenharmony_ci/// `local_iov` is a list of [`IoSlice`]s containing the data to be written, 2263da5c369Sopenharmony_ci/// and `remote_iov` is a list of [`RemoteIoVec`]s identifying where the 2273da5c369Sopenharmony_ci/// data should be written in the target process. On success, returns the 2283da5c369Sopenharmony_ci/// number of bytes written, which will always be a whole 2293da5c369Sopenharmony_ci/// number of `remote_iov` chunks. 2303da5c369Sopenharmony_ci/// 2313da5c369Sopenharmony_ci/// This requires the same permissions as debugging the process using 2323da5c369Sopenharmony_ci/// [ptrace]: you must either be a privileged process (with 2333da5c369Sopenharmony_ci/// `CAP_SYS_PTRACE`), or you must be running as the same user as the 2343da5c369Sopenharmony_ci/// target process and the OS must have unprivileged debugging enabled. 2353da5c369Sopenharmony_ci/// 2363da5c369Sopenharmony_ci/// This function is only available on Linux and Android(SDK23+). 2373da5c369Sopenharmony_ci/// 2383da5c369Sopenharmony_ci/// [`process_vm_writev`(2)]: https://man7.org/linux/man-pages/man2/process_vm_writev.2.html 2393da5c369Sopenharmony_ci/// [ptrace]: ../ptrace/index.html 2403da5c369Sopenharmony_ci/// [`IoSlice`]: https://doc.rust-lang.org/std/io/struct.IoSlice.html 2413da5c369Sopenharmony_ci/// [`RemoteIoVec`]: struct.RemoteIoVec.html 2423da5c369Sopenharmony_ci#[cfg(all(any(target_os = "linux", target_os = "android"), not(target_env = "uclibc")))] 2433da5c369Sopenharmony_cipub fn process_vm_writev( 2443da5c369Sopenharmony_ci pid: crate::unistd::Pid, 2453da5c369Sopenharmony_ci local_iov: &[IoSlice<'_>], 2463da5c369Sopenharmony_ci remote_iov: &[RemoteIoVec]) -> Result<usize> 2473da5c369Sopenharmony_ci{ 2483da5c369Sopenharmony_ci let res = unsafe { 2493da5c369Sopenharmony_ci libc::process_vm_writev(pid.into(), 2503da5c369Sopenharmony_ci local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong, 2513da5c369Sopenharmony_ci remote_iov.as_ptr() as *const libc::iovec, remote_iov.len() as libc::c_ulong, 0) 2523da5c369Sopenharmony_ci }; 2533da5c369Sopenharmony_ci 2543da5c369Sopenharmony_ci Errno::result(res).map(|r| r as usize) 2553da5c369Sopenharmony_ci} 2563da5c369Sopenharmony_ci 2573da5c369Sopenharmony_ci/// Read data directly from another process's virtual memory 2583da5c369Sopenharmony_ci/// (see [`process_vm_readv`(2)]). 2593da5c369Sopenharmony_ci/// 2603da5c369Sopenharmony_ci/// `local_iov` is a list of [`IoSliceMut`]s containing the buffer to copy 2613da5c369Sopenharmony_ci/// data into, and `remote_iov` is a list of [`RemoteIoVec`]s identifying 2623da5c369Sopenharmony_ci/// where the source data is in the target process. On success, 2633da5c369Sopenharmony_ci/// returns the number of bytes written, which will always be a whole 2643da5c369Sopenharmony_ci/// number of `remote_iov` chunks. 2653da5c369Sopenharmony_ci/// 2663da5c369Sopenharmony_ci/// This requires the same permissions as debugging the process using 2673da5c369Sopenharmony_ci/// [`ptrace`]: you must either be a privileged process (with 2683da5c369Sopenharmony_ci/// `CAP_SYS_PTRACE`), or you must be running as the same user as the 2693da5c369Sopenharmony_ci/// target process and the OS must have unprivileged debugging enabled. 2703da5c369Sopenharmony_ci/// 2713da5c369Sopenharmony_ci/// This function is only available on Linux and Android(SDK23+). 2723da5c369Sopenharmony_ci/// 2733da5c369Sopenharmony_ci/// [`process_vm_readv`(2)]: https://man7.org/linux/man-pages/man2/process_vm_readv.2.html 2743da5c369Sopenharmony_ci/// [`ptrace`]: ../ptrace/index.html 2753da5c369Sopenharmony_ci/// [`IoSliceMut`]: https://doc.rust-lang.org/std/io/struct.IoSliceMut.html 2763da5c369Sopenharmony_ci/// [`RemoteIoVec`]: struct.RemoteIoVec.html 2773da5c369Sopenharmony_ci#[cfg(all(any(target_os = "linux", target_os = "android"), not(target_env = "uclibc")))] 2783da5c369Sopenharmony_cipub fn process_vm_readv( 2793da5c369Sopenharmony_ci pid: crate::unistd::Pid, 2803da5c369Sopenharmony_ci local_iov: &mut [IoSliceMut<'_>], 2813da5c369Sopenharmony_ci remote_iov: &[RemoteIoVec]) -> Result<usize> 2823da5c369Sopenharmony_ci{ 2833da5c369Sopenharmony_ci let res = unsafe { 2843da5c369Sopenharmony_ci libc::process_vm_readv(pid.into(), 2853da5c369Sopenharmony_ci local_iov.as_ptr() as *const libc::iovec, local_iov.len() as libc::c_ulong, 2863da5c369Sopenharmony_ci remote_iov.as_ptr() as *const libc::iovec, remote_iov.len() as libc::c_ulong, 0) 2873da5c369Sopenharmony_ci }; 2883da5c369Sopenharmony_ci 2893da5c369Sopenharmony_ci Errno::result(res).map(|r| r as usize) 2903da5c369Sopenharmony_ci} 2913da5c369Sopenharmony_ci} 292