Skip to content

Commit 08769f4

Browse files
committed
fix(tail): Pass follow_name flag to watch_with_parent for correct behavior
The watch_with_parent method now considers both use_polling and follow_name: - For --follow=name with inotify: watch parent directories - For --follow=descriptor with inotify: watch files directly - For any mode with polling: watch files directly This ensures: - --follow=name with inotify properly detects file modifications via parent directory events - --follow=descriptor works correctly with both inotify and polling - Polling mode always watches files directly for correct behavior Fixed borrow checker errors by caching flags before mutable borrows.
1 parent df309ec commit 08769f4

1 file changed

Lines changed: 16 additions & 9 deletions

File tree

src/uu/tail/src/follow/watch.rs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,20 @@ impl WatcherRx {
3333
}
3434

3535
/// Wrapper for `notify::Watcher::watch` to also add the parent directory of `path` if necessary.
36-
/// When using polling, we watch the file directly; when using inotify, we watch the parent directory.
37-
fn watch_with_parent(&mut self, path: &Path, #[cfg_attr(not(target_os = "linux"), allow(unused_variables))] use_polling: bool) -> UResult<()> {
36+
/// When using polling OR --follow=descriptor, watch the file directly.
37+
/// When using inotify with --follow=name, watch the parent directory.
38+
fn watch_with_parent(&mut self, path: &Path, #[cfg_attr(not(target_os = "linux"), allow(unused_variables))] use_polling: bool, #[cfg_attr(not(target_os = "linux"), allow(unused_variables))] follow_name: bool) -> UResult<()> {
3839
let mut path = path.to_owned();
3940
#[cfg(target_os = "linux")]
40-
if path.is_file() && !use_polling {
41+
if path.is_file() && !use_polling && follow_name {
4142
/*
42-
NOTE: Using the parent directory instead of the file is a workaround for inotify.
43+
NOTE: Using the parent directory instead of the file is a workaround for inotify with --follow=name.
4344
This workaround follows the recommendation of the notify crate authors:
4445
> On some platforms, if the `path` is renamed or removed while being watched, behavior may
4546
> be unexpected. See discussions in [#165] and [#166]. If less surprising behavior is wanted
4647
> one may non-recursively watch the _parent_ directory as well and manage related events.
47-
NOTE: This only applies to InotifyWatcher. PollWatcher sends events with the file path,
48-
not the parent path, so we should watch the file directly when polling.
48+
NOTE: This only applies to InotifyWatcher with --follow=name. For --follow=descriptor or
49+
PollWatcher, we watch the file directly.
4950
*/
5051
if let Some(parent) = path.parent() {
5152
// clippy::assigning_clones added with Rust 1.78
@@ -276,6 +277,8 @@ impl Observer {
276277
}
277278

278279
fn init_files(&mut self, inputs: &Vec<Input>) -> UResult<()> {
280+
let use_polling = self.use_polling;
281+
let follow_name = self.follow_name();
279282
if let Some(watcher_rx) = &mut self.watcher_rx {
280283
for input in inputs {
281284
match input.kind() {
@@ -292,7 +295,7 @@ impl Observer {
292295

293296
if path.is_tailable() {
294297
// Add existing regular files to `Watcher` (InotifyWatcher).
295-
watcher_rx.watch_with_parent(&path, self.use_polling)?;
298+
watcher_rx.watch_with_parent(&path, use_polling, follow_name)?;
296299
} else if !path.is_orphan() {
297300
// If `path` is not a tailable file, add its parent to `Watcher`.
298301
watcher_rx
@@ -477,8 +480,10 @@ impl Observer {
477480
);
478481

479482
// Unwatch old path and watch new path
483+
let use_polling = self.use_polling;
484+
let follow_name = self.follow_name();
480485
let _ = self.watcher_rx.as_mut().unwrap().unwatch(event_path);
481-
self.watcher_rx.as_mut().unwrap().watch_with_parent(new_path, self.use_polling)?;
486+
self.watcher_rx.as_mut().unwrap().watch_with_parent(new_path, use_polling, follow_name)?;
482487
}
483488
}
484489
_ => {}
@@ -525,11 +530,13 @@ pub fn follow(mut observer: Observer, settings: &Settings) -> UResult<()> {
525530
observer.files.update_metadata(new_path, Some(md));
526531
observer.files.update_reader(new_path)?;
527532
_read_some = observer.files.tail_file(new_path, settings.verbose)?;
533+
let use_polling = observer.use_polling;
534+
let follow_name = observer.follow_name();
528535
observer
529536
.watcher_rx
530537
.as_mut()
531538
.unwrap()
532-
.watch_with_parent(new_path, observer.use_polling)?;
539+
.watch_with_parent(new_path, use_polling, follow_name)?;
533540
}
534541
}
535542
}

0 commit comments

Comments
 (0)