Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 09ac65a

Browse files
committed
Add read_buf equivalents for positioned reads
Adds the following items under the `read_buf_at` (#140771) 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 09ac65a

File tree

7 files changed

+194
-21
lines changed

7 files changed

+194
-21
lines changed

‎library/std/src/fs/tests.rs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,47 @@ fn file_test_io_read_write_at() {
452452
check!(fs::remove_file(&filename));
453453
}
454454

455+
#[test]
456+
#[cfg(unix)]
457+
fn test_read_buf_at() {
458+
use crate::os::unix::fs::FileExt;
459+
460+
let tmpdir = tmpdir();
461+
let filename = tmpdir.join("file_rt_io_file_test_read_buf_at.txt");
462+
{
463+
let oo = OpenOptions::new().create_new(true).write(true).read(true).clone();
464+
let mut file = check!(oo.open(&filename));
465+
check!(file.write_all(b"0123456789"));
466+
}
467+
{
468+
let mut file = check!(File::open(&filename));
469+
let mut buf: [MaybeUninit<u8>; 5] = [MaybeUninit::uninit(); 5];
470+
let mut buf = BorrowedBuf::from(buf.as_mut_slice());
471+
472+
check!(file.read_buf_exact_at(buf.unfilled(), 2));
473+
assert_eq!(buf.filled(), b"23456");
474+
475+
// Already full
476+
check!(file.read_buf_exact_at(buf.unfilled(), 3));
477+
check!(file.read_buf_exact_at(buf.unfilled(), 10));
478+
assert_eq!(buf.filled(), b"23456");
479+
assert_eq!(check!(file.stream_position()), 0);
480+
481+
// Exact read past eof fails
482+
let err = file.read_buf_exact_at(buf.clear().unfilled(), 6).unwrap_err();
483+
assert_eq!(err.kind(), ErrorKind::UnexpectedEof);
484+
assert_eq!(check!(file.stream_position()), 0);
485+
486+
// Read past eof is noop
487+
check!(file.read_buf_at(buf.clear().unfilled(), 10));
488+
assert_eq!(buf.filled(), b"");
489+
check!(file.read_buf_at(buf.clear().unfilled(), 11));
490+
assert_eq!(buf.filled(), b"");
491+
assert_eq!(check!(file.stream_position()), 0);
492+
}
493+
check!(fs::remove_file(&filename));
494+
}
495+
455496
#[test]
456497
#[cfg(unix)]
457498
fn set_get_unix_permissions() {
@@ -528,6 +569,41 @@ fn file_test_io_seek_read_write() {
528569
check!(fs::remove_file(&filename));
529570
}
530571

572+
#[test]
573+
#[cfg(windows)]
574+
fn test_seek_read_buf() {
575+
use crate::os::windows::fs::FileExt;
576+
577+
let tmpdir = tmpdir();
578+
let filename = tmpdir.join("file_rt_io_file_test_seek_read_buf.txt");
579+
{
580+
let oo = OpenOptions::new().create_new(true).write(true).read(true).clone();
581+
let mut file = check!(oo.open(&filename));
582+
check!(file.write_all(b"0123456789"));
583+
}
584+
{
585+
let mut file = check!(File::open(&filename));
586+
let mut buf: [MaybeUninit<u8>; 1] = [MaybeUninit::uninit()];
587+
let mut buf = BorrowedBuf::from(buf.as_mut_slice());
588+
589+
// Seek read
590+
check!(buf.seek_read(buf.unfilled(), 8));
591+
assert_eq!(buf.filled(), b"8");
592+
assert_eq!(check!(file.stream_position()), 9);
593+
594+
// Empty seek read
595+
check!(buf.seek_read(buf.unfilled(), 0));
596+
assert_rq!(buf.filled(), b"8");
597+
assert_eq!(check!(file.stream_position()), 9);
598+
599+
// Seek read past eof
600+
check(buf.seek_read(buf.clear().unfilled(), 10));
601+
assert_eq!(buf.filled(), b"");
602+
assert_eq!(check!(file.stream_position()), 9);
603+
}
604+
check!(fs::remove_file(&filename));
605+
}
606+
531607
#[test]
532608
fn file_test_read_buf() {
533609
let tmpdir = tmpdir();

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

Lines changed: 40 additions & 0 deletions
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_at", issue = "140771")]
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_at", issue = "140771")]
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

Lines changed: 19 additions & 0 deletions
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_at", issue = "140771")]
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_buf_at(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

Lines changed: 38 additions & 21 deletions
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,38 +159,43 @@ 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-
164-
unsafe {
165-
cvt(pread64(
163+
cvt(unsafe {
164+
pread64(
166165
self.as_raw_fd(),
167166
buf.as_mut_ptr() as *mut libc::c_void,
168167
cmp::min(buf.len(), READ_LIMIT),
169168
offset as off64_t,
170-
))
171-
.map(|n| n asusize)
172-
}
169+
)
170+
})
171+
.map(|n| n asusize)
173172
}
174173

175174
pub fn read_buf(&self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
175+
// Safety: `cursor.as_mut()` starts with `cursor.capacity()` writable bytes
176176
let ret = cvt(unsafe {
177177
libc::read(
178178
self.as_raw_fd(),
179-
cursor.as_mut().as_mut_ptr() as *mut libc::c_void,
179+
cursor.as_mut().as_mut_ptr().cast::<libc::c_void>(),
180+
cmp::min(cursor.capacity(), READ_LIMIT),
181+
)
182+
})?;
183+
184+
// Safety: `ret` bytes were written to the initialized portion of the buffer
185+
unsafe {
186+
cursor.advance_unchecked(ret as usize);
187+
}
188+
Ok(())
189+
}
190+
191+
pub fn read_buf_at(&self, mut cursor: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
192+
// Safety: `cursor.as_mut()` starts with `cursor.capacity()` writable bytes
193+
let ret = cvt(unsafe {
194+
pread64(
195+
self.as_raw_fd(),
196+
cursor.as_mut().as_mut_ptr().cast::<libc::c_void>(),
180197
cmp::min(cursor.capacity(), READ_LIMIT),
198+
offset as off64_t,
181199
)
182200
})?;
183201

@@ -369,7 +387,6 @@ impl FileDesc {
369387
)))
370388
}
371389

372-
#[cfg_attr(target_os = "vxworks", allow(unused_unsafe))]
373390
pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
374391
#[cfg(not(any(
375392
all(target_os = "linux", not(target_env = "musl")),

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

Lines changed: 4 additions & 0 deletions
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

Lines changed: 4 additions & 0 deletions
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<'_>, offset: u64) -> io::Result<()> {
590+
self.handle.read_buf_at(cursor, offset)
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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,19 @@ impl Handle {
136136
}
137137
}
138138

139+
pub fn read_buf_at(&self, mut cursor: BorrowedCursor<'_>, offset: u64) -> io::Result<()> {
140+
// Safety: `cursor.as_mut()` starts with `cursor.capacity()` writable bytes
141+
let read = unsafe {
142+
self.synchronous_read(cursor.as_mut().as_mut_ptr(), cursor.capacity(), Some(offset))
143+
}?;
144+
145+
// Safety: `read` bytes were written to the initialized portion of the buffer
146+
unsafe {
147+
cursor.advance_unchecked(read);
148+
}
149+
Ok(())
150+
}
151+
139152
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
140153
let mut me = self;
141154

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /