Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corefx.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIan Hays <ianha@microsoft.com>2017-08-08 18:53:18 +0300
committerGitHub <noreply@github.com>2017-08-08 18:53:18 +0300
commitf16c8dccb7d38fbaaa69fd331d6ee339315fcaf2 (patch)
treef3d874fdc63c19796b8268d10fe9ad434450a1af /src
parent4a97f92f27d1b0bd2f2c67ffb05e50833d652ae4 (diff)
parent77883e33b94164a318eb128605340dc2e61cd358 (diff)
Merge pull request #22976 from ianhays/fsw_filter
Add FSW file/directory event filtering to Linux
Diffstat (limited to 'src')
-rw-r--r--src/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.Linux.cs29
-rw-r--r--src/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.Directory.NotifyFilter.cs59
-rw-r--r--src/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.File.NotifyFilter.cs62
3 files changed, 137 insertions, 13 deletions
diff --git a/src/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.Linux.cs b/src/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.Linux.cs
index 6de6aba533..04cdfb9c2a 100644
--- a/src/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.Linux.cs
+++ b/src/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.Linux.cs
@@ -69,7 +69,7 @@ namespace System.IO
// active operations to all be outstanding at the same time.
var runner = new RunningInstance(
this, handle, _directory,
- IncludeSubdirectories, TranslateFilters(NotifyFilter), cancellation.Token);
+ IncludeSubdirectories, NotifyFilter, cancellation.Token);
// Now that we've created the runner, store the cancellation object and mark the instance
// as running. We wait to do this so that if there was a failure, StartRaisingEvents
@@ -256,7 +256,8 @@ namespace System.IO
/// <summary>
/// Filters to use when adding a watch on directories.
/// </summary>
- private readonly Interop.Sys.NotifyEvents _notifyFilters;
+ private readonly NotifyFilters _notifyFilters;
+ private readonly Interop.Sys.NotifyEvents _watchFilters;
/// <summary>
/// Whether to monitor subdirectories. Unlike Win32, inotify does not implicitly monitor subdirectories;
/// watches must be explicitly added for those subdirectories.
@@ -282,7 +283,7 @@ namespace System.IO
/// <summary>Initializes the instance with all state necessary to operate a watch.</summary>
internal RunningInstance(
FileSystemWatcher watcher, SafeFileHandle inotifyHandle, string directoryPath,
- bool includeSubdirectories, Interop.Sys.NotifyEvents notifyFilters, CancellationToken cancellationToken)
+ bool includeSubdirectories, NotifyFilters notifyFilters, CancellationToken cancellationToken)
{
Debug.Assert(watcher != null);
Debug.Assert(inotifyHandle != null && !inotifyHandle.IsInvalid && !inotifyHandle.IsClosed);
@@ -295,6 +296,7 @@ namespace System.IO
Debug.Assert(_buffer != null && _buffer.Length > (c_INotifyEventSize + NAME_MAX + 1));
_includeSubdirectories = includeSubdirectories;
_notifyFilters = notifyFilters;
+ _watchFilters = TranslateFilters(notifyFilters);
_cancellationToken = cancellationToken;
// Add a watch for this starting directory. We keep track of the watch descriptor => directory information
@@ -358,7 +360,7 @@ namespace System.IO
// the existing descriptor. This works even in the case of a rename. We also add the DONT_FOLLOW
// and EXCL_UNLINK flags to keep parity with Windows where we don't pickup symlinks or unlinked
// files (which don't exist in Windows)
- int wd = Interop.Sys.INotifyAddWatch(_inotifyHandle, fullPath, (uint)(this._notifyFilters | Interop.Sys.NotifyEvents.IN_DONT_FOLLOW | Interop.Sys.NotifyEvents.IN_EXCL_UNLINK));
+ int wd = Interop.Sys.INotifyAddWatch(_inotifyHandle, fullPath, (uint)(this._watchFilters | Interop.Sys.NotifyEvents.IN_DONT_FOLLOW | Interop.Sys.NotifyEvents.IN_EXCL_UNLINK));
if (wd == -1)
{
// If we get an error when trying to add the watch, don't let that tear down processing. Instead,
@@ -637,10 +639,21 @@ namespace System.IO
AddDirectoryWatch(associatedDirectoryEntry, nextEvent.name);
}
- const Interop.Sys.NotifyEvents switchMask =
- Interop.Sys.NotifyEvents.IN_IGNORED |Interop.Sys.NotifyEvents.IN_CREATE | Interop.Sys.NotifyEvents.IN_DELETE |
- Interop.Sys.NotifyEvents.IN_ACCESS | Interop.Sys.NotifyEvents.IN_MODIFY | Interop.Sys.NotifyEvents.IN_ATTRIB |
- Interop.Sys.NotifyEvents.IN_MOVED_FROM | Interop.Sys.NotifyEvents.IN_MOVED_TO;
+ // Check if the event should have been filtered but was unable because of inotify's inability
+ // to filter files vs directories.
+ const Interop.Sys.NotifyEvents fileDirEvents = Interop.Sys.NotifyEvents.IN_CREATE |
+ Interop.Sys.NotifyEvents.IN_DELETE |
+ Interop.Sys.NotifyEvents.IN_MOVED_FROM |
+ Interop.Sys.NotifyEvents.IN_MOVED_TO;
+ if ((((uint)fileDirEvents & mask) > 0) &&
+ (isDir && ((_notifyFilters & NotifyFilters.DirectoryName) == 0) ||
+ (!isDir && ((_notifyFilters & NotifyFilters.FileName) == 0))))
+ {
+ continue;
+ }
+
+ const Interop.Sys.NotifyEvents switchMask = fileDirEvents | Interop.Sys.NotifyEvents.IN_IGNORED |
+ Interop.Sys.NotifyEvents.IN_ACCESS | Interop.Sys.NotifyEvents.IN_MODIFY | Interop.Sys.NotifyEvents.IN_ATTRIB;
switch ((Interop.Sys.NotifyEvents)(mask & (uint)switchMask))
{
case Interop.Sys.NotifyEvents.IN_CREATE:
diff --git a/src/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.Directory.NotifyFilter.cs b/src/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.Directory.NotifyFilter.cs
index f390e58913..fbcf20d35d 100644
--- a/src/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.Directory.NotifyFilter.cs
+++ b/src/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.Directory.NotifyFilter.cs
@@ -87,8 +87,6 @@ namespace System.IO.Tests
WatcherChangeTypes expected = 0;
if (filter == NotifyFilters.DirectoryName)
expected |= WatcherChangeTypes.Renamed;
- else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && (filter == NotifyFilters.FileName))
- expected |= WatcherChangeTypes.Renamed;
ExpectEvent(watcher, expected, action, cleanup, targetPath);
}
@@ -141,6 +139,33 @@ namespace System.IO.Tests
}
[Theory]
+ [OuterLoop]
+ [MemberData(nameof(FilterTypes))]
+ public void FileSystemWatcher_Directory_NotifyFilter_LastWriteTime_TwoFilters(NotifyFilters filter)
+ {
+ Assert.All(FilterTypes(), (filter2Arr =>
+ {
+ using (var testDirectory = new TempDirectory(GetTestFilePath()))
+ using (var dir = new TempDirectory(Path.Combine(testDirectory.Path, "dir")))
+ using (var watcher = new FileSystemWatcher(testDirectory.Path, Path.GetFileName(dir.Path)))
+ {
+ filter |= (NotifyFilters)filter2Arr[0];
+ watcher.NotifyFilter = filter;
+ Action action = () => Directory.SetLastWriteTime(dir.Path, DateTime.Now + TimeSpan.FromSeconds(10));
+
+ WatcherChangeTypes expected = 0;
+ if ((filter & NotifyFilters.LastWrite) > 0)
+ expected |= WatcherChangeTypes.Changed;
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && ((filter & LinuxFiltersForAttribute) > 0))
+ expected |= WatcherChangeTypes.Changed;
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) && ((filter & OSXFiltersForModify) > 0))
+ expected |= WatcherChangeTypes.Changed;
+ ExpectEvent(watcher, expected, action, expectedPath: dir.Path);
+ }
+ }));
+ }
+
+ [Theory]
[MemberData(nameof(FilterTypes))]
[PlatformSpecific(TestPlatforms.Windows)] // Uses P/Invokes to set security info
[ActiveIssue(21109, TargetFrameworkMonikers.Uap)]
@@ -255,5 +280,35 @@ namespace System.IO.Tests
ExpectEvent(watcher, expected, action, cleanup, new string[] { otherDir, dir.Path });
}
}
+
+ [Fact]
+ public void FileSystemWatcher_Directory_NotifyFilter_DirectoryNameDoesntTriggerOnFileEvent()
+ {
+ using (var testDirectory = new TempDirectory(GetTestFilePath()))
+ using (var dir = new TempDirectory(Path.Combine(testDirectory.Path, "dir")))
+ using (var watcher = new FileSystemWatcher(testDirectory.Path, "*"))
+ {
+ watcher.NotifyFilter = NotifyFilters.FileName;
+ string renameDirSource = Path.Combine(testDirectory.Path, "dir2_source");
+ string renameDirDest = Path.Combine(testDirectory.Path, "dir2_dest");
+ string otherDir = Path.Combine(testDirectory.Path, "dir3");
+ Directory.CreateDirectory(renameDirSource);
+
+ Action action = () =>
+ {
+ Directory.CreateDirectory(otherDir);
+ Directory.Move(renameDirSource, renameDirDest);
+ Directory.SetLastWriteTime(dir.Path, DateTime.Now + TimeSpan.FromSeconds(10));
+ Directory.Delete(otherDir);
+ };
+ Action cleanup = () =>
+ {
+ Directory.Move(renameDirDest, renameDirSource);
+ };
+
+ WatcherChangeTypes expected = 0;
+ ExpectEvent(watcher, expected, action, cleanup, new string[] { otherDir, dir.Path });
+ }
+ }
}
} \ No newline at end of file
diff --git a/src/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.File.NotifyFilter.cs b/src/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.File.NotifyFilter.cs
index 30789b2546..991d42c296 100644
--- a/src/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.File.NotifyFilter.cs
+++ b/src/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.File.NotifyFilter.cs
@@ -91,9 +91,6 @@ namespace System.IO.Tests
if (filter == NotifyFilters.DirectoryName)
expected |= WatcherChangeTypes.Renamed;
- else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && (filter == NotifyFilters.FileName))
- expected |= WatcherChangeTypes.Renamed;
-
ExpectEvent(watcher, expected, action, cleanup, targetPath);
}
}
@@ -168,6 +165,36 @@ namespace System.IO.Tests
}
[Theory]
+ [OuterLoop]
+ [MemberData(nameof(FilterTypes))]
+ public void FileSystemWatcher_File_NotifyFilter_Size_TwoFilters(NotifyFilters filter)
+ {
+ Assert.All(FilterTypes(), (filter2Arr =>
+ {
+ using (var testDirectory = new TempDirectory(GetTestFilePath()))
+ using (var file = new TempFile(Path.Combine(testDirectory.Path, "file")))
+ using (var watcher = new FileSystemWatcher(testDirectory.Path, Path.GetFileName(file.Path)))
+ {
+ filter |= (NotifyFilters)filter2Arr[0];
+ watcher.NotifyFilter = filter;
+ Action action = () => File.AppendAllText(file.Path, "longText!");
+ Action cleanup = () => File.AppendAllText(file.Path, "short");
+
+ WatcherChangeTypes expected = 0;
+ if (((filter & NotifyFilters.Size) > 0) || ((filter & NotifyFilters.LastWrite) > 0))
+ expected |= WatcherChangeTypes.Changed;
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && ((filter & LinuxFiltersForModify) > 0))
+ expected |= WatcherChangeTypes.Changed;
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) && ((filter & OSXFiltersForModify) > 0))
+ expected |= WatcherChangeTypes.Changed;
+ else if (PlatformDetection.IsWindows7 && ((filter & NotifyFilters.Attributes) > 0)) // win7 FSW Size change passes the Attribute filter
+ expected |= WatcherChangeTypes.Changed;
+ ExpectEvent(watcher, expected, action, expectedPath: file.Path);
+ }
+ }));
+ }
+
+ [Theory]
[MemberData(nameof(FilterTypes))]
[PlatformSpecific(TestPlatforms.Windows)] // Uses P/Invokes to set security info
public void FileSystemWatcher_File_NotifyFilter_Security(NotifyFilters filter)
@@ -281,5 +308,34 @@ namespace System.IO.Tests
ExpectEvent(watcher, expected, action, cleanup, new string[] { otherFile, file.Path });
}
}
+
+ [Fact]
+ public void FileSystemWatcher_File_NotifyFilter_FileNameDoesntTriggerOnDirectoryEvent()
+ {
+ using (var testDirectory = new TempDirectory(GetTestFilePath()))
+ using (var file = new TempFile(Path.Combine(testDirectory.Path, "file")))
+ using (var sourcePath = new TempFile(Path.Combine(testDirectory.Path, "sourceFile")))
+ using (var watcher = new FileSystemWatcher(testDirectory.Path, "*"))
+ {
+ watcher.NotifyFilter = NotifyFilters.DirectoryName;
+ string otherFile = Path.Combine(testDirectory.Path, "file2");
+ string destPath = Path.Combine(testDirectory.Path, "destFile");
+
+ Action action = () =>
+ {
+ File.Create(otherFile).Dispose();
+ File.SetLastWriteTime(file.Path, DateTime.Now + TimeSpan.FromSeconds(10));
+ File.Delete(otherFile);
+ File.Move(sourcePath.Path, destPath);
+ };
+ Action cleanup = () =>
+ {
+ File.Move(destPath, sourcePath.Path);
+ };
+
+ WatcherChangeTypes expected = 0;
+ ExpectEvent(watcher, expected, action, cleanup, new string[] { otherFile, file.Path });
+ }
+ }
}
} \ No newline at end of file