2 // System.IO.FAM.cs: interface with libfam
5 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 // (c) 2004 Novell, Inc. (http://www.novell.com)
11 using System.Collections;
12 using System.ComponentModel;
13 using System.Runtime.CompilerServices;
14 using System.Runtime.InteropServices;
16 using System.Threading;
19 struct FAMConnection {
41 public FileSystemWatcher FSW;
42 public string Directory;
43 public string FileMask;
44 public bool IncludeSubdirs;
46 public FAMRequest Request;
47 public Hashtable SubDirs;
50 class FAMWatcher : IFileWatcher
53 static FAMWatcher instance;
54 static Hashtable watches;
55 static Hashtable requests;
56 static FAMConnection conn;
64 public static bool GetInstance (out IFileWatcher watcher)
66 lock (typeof (FAMWatcher)) {
72 if (instance != null) {
77 watches = Hashtable.Synchronized (new Hashtable ());
78 requests = Hashtable.Synchronized (new Hashtable ());
79 if (FAMOpen (out conn) == -1) {
85 instance = new FAMWatcher ();
91 public void StartDispatching (FileSystemWatcher fsw)
96 thread = new Thread (new ThreadStart (Monitor));
97 thread.IsBackground = true;
101 data = (FAMData) watches [fsw];
105 data = new FAMData ();
107 data.Directory = fsw.FullPath;
108 data.FileMask = fsw.Filter;
109 data.IncludeSubdirs = fsw.IncludeSubdirectories;
110 if (data.IncludeSubdirs)
111 data.SubDirs = new Hashtable ();
115 StartMonitoringDirectory (data);
116 watches [fsw] = data;
117 requests [data.Request.ReqNum] = data;
123 static void StartMonitoringDirectory (FAMData data)
126 if (FAMMonitorDirectory (ref conn, data.Directory, out fr, IntPtr.Zero) == -1)
127 throw new Win32Exception ();
130 if (!data.IncludeSubdirs)
133 foreach (string directory in Directory.GetDirectories (data.Directory)) {
134 FAMData fd = new FAMData ();
136 fd.Directory = directory;
137 fd.FileMask = data.FSW.Filter;
138 fd.IncludeSubdirs = true;
139 fd.SubDirs = new Hashtable ();
142 StartMonitoringDirectory (fd);
143 data.SubDirs [directory] = fd;
144 requests [fd.Request.ReqNum] = fd;
148 public void StopDispatching (FileSystemWatcher fsw)
152 data = (FAMData) watches [fsw];
156 StopMonitoringDirectory (data);
157 watches.Remove (fsw);
158 requests.Remove (data.Request.ReqNum);
159 if (watches.Count == 0)
162 if (!data.IncludeSubdirs)
165 foreach (FAMData fd in data.SubDirs) {
166 StopMonitoringDirectory (fd);
167 requests.Remove (fd.Request.ReqNum);
172 static void StopMonitoringDirectory (FAMData data)
174 if (FAMCancelMonitor (ref conn, ref data.Request) == -1)
175 throw new Win32Exception ();
183 haveEvents = FAMPending (ref conn);
186 if (haveEvents > 0) {
199 const NotifyFilters changed = NotifyFilters.Attributes |
200 NotifyFilters.LastAccess |
202 NotifyFilters.LastWrite;
204 void ProcessEvents ()
211 FileSystemWatcher fsw;
213 if (InternalFAMNextEvent (ref conn, out filename,
214 out code, out requestNumber) != 1)
218 switch ((FAMCodes) code) {
219 case FAMCodes.Changed:
220 case FAMCodes.Deleted:
221 case FAMCodes.Created:
222 found = requests.ContainsKey (requestNumber);
225 case FAMCodes.StartExecuting:
226 case FAMCodes.StopExecuting:
227 case FAMCodes.Acknowledge:
228 case FAMCodes.Exists:
229 case FAMCodes.EndExist:
238 FAMData data = (FAMData) requests [requestNumber];
243 NotifyFilters flt = fsw.NotifyFilter;
244 RenamedEventArgs renamed = null;
246 if (code == (int) FAMCodes.Changed && (flt & changed) != 0)
247 fa = FileAction.Modified;
248 else if (code == (int) FAMCodes.Deleted)
249 fa = FileAction.Removed;
250 else if (code == (int) FAMCodes.Created)
251 fa = FileAction.Added;
256 if (fsw.IncludeSubdirectories) {
257 string full = fsw.FullPath;
258 string datadir = data.Directory;
259 if (datadir != full) {
260 string reldir = datadir.Substring (full.Length + 1);
261 datadir = Path.Combine (datadir, filename);
262 filename = Path.Combine (reldir, filename);
264 datadir = Path.Combine (fsw.FullPath, filename);
267 if (fa == FileAction.Added && Directory.Exists (datadir)) {
268 FAMData fd = new FAMData ();
270 fd.Directory = datadir;
271 fd.FileMask = fsw.Filter;
272 fd.IncludeSubdirs = true;
273 fd.SubDirs = new Hashtable ();
277 StartMonitoringDirectory (fd);
281 data.SubDirs [datadir] = fd;
284 requests [fd.Request.ReqNum] = fd;
288 if (filename != data.Directory && !fsw.Pattern.IsMatch (filename))
292 fsw.DispatchEvents (fa, filename, ref renamed);
295 System.Threading.Monitor.PulseAll (fsw);
298 } while (FAMPending (ref conn) > 0);
303 extern static int FAMOpen (out FAMConnection fc);
306 extern static int FAMClose (ref FAMConnection fc);
309 extern static int FAMMonitorDirectory (ref FAMConnection fc, string filename,
310 out FAMRequest fr, IntPtr user_data);
313 extern static int FAMCancelMonitor (ref FAMConnection fc, ref FAMRequest fr);
315 [MethodImplAttribute(MethodImplOptions.InternalCall)]
316 extern static int InternalFAMNextEvent (ref FAMConnection fc, out string filename,
317 out int code, out int reqnum);
320 extern static int FAMPending (ref FAMConnection fc);