Skip to content

Add read_buf equivalents for positioned reads #140459

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions library/std/src/os/unix/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use super::platform::fs::MetadataExt as _;
// Used for `File::read` on intra-doc links
use crate::ffi::OsStr;
use crate::fs::{self, OpenOptions, Permissions};
use crate::io::BorrowedCursor;
use crate::os::unix::io::{AsFd, AsRawFd};
use crate::path::Path;
use crate::sealed::Sealed;
Expand Down Expand Up @@ -130,6 +131,42 @@ pub trait FileExt {
if !buf.is_empty() { Err(io::Error::READ_EXACT_EOF) } else { Ok(()) }
}

/// Reads some bytes starting from a given offset into the buffer.
///
/// This equivalent to the [`read_at`](FileExt::read_at) method,
/// except that it is passed a [`BorrowedCursor`] rather than `&mut [u8]` to allow
/// use with uninitialized buffers. The new data will be appended to any
/// existing contents of `buf`.
#[unstable(feature = "read_buf", issue = "78485")]
fn read_buf_at(&self, buf: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
io::default_read_buf(|b| self.read_at(b, offset), buf)
}

/// Reads the exact number of bytes required to fill the buffer from a given
/// offset.
///
/// This is equivalent to the [`read_exact_at`](FileExt::read_exact_at) method,
/// except that it is passed a [`BorrowedCursor`] rather than `&mut [u8]` to allow
/// use with uninitialized buffers. The new data will be appended to any
/// existing contents of `buf`.
#[unstable(feature = "read_buf", issue = "78485")]
fn read_buf_exact_at(&self, mut buf: BorrowedCursor<'_>, mut offset: u64) -> io::Result<()> {
while buf.capacity() > 0 {
let prev_written = buf.written();
match self.read_buf_at(buf.reborrow(), offset) {
Ok(()) => {}
Err(e) if e.is_interrupted() => {}
Err(e) => return Err(e),
}
let n = buf.written() - prev_written;
offset += n as u64;
if n == 0 {
return Err(io::Error::READ_EXACT_EOF);
}
}
Ok(())
}

/// Writes a number of bytes starting from a given offset.
///
/// Returns the number of bytes written.
Expand Down Expand Up @@ -264,6 +301,9 @@ impl FileExt for fs::File {
fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
self.as_inner().read_at(buf, offset)
}
fn read_buf_at(&self, buf: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
self.as_inner().read_buf_at(buf, offset)
}
fn read_vectored_at(&self, bufs: &mut [io::IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
self.as_inner().read_vectored_at(bufs, offset)
}
Expand Down
19 changes: 19 additions & 0 deletions library/std/src/os/windows/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#![stable(feature = "rust1", since = "1.0.0")]

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

/// Seeks to a given position and reads some bytes into the buffer.
///
/// This is equivalent to the [`seek_read`](FileExt::seek_read) method, except
/// that it is passed a [`BorrowedCursor`] rather than `&mut [u8]` to allow use
/// with uninitialized buffers. The new data will be appended to any existing
/// contents of `buf`.
///
/// Reading beyond the end of the file will always succeed without reading
/// any bytes.
#[unstable(feature = "read_buf", issue = "78485")]
fn seek_read_buf(&self, buf: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
io::default_read_buf(|b| self.seek_read(b, offset), buf)
}

/// Seeks to a given position and writes a number of bytes.
///
/// Returns the number of bytes written.
Expand Down Expand Up @@ -89,6 +104,10 @@ impl FileExt for fs::File {
self.as_inner().read_at(buf, offset)
}

fn seek_read_buf(&self, buf: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
self.as_inner().read_buf_at(buf, offset)
}

fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
self.as_inner().write_at(buf, offset)
}
Expand Down
46 changes: 32 additions & 14 deletions library/std/src/sys/fd/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,19 @@ const fn max_iov() -> usize {
16 // The minimum value required by POSIX.
}

#[cfg(not(any(
all(target_os = "linux", not(target_env = "musl")),
target_os = "android",
target_os = "hurd"
)))]
use libc::pread as pread64;
#[cfg(any(
all(target_os = "linux", not(target_env = "musl")),
target_os = "android",
target_os = "hurd"
))]
use libc::pread64;

impl FileDesc {
#[inline]
pub fn try_clone(&self) -> io::Result<Self> {
Expand Down Expand Up @@ -146,21 +159,8 @@ impl FileDesc {
(&mut me).read_to_end(buf)
}

#[cfg_attr(target_os = "vxworks", allow(unused_unsafe))]
pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
#[cfg(not(any(
all(target_os = "linux", not(target_env = "musl")),
target_os = "android",
target_os = "hurd"
)))]
use libc::pread as pread64;
#[cfg(any(
all(target_os = "linux", not(target_env = "musl")),
target_os = "android",
target_os = "hurd"
))]
use libc::pread64;

#[cfg_attr(target_os = "vxworks", allow(unused_unsafe))]
unsafe {
cvt(pread64(
self.as_raw_fd(),
Expand Down Expand Up @@ -188,6 +188,24 @@ impl FileDesc {
Ok(())
}

pub fn read_buf_at(&self, mut cursor: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
#[cfg_attr(target_os = "vxworks", allow(unused_unsafe))]
let ret = cvt(unsafe {
pread64(
self.as_raw_fd(),
cursor.as_mut().as_mut_ptr() as *mut libc::c_void,
cmp::min(cursor.capacity(), READ_LIMIT),
offset as off64_t,
)
})?;

// Safety: `ret` bytes were written to the initialized portion of the buffer
unsafe {
cursor.advance_unchecked(ret as usize);
}
Ok(())
}

#[cfg(any(
target_os = "aix",
target_os = "dragonfly", // DragonFly 1.5
Expand Down
4 changes: 4 additions & 0 deletions library/std/src/sys/fs/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1411,6 +1411,10 @@ impl File {
self.0.read_buf(cursor)
}

pub fn read_buf_at(&self, cursor: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
self.0.read_buf_at(cursor, offset)
}

pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
self.0.read_vectored_at(bufs, offset)
}
Expand Down
4 changes: 4 additions & 0 deletions library/std/src/sys/fs/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,10 @@ impl File {
self.handle.read_buf(cursor)
}

pub fn read_buf_at(&self, cursor: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
self.handle.read_buf_at(cursor, offset)
}

pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
self.handle.write(buf)
}
Expand Down
18 changes: 18 additions & 0 deletions library/std/src/sys/pal/windows/handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,24 @@ impl Handle {
}
}

pub fn read_buf_at(&self, mut cursor: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
let res = unsafe {
self.synchronous_read(cursor.as_mut().as_mut_ptr(), cursor.capacity(), Some(offset))
};

match res {
Ok(read) => {
// Safety: `read` bytes were written to the initialized portion of the buffer
unsafe {
cursor.advance_unchecked(read);
}
Ok(())
}
Err(ref e) if e.raw_os_error() == Some(c::ERROR_HANDLE_EOF as i32) => Ok(()),
Err(e) => Err(e),
}
}

pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
let mut me = self;

Expand Down
Loading