From 64b7791ee5810744a478708d3dd5d4b88b74fe71 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 30 Jun 2022 02:00:09 -0700 Subject: [PATCH 1/2] When read returns EOF, ensure future reads still check the file for EOF Go back to the idle mode when returning EOF, so that the next read will make another attempt to read from the file in case the file grew. --- src/fs/file.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/fs/file.rs b/src/fs/file.rs index 47e2fee7..a074eae2 100644 --- a/src/fs/file.rs +++ b/src/fs/file.rs @@ -670,14 +670,19 @@ impl LockGuard { 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)]); From dfdf56cc9a97c853e7e6caa775fdb439e87a649c Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Mon, 20 Jun 2022 04:10:00 -0700 Subject: [PATCH 2/2] Test that file EOF is not permanent: reading again should give new data --- src/fs/file.rs | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/fs/file.rs b/src/fs/file.rs index a074eae2..9a4ab77b 100644 --- a/src/fs/file.rs +++ b/src/fs/file.rs @@ -918,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(()) + }) + } }