|
// <copyright file="FileChangeNotificationSystem.cs" company="Microsoft">
// Copyright (c) 2009 Microsoft Corporation. All rights reserved.
// </copyright>
using System;
using System.Runtime.Caching.Hosting;
using System.Runtime.Caching.Resources;
using System.Collections;
using System.IO;
using System.Security;
using System.Security.Permissions;
namespace System.Runtime.Caching {
internal sealed class FileChangeNotificationSystem : IFileChangeNotificationSystem {
private Hashtable _dirMonitors;
private object _lock;
internal class DirectoryMonitor {
internal FileSystemWatcher Fsw;
}
internal class FileChangeEventTarget {
private string _fileName;
private OnChangedCallback _onChangedCallback;
private FileSystemEventHandler _changedHandler;
private ErrorEventHandler _errorHandler;
private 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;
}
if(s2.Length != s1.Length) {
return false;
}
return 0 == string.Compare(s1, 0, s2, 0, s2.Length, 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();
}
[SecuritySafeCritical]
[PermissionSet(SecurityAction.Assert, Unrestricted = true)]
void IFileChangeNotificationSystem.StartMonitoring(string filePath, OnChangedCallback onChangedCallback, out Object state, out DateTimeOffset lastWriteTime, out long fileSize) {
if (filePath == null) {
throw new ArgumentNullException("filePath");
}
if (onChangedCallback == null) {
throw new ArgumentNullException("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;
}
[SecuritySafeCritical]
[PermissionSet(SecurityAction.Assert, Unrestricted = true)]
void IFileChangeNotificationSystem.StopMonitoring(string filePath, Object state) {
if (filePath == null) {
throw new ArgumentNullException("filePath");
}
if (state == null) {
throw new ArgumentNullException("state");
}
FileChangeEventTarget target = state as FileChangeEventTarget;
if (target == null) {
throw new ArgumentException(R.Invalid_state,"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;
}
}
}
}
}
|