fix(inotify): report subdirectories found by the recursive catch-up walk - #976
Closed
teddytennant wants to merge 1 commit into
Closed
fix(inotify): report subdirectories found by the recursive catch-up walk#976teddytennant wants to merge 1 commit into
teddytennant wants to merge 1 commit into
Conversation
Creating a nested tree in a single call, `create_dir_all("1/2/.../10")`
inside a recursively watched directory, only produced a create event for
`1`. The kernel reports the creation of the topmost directory alone: by
the time we react to that event and install a watch for it, the rest of
the tree already exists, so no further inotify event will ever arrive.
`add_watch` walks the new directory to install watches on what it finds,
but said nothing about it, so those nine subdirectories were never
reported to the user even though they were newly created from the
watcher's point of view.
Report a `Create(Folder)` event for each directory that walk discovers
below its root. This applies only to the walk triggered by an inotify
CREATE or MOVED_TO event; the walk performed for an explicit `watch()`
call keeps quiet about a tree that was already there.
Un-ignores the existing `recursive_creation` test.
Member
|
I see you're spamming LLM-generated PRs in many OSS repos, we don't welcome such a contribution. |
Author
|
Fair enough. You're right on both counts, and sorry for the noise. Opening that many PRs across repos I have no history with was a bad way to show up, and I should have asked on #727 before writing code rather than after. I won't open anything else here. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Watching a directory recursively and then creating a nested tree in one call only reports the topmost directory:
Before this change the only create event is
Create(Folder)forpath/1. The nine directories below it are never reported, even though the watcher demonstrably walks into all of them — withEventKindMask::ALLyou can seeAccess(Open)/Access(Close)for every level.Cause
The kernel reports the creation of
1and nothing else:2through10are created before the watch for1exists, so no inotify event is ever generated for them.EventLoop::handle_inotifyreacts to the CREATE event by queueing1intoadd_watchesand then callingadd_watch(path, true, false), which runs aWalkDircatch-up scan and installs a watch on every directory it finds. That scan is the only thing in the process that ever learns those directories exist, and it discarded that knowledge — it registered the watches and reported nothing. This is the TOCTOU window the surrounding comments already acknowledge, just observed from the event side rather than the watch side.This is the diagnosis @riberk gave in #727 ("I think, the way to solve it may be raising events while scanning the dirs"); the issue has sat unclaimed since.
Fix
add_watches_for_pathsnow takes aReportCreatedflag. When the walk was triggered by an inotify CREATE/MOVED_TO event, every directory the walk finds below its root is reported asCreate(Folder), after its watch is installed so that a handler reacting to the event cannot make a change nothing is watching for yet. The walk root itself is skipped because the kernel already announced it.This is the right layer because the catch-up walk is the only place that ever observes these paths; nothing downstream can reconstruct them.
Deliberately unchanged:
watch()call stays silent. Watching a path is not a change, so a pre-existing tree must not be reported.add_watchpassesReportCreated::Nothing, and a new test pins that.filter_dir), and widening it would turn moving a large tree into a watched directory into a per-file event storm. Directory count already bounds the work done here, so the event volume stays proportional to the watches being installed.Verification
Fail-before (fix reverted, tests kept):
Pass-after:
cargo test --workspace --all-features --no-fail-fast, three consecutive runs, all identical:notifylib 85 passed / 0 failed / 1 ignored, everything else green excepttests/serialise-events.rs(6 failures,left: String("any"), right: Object {"type": String("any")}) which fails the same way on a clean checkout of d285062 and is unrelated to this change.cargo fmt --all -- --checkandcargo clippy --all-targets --all-features -- -D warningsare clean.Tests
recursive_creationalready existed, marked#[ignore = "see .../issues/727"], and now passes — the#[ignore]is removed.watching_a_directory_does_not_report_its_existing_contentsis new: it recursively watches a directory that already contains1/2/3and asserts no create events are emitted. Makingadd_watchreport its own walk fails this test.Related Issues
Fixes #727
Note
#970 also refactors
add_watches_for_paths, so one of these two will need a trivial rebase over the other.