@@ -12,6 +12,24 @@ use crate::sys_common::{AsInner, AsInnerMut, FromInner};
12
12
///
13
13
/// [`File`]: ../../../../std/fs/struct.File.html
14
14
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
+
15
33
/// Reads a number of bytes starting from a given offset.
16
34
///
17
35
/// Returns the number of bytes read.
@@ -25,7 +43,80 @@ pub trait FileExt {
25
43
/// return with a short read.
26
44
///
27
45
/// [`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
+ }
29
120
30
121
/// Writes a number of bytes starting from a given offset.
31
122
///
@@ -43,7 +134,49 @@ pub trait FileExt {
43
134
/// short write.
44
135
///
45
136
/// [`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
+ }
47
180
48
181
/// Returns the current position within the file.
49
182
///
@@ -105,11 +238,11 @@ pub trait FileExt {
105
238
// FIXME: bind random_get maybe? - on crates.io for unix
106
239
107
240
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 > {
109
242
self . as_inner ( ) . fd ( ) . pread ( bufs, offset)
110
243
}
111
244
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 > {
113
246
self . as_inner ( ) . fd ( ) . pwrite ( bufs, offset)
114
247
}
115
248
0 commit comments