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