Skip to content

Fix file EOF to not be permanent: reading again should give new data #1030

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 45 additions & 4 deletions src/fs/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -670,14 +670,19 @@ impl LockGuard<State> {

match self.mode {
Mode::Idle => {}
Mode::Reading(0) if self.cache.is_empty() => {
// If the cache is empty in reading mode, the last operation didn't read any bytes,
// which indicates that it reached the end of the file. In this case we need to
// reset the mode to idle so that next time we try to read again, since the file
// may grow after the first EOF.
self.mode = Mode::Idle;
return Poll::Ready(Ok(0));
}
Mode::Reading(start) => {
// How many bytes in the cache are available for reading.
let available = self.cache.len() - start;

// If there is cached unconsumed data or if the cache is empty, we can read from
// it. Empty cache in reading mode indicates that the last operation didn't read
// any bytes, i.e. it reached the end of the file.
if available > 0 || self.cache.is_empty() {
if available > 0 {
// Copy data from the cache into the buffer.
let n = cmp::min(available, buf.len());
buf[..n].copy_from_slice(&self.cache[start..(start + n)]);
Expand Down Expand Up @@ -913,4 +918,40 @@ mod tests {
assert_eq!(format!("{}", expect), format!("{}", actual));
})
}

#[test]
fn file_eof_is_not_permanent() -> crate::io::Result<()> {
let tempdir = tempfile::Builder::new()
.prefix("async-std-file-eof-test")
.tempdir()?;
let path = tempdir.path().join("testfile");

crate::task::block_on(async {
let mut file_w = File::create(&path).await?;
let mut file_r = File::open(&path).await?;

file_w.write_all(b"data").await?;
file_w.flush().await?;

let mut buf = [0u8; 4];
let mut len = file_r.read(&mut buf).await?;
assert_eq!(len, 4);
assert_eq!(&buf, b"data");

len = file_r.read(&mut buf).await?;
assert_eq!(len, 0);

file_w.write_all(b"more").await?;
file_w.flush().await?;

len = file_r.read(&mut buf).await?;
assert_eq!(len, 4);
assert_eq!(&buf, b"more");

len = file_r.read(&mut buf).await?;
assert_eq!(len, 0);

Ok(())
})
}
}