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&section=2
40/// [illumos]: https://illumos.org/man/2/read
41/// [glibc]: https://sourceware.org/glibc/manual/latest/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&section=2
86/// [illumos]: https://illumos.org/man/2/write
87/// [glibc]: https://sourceware.org/glibc/manual/latest/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///  - [glibc]
108///
109/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/pread.html
110/// [Linux]: https://man7.org/linux/man-pages/man2/pread.2.html
111/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/pread.2.html
112/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=pread&sektion=2
113/// [NetBSD]: https://man.netbsd.org/pread.2
114/// [OpenBSD]: https://man.openbsd.org/pread.2
115/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=pread&section=2
116/// [illumos]: https://illumos.org/man/2/pread
117/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/I_002fO-Primitives.html#index-pread64
118#[inline]
119pub fn pread<Fd: AsFd>(fd: Fd, buf: &mut [u8], offset: u64) -> io::Result<usize> {
120    unsafe { backend::io::syscalls::pread(fd.as_fd(), buf.as_mut_ptr(), buf.len(), offset) }
121}
122
123/// `pread(fd, buf, offset)`—Reads from a file at a given position.
124///
125/// This is equivalent to [`pread`], except that it can read into uninitialized
126/// memory. It returns the slice that was initialized by this function and the
127/// slice that remains uninitialized.
128#[inline]
129pub fn pread_uninit<Fd: AsFd>(
130    fd: Fd,
131    buf: &mut [MaybeUninit<u8>],
132    offset: u64,
133) -> io::Result<(&mut [u8], &mut [MaybeUninit<u8>])> {
134    let length = unsafe {
135        backend::io::syscalls::pread(fd.as_fd(), buf.as_mut_ptr().cast::<u8>(), buf.len(), offset)
136    };
137    Ok(unsafe { split_init(buf, length?) })
138}
139
140/// `pwrite(fd, bufs)`—Writes to a file at a given position.
141///
142/// Contrary to POSIX, on many popular platforms including Linux and FreeBSD,
143/// if the file is opened in append mode, this ignores the offset appends the
144/// data to the end of the file.
145///
146/// # References
147///  - [POSIX]
148///  - [Linux]
149///  - [Apple]
150///  - [FreeBSD]
151///  - [NetBSD]
152///  - [OpenBSD]
153///  - [DragonFly BSD]
154///  - [illumos]
155///  - [glibc]
156///
157/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/pwrite.html
158/// [Linux]: https://man7.org/linux/man-pages/man2/pwrite.2.html
159/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/pwrite.2.html
160/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=pwrite&sektion=2
161/// [NetBSD]: https://man.netbsd.org/pwrite.2
162/// [OpenBSD]: https://man.openbsd.org/pwrite.2
163/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=pwrite&section=2
164/// [illumos]: https://illumos.org/man/2/pwrite
165/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/I_002fO-Primitives.html#index-pwrite64
166#[inline]
167pub fn pwrite<Fd: AsFd>(fd: Fd, buf: &[u8], offset: u64) -> io::Result<usize> {
168    backend::io::syscalls::pwrite(fd.as_fd(), buf, offset)
169}
170
171/// `readv(fd, bufs)`—Reads from a stream into multiple buffers.
172///
173/// # References
174///  - [POSIX]
175///  - [Linux]
176///  - [Apple]
177///  - [FreeBSD]
178///  - [NetBSD]
179///  - [OpenBSD]
180///  - [DragonFly BSD]
181///  - [illumos]
182///  - [glibc]
183///
184/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/readv.html
185/// [Linux]: https://man7.org/linux/man-pages/man2/readv.2.html
186/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/readv.2.html
187/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=readv&sektion=2
188/// [NetBSD]: https://man.netbsd.org/readv.2
189/// [OpenBSD]: https://man.openbsd.org/readv.2
190/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=readv&section=2
191/// [illumos]: https://illumos.org/man/2/readv
192/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Scatter_002dGather.html#index-readv
193#[cfg(not(any(target_os = "espidf", target_os = "horizon")))]
194#[inline]
195pub fn readv<Fd: AsFd>(fd: Fd, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
196    backend::io::syscalls::readv(fd.as_fd(), bufs)
197}
198
199/// `writev(fd, bufs)`—Writes to a stream from multiple buffers.
200///
201/// # References
202///  - [POSIX]
203///  - [Linux]
204///  - [Apple]
205///  - [FreeBSD]
206///  - [NetBSD]
207///  - [OpenBSD]
208///  - [DragonFly BSD]
209///  - [illumos]
210///  - [glibc]
211///
212/// [POSIX]: https://pubs.opengroup.org/onlinepubs/9799919799/functions/writev.html
213/// [Linux]: https://man7.org/linux/man-pages/man2/writev.2.html
214/// [Apple]: https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/writev.2.html
215/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=writev&sektion=2
216/// [NetBSD]: https://man.netbsd.org/writev.2
217/// [OpenBSD]: https://man.openbsd.org/writev.2
218/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=writev&section=2
219/// [illumos]: https://illumos.org/man/2/writev
220/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Scatter_002dGather.html#index-writev
221#[cfg(not(any(target_os = "espidf", target_os = "horizon")))]
222#[inline]
223pub fn writev<Fd: AsFd>(fd: Fd, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
224    backend::io::syscalls::writev(fd.as_fd(), bufs)
225}
226
227/// `preadv(fd, bufs, offset)`—Reads from a file at a given position into
228/// multiple buffers.
229///
230/// # References
231///  - [Linux]
232///  - [FreeBSD]
233///  - [NetBSD]
234///  - [OpenBSD]
235///  - [DragonFly BSD]
236///  - [illumos]
237///  - [glibc]
238///
239/// [Linux]: https://man7.org/linux/man-pages/man2/preadv.2.html
240/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=preadv&sektion=2
241/// [NetBSD]: https://man.netbsd.org/preadv.2
242/// [OpenBSD]: https://man.openbsd.org/preadv.2
243/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=preadv&section=2
244/// [illumos]: https://illumos.org/man/2/preadv
245/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Scatter_002dGather.html#index-preadv64
246#[cfg(not(any(
247    target_os = "espidf",
248    target_os = "haiku",
249    target_os = "horizon",
250    target_os = "nto",
251    target_os = "redox",
252    target_os = "solaris",
253    target_os = "vita"
254)))]
255#[inline]
256pub fn preadv<Fd: AsFd>(fd: Fd, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
257    backend::io::syscalls::preadv(fd.as_fd(), bufs, offset)
258}
259
260/// `pwritev(fd, bufs, offset)`—Writes to a file at a given position from
261/// multiple buffers.
262///
263/// Contrary to POSIX, on many popular platforms including Linux and FreeBSD,
264/// if the file is opened in append mode, this ignores the offset appends the
265/// data to the end of the file.
266///
267/// # References
268///  - [Linux]
269///  - [FreeBSD]
270///  - [NetBSD]
271///  - [OpenBSD]
272///  - [DragonFly BSD]
273///  - [illumos]
274///  - [glibc]
275///
276/// [Linux]: https://man7.org/linux/man-pages/man2/pwritev.2.html
277/// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=pwritev&sektion=2
278/// [NetBSD]: https://man.netbsd.org/pwritev.2
279/// [OpenBSD]: https://man.openbsd.org/pwritev.2
280/// [DragonFly BSD]: https://man.dragonflybsd.org/?command=pwritev&section=2
281/// [illumos]: https://illumos.org/man/2/pwritev
282/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/I_002fO-Primitives.html#index-pwrite64
283#[cfg(not(any(
284    target_os = "espidf",
285    target_os = "haiku",
286    target_os = "horizon",
287    target_os = "nto",
288    target_os = "redox",
289    target_os = "solaris",
290    target_os = "vita"
291)))]
292#[inline]
293pub fn pwritev<Fd: AsFd>(fd: Fd, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
294    backend::io::syscalls::pwritev(fd.as_fd(), bufs, offset)
295}
296
297/// `preadv2(fd, bufs, offset, flags)`—Reads data, with several options.
298///
299/// An `offset` of `u64::MAX` means to use and update the current file offset.
300///
301/// # References
302///  - [Linux]
303///  - [glibc]
304///
305/// [Linux]: https://man7.org/linux/man-pages/man2/preadv2.2.html
306/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Scatter_002dGather.html#index-preadv64v2
307#[cfg(linux_kernel)]
308#[inline]
309pub fn preadv2<Fd: AsFd>(
310    fd: Fd,
311    bufs: &mut [IoSliceMut<'_>],
312    offset: u64,
313    flags: ReadWriteFlags,
314) -> io::Result<usize> {
315    backend::io::syscalls::preadv2(fd.as_fd(), bufs, offset, flags)
316}
317
318/// `pwritev2(fd, bufs, offset, flags)`—Writes data, with several options.
319///
320/// An `offset` of `u64::MAX` means to use and update the current file offset.
321///
322/// # References
323///  - [Linux]
324///  - [glibc]
325///
326/// [Linux]: https://man7.org/linux/man-pages/man2/pwritev2.2.html
327/// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Scatter_002dGather.html#index-pwritev64v2
328#[cfg(linux_kernel)]
329#[inline]
330pub fn pwritev2<Fd: AsFd>(
331    fd: Fd,
332    bufs: &[IoSlice<'_>],
333    offset: u64,
334    flags: ReadWriteFlags,
335) -> io::Result<usize> {
336    backend::io::syscalls::pwritev2(fd.as_fd(), bufs, offset, flags)
337}