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 (object handle
)
84 var fsw
= handle
as FileSystemWatcher
;
85 DefaultWatcherData data
;
88 watches
= new Hashtable ();
91 thread
= new Thread (new ThreadStart (Monitor
));
92 thread
.IsBackground
= true;
98 data
= (DefaultWatcherData
) watches
[fsw
];
100 data
= new DefaultWatcherData ();
101 data
.Files
= new Hashtable ();
102 watches
[fsw
] = data
;
106 data
.Directory
= fsw
.FullPath
;
107 data
.NoWildcards
= !fsw
.Pattern
.HasWildcard
;
108 if (data
.NoWildcards
)
109 data
.FileMask
= Path
.Combine (data
.Directory
, fsw
.MangledFilter
);
111 data
.FileMask
= fsw
.MangledFilter
;
113 data
.IncludeSubdirs
= fsw
.IncludeSubdirectories
;
115 data
.DisabledTime
= DateTime
.MaxValue
;
116 UpdateDataAndDispatch (data
, false);
120 public void StopDispatching (object handle
)
122 var fsw
= handle
as FileSystemWatcher
;
123 DefaultWatcherData data
;
125 if (watches
== null) return;
129 data
= (DefaultWatcherData
) watches
[fsw
];
131 data
.Enabled
= false;
132 data
.DisabledTime
= DateTime
.UtcNow
;
137 public void Dispose (object handle
)
150 Hashtable my_watches
;
152 if (watches
.Count
== 0) {
158 my_watches
= (Hashtable
) watches
.Clone ();
161 if (my_watches
.Count
!= 0) {
163 foreach (DefaultWatcherData data
in my_watches
.Values
) {
164 bool remove = UpdateDataAndDispatch (data
, true);
167 watches
.Remove (data
.FSW
);
177 bool UpdateDataAndDispatch (DefaultWatcherData data
, bool dispatch
)
180 return (data
.DisabledTime
!= DateTime
.MaxValue
&&
181 (DateTime
.UtcNow
- data
.DisabledTime
).TotalSeconds
> 5);
184 DoFiles (data
, data
.Directory
, dispatch
);
188 static void DispatchEvents (FileSystemWatcher fsw
, FileAction action
, string filename
)
190 RenamedEventArgs renamed
= null;
193 fsw
.DispatchEvents (action
, filename
, ref renamed
);
196 System
.Threading
.Monitor
.PulseAll (fsw
);
201 static string [] NoStringsArray
= new string [0];
202 void DoFiles (DefaultWatcherData data
, string directory
, bool dispatch
)
204 bool direxists
= Directory
.Exists (directory
);
205 if (direxists
&& data
.IncludeSubdirs
) {
206 foreach (string d
in Directory
.GetDirectories (directory
))
207 DoFiles (data
, d
, dispatch
);
210 string [] files
= null;
212 files
= NoStringsArray
;
213 } else if (!data
.NoWildcards
) {
214 files
= Directory
.GetFileSystemEntries (directory
, data
.FileMask
);
216 // The pattern does not have wildcards
217 if (File
.Exists (data
.FileMask
) || Directory
.Exists (data
.FileMask
))
218 files
= new string [] { data.FileMask }
;
220 files
= NoStringsArray
;
223 lock (data
.FilesLock
) {
224 IterateAndModifyFilesData (data
, directory
, dispatch
, files
);
228 void IterateAndModifyFilesData (DefaultWatcherData data
, string directory
, bool dispatch
, string[] files
)
230 /* Set all as untested */
231 foreach (string filename
in data
.Files
.Keys
) {
232 FileData fd
= (FileData
) data
.Files
[filename
];
233 if (fd
.Directory
== directory
)
238 foreach (string filename
in files
) {
239 FileData fd
= (FileData
) data
.Files
[filename
];
242 data
.Files
.Add (filename
, CreateFileData (directory
, filename
));
244 // The file might have been removed in the meanwhile
245 data
.Files
.Remove (filename
);
250 DispatchEvents (data
.FSW
, FileAction
.Added
, filename
);
251 } else if (fd
.Directory
== directory
) {
252 fd
.NotExists
= false;
256 if (!dispatch
) // We only initialize the file list
260 List
<string> removed
= null;
261 foreach (string filename
in data
.Files
.Keys
) {
262 FileData fd
= (FileData
) data
.Files
[filename
];
265 removed
= new List
<string> ();
267 removed
.Add (filename
);
268 DispatchEvents (data
.FSW
, FileAction
.Removed
, filename
);
272 if (removed
!= null) {
273 foreach (string filename
in removed
)
274 data
.Files
.Remove (filename
);
280 foreach (string filename
in data
.Files
.Keys
) {
281 FileData fd
= (FileData
) data
.Files
[filename
];
282 DateTime creation
, write
;
284 creation
= File
.GetCreationTime (filename
);
285 write
= File
.GetLastWriteTime (filename
);
289 removed
= new List
<string> ();
291 removed
.Add (filename
);
292 DispatchEvents (data
.FSW
, FileAction
.Removed
, filename
);
296 if (creation
!= fd
.CreationTime
|| write
!= fd
.LastWriteTime
) {
297 fd
.CreationTime
= creation
;
298 fd
.LastWriteTime
= write
;
299 DispatchEvents (data
.FSW
, FileAction
.Modified
, filename
);
303 if (removed
!= null) {
304 foreach (string filename
in removed
)
305 data
.Files
.Remove (filename
);
310 static FileData
CreateFileData (string directory
, string filename
)
312 FileData fd
= new FileData ();
313 string fullpath
= Path
.Combine (directory
, filename
);
314 fd
.Directory
= directory
;
315 fd
.Attributes
= File
.GetAttributes (fullpath
);
316 fd
.CreationTime
= File
.GetCreationTime (fullpath
);
317 fd
.LastWriteTime
= File
.GetLastWriteTime (fullpath
);