Skip to content

Commit 74e016c

Browse files
committed
Add read_buf equivalents for positioned reads
Adds the following items under the `read_buf` (#78485) feature: - `std::os::unix::FileExt::read_buf_at` - `std::os::unix::FileExt::read_buf_exact_at` - `std::os::windows::FileExt::seek_read_buf`
1 parent 4c83e55 commit 74e016c

File tree

6 files changed

+117
-14
lines changed

6 files changed

+117
-14
lines changed

library/std/src/os/unix/fs.rs

+40
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use super::platform::fs::MetadataExt as _;
1111
// Used for `File::read` on intra-doc links
1212
use crate::ffi::OsStr;
1313
use crate::fs::{self, OpenOptions, Permissions};
14+
use crate::io::BorrowedCursor;
1415
use crate::os::unix::io::{AsFd, AsRawFd};
1516
use crate::path::Path;
1617
use crate::sealed::Sealed;
@@ -130,6 +131,42 @@ pub trait FileExt {
130131
if !buf.is_empty() { Err(io::Error::READ_EXACT_EOF) } else { Ok(()) }
131132
}
132133

134+
/// Reads some bytes starting from a given offset into the buffer.
135+
///
136+
/// This equivalent to the [`read_at`](FileExt::read_at) method,
137+
/// except that it is passed a [`BorrowedCursor`] rather than `&mut [u8]` to allow
138+
/// use with uninitialized buffers. The new data will be appended to any
139+
/// existing contents of `buf`.
140+
#[unstable(feature = "read_buf", issue = "78485")]
141+
fn read_buf_at(&self, buf: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
142+
io::default_read_buf(|b| self.read_at(b, offset), buf)
143+
}
144+
145+
/// Reads the exact number of bytes required to fill the buffer from a given
146+
/// offset.
147+
///
148+
/// This is equivalent to the [`read_exact_at`](FileExt::read_exact_at) method,
149+
/// except that it is passed a [`BorrowedCursor`] rather than `&mut [u8]` to allow
150+
/// use with uninitialized buffers. The new data will be appended to any
151+
/// existing contents of `buf`.
152+
#[unstable(feature = "read_buf", issue = "78485")]
153+
fn read_buf_exact_at(&self, mut buf: BorrowedCursor<'_>, mut offset: u64) -> io::Result<()> {
154+
while buf.capacity() > 0 {
155+
let prev_written = buf.written();
156+
match self.read_buf_at(buf.reborrow(), offset) {
157+
Ok(()) => {}
158+
Err(e) if e.is_interrupted() => {}
159+
Err(e) => return Err(e),
160+
}
161+
let n = buf.written() - prev_written;
162+
offset += n as u64;
163+
if n == 0 {
164+
return Err(io::Error::READ_EXACT_EOF);
165+
}
166+
}
167+
Ok(())
168+
}
169+
133170
/// Writes a number of bytes starting from a given offset.
134171
///
135172
/// Returns the number of bytes written.
@@ -264,6 +301,9 @@ impl FileExt for fs::File {
264301
fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
265302
self.as_inner().read_at(buf, offset)
266303
}
304+
fn read_buf_at(&self, buf: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
305+
self.as_inner().read_buf_at(buf, offset)
306+
}
267307
fn read_vectored_at(&self, bufs: &mut [io::IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
268308
self.as_inner().read_vectored_at(bufs, offset)
269309
}

library/std/src/os/windows/fs.rs

+19
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#![stable(feature = "rust1", since = "1.0.0")]
66

77
use crate::fs::{self, Metadata, OpenOptions};
8+
use crate::io::BorrowedCursor;
89
use crate::path::Path;
910
use crate::sealed::Sealed;
1011
use crate::sys_common::{AsInner, AsInnerMut, IntoInner};
@@ -49,6 +50,20 @@ pub trait FileExt {
4950
#[stable(feature = "file_offset", since = "1.15.0")]
5051
fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
5152

53+
/// Seeks to a given position and reads some bytes into the buffer.
54+
///
55+
/// This is equivalent to the [`seek_read`](FileExt::seek_read) method, except
56+
/// that it is passed a [`BorrowedCursor`] rather than `&mut [u8]` to allow use
57+
/// with uninitialized buffers. The new data will be appended to any existing
58+
/// contents of `buf`.
59+
///
60+
/// Reading beyond the end of the file will always succeed without reading
61+
/// any bytes.
62+
#[unstable(feature = "read_buf", issue = "78485")]
63+
fn seek_read_buf(&self, buf: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
64+
io::default_read_buf(|b| self.seek_read(b, offset), buf)
65+
}
66+
5267
/// Seeks to a given position and writes a number of bytes.
5368
///
5469
/// Returns the number of bytes written.
@@ -89,6 +104,10 @@ impl FileExt for fs::File {
89104
self.as_inner().read_at(buf, offset)
90105
}
91106

107+
fn seek_read_buf(&self, buf: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
108+
self.as_inner().read_at_buf(buf, offset)
109+
}
110+
92111
fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
93112
self.as_inner().write_at(buf, offset)
94113
}

library/std/src/sys/fd/unix.rs

+32-14
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,19 @@ const fn max_iov() -> usize {
8787
16 // The minimum value required by POSIX.
8888
}
8989

90+
#[cfg(not(any(
91+
all(target_os = "linux", not(target_env = "musl")),
92+
target_os = "android",
93+
target_os = "hurd"
94+
)))]
95+
use libc::pread as pread64;
96+
#[cfg(any(
97+
all(target_os = "linux", not(target_env = "musl")),
98+
target_os = "android",
99+
target_os = "hurd"
100+
))]
101+
use libc::pread64;
102+
90103
impl FileDesc {
91104
#[inline]
92105
pub fn try_clone(&self) -> io::Result<Self> {
@@ -146,21 +159,8 @@ impl FileDesc {
146159
(&mut me).read_to_end(buf)
147160
}
148161

149-
#[cfg_attr(target_os = "vxworks", allow(unused_unsafe))]
150162
pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
151-
#[cfg(not(any(
152-
all(target_os = "linux", not(target_env = "musl")),
153-
target_os = "android",
154-
target_os = "hurd"
155-
)))]
156-
use libc::pread as pread64;
157-
#[cfg(any(
158-
all(target_os = "linux", not(target_env = "musl")),
159-
target_os = "android",
160-
target_os = "hurd"
161-
))]
162-
use libc::pread64;
163-
163+
#[cfg_attr(target_os = "vxworks", allow(unused_unsafe))]
164164
unsafe {
165165
cvt(pread64(
166166
self.as_raw_fd(),
@@ -188,6 +188,24 @@ impl FileDesc {
188188
Ok(())
189189
}
190190

191+
pub fn read_buf_at(&self, mut cursor: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
192+
#[cfg_attr(target_os = "vxworks", allow(unused_unsafe))]
193+
let ret = cvt(unsafe {
194+
pread64(
195+
self.as_raw_fd(),
196+
cursor.as_mut().as_mut_ptr() as *mut libc::c_void,
197+
cmp::min(cursor.capacity(), READ_LIMIT),
198+
offset as off64_t,
199+
)
200+
})?;
201+
202+
// Safety: `ret` bytes were written to the initialized portion of the buffer
203+
unsafe {
204+
cursor.advance_unchecked(ret as usize);
205+
}
206+
Ok(())
207+
}
208+
191209
#[cfg(any(
192210
target_os = "aix",
193211
target_os = "dragonfly", // DragonFly 1.5

library/std/src/sys/fs/unix.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1411,6 +1411,10 @@ impl File {
14111411
self.0.read_buf(cursor)
14121412
}
14131413

1414+
pub fn read_buf_at(&self, cursor: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
1415+
self.0.read_buf_at(cursor, offset)
1416+
}
1417+
14141418
pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
14151419
self.0.read_vectored_at(bufs, offset)
14161420
}

library/std/src/sys/fs/windows.rs

+4
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,10 @@ impl File {
586586
self.handle.read_buf(cursor)
587587
}
588588

589+
pub fn read_buf_at(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
590+
self.handle.read_buf_at(cursor)
591+
}
592+
589593
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
590594
self.handle.write(buf)
591595
}

library/std/src/sys/pal/windows/handle.rs

+18
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,24 @@ impl Handle {
136136
}
137137
}
138138

139+
pub fn read_buf_at(&self, mut cursor: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
140+
let res = unsafe {
141+
self.synchronous_read(cursor.as_nut().as_mut_ptr(), cursor.capacity(), Some(offset))
142+
};
143+
144+
match res {
145+
Ok(read) => {
146+
// Safety: `read` bytes were written to the initialized portion of the buffer
147+
unsafe {
148+
cursor.advance_unchecked(read);
149+
}
150+
Ok(())
151+
}
152+
Err(ref e) if e.raw_os_error() == Some(c::ERROR_HANDLE_EOF as i32) => Ok(()),
153+
Err(e) => Err(e),
154+
}
155+
}
156+
139157
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
140158
let mut me = self;
141159

0 commit comments

Comments
 (0)