2 // System.IO.DefaultWatcher.cs: default IFileWatcher
5 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 // (c) 2004 Novell, Inc. (http://www.novell.com)
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System.Collections;
33 using System.Collections.Generic;
35 using System.Threading;
38 class DefaultWatcherData {
39 public FileSystemWatcher FSW;
40 public string Directory;
41 public string FileMask; // If NoWildcards, contains the full path to the file.
42 public bool IncludeSubdirs;
44 public bool NoWildcards;
45 public DateTime DisabledTime;
47 public object FilesLock = new object ();
48 public Hashtable Files;
52 public string Directory;
53 public FileAttributes Attributes;
54 public bool NotExists;
55 public DateTime CreationTime;
56 public DateTime LastWriteTime;
59 class DefaultWatcher : IFileWatcher
61 static DefaultWatcher instance;
63 static Hashtable watches;
65 private DefaultWatcher ()
70 public static bool GetInstance (out IFileWatcher watcher)
72 if (instance != null) {
77 instance = new DefaultWatcher ();
82 public void StartDispatching (FileSystemWatcher fsw)
84 DefaultWatcherData data;
87 watches = new Hashtable ();
90 thread = new Thread (new ThreadStart (Monitor));
91 thread.IsBackground = true;
97 data = (DefaultWatcherData) watches [fsw];
99 data = new DefaultWatcherData ();
100 data.Files = new Hashtable ();
101 watches [fsw] = data;
105 data.Directory = fsw.FullPath;
106 data.NoWildcards = !fsw.Pattern.HasWildcard;
107 if (data.NoWildcards)
108 data.FileMask = Path.Combine (data.Directory, fsw.MangledFilter);
110 data.FileMask = fsw.MangledFilter;
112 data.IncludeSubdirs = fsw.IncludeSubdirectories;
114 data.DisabledTime = DateTime.MaxValue;
115 UpdateDataAndDispatch (data, false);
119 public void StopDispatching (FileSystemWatcher fsw)
121 DefaultWatcherData data;
123 if (watches == null) return;
127 data = (DefaultWatcherData) watches [fsw];
129 data.Enabled = false;
130 data.DisabledTime = DateTime.Now;
143 Hashtable my_watches;
145 if (watches.Count == 0) {
151 my_watches = (Hashtable) watches.Clone ();
154 if (my_watches.Count != 0) {
156 foreach (DefaultWatcherData data in my_watches.Values) {
157 bool remove = UpdateDataAndDispatch (data, true);
160 watches.Remove (data.FSW);
170 bool UpdateDataAndDispatch (DefaultWatcherData data, bool dispatch)
173 return (data.DisabledTime != DateTime.MaxValue &&
174 (DateTime.Now - data.DisabledTime).TotalSeconds > 5);
177 DoFiles (data, data.Directory, dispatch);
181 static void DispatchEvents (FileSystemWatcher fsw, FileAction action, string filename)
183 RenamedEventArgs renamed = null;
186 fsw.DispatchEvents (action, filename, ref renamed);
189 System.Threading.Monitor.PulseAll (fsw);
194 static string [] NoStringsArray = new string [0];
195 void DoFiles (DefaultWatcherData data, string directory, bool dispatch)
197 bool direxists = Directory.Exists (directory);
198 if (direxists && data.IncludeSubdirs) {
199 foreach (string d in Directory.GetDirectories (directory))
200 DoFiles (data, d, dispatch);
203 string [] files = null;
205 files = NoStringsArray;
206 } else if (!data.NoWildcards) {
207 files = Directory.GetFileSystemEntries (directory, data.FileMask);
209 // The pattern does not have wildcards
210 if (File.Exists (data.FileMask) || Directory.Exists (data.FileMask))
211 files = new string [] { data.FileMask };
213 files = NoStringsArray;
216 lock (data.FilesLock) {
217 IterateAndModifyFilesData (data, directory, dispatch, files);
221 void IterateAndModifyFilesData (DefaultWatcherData data, string directory, bool dispatch, string[] files)
223 /* Set all as untested */
224 foreach (string filename in data.Files.Keys) {
225 FileData fd = (FileData) data.Files [filename];
226 if (fd.Directory == directory)
231 foreach (string filename in files) {
232 FileData fd = (FileData) data.Files [filename];
235 data.Files.Add (filename, CreateFileData (directory, filename));
237 // The file might have been removed in the meanwhile
238 data.Files.Remove (filename);
243 DispatchEvents (data.FSW, FileAction.Added, filename);
244 } else if (fd.Directory == directory) {
245 fd.NotExists = false;
249 if (!dispatch) // We only initialize the file list
253 List<string> removed = null;
254 foreach (string filename in data.Files.Keys) {
255 FileData fd = (FileData) data.Files [filename];
258 removed = new List<string> ();
260 removed.Add (filename);
261 DispatchEvents (data.FSW, FileAction.Removed, filename);
265 if (removed != null) {
266 foreach (string filename in removed)
267 data.Files.Remove (filename);
273 foreach (string filename in data.Files.Keys) {
274 FileData fd = (FileData) data.Files [filename];
275 DateTime creation, write;
277 creation = File.GetCreationTime (filename);
278 write = File.GetLastWriteTime (filename);
282 removed = new List<string> ();
284 removed.Add (filename);
285 DispatchEvents (data.FSW, FileAction.Removed, filename);
289 if (creation != fd.CreationTime || write != fd.LastWriteTime) {
290 fd.CreationTime = creation;
291 fd.LastWriteTime = write;
292 DispatchEvents (data.FSW, FileAction.Modified, filename);
296 if (removed != null) {
297 foreach (string filename in removed)
298 data.Files.Remove (filename);
303 static FileData CreateFileData (string directory, string filename)
305 FileData fd = new FileData ();
306 string fullpath = Path.Combine (directory, filename);
307 fd.Directory = directory;
308 fd.Attributes = File.GetAttributes (fullpath);
309 fd.CreationTime = File.GetCreationTime (fullpath);
310 fd.LastWriteTime = File.GetLastWriteTime (fullpath);