* roottypes.cs: Rename from tree.cs.
[mono.git] / mcs / class / System / System.IO / FAMWatcher.cs
index 2da293591390399aaca01d79448372953dc0e7fe..63faf5fed7c33acf9f2d6f53675f0cff53af96f4 100644 (file)
@@ -7,6 +7,27 @@
 // (c) 2004 Novell, Inc. (http://www.novell.com)
 //
 
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
 using System;
 using System.Collections;
 using System.ComponentModel;
@@ -18,7 +39,7 @@ using System.Threading;
 namespace System.IO {
        struct FAMConnection {
                public int FD;
-               IntPtr opaque;
+               public IntPtr opaque;
        }
 
        struct FAMRequest {
@@ -56,36 +77,37 @@ namespace System.IO {
                static FAMConnection conn;
                static Thread thread;
                static bool stop;
+               static bool use_gamin;
                
                private FAMWatcher ()
                {
                }
                
-               public static bool GetInstance (out IFileWatcher watcher)
+               // Locked by caller
+               public static bool GetInstance (out IFileWatcher watcher, bool gamin)
                {
-                       lock (typeof (FAMWatcher)) {
-                               if (failed == true) {
-                                       watcher = null;
-                                       return false;
-                               }
-
-                               if (instance != null) {
-                                       watcher = instance;
-                                       return true;
-                               }
-
-                               watches = Hashtable.Synchronized (new Hashtable ());
-                               requests = Hashtable.Synchronized (new Hashtable ());
-                               if (FAMOpen (out conn) == -1) {
-                                       failed = true;
-                                       watcher = null;
-                                       return false;
-                               }
+                       if (failed == true) {
+                               watcher = null;
+                               return false;
+                       }
 
-                               instance = new FAMWatcher ();
+                       if (instance != null) {
                                watcher = instance;
                                return true;
                        }
+
+                       use_gamin = gamin;
+                       watches = Hashtable.Synchronized (new Hashtable ());
+                       requests = Hashtable.Synchronized (new Hashtable ());
+                       if (FAMOpen (out conn) == -1) {
+                               failed = true;
+                               watcher = null;
+                               return false;
+                       }
+
+                       instance = new FAMWatcher ();
+                       watcher = instance;
+                       return true;
                }
                
                public void StartDispatching (FileSystemWatcher fsw)
@@ -105,14 +127,14 @@ namespace System.IO {
                                data = new FAMData ();
                                data.FSW = fsw;
                                data.Directory = fsw.FullPath;
-                               data.FileMask = fsw.Filter;
+                               data.FileMask = fsw.MangledFilter;
                                data.IncludeSubdirs = fsw.IncludeSubdirectories;
                                if (data.IncludeSubdirs)
                                        data.SubDirs = new Hashtable ();
 
                                data.Enabled = true;
+                               StartMonitoringDirectory (data, false);
                                lock (this) {
-                                       StartMonitoringDirectory (data);
                                        watches [fsw] = data;
                                        requests [data.Request.ReqNum] = data;
                                        stop = false;
@@ -120,28 +142,60 @@ namespace System.IO {
                        }
                }
 
-               static void StartMonitoringDirectory (FAMData data)
+               static void StartMonitoringDirectory (FAMData data, bool justcreated)
                {
                        FAMRequest fr;
+                       FileSystemWatcher fsw;
                        if (FAMMonitorDirectory (ref conn, data.Directory, out fr, IntPtr.Zero) == -1)
                                throw new Win32Exception ();
 
+                       fsw = data.FSW;
                        data.Request = fr;
-                       if (!data.IncludeSubdirs)
-                               return;
-
-                       foreach (string directory in Directory.GetDirectories (data.Directory)) {
-                               FAMData fd = new FAMData ();
-                               fd.FSW = data.FSW;
-                               fd.Directory = directory;
-                               fd.FileMask = data.FSW.Filter;
-                               fd.IncludeSubdirs = true;
-                               fd.SubDirs = new Hashtable ();
-                               fd.Enabled = true;
-
-                               StartMonitoringDirectory (fd);
-                               data.SubDirs [directory] = fd;
-                               requests [fd.Request.ReqNum] = fd;
+
+                       if (data.IncludeSubdirs) {
+                               foreach (string directory in Directory.GetDirectories (data.Directory)) {
+                                       FAMData fd = new FAMData ();
+                                       fd.FSW = data.FSW;
+                                       fd.Directory = directory;
+                                       fd.FileMask = data.FSW.MangledFilter;
+                                       fd.IncludeSubdirs = true;
+                                       fd.SubDirs = new Hashtable ();
+                                       fd.Enabled = true;
+
+                                       if (justcreated) {
+                                               lock (fsw) {
+                                                       RenamedEventArgs renamed = null;
+
+                                                       fsw.DispatchEvents (FileAction.Added, directory, ref renamed);
+
+                                                       if (fsw.Waiting) {
+                                                               fsw.Waiting = false;
+                                                               System.Threading.Monitor.PulseAll (fsw);
+                                                       }
+                                               }
+                                       }
+
+                                       StartMonitoringDirectory (fd, justcreated);
+                                       data.SubDirs [directory] = fd;
+                                       requests [fd.Request.ReqNum] = fd;
+                               }
+                       }
+
+                       if (justcreated) {
+                               foreach (string filename in Directory.GetFiles(data.Directory)) {
+                                       lock (fsw) {
+                                               RenamedEventArgs renamed = null;
+
+                                               fsw.DispatchEvents (FileAction.Added, filename, ref renamed);
+                                               /* If a file has been created, then it has been written to */
+                                               fsw.DispatchEvents (FileAction.Modified, filename, ref renamed);
+
+                                               if (fsw.Waiting) {
+                                                       fsw.Waiting = false;
+                                                       System.Threading.Monitor.PulseAll(fsw);
+                                               }
+                                       }
+                               }
                        }
                }
 
@@ -162,7 +216,7 @@ namespace System.IO {
                                if (!data.IncludeSubdirs)
                                        return;
 
-                               foreach (FAMData fd in data.SubDirs) {
+                               foreach (FAMData fd in data.SubDirs.Values) {
                                        StopMonitoringDirectory (fd);
                                        requests.Remove (fd.Request.ReqNum);
                                }
@@ -203,6 +257,7 @@ namespace System.IO {
 
                void ProcessEvents ()
                {
+                       ArrayList newdirs = null;
                        lock (this) {
                                do {
                                        int code;
@@ -257,31 +312,30 @@ namespace System.IO {
                                                string full = fsw.FullPath;
                                                string datadir = data.Directory;
                                                if (datadir != full) {
-                                                       string reldir = datadir.Substring (full.Length + 1);
+                                                       int len = full.Length;
+                                                       int slash = 1;
+                                                       if (len > 1 && full [len - 1] == Path.DirectorySeparatorChar)
+                                                               slash = 0;
+                                                       string reldir = datadir.Substring (full.Length + slash);
                                                        datadir = Path.Combine (datadir, filename);
                                                        filename = Path.Combine (reldir, filename);
                                                } else {
-                                                       datadir = Path.Combine (fsw.FullPath, filename);
+                                                       datadir = Path.Combine (full, filename);
                                                }
 
                                                if (fa == FileAction.Added && Directory.Exists (datadir)) {
+                                                       if (newdirs == null)
+                                                               newdirs = new ArrayList (4);
+
                                                        FAMData fd = new FAMData ();
                                                        fd.FSW = fsw;
                                                        fd.Directory = datadir;
-                                                       fd.FileMask = fsw.Filter;
+                                                       fd.FileMask = fsw.MangledFilter;
                                                        fd.IncludeSubdirs = true;
                                                        fd.SubDirs = new Hashtable ();
                                                        fd.Enabled = true;
-
-                                                       lock (instance) {
-                                                               StartMonitoringDirectory (fd);
-                                                       }
-
-                                                       lock (data) {
-                                                               data.SubDirs [datadir] = fd;
-                                                       }
-
-                                                       requests [fd.Request.ReqNum] = fd;
+                                                       newdirs.Add (fd);
+                                                       newdirs.Add (data);
                                                }
                                        }
 
@@ -297,27 +351,101 @@ namespace System.IO {
                                        }
                                } while (FAMPending (ref conn) > 0);
                        }
+
+
+                       if (newdirs != null) {
+                               int count = newdirs.Count;
+                               for (int n = 0; n < count; n += 2) {
+                                       FAMData newdir = (FAMData) newdirs [n];
+                                       FAMData parent = (FAMData) newdirs [n + 1];
+                                       StartMonitoringDirectory (newdir, true);
+                                       requests [newdir.Request.ReqNum] = newdir;
+                                       lock (parent) {
+                                               parent.SubDirs [newdir.Directory] = newdir;
+                                       }
+                               }
+                               newdirs.Clear ();
+                       }
+               }
+
+               ~FAMWatcher ()
+               {
+                       FAMClose (ref conn);
+               }
+
+               static int FAMOpen (out FAMConnection fc)
+               {
+                       if (use_gamin)
+                               return gamin_Open (out fc);
+                       return fam_Open (out fc);
+               }
+
+               static int FAMClose (ref FAMConnection fc)
+               {
+                       if (use_gamin)
+                               return gamin_Close (ref fc);
+                       return fam_Close (ref fc);
+               }
+
+               static int FAMMonitorDirectory (ref FAMConnection fc, string filename, out FAMRequest fr, IntPtr user_data)
+               {
+                       if (use_gamin)
+                               return gamin_MonitorDirectory (ref fc, filename, out fr, user_data);
+                       return fam_MonitorDirectory (ref fc, filename, out fr, user_data);
                }
 
-               [DllImport ("fam")]
-               extern static int FAMOpen (out FAMConnection fc);
+               static int FAMCancelMonitor (ref FAMConnection fc, ref FAMRequest fr)
+               {
+                       if (use_gamin)
+                               return gamin_CancelMonitor (ref fc, ref fr);
+                       return fam_CancelMonitor (ref fc, ref fr);
+               }
 
-               [DllImport ("fam")]
-               extern static int FAMClose (ref FAMConnection fc);
+               static int FAMPending (ref FAMConnection fc)
+               {
+                       if (use_gamin)
+                               return gamin_Pending (ref fc);
+                       return fam_Pending (ref fc);
+               }
+
+
+               
+               [DllImport ("libfam.so.0", EntryPoint="FAMOpen")]
+               extern static int fam_Open (out FAMConnection fc);
 
-               [DllImport ("fam")]
-               extern static int FAMMonitorDirectory (ref FAMConnection fc, string filename,
+               [DllImport ("libfam.so.0", EntryPoint="FAMClose")]
+               extern static int fam_Close (ref FAMConnection fc);
+
+               [DllImport ("libfam.so.0", EntryPoint="FAMMonitorDirectory")]
+               extern static int fam_MonitorDirectory (ref FAMConnection fc, string filename,
+                                                       out FAMRequest fr, IntPtr user_data);
+
+               [DllImport ("libfam.so.0", EntryPoint="FAMCancelMonitor")]
+               extern static int fam_CancelMonitor (ref FAMConnection fc, ref FAMRequest fr);
+
+               [DllImport ("libfam.so.0", EntryPoint="FAMPending")]
+               extern static int fam_Pending (ref FAMConnection fc);
+
+               [DllImport ("libgamin-1.so.0", EntryPoint="FAMOpen")]
+               extern static int gamin_Open (out FAMConnection fc);
+
+               [DllImport ("libgamin-1.so.0", EntryPoint="FAMClose")]
+               extern static int gamin_Close (ref FAMConnection fc);
+
+               [DllImport ("libgamin-1.so.0", EntryPoint="FAMMonitorDirectory")]
+               extern static int gamin_MonitorDirectory (ref FAMConnection fc, string filename,
                                                        out FAMRequest fr, IntPtr user_data);
 
-               [DllImport ("fam")]
-               extern static int FAMCancelMonitor (ref FAMConnection fc, ref FAMRequest fr);
+               [DllImport ("libgamin-1.so.0", EntryPoint="FAMCancelMonitor")]
+               extern static int gamin_CancelMonitor (ref FAMConnection fc, ref FAMRequest fr);
+
+               [DllImport ("libgamin-1.so.0", EntryPoint="FAMPending")]
+               extern static int gamin_Pending (ref FAMConnection fc);
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                extern static int InternalFAMNextEvent (ref FAMConnection fc, out string filename,
                                                        out int code, out int reqnum);
 
-               [DllImport ("fam")]
-               extern static int FAMPending (ref FAMConnection fc);
        }
 }