rustix/io/read_write.rs
1//! `read` and `write`, optionally positioned, optionally vectored.
2
3#![allow(unsafe_code)]
4
5use crate::buffer::split_init;
6use crate::{backend, io};
7use backend::fd::AsFd;
8use core::mem::MaybeUninit;
9
10// Declare `IoSlice` and `IoSliceMut`.
11#[cfg(not(windows))]
12pub use crate::maybe_polyfill::io::{IoSlice, IoSliceMut};
13
14#[cfg(linux_kernel)]
15pub use backend::io::types::ReadWriteFlags;
16
17/// `read(fd, buf)`—Reads from a stream.
18///
19/// This takes a `&mut [u8]` which Rust requires to contain initialized memory.
20/// To use an uninitialized buffer, use [`read_uninit`].
21///
22/// # References
23/// - [POSIX]
24/// - [Linux]
25/// - [Apple]
26/// - [FreeBSD]
27/// - [NetBSD]
28/// - [OpenBSD]
29/// - [DragonFly BSD]
30/// - [illumos]
31/// - [glibc]
32///
33/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/read.html
34/// [Linux]: https://man7.org/linux/man-pages/man2/read.2.html
35/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/read.2.html
36/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=read&sektion=2
37/// [NetBSD]: https://man.netbsd.org/read.2
38/// [OpenBSD]: https://man.openbsd.org/read.2
39/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=read§ion=2
40/// [illumos]: https://illumos.org/man/2/read
41/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/I_002fO-Primitives.html#index-reading-from-a-file-descriptor
42#[inline]
43pub fn read<Fd: AsFd>(fd: Fd, buf: &mut [u8]) -> io::Result<usize> {
44 unsafe { backend::io::syscalls::read(fd.as_fd(), buf.as_mut_ptr(), buf.len()) }
45}
46
47/// `read(fd, buf)`—Reads from a stream.
48///
49/// This is equivalent to [`read`], except that it can read into uninitialized
50/// memory. It returns the slice that was initialized by this function and the
51/// slice that remains uninitialized.
52#[inline]
53pub fn read_uninit<Fd: AsFd>(
54 fd: Fd,
55 buf: &mut [MaybeUninit<u8>],
56) -> io::Result<(&mut [u8], &mut [MaybeUninit<u8>])> {
57 // Get number of initialized bytes.
58 let length = unsafe {
59 backend::io::syscalls::read(fd.as_fd(), buf.as_mut_ptr().cast::<u8>(), buf.len())
60 };
61
62 // Split into the initialized and uninitialized portions.
63 Ok(unsafe { split_init(buf, length?) })
64}
65
66/// `write(fd, buf)`—Writes to a stream.
67///
68/// # References
69/// - [POSIX]
70/// - [Linux]
71/// - [Apple]
72/// - [FreeBSD]
73/// - [NetBSD]
74/// - [OpenBSD]
75/// - [DragonFly BSD]
76/// - [illumos]
77/// - [glibc]
78///
79/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/write.html
80/// [Linux]: https://man7.org/linux/man-pages/man2/write.2.html
81/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/write.2.html
82/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=write&sektion=2
83/// [NetBSD]: https://man.netbsd.org/write.2
84/// [OpenBSD]: https://man.openbsd.org/write.2
85/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=write§ion=2
86/// [illumos]: https://illumos.org/man/2/write
87/// [glibc]: https://www.gnu.org/software/libc/manual/html_node/I_002fO-Primitives.html#index-writing-to-a-file-descriptor
88#[inline]
89pub fn write<Fd: AsFd>(fd: Fd, buf: &[u8]) -> io::Result<usize> {
90 backend::io::syscalls::write(fd.as_fd(), buf)
91}
92
93/// `pread(fd, buf, offset)`—Reads from a file at a given position.
94///
95/// This takes a `&mut [u8]` which Rust requires to contain initialized memory.
96/// To use an uninitialized buffer, use [`pread_uninit`].
97///
98/// # References
99/// - [POSIX]
100/// - [Linux]
101/// - [Apple]
102/// - [FreeBSD]
103/// - [NetBSD]
104/// - [OpenBSD]
105/// - [DragonFly BSD]
106/// - [illumos]
107///
108/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/pread.html
109/// [Linux]: https://man7.org/linux/man-pages/man2/pread.2.html
110/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/pread.2.html
111/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=pread&sektion=2
112/// [NetBSD]: https://man.netbsd.org/pread.2
113/// [OpenBSD]: https://man.openbsd.org/pread.2
114/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=pread§ion=2
115/// [illumos]: https://illumos.org/man/2/pread
116#[inline]
117pub fn pread<Fd: AsFd>(fd: Fd, buf: &mut [u8], offset: u64) -> io::Result<usize> {
118 unsafe { backend::io::syscalls::pread(fd.as_fd(), buf.as_mut_ptr(), buf.len(), offset) }
119}
120
121/// `pread(fd, buf, offset)`—Reads from a file at a given position.
122///
123/// This is equivalent to [`pread`], except that it can read into uninitialized
124/// memory. It returns the slice that was initialized by this function and the
125/// slice that remains uninitialized.
126#[inline]
127pub fn pread_uninit<Fd: AsFd>(
128 fd: Fd,
129 buf: &mut [MaybeUninit<u8>],
130 offset: u64,
131) -> io::Result<(&mut [u8], &mut [MaybeUninit<u8>])> {
132 let length = unsafe {
133 backend::io::syscalls::pread(fd.as_fd(), buf.as_mut_ptr().cast::<u8>(), buf.len(), offset)
134 };
135 Ok(unsafe { split_init(buf, length?) })
136}
137
138/// `pwrite(fd, bufs)`—Writes to a file at a given position.
139///
140/// Contrary to POSIX, on many popular platforms including Linux and FreeBSD,
141/// if the file is opened in append mode, this ignores the offset appends the
142/// data to the end of the file.
143///
144/// # References
145/// - [POSIX]
146/// - [Linux]
147/// - [Apple]
148/// - [FreeBSD]
149/// - [NetBSD]
150/// - [OpenBSD]
151/// - [DragonFly BSD]
152/// - [illumos]
153///
154/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/pwrite.html
155/// [Linux]: https://man7.org/linux/man-pages/man2/pwrite.2.html
156/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/pwrite.2.html
157/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=pwrite&sektion=2
158/// [NetBSD]: https://man.netbsd.org/pwrite.2
159/// [OpenBSD]: https://man.openbsd.org/pwrite.2
160/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=pwrite§ion=2
161/// [illumos]: https://illumos.org/man/2/pwrite
162#[inline]
163pub fn pwrite<Fd: AsFd>(fd: Fd, buf: &[u8], offset: u64) -> io::Result<usize> {
164 backend::io::syscalls::pwrite(fd.as_fd(), buf, offset)
165}
166
167/// `readv(fd, bufs)`—Reads from a stream into multiple buffers.
168///
169/// # References
170/// - [POSIX]
171/// - [Linux]
172/// - [Apple]
173/// - [FreeBSD]
174/// - [NetBSD]
175/// - [OpenBSD]
176/// - [DragonFly BSD]
177/// - [illumos]
178///
179/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/readv.html
180/// [Linux]: https://man7.org/linux/man-pages/man2/readv.2.html
181/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/readv.2.html
182/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=readv&sektion=2
183/// [NetBSD]: https://man.netbsd.org/readv.2
184/// [OpenBSD]: https://man.openbsd.org/readv.2
185/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=readv§ion=2
186/// [illumos]: https://illumos.org/man/2/readv
187#[cfg(not(any(target_os = "espidf", target_os = "horizon")))]
188#[inline]
189pub fn readv<Fd: AsFd>(fd: Fd, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
190 backend::io::syscalls::readv(fd.as_fd(), bufs)
191}
192
193/// `writev(fd, bufs)`—Writes to a stream from multiple buffers.
194///
195/// # References
196/// - [POSIX]
197/// - [Linux]
198/// - [Apple]
199/// - [FreeBSD]
200/// - [NetBSD]
201/// - [OpenBSD]
202/// - [DragonFly BSD]
203/// - [illumos]
204///
205/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/writev.html
206/// [Linux]: https://man7.org/linux/man-pages/man2/writev.2.html
207/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/writev.2.html
208/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=writev&sektion=2
209/// [NetBSD]: https://man.netbsd.org/writev.2
210/// [OpenBSD]: https://man.openbsd.org/writev.2
211/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=writev§ion=2
212/// [illumos]: https://illumos.org/man/2/writev
213#[cfg(not(any(target_os = "espidf", target_os = "horizon")))]
214#[inline]
215pub fn writev<Fd: AsFd>(fd: Fd, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
216 backend::io::syscalls::writev(fd.as_fd(), bufs)
217}
218
219/// `preadv(fd, bufs, offset)`—Reads from a file at a given position into
220/// multiple buffers.
221///
222/// # References
223/// - [Linux]
224/// - [FreeBSD]
225/// - [NetBSD]
226/// - [OpenBSD]
227/// - [DragonFly BSD]
228/// - [illumos]
229///
230/// [Linux]: https://man7.org/linux/man-pages/man2/preadv.2.html
231/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=preadv&sektion=2
232/// [NetBSD]: https://man.netbsd.org/preadv.2
233/// [OpenBSD]: https://man.openbsd.org/preadv.2
234/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=preadv§ion=2
235/// [illumos]: https://illumos.org/man/2/preadv
236#[cfg(not(any(
237 target_os = "espidf",
238 target_os = "haiku",
239 target_os = "horizon",
240 target_os = "nto",
241 target_os = "redox",
242 target_os = "solaris",
243 target_os = "vita"
244)))]
245#[inline]
246pub fn preadv<Fd: AsFd>(fd: Fd, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
247 backend::io::syscalls::preadv(fd.as_fd(), bufs, offset)
248}
249
250/// `pwritev(fd, bufs, offset)`—Writes to a file at a given position from
251/// multiple buffers.
252///
253/// Contrary to POSIX, on many popular platforms including Linux and FreeBSD,
254/// if the file is opened in append mode, this ignores the offset appends the
255/// data to the end of the file.
256///
257/// # References
258/// - [Linux]
259/// - [FreeBSD]
260/// - [NetBSD]
261/// - [OpenBSD]
262/// - [DragonFly BSD]
263/// - [illumos]
264///
265/// [Linux]: https://man7.org/linux/man-pages/man2/pwritev.2.html
266/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=pwritev&sektion=2
267/// [NetBSD]: https://man.netbsd.org/pwritev.2
268/// [OpenBSD]: https://man.openbsd.org/pwritev.2
269/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=pwritev§ion=2
270/// [illumos]: https://illumos.org/man/2/pwritev
271#[cfg(not(any(
272 target_os = "espidf",
273 target_os = "haiku",
274 target_os = "horizon",
275 target_os = "nto",
276 target_os = "redox",
277 target_os = "solaris",
278 target_os = "vita"
279)))]
280#[inline]
281pub fn pwritev<Fd: AsFd>(fd: Fd, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
282 backend::io::syscalls::pwritev(fd.as_fd(), bufs, offset)
283}
284
285/// `preadv2(fd, bufs, offset, flags)`—Reads data, with several options.
286///
287/// An `offset` of `u64::MAX` means to use and update the current file offset.
288///
289/// # References
290/// - [Linux]
291///
292/// [Linux]: https://man7.org/linux/man-pages/man2/preadv2.2.html
293#[cfg(linux_kernel)]
294#[inline]
295pub fn preadv2<Fd: AsFd>(
296 fd: Fd,
297 bufs: &mut [IoSliceMut<'_>],
298 offset: u64,
299 flags: ReadWriteFlags,
300) -> io::Result<usize> {
301 backend::io::syscalls::preadv2(fd.as_fd(), bufs, offset, flags)
302}
303
304/// `pwritev2(fd, bufs, offset, flags)`—Writes data, with several options.
305///
306/// An `offset` of `u64::MAX` means to use and update the current file offset.
307///
308/// # References
309/// - [Linux]
310///
311/// [Linux]: https://man7.org/linux/man-pages/man2/pwritev2.2.html
312#[cfg(linux_kernel)]
313#[inline]
314pub fn pwritev2<Fd: AsFd>(
315 fd: Fd,
316 bufs: &[IoSlice<'_>],
317 offset: u64,
318 flags: ReadWriteFlags,
319) -> io::Result<usize> {
320 backend::io::syscalls::pwritev2(fd.as_fd(), bufs, offset, flags)
321}