Skip to content

Commit 1be4a4f

Browse files
committed
Unix: Add read_buf_at and read_buf_exact_at to FileExt
1 parent 73476d4 commit 1be4a4f

File tree

3 files changed

+93
-2
lines changed

3 files changed

+93
-2
lines changed

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

+59-2
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,7 @@ pub trait FileExt {
119119
match self.read_at(buf, offset) {
120120
Ok(0) => break,
121121
Ok(n) => {
122-
let tmp = buf;
123-
buf = &mut tmp[n..];
122+
buf = &mut buf[n..];
124123
offset += n as u64;
125124
}
126125
Err(ref e) if e.is_interrupted() => {}
@@ -134,6 +133,61 @@ pub trait FileExt {
134133
}
135134
}
136135

136+
/// Reads a number of bytes starting from a given offset.
137+
///
138+
/// This is equivalent to the [`read_at`](FileExt::read_at) method, except
139+
/// that it is passed a [`BorrowedCursor`] rather than `[u8]` to allow use
140+
/// with uninitialized buffers. The new data will be appended to any
141+
/// existing contents of `buf`.
142+
///
143+
/// The offset is relative to the start of the file and thus independent
144+
/// from the current cursor.
145+
///
146+
/// The current file cursor is not affected by this function.
147+
///
148+
/// Note that similar to [`File::read_buf`], it is not an error to return with a
149+
/// short read.
150+
///
151+
/// [`File::read_buf`]: fs::File::read_buf
152+
/// [`BorrowedCursor`]: io::BorrowedCursor
153+
#[unstable(feature = "read_buf", issue = "78485")]
154+
fn read_buf_at(&self, mut cursor: io::BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
155+
let n = self.read_at(cursor.ensure_init().init_mut(), offset)?;
156+
cursor.advance(n);
157+
Ok(())
158+
}
159+
160+
/// Reads the exact number of bytes required to fill `buf` from the given offset.
161+
///
162+
/// The offset is relative to the start of the file and thus independent
163+
/// from the current cursor.
164+
///
165+
/// The current file cursor is not affected by this function.
166+
#[unstable(feature = "read_buf", issue = "78485")]
167+
fn read_buf_exact_at(
168+
&self,
169+
mut cursor: io::BorrowedCursor<'_>,
170+
mut offset: u64,
171+
) -> io::Result<()> {
172+
while cursor.capacity() > 0 {
173+
let prev_written = cursor.written();
174+
match self.read_buf_at(cursor.reborrow(), offset) {
175+
Ok(()) => offset += (cursor.written() - prev_written) as u64,
176+
Err(e) if e.is_interrupted() => continue,
177+
Err(e) => return Err(e),
178+
}
179+
180+
if cursor.written() == prev_written {
181+
return Err(io::const_io_error!(
182+
io::ErrorKind::UnexpectedEof,
183+
"failed to fill whole buffer"
184+
));
185+
}
186+
}
187+
188+
Ok(())
189+
}
190+
137191
/// Writes a number of bytes starting from a given offset.
138192
///
139193
/// Returns the number of bytes written.
@@ -271,6 +325,9 @@ impl FileExt for fs::File {
271325
fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
272326
self.as_inner().read_at(buf, offset)
273327
}
328+
fn read_buf_at(&self, cursor: io::BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
329+
self.as_inner().read_buf_at(cursor, offset)
330+
}
274331
fn read_vectored_at(&self, bufs: &mut [io::IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
275332
self.as_inner().read_vectored_at(bufs, offset)
276333
}

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

+30
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,36 @@ impl FileDesc {
166166
Ok(())
167167
}
168168

169+
pub fn read_buf_at(&self, mut cursor: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
170+
#[cfg(not(any(
171+
all(target_os = "linux", not(target_env = "musl")),
172+
target_os = "android",
173+
target_os = "hurd"
174+
)))]
175+
use libc::pread as pread64;
176+
#[cfg(any(
177+
all(target_os = "linux", not(target_env = "musl")),
178+
target_os = "android",
179+
target_os = "hurd"
180+
))]
181+
use libc::pread64;
182+
183+
let ret = cvt(unsafe {
184+
pread64(
185+
self.as_raw_fd(),
186+
cursor.as_mut().as_mut_ptr() as *mut libc::c_void,
187+
cmp::min(cursor.capacity(), READ_LIMIT),
188+
offset as off64_t,
189+
)
190+
})?;
191+
192+
// Safety: `ret` bytes were written to the initialized portion of the buffer
193+
unsafe {
194+
cursor.advance_unchecked(ret as usize);
195+
}
196+
Ok(())
197+
}
198+
169199
#[cfg(any(
170200
target_os = "emscripten",
171201
target_os = "freebsd",

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

+4
Original file line numberDiff line numberDiff line change
@@ -1247,6 +1247,10 @@ impl File {
12471247
self.0.read_buf(cursor)
12481248
}
12491249

1250+
pub fn read_buf_at(&self, cursor: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
1251+
self.0.read_buf_at(cursor, offset)
1252+
}
1253+
12501254
pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
12511255
self.0.read_vectored_at(bufs, offset)
12521256
}

0 commit comments

Comments
 (0)