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 (linux_kernel)] |
15 | pub 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://sourceware.org/glibc/manual/latest/html_node/I_002fO-Primitives.html#index-reading-from-a-file-descriptor |
42 | #[inline ] |
43 | pub 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 ] |
53 | pub 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: Result = 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, init_len: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://sourceware.org/glibc/manual/latest/html_node/I_002fO-Primitives.html#index-writing-to-a-file-descriptor |
88 | #[inline ] |
89 | pub 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§ion=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 ] |
119 | pub 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(), pos: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 ] |
129 | pub 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: Result = unsafe { |
135 | backend::io::syscalls::pread(fd.as_fd(), buf.as_mut_ptr().cast::<u8>(), buf.len(), pos:offset) |
136 | }; |
137 | Ok(unsafe { split_init(buf, init_len: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§ion=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 ] |
167 | pub fn pwrite<Fd: AsFd>(fd: Fd, buf: &[u8], offset: u64) -> io::Result<usize> { |
168 | backend::io::syscalls::pwrite(fd.as_fd(), buf, pos: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§ion=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 ] |
195 | pub 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§ion=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 ] |
223 | pub 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§ion=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 ] |
256 | pub fn preadv<Fd: AsFd>(fd: Fd, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> { |
257 | backend::io::syscalls::preadv(fd.as_fd(), bufs, pos: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§ion=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 ] |
293 | pub fn pwritev<Fd: AsFd>(fd: Fd, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> { |
294 | backend::io::syscalls::pwritev(fd.as_fd(), bufs, pos: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 ] |
309 | pub 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, pos: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 ] |
330 | pub 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, pos:offset, flags) |
337 | } |
338 | |