@@ -127,10 +127,39 @@ impl FileLoader for RealFileLoader {
127127
128128 let mut bytes = Lrc :: new_uninit_slice ( len as usize ) ;
129129 let mut buf = BorrowedBuf :: from ( Lrc :: get_mut ( & mut bytes) . unwrap ( ) ) ;
130- file. read_buf_exact ( buf. unfilled ( ) ) ?;
130+ match file. read_buf_exact ( buf. unfilled ( ) ) {
131+ Ok ( ( ) ) => { }
132+ Err ( e) if e. kind ( ) == io:: ErrorKind :: UnexpectedEof => {
133+ drop ( bytes) ;
134+ return fs:: read ( path) . map ( Vec :: into) ;
135+ }
136+ Err ( e) => return Err ( e) ,
137+ }
131138 // SAFETY: If the read_buf_exact call returns Ok(()), then we have
132139 // read len bytes and initialized the buffer.
133- Ok ( unsafe { bytes. assume_init ( ) } )
140+ let bytes = unsafe { bytes. assume_init ( ) } ;
141+
142+ // At this point, we've read all the bytes that filesystem metadata reported exist.
143+ // But we are not guaranteed to be at the end of the file, because we did not attempt to do
144+ // a read with a non-zero-sized buffer and get Ok(0).
145+ // So we do small read to a fixed-size buffer. If the read returns no bytes then we're
146+ // already done, and we just return the Lrc we built above.
147+ // If the read returns bytes however, we just fall back to reading into a Vec then turning
148+ // that into an Lrc, losing our nice peak memory behavior. This fallback code path should
149+ // be rarely exercised.
150+
151+ let mut probe = [ 0u8 ; 32 ] ;
152+ let n = loop {
153+ match file. read ( & mut probe) {
154+ Ok ( 0 ) => return Ok ( bytes) ,
155+ Err ( e) if e. kind ( ) == io:: ErrorKind :: Interrupted => continue ,
156+ Err ( e) => return Err ( e) ,
157+ Ok ( n) => break n,
158+ }
159+ } ;
160+ let mut bytes: Vec < u8 > = bytes. iter ( ) . copied ( ) . chain ( probe[ ..n] . iter ( ) . copied ( ) ) . collect ( ) ;
161+ file. read_to_end ( & mut bytes) ?;
162+ Ok ( bytes. into ( ) )
134163 }
135164}
136165
0 commit comments