-
Notifications
You must be signed in to change notification settings - Fork 5.3k
FileSystemWatcher.Linux: handle races while adding child directories. #64906
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -324,9 +324,8 @@ private void AddDirectoryWatch(WatchedDirectory parent, string directoryName) | |||||||||||||
| // against the handle, so we'd deadlock if we relied on that approach. Instead, we want to follow | ||||||||||||||
| // the approach of removing all watches when we're done, which means we also don't want to | ||||||||||||||
| // add any new watches once the count hits zero. | ||||||||||||||
| if (parent == null || _wdToPathMap.Count > 0) | ||||||||||||||
| if (_wdToPathMap.Count > 0) | ||||||||||||||
| { | ||||||||||||||
| Debug.Assert(parent != null || _wdToPathMap.Count == 0); | ||||||||||||||
| AddDirectoryWatchUnlocked(parent, directoryName); | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
|
|
@@ -361,6 +360,15 @@ private void AddDirectoryWatchUnlocked(WatchedDirectory? parent, string director | |||||||||||||
| // raise the Error event with the exception and let the user decide how to handle it. | ||||||||||||||
|
|
||||||||||||||
| Interop.ErrorInfo error = Interop.Sys.GetLastErrorInfo(); | ||||||||||||||
|
|
||||||||||||||
| // Don't report an error when we can't add a watch because the child directory | ||||||||||||||
| // was removed or replaced by a file. | ||||||||||||||
| if (hasParent && (error.Error == Interop.Error.ENOENT || | ||||||||||||||
| error.Error == Interop.Error.ENOTDIR)) | ||||||||||||||
| { | ||||||||||||||
| return; | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| Exception exc; | ||||||||||||||
| if (error.Error == Interop.Error.ENOSPC) | ||||||||||||||
| { | ||||||||||||||
|
|
@@ -432,16 +440,30 @@ private void AddDirectoryWatchUnlocked(WatchedDirectory? parent, string director | |||||||||||||
| // asked for subdirectories to be included. | ||||||||||||||
| if (isNewDirectory && _includeSubdirectories) | ||||||||||||||
| { | ||||||||||||||
| // This method is recursive. If we expect to see hierarchies | ||||||||||||||
| // so deep that it would cause us to overflow the stack, we could | ||||||||||||||
| // consider using an explicit stack object rather than recursion. | ||||||||||||||
| // This is unlikely, however, given typical directory names | ||||||||||||||
| // and max path limits. | ||||||||||||||
| foreach (string subDir in Directory.EnumerateDirectories(fullPath)) | ||||||||||||||
| try | ||||||||||||||
adamsitnik marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
| { | ||||||||||||||
| AddDirectoryWatchUnlocked(directoryEntry, System.IO.Path.GetFileName(subDir)); | ||||||||||||||
| // AddDirectoryWatchUnlocked will add the new directory to | ||||||||||||||
| // this.Children, so we don't have to / shouldn't also do it here. | ||||||||||||||
| // This method is recursive. If we expect to see hierarchies | ||||||||||||||
| // so deep that it would cause us to overflow the stack, we could | ||||||||||||||
| // consider using an explicit stack object rather than recursion. | ||||||||||||||
| // This is unlikely, however, given typical directory names | ||||||||||||||
| // and max path limits. | ||||||||||||||
| foreach (string subDir in Directory.EnumerateDirectories(fullPath)) | ||||||||||||||
| { | ||||||||||||||
| AddDirectoryWatchUnlocked(directoryEntry, System.IO.Path.GetFileName(subDir)); | ||||||||||||||
| // AddDirectoryWatchUnlocked will add the new directory to | ||||||||||||||
| // this.Children, so we don't have to / shouldn't also do it here. | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
| catch (DirectoryNotFoundException) | ||||||||||||||
| { } // The child directory was removed. | ||||||||||||||
| catch (IOException ex) when (ex.HResult == Interop.Error.ENOTDIR.Info().RawErrno) | ||||||||||||||
| { } // The child directory was replaced by a file. | ||||||||||||||
adamsitnik marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
| catch (Exception ex) | ||||||||||||||
| { | ||||||||||||||
| if (_weakWatcher.TryGetTarget(out FileSystemWatcher? watcher)) | ||||||||||||||
|
Comment on lines
+462
to
+463
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the reported issue I assume that you added But how about the
Suggested change
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
If there are other errors, we report them to the user, similar to what already happens for
It isn't there for |
||||||||||||||
| { | ||||||||||||||
| watcher.OnError(new ErrorEventArgs(ex)); | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've removed the
nullcheck because the method doesn't get called withparent==null, and the argument is also not nullable (WatchedDirectory parent).