@@ -12,6 +12,24 @@ use crate::sys_common::{AsInner, AsInnerMut, FromInner};
1212///
1313/// [`File`]: ../../../../std/fs/struct.File.html
1414pub 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
107240impl 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