1 //! `read` and `write`, optionally positioned, optionally vectored
2
3 #![allow(unsafe_code)]
4
5 use crate::buffer::split_init;
6 use crate::{backend, io};
7 use backend::fd::AsFd;
8 use core::mem::MaybeUninit;
9
10 // Declare `IoSlice` and `IoSliceMut`.
11 #[cfg(not(windows))]
12 pub use crate::maybe_polyfill::io::{IoSlice, IoSliceMut};
13
14 #[cfg(feature = "linux-raw-sys")]
15 pub 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§ion=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]
read<Fd: AsFd>(fd: Fd, buf: &mut [u8]) -> io::Result<usize>40 pub fn read<Fd: AsFd>(fd: Fd, buf: &mut [u8]) -> io::Result<usize> {
41 unsafe { backend::io::syscalls::read(fd.as_fd(), 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]
read_uninit<Fd: AsFd>( fd: Fd, buf: &mut [MaybeUninit<u8>], ) -> io::Result<(&mut [u8], &mut [MaybeUninit<u8>])>50 pub 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 =
56 unsafe { backend::io::syscalls::read(fd.as_fd(), buf.as_mut_ptr() as *mut u8, buf.len()) };
57
58 // Split into the initialized and uninitialized portions.
59 Ok(unsafe { split_init(buf, 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§ion=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]
write<Fd: AsFd>(fd: Fd, buf: &[u8]) -> io::Result<usize>85 pub 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§ion=2
108 /// [illumos]: https://illumos.org/man/2/pread
109 #[inline]
pread<Fd: AsFd>(fd: Fd, buf: &mut [u8], offset: u64) -> io::Result<usize>110 pub fn pread<Fd: AsFd>(fd: Fd, buf: &mut [u8], offset: u64) -> io::Result<usize> {
111 unsafe { backend::io::syscalls::pread(fd.as_fd(), buf.as_mut_ptr(), buf.len(), 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]
pread_uninit<Fd: AsFd>( fd: Fd, buf: &mut [MaybeUninit<u8>], offset: u64, ) -> io::Result<(&mut [u8], &mut [MaybeUninit<u8>])>120 pub 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 = unsafe {
126 backend::io::syscalls::pread(fd.as_fd(), buf.as_mut_ptr() as *mut u8, buf.len(), offset)
127 };
128 Ok(unsafe { split_init(buf, 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§ion=2
154 /// [illumos]: https://illumos.org/man/2/pwrite
155 #[inline]
pwrite<Fd: AsFd>(fd: Fd, buf: &[u8], offset: u64) -> io::Result<usize>156 pub fn pwrite<Fd: AsFd>(fd: Fd, buf: &[u8], offset: u64) -> io::Result<usize> {
157 backend::io::syscalls::pwrite(fd.as_fd(), buf, 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§ion=2
179 /// [illumos]: https://illumos.org/man/2/readv
180 #[cfg(not(target_os = "espidf"))]
181 #[inline]
readv<Fd: AsFd>(fd: Fd, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize>182 pub 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§ion=2
205 /// [illumos]: https://illumos.org/man/2/writev
206 #[cfg(not(target_os = "espidf"))]
207 #[inline]
writev<Fd: AsFd>(fd: Fd, bufs: &[IoSlice<'_>]) -> io::Result<usize>208 pub 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§ion=2
228 /// [illumos]: https://illumos.org/man/2/preadv
229 #[cfg(not(any(
230 target_os = "espidf",
231 target_os = "haiku",
232 target_os = "nto",
233 target_os = "redox",
234 target_os = "solaris",
235 target_os = "vita"
236 )))]
237 #[inline]
preadv<Fd: AsFd>(fd: Fd, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize>238 pub fn preadv<Fd: AsFd>(fd: Fd, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
239 backend::io::syscalls::preadv(fd.as_fd(), bufs, offset)
240 }
241
242 /// `pwritev(fd, bufs, offset)`—Writes to a file at a given position from
243 /// multiple buffers.
244 ///
245 /// Contrary to POSIX, on many popular platforms including Linux and FreeBSD,
246 /// if the file is opened in append mode, this ignores the offset appends the
247 /// data to the end of the file.
248 ///
249 /// # References
250 /// - [Linux]
251 /// - [FreeBSD]
252 /// - [NetBSD]
253 /// - [OpenBSD]
254 /// - [DragonFly BSD]
255 /// - [illumos]
256 ///
257 /// [Linux]: https://man7.org/linux/man-pages/man2/pwritev.2.html
258 /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=pwritev&sektion=2
259 /// [NetBSD]: https://man.netbsd.org/pwritev.2
260 /// [OpenBSD]: https://man.openbsd.org/pwritev.2
261 /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=pwritev§ion=2
262 /// [illumos]: https://illumos.org/man/2/pwritev
263 #[cfg(not(any(
264 target_os = "espidf",
265 target_os = "haiku",
266 target_os = "nto",
267 target_os = "redox",
268 target_os = "solaris",
269 target_os = "vita"
270 )))]
271 #[inline]
pwritev<Fd: AsFd>(fd: Fd, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize>272 pub fn pwritev<Fd: AsFd>(fd: Fd, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
273 backend::io::syscalls::pwritev(fd.as_fd(), bufs, offset)
274 }
275
276 /// `preadv2(fd, bufs, offset, flags)`—Reads data, with several options.
277 ///
278 /// An `offset` of `u64::MAX` means to use and update the current file offset.
279 ///
280 /// # References
281 /// - [Linux]
282 ///
283 /// [Linux]: https://man7.org/linux/man-pages/man2/preadv2.2.html
284 #[cfg(feature = "linux-raw-sys")]
285 #[inline]
preadv2<Fd: AsFd>( fd: Fd, bufs: &mut [IoSliceMut<'_>], offset: u64, flags: ReadWriteFlags, ) -> io::Result<usize>286 pub fn preadv2<Fd: AsFd>(
287 fd: Fd,
288 bufs: &mut [IoSliceMut<'_>],
289 offset: u64,
290 flags: ReadWriteFlags,
291 ) -> io::Result<usize> {
292 backend::io::syscalls::preadv2(fd.as_fd(), bufs, offset, flags)
293 }
294
295 /// `pwritev2(fd, bufs, offset, flags)`—Writes data, with several options.
296 ///
297 /// An `offset` of `u64::MAX` means to use and update the current file offset.
298 ///
299 /// # References
300 /// - [Linux]
301 ///
302 /// [Linux]: https://man7.org/linux/man-pages/man2/pwritev2.2.html
303 #[cfg(feature = "linux-raw-sys")]
304 #[inline]
pwritev2<Fd: AsFd>( fd: Fd, bufs: &[IoSlice<'_>], offset: u64, flags: ReadWriteFlags, ) -> io::Result<usize>305 pub fn pwritev2<Fd: AsFd>(
306 fd: Fd,
307 bufs: &[IoSlice<'_>],
308 offset: u64,
309 flags: ReadWriteFlags,
310 ) -> io::Result<usize> {
311 backend::io::syscalls::pwritev2(fd.as_fd(), bufs, offset, flags)
312 }
313