From a1825f7c4aaa8c3e2e0aa9815087b5d5eb9a7a4c Mon Sep 17 00:00:00 2001 From: Joe Date: Fri, 6 Mar 2026 17:49:50 -0600 Subject: [PATCH] Enhance VFS watch functionality to support upgrade from non-recursive to recursive watching - Modified the `watch` method in `StdBackend` to allow upgrading a non-recursive watch to a recursive one, improving flexibility in file watching. - Added a new test to verify that a non-recursive watch can be upgraded to recursive, ensuring correct behavior in directory watching scenarios. These changes aim to enhance the VFS's ability to manage file system events more effectively. --- crates/memofs/src/std_backend.rs | 39 +++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/crates/memofs/src/std_backend.rs b/crates/memofs/src/std_backend.rs index a8bf9fbb..f3c2c145 100644 --- a/crates/memofs/src/std_backend.rs +++ b/crates/memofs/src/std_backend.rs @@ -332,7 +332,11 @@ impl VfsBackend for StdBackend { fn watch(&mut self, path: &Path, recursive: bool) -> io::Result<()> { if self.watches.contains(path) { - return Ok(()); + if !recursive || self.recursive_watches.contains(path) { + return Ok(()); + } + // Upgrade: path was watched non-recursively, now needs recursive. + // Fall through to re-issue the watch with RecursiveMode::Recursive. } if path .ancestors() @@ -498,6 +502,39 @@ mod tests { assert!(backend.watch(&file_path, true).is_ok()); } + #[test] + fn non_recursive_watch_upgrades_to_recursive() { + let dir = tempdir().unwrap(); + let subdir = dir.path().join("subdir"); + fs_err::create_dir(&subdir).unwrap(); + let child = subdir.join("child.txt"); + fs_err::write(&child, "content").unwrap(); + + let mut backend = StdBackend::new_for_testing(); + + // Watch non-recursively first + assert!(backend.watch(&subdir, false).is_ok()); + assert!(backend.watches.contains(subdir.as_path())); + assert!(!backend.recursive_watches.contains(subdir.as_path())); + + // Child should NOT be covered (parent is non-recursive) + assert!(!subdir + .ancestors() + .skip(1) + .any(|a| backend.recursive_watches.contains(a))); + + // Upgrade to recursive + assert!(backend.watch(&subdir, true).is_ok()); + assert!(backend.recursive_watches.contains(subdir.as_path())); + + // Now a child path should be recognized as covered by the recursive ancestor + assert!(child + .ancestors() + .skip(1) + .any(|a| backend.recursive_watches.contains(a))); + assert!(backend.watch(&child, true).is_ok()); + } + #[test] fn critical_error_receiver_works() { let error_received = Arc::new(AtomicBool::new(false));