| File: System\Runtime\Caching\FileChangeNotificationSystem.cs | Web Access |
| Project: src\runtime\src\libraries\System.Runtime.Caching\src\System.Runtime.Caching.csproj (System.Runtime.Caching) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections; using System.IO; using System.Runtime.Caching.Hosting; using System.Runtime.Caching.Resources; using System.Runtime.Versioning; using System.Security; namespace System.Runtime.Caching { #if NET [UnsupportedOSPlatform("browser")] [UnsupportedOSPlatform("ios")] [UnsupportedOSPlatform("tvos")] [SupportedOSPlatform("maccatalyst")] #endif internal sealed class FileChangeNotificationSystem : IFileChangeNotificationSystem { private readonly Hashtable _dirMonitors; private readonly object _lock; internal sealed class DirectoryMonitor { internal FileSystemWatcher Fsw; } internal sealed class FileChangeEventTarget { private readonly string _fileName; private readonly OnChangedCallback _onChangedCallback; private readonly FileSystemEventHandler _changedHandler; private readonly ErrorEventHandler _errorHandler; private readonly RenamedEventHandler _renamedHandler; private static bool EqualsIgnoreCase(string s1, string s2) { if (string.IsNullOrEmpty(s1) && string.IsNullOrEmpty(s2)) { return true; } if (string.IsNullOrEmpty(s1) || string.IsNullOrEmpty(s2)) { return false; } return s1.Equals(s2, StringComparison.OrdinalIgnoreCase); } private void OnChanged(object sender, FileSystemEventArgs e) { if (EqualsIgnoreCase(_fileName, e.Name)) { _onChangedCallback(null); } } private void OnError(object sender, ErrorEventArgs e) { _onChangedCallback(null); } private void OnRenamed(object sender, RenamedEventArgs e) { if (EqualsIgnoreCase(_fileName, e.Name) || EqualsIgnoreCase(_fileName, e.OldName)) { _onChangedCallback(null); } } internal FileSystemEventHandler ChangedHandler { get { return _changedHandler; } } internal ErrorEventHandler ErrorHandler { get { return _errorHandler; } } internal RenamedEventHandler RenamedHandler { get { return _renamedHandler; } } internal FileChangeEventTarget(string fileName, OnChangedCallback onChangedCallback) { _fileName = fileName; _onChangedCallback = onChangedCallback; _changedHandler = new FileSystemEventHandler(this.OnChanged); _errorHandler = new ErrorEventHandler(this.OnError); _renamedHandler = new RenamedEventHandler(this.OnRenamed); } } internal FileChangeNotificationSystem() { _dirMonitors = Hashtable.Synchronized(new Hashtable(StringComparer.OrdinalIgnoreCase)); _lock = new object(); } void IFileChangeNotificationSystem.StartMonitoring(string filePath, OnChangedCallback onChangedCallback, out object state, out DateTimeOffset lastWriteTime, out long fileSize) { ArgumentNullException.ThrowIfNull(filePath); ArgumentNullException.ThrowIfNull(onChangedCallback); FileInfo fileInfo = new FileInfo(filePath); string dir = Path.GetDirectoryName(filePath); DirectoryMonitor dirMon = _dirMonitors[dir] as DirectoryMonitor; if (dirMon == null) { lock (_lock) { dirMon = _dirMonitors[dir] as DirectoryMonitor; if (dirMon == null) { dirMon = new DirectoryMonitor(); dirMon.Fsw = new FileSystemWatcher(dir); dirMon.Fsw.NotifyFilter = NotifyFilters.FileName | NotifyFilters.DirectoryName | NotifyFilters.CreationTime | NotifyFilters.Size | NotifyFilters.LastWrite | NotifyFilters.Security; dirMon.Fsw.EnableRaisingEvents = true; } _dirMonitors[dir] = dirMon; } } FileChangeEventTarget target = new FileChangeEventTarget(fileInfo.Name, onChangedCallback); lock (dirMon) { dirMon.Fsw.Changed += target.ChangedHandler; dirMon.Fsw.Created += target.ChangedHandler; dirMon.Fsw.Deleted += target.ChangedHandler; dirMon.Fsw.Error += target.ErrorHandler; dirMon.Fsw.Renamed += target.RenamedHandler; } state = target; lastWriteTime = File.GetLastWriteTime(filePath); fileSize = (fileInfo.Exists) ? fileInfo.Length : -1; } void IFileChangeNotificationSystem.StopMonitoring(string filePath, object state) { ArgumentNullException.ThrowIfNull(filePath); ArgumentNullException.ThrowIfNull(state); FileChangeEventTarget target = state as FileChangeEventTarget; if (target == null) { throw new ArgumentException(SR.Invalid_state, nameof(state)); } string dir = Path.GetDirectoryName(filePath); DirectoryMonitor dirMon = _dirMonitors[dir] as DirectoryMonitor; if (dirMon != null) { lock (dirMon) { dirMon.Fsw.Changed -= target.ChangedHandler; dirMon.Fsw.Created -= target.ChangedHandler; dirMon.Fsw.Deleted -= target.ChangedHandler; dirMon.Fsw.Error -= target.ErrorHandler; dirMon.Fsw.Renamed -= target.RenamedHandler; } } } } }