Skip to content

Commit b424009

Browse files
authored
Rollup merge of rust-lang#74076 - sunfishcode:wasi-fileext-newmethods, r=alexcrichton
Add `read_exact_at` and `write_all_at` to WASI's `FileExt` This adds `read_exact_at` and `write_all_at` to WASI's `FileExt`, similar to the Unix versions of the same names.
2 parents a2e3e19 + 58fc61b commit b424009

File tree

1 file changed

+137
-4
lines changed
  • src/libstd/sys/wasi/ext

1 file changed

+137
-4
lines changed

Diff for: src/libstd/sys/wasi/ext/fs.rs

+137-4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,24 @@ use crate::sys_common::{AsInner, AsInnerMut, FromInner};
1212
///
1313
/// [`File`]: ../../../../std/fs/struct.File.html
1414
pub trait FileExt {
15+
/// Reads a number of bytes starting from a given offset.
16+
///
17+
/// Returns the number of bytes read.
18+
///
19+
/// The offset is relative to the start of the file and thus independent
20+
/// from the current cursor.
21+
///
22+
/// The current file cursor is not affected by this function.
23+
///
24+
/// Note that similar to [`File::read`], it is not an error to return with a
25+
/// short read.
26+
///
27+
/// [`File::read`]: ../../../../std/fs/struct.File.html#method.read
28+
fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
29+
let bufs = &mut [IoSliceMut::new(buf)];
30+
self.read_vectored_at(bufs, offset)
31+
}
32+
1533
/// Reads a number of bytes starting from a given offset.
1634
///
1735
/// Returns the number of bytes read.
@@ -25,7 +43,80 @@ pub trait FileExt {
2543
/// return with a short read.
2644
///
2745
/// [`File::read`]: ../../../../std/fs/struct.File.html#method.read_vectored
28-
fn read_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize>;
46+
fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize>;
47+
48+
/// Reads the exact number of byte required to fill `buf` from the given offset.
49+
///
50+
/// The offset is relative to the start of the file and thus independent
51+
/// from the current cursor.
52+
///
53+
/// The current file cursor is not affected by this function.
54+
///
55+
/// Similar to [`Read::read_exact`] but uses [`read_at`] instead of `read`.
56+
///
57+
/// [`Read::read_exact`]: ../../../../std/io/trait.Read.html#method.read_exact
58+
/// [`read_at`]: #tymethod.read_at
59+
///
60+
/// # Errors
61+
///
62+
/// If this function encounters an error of the kind
63+
/// [`ErrorKind::Interrupted`] then the error is ignored and the operation
64+
/// will continue.
65+
///
66+
/// If this function encounters an "end of file" before completely filling
67+
/// the buffer, it returns an error of the kind [`ErrorKind::UnexpectedEof`].
68+
/// The contents of `buf` are unspecified in this case.
69+
///
70+
/// If any other read error is encountered then this function immediately
71+
/// returns. The contents of `buf` are unspecified in this case.
72+
///
73+
/// If this function returns an error, it is unspecified how many bytes it
74+
/// has read, but it will never read more than would be necessary to
75+
/// completely fill the buffer.
76+
///
77+
/// [`ErrorKind::Interrupted`]: ../../../../std/io/enum.ErrorKind.html#variant.Interrupted
78+
/// [`ErrorKind::UnexpectedEof`]: ../../../../std/io/enum.ErrorKind.html#variant.UnexpectedEof
79+
#[stable(feature = "rw_exact_all_at", since = "1.33.0")]
80+
fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> {
81+
while !buf.is_empty() {
82+
match self.read_at(buf, offset) {
83+
Ok(0) => break,
84+
Ok(n) => {
85+
let tmp = buf;
86+
buf = &mut tmp[n..];
87+
offset += n as u64;
88+
}
89+
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
90+
Err(e) => return Err(e),
91+
}
92+
}
93+
if !buf.is_empty() {
94+
Err(io::Error::new(io::ErrorKind::UnexpectedEof, "failed to fill whole buffer"))
95+
} else {
96+
Ok(())
97+
}
98+
}
99+
100+
/// Writes a number of bytes starting from a given offset.
101+
///
102+
/// Returns the number of bytes written.
103+
///
104+
/// The offset is relative to the start of the file and thus independent
105+
/// from the current cursor.
106+
///
107+
/// The current file cursor is not affected by this function.
108+
///
109+
/// When writing beyond the end of the file, the file is appropriately
110+
/// extended and the intermediate bytes are initialized with the value 0.
111+
///
112+
/// Note that similar to [`File::write`], it is not an error to return a
113+
/// short write.
114+
///
115+
/// [`File::write`]: ../../../../std/fs/struct.File.html#write.v
116+
fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
117+
let bufs = &[IoSlice::new(buf)];
118+
self.write_vectored_at(bufs, offset)
119+
}
29120

30121
/// Writes a number of bytes starting from a given offset.
31122
///
@@ -43,7 +134,49 @@ pub trait FileExt {
43134
/// short write.
44135
///
45136
/// [`File::write`]: ../../../../std/fs/struct.File.html#method.write_vectored
46-
fn write_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize>;
137+
fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize>;
138+
139+
/// Attempts to write an entire buffer starting from a given offset.
140+
///
141+
/// The offset is relative to the start of the file and thus independent
142+
/// from the current cursor.
143+
///
144+
/// The current file cursor is not affected by this function.
145+
///
146+
/// This method will continuously call [`write_at`] until there is no more data
147+
/// to be written or an error of non-[`ErrorKind::Interrupted`] kind is
148+
/// returned. This method will not return until the entire buffer has been
149+
/// successfully written or such an error occurs. The first error that is
150+
/// not of [`ErrorKind::Interrupted`] kind generated from this method will be
151+
/// returned.
152+
///
153+
/// # Errors
154+
///
155+
/// This function will return the first error of
156+
/// non-[`ErrorKind::Interrupted`] kind that [`write_at`] returns.
157+
///
158+
/// [`ErrorKind::Interrupted`]: ../../../../std/io/enum.ErrorKind.html#variant.Interrupted
159+
/// [`write_at`]: #tymethod.write_at
160+
#[stable(feature = "rw_exact_all_at", since = "1.33.0")]
161+
fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> {
162+
while !buf.is_empty() {
163+
match self.write_at(buf, offset) {
164+
Ok(0) => {
165+
return Err(io::Error::new(
166+
io::ErrorKind::WriteZero,
167+
"failed to write whole buffer",
168+
));
169+
}
170+
Ok(n) => {
171+
buf = &buf[n..];
172+
offset += n as u64
173+
}
174+
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
175+
Err(e) => return Err(e),
176+
}
177+
}
178+
Ok(())
179+
}
47180

48181
/// Returns the current position within the file.
49182
///
@@ -105,11 +238,11 @@ pub trait FileExt {
105238
// FIXME: bind random_get maybe? - on crates.io for unix
106239

107240
impl FileExt for fs::File {
108-
fn read_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
241+
fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
109242
self.as_inner().fd().pread(bufs, offset)
110243
}
111244

112-
fn write_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
245+
fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
113246
self.as_inner().fd().pwrite(bufs, offset)
114247
}
115248

0 commit comments

Comments
 (0)