From cdc664305e7d7d147018773ebbdd14d8a6bdd197 Mon Sep 17 00:00:00 2001 From: Niyaz Nigmatullin Date: Thu, 11 Aug 2022 22:38:58 +0300 Subject: [PATCH] tail: reuse opened file with the same descriptor when --follow=descriptor and renamed --- src/uu/tail/src/tail.rs | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/uu/tail/src/tail.rs b/src/uu/tail/src/tail.rs index 486a7c127..32ebb21b0 100644 --- a/src/uu/tail/src/tail.rs +++ b/src/uu/tail/src/tail.rs @@ -1037,21 +1037,28 @@ fn handle_event( if settings.follow_descriptor() { let new_path = event.paths.last().unwrap(); paths.push(new_path.to_owned()); - // Open new file and seek to End: - let mut file = File::open(&new_path)?; - file.seek(SeekFrom::End(0))?; + // Remove old reader + let old_reader = files.remove(event_path).reader; + let reader = if old_reader.is_some() { + // Use old reader with the same file descriptor if there is one + old_reader + } else if let Ok(file) = File::open(&new_path) { + // Open new file tail from start + Some(Box::new(BufReader::new(file)) as Box) + } else { + // Probably file was renamed/moved or removed again + None + }; // Add new reader but keep old display name files.insert( new_path, PathData { - metadata: file.metadata().ok(), - reader: Some(Box::new(BufReader::new(file))), + metadata: new_path.metadata().ok(), + reader, display_name, // mimic GNU's tail and show old name in header }, files.get_last().unwrap() == event_path ); - // Remove old reader - files.remove(event_path); // Unwatch old path and watch new path let _ = watcher.unwatch(event_path); watcher.watch_with_parent(new_path)?; @@ -1103,8 +1110,8 @@ mod files { } /// Wrapper for HashMap::remove using Path::canonicalize - pub fn remove(&mut self, k: &Path) { - self.map.remove(&Self::canonicalize_path(k)).unwrap(); + pub fn remove(&mut self, k: &Path) -> PathData { + self.map.remove(&Self::canonicalize_path(k)).unwrap() } /// Wrapper for HashMap::get using Path::canonicalize