Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'mcs/class/System/System.IO')
-rwxr-xr-xmcs/class/System/System.IO/ChangeLog21
-rw-r--r--mcs/class/System/System.IO/DefaultWatcher.cs30
-rw-r--r--mcs/class/System/System.IO/FAMWatcher.cs10
-rw-r--r--mcs/class/System/System.IO/KeventWatcher.cs351
4 files changed, 402 insertions, 10 deletions
diff --git a/mcs/class/System/System.IO/ChangeLog b/mcs/class/System/System.IO/ChangeLog
index 085d366180a..014914f20ca 100755
--- a/mcs/class/System/System.IO/ChangeLog
+++ b/mcs/class/System/System.IO/ChangeLog
@@ -1,3 +1,24 @@
+2004-10-07 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ * DefaultWatcher.cs: if the file is removed between reading the
+ directory and filling the file info, catch the exception and ignore the
+ file. Fixes bug #59482.
+
+2004-10-07 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ * DefaultWatcher.cs: don't use Directory.GetFileSystemEntries when the
+ pattern has no wildcards. Fixes bug #67447.
+
+2004-09-04 Gonzalo Paniagua Javier <gonzalo@ximian.com>
+
+ * FAMWatcher.cs: s/fam/libfam.so.0/ so that g_module finds it even
+ when the development package is not installed.
+
+2004-08-06 Geoff Norton <gnorton@customerdna.com>
+
+ * FileSystemWatcher.cs: Use the new KeventWatcher if its supported
+ * KeventWatcher.cs: Added to cvs
+
2004-06-24 Gonzalo Paniagua Javier <gonzalo@ximian.com>
* DefaultWatcher.cs: fixed subdirectories notifications and don't
diff --git a/mcs/class/System/System.IO/DefaultWatcher.cs b/mcs/class/System/System.IO/DefaultWatcher.cs
index 36d6d939f4e..b68149c4ca3 100644
--- a/mcs/class/System/System.IO/DefaultWatcher.cs
+++ b/mcs/class/System/System.IO/DefaultWatcher.cs
@@ -37,9 +37,10 @@ namespace System.IO {
class DefaultWatcherData {
public FileSystemWatcher FSW;
public string Directory;
- public string FileMask;
+ public string FileMask; // If NoWildcards, contains the full path to the file.
public bool IncludeSubdirs;
public bool Enabled;
+ public bool NoWildcards;
public DateTime DisabledTime;
public Hashtable Files;
}
@@ -100,7 +101,12 @@ namespace System.IO {
data.FSW = fsw;
data.Directory = fsw.FullPath;
- data.FileMask = fsw.MangledFilter;
+ data.NoWildcards = !fsw.Pattern.HasWildcard;
+ if (data.NoWildcards)
+ data.FileMask = Path.Combine (data.Directory, fsw.MangledFilter);
+ else
+ data.FileMask = fsw.MangledFilter;
+
data.IncludeSubdirs = fsw.IncludeSubdirectories;
data.Enabled = true;
data.DisabledTime = DateTime.MaxValue;
@@ -185,6 +191,7 @@ namespace System.IO {
}
}
+ static string [] NoStringsArray = new string [0];
void DoFiles (DefaultWatcherData data, string directory, bool dispatch)
{
bool direxists = Directory.Exists (directory);
@@ -194,10 +201,16 @@ namespace System.IO {
}
string [] files = null;
- if (direxists) {
+ if (!direxists) {
+ files = NoStringsArray;
+ } else if (!data.NoWildcards) {
files = Directory.GetFileSystemEntries (directory, data.FileMask);
} else {
- files = new string [0];
+ // The pattern does not have wildcards
+ if (File.Exists (data.FileMask))
+ files = new string [] { data.FileMask };
+ else
+ files = NoStringsArray;
}
/* Set all as untested */
@@ -211,7 +224,14 @@ namespace System.IO {
foreach (string filename in files) {
FileData fd = (FileData) data.Files [filename];
if (fd == null) {
- data.Files.Add (filename, CreateFileData (directory, filename));
+ try {
+ data.Files.Add (filename, CreateFileData (directory, filename));
+ } catch {
+ // The file might have been removed in the meanwhile
+ data.Files.Remove (filename);
+ continue;
+ }
+
if (dispatch)
DispatchEvents (data.FSW, FileAction.Added, filename);
} else if (fd.Directory == directory) {
diff --git a/mcs/class/System/System.IO/FAMWatcher.cs b/mcs/class/System/System.IO/FAMWatcher.cs
index 21e9bfeaff6..146411b8e91 100644
--- a/mcs/class/System/System.IO/FAMWatcher.cs
+++ b/mcs/class/System/System.IO/FAMWatcher.cs
@@ -320,24 +320,24 @@ namespace System.IO {
}
}
- [DllImport ("fam")]
+ [DllImport ("libfam.so.0")]
extern static int FAMOpen (out FAMConnection fc);
- [DllImport ("fam")]
+ [DllImport ("libfam.so.0")]
extern static int FAMClose (ref FAMConnection fc);
- [DllImport ("fam")]
+ [DllImport ("libfam.so.0")]
extern static int FAMMonitorDirectory (ref FAMConnection fc, string filename,
out FAMRequest fr, IntPtr user_data);
- [DllImport ("fam")]
+ [DllImport ("libfam.so.0")]
extern static int FAMCancelMonitor (ref FAMConnection fc, ref FAMRequest fr);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
extern static int InternalFAMNextEvent (ref FAMConnection fc, out string filename,
out int code, out int reqnum);
- [DllImport ("fam")]
+ [DllImport ("libfam.so.0")]
extern static int FAMPending (ref FAMConnection fc);
}
}
diff --git a/mcs/class/System/System.IO/KeventWatcher.cs b/mcs/class/System/System.IO/KeventWatcher.cs
new file mode 100644
index 00000000000..56eab5a1eef
--- /dev/null
+++ b/mcs/class/System/System.IO/KeventWatcher.cs
@@ -0,0 +1,351 @@
+//
+// System.IO.KeventWatcher.cs: interface with osx kevent
+//
+// Authors:
+// Geoff Norton (gnorton@customerdna.com)
+//
+// (c) 2004 Geoff Norton
+
+//
+// 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;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading;
+
+namespace System.IO {
+
+ struct kevent {
+ public int ident;
+ public short filter;
+ public ushort flags;
+ public uint fflags;
+ public int data;
+ public string udata;
+ }
+
+ struct timespec {
+ public int tv_sec;
+ public int tv_usec;
+ }
+
+ class KeventFileData {
+ public FileSystemInfo fsi;
+ public DateTime LastAccessTime;
+ public DateTime LastWriteTime;
+
+ public KeventFileData(FileSystemInfo fsi, DateTime LastAccessTime, DateTime LastWriteTime) {
+ this.fsi = fsi;
+ this.LastAccessTime = LastAccessTime;
+ this.LastWriteTime = LastWriteTime;
+ }
+ }
+
+ class KeventData {
+ public FileSystemWatcher FSW;
+ public string Directory;
+ public string FileMask;
+ public bool IncludeSubdirs;
+ public bool Enabled;
+ public Hashtable DirEntries;
+ public kevent ev;
+ }
+
+ class KeventWatcher : IFileWatcher
+ {
+ static bool failed;
+ static KeventWatcher instance;
+ static Hashtable watches;
+ static Hashtable requests;
+ static Thread thread;
+ static int conn;
+ static bool stop;
+
+ private KeventWatcher ()
+ {
+ }
+
+ public static bool GetInstance (out IFileWatcher watcher)
+ {
+ lock (typeof (KeventWatcher)) {
+ if (failed == true) {
+ watcher = null;
+ return false;
+ }
+
+ if (instance != null) {
+ watcher = instance;
+ return true;
+ }
+
+ watches = Hashtable.Synchronized (new Hashtable ());
+ requests = Hashtable.Synchronized (new Hashtable ());
+ conn = kqueue();
+ if (conn == -1) {
+ failed = true;
+ watcher = null;
+ return false;
+ }
+
+ instance = new KeventWatcher ();
+ watcher = instance;
+ return true;
+ }
+ }
+
+ public void StartDispatching (FileSystemWatcher fsw)
+ {
+ KeventData data;
+ lock (this) {
+ if (thread == null) {
+ thread = new Thread (new ThreadStart (Monitor));
+ thread.IsBackground = true;
+ thread.Start ();
+ }
+
+ data = (KeventData) watches [fsw];
+ }
+
+ if (data == null) {
+ data = new KeventData ();
+ data.FSW = fsw;
+ data.Directory = fsw.FullPath;
+ data.FileMask = fsw.MangledFilter;
+ data.IncludeSubdirs = fsw.IncludeSubdirectories;
+
+ data.Enabled = true;
+ lock (this) {
+ StartMonitoringDirectory (data);
+ watches [fsw] = data;
+ stop = false;
+ }
+ }
+ }
+
+ static void StartMonitoringDirectory (KeventData data)
+ {
+ DirectoryInfo dir = new DirectoryInfo (data.Directory);
+ if(data.DirEntries == null) {
+ data.DirEntries = new Hashtable();
+ foreach (FileSystemInfo fsi in dir.GetFileSystemInfos() )
+ data.DirEntries.Add(fsi.FullName, new KeventFileData(fsi, fsi.LastAccessTime, fsi.LastWriteTime));
+ }
+
+ int fd = open(data.Directory, 0, 0);
+ kevent ev = new kevent();
+ timespec nullts = new timespec();
+ nullts.tv_sec = 0;
+ nullts.tv_usec = 0;
+ if (fd > 0) {
+ ev.ident = fd;
+ ev.filter = -4;
+ ev.flags = 1 | 4 | 20;
+ ev.fflags = 20 | 2 | 1 | 8;
+ ev.data = 0;
+ ev.udata = data.Directory;
+ kevent outev = new kevent();
+ outev.udata = "";
+ kevent (conn, ref ev, 1, ref outev, 0, ref nullts);
+ data.ev = ev;
+ requests [fd] = data;
+ }
+
+ if (!data.IncludeSubdirs)
+ return;
+
+ }
+
+ public void StopDispatching (FileSystemWatcher fsw)
+ {
+ KeventData data;
+ lock (this) {
+ data = (KeventData) watches [fsw];
+ if (data == null)
+ return;
+
+ StopMonitoringDirectory (data);
+ watches.Remove (fsw);
+ if (watches.Count == 0)
+ stop = true;
+
+ if (!data.IncludeSubdirs)
+ return;
+
+ }
+ }
+
+ static void StopMonitoringDirectory (KeventData data)
+ {
+ close(data.ev.ident);
+ }
+
+ void Monitor ()
+ {
+
+ while (!stop) {
+ kevent ev = new kevent();
+ ev.udata = "";
+ kevent nullev = new kevent();
+ nullev.udata = "";
+ timespec ts = new timespec();
+ ts.tv_sec = 0;
+ ts.tv_usec = 0;
+ int haveEvents;
+ lock (this) {
+ haveEvents = kevent (conn, ref nullev, 0, ref ev, 1, ref ts);
+ }
+
+ if (haveEvents > 0) {
+ // Restart monitoring
+ KeventData data = (KeventData) requests [ev.ident];
+ StartMonitoringDirectory(data);
+ ProcessEvent (ev);
+ } else {
+ System.Threading.Thread.Sleep (500);
+ }
+ }
+
+ lock (this) {
+ thread = null;
+ stop = false;
+ }
+ }
+
+ void ProcessEvent (kevent ev)
+ {
+ lock (this) {
+ KeventData data = (KeventData) requests [ev.ident];
+ if (!data.Enabled)
+ return;
+
+ FileSystemWatcher fsw;
+ string filename = "";
+
+ fsw = data.FSW;
+ FileAction fa = 0;
+ DirectoryInfo dir = new DirectoryInfo (data.Directory);
+ FileSystemInfo changedFsi = null;
+
+ try {
+ foreach (FileSystemInfo fsi in dir.GetFileSystemInfos() )
+ if (data.DirEntries.ContainsKey (fsi.FullName) && (fsi is FileInfo)) {
+ KeventFileData entry = (KeventFileData) data.DirEntries [fsi.FullName];
+ if ( (entry.LastWriteTime != fsi.LastWriteTime) || (entry.LastAccessTime != fsi.LastAccessTime) ) {
+ filename = fsi.FullName;
+ fa = FileAction.Modified;
+ data.DirEntries [fsi.FullName] = new KeventFileData(fsi, fsi.LastAccessTime, fsi.LastWriteTime);
+ if (fsw.IncludeSubdirectories && fsi is DirectoryInfo) {
+ data.Directory = filename;
+ requests [ev.ident] = data;
+ ProcessEvent(ev);
+ }
+ PostEvent(filename, fsw, fa, changedFsi);
+ }
+ }
+ } catch (Exception) {
+ // The file system infos were changed while we processed them
+ }
+ // Deleted
+ try {
+ bool deleteMatched = true;
+ while(deleteMatched) {
+ foreach (KeventFileData entry in data.DirEntries.Values) {
+ if (!File.Exists (entry.fsi.FullName) && !Directory.Exists (entry.fsi.FullName)) {
+ filename = entry.fsi.FullName;
+ fa = FileAction.Removed;
+ data.DirEntries.Remove (entry.fsi.FullName);
+ PostEvent(filename, fsw, fa, changedFsi);
+ break;
+ }
+ }
+ deleteMatched = false;
+ }
+ } catch (Exception) {
+ // The file system infos were changed while we processed them
+ }
+ // Added
+ try {
+ foreach (FileSystemInfo fsi in dir.GetFileSystemInfos())
+ if (!data.DirEntries.ContainsKey (fsi.FullName)) {
+ changedFsi = fsi;
+ filename = fsi.FullName;
+ fa = FileAction.Added;
+ data.DirEntries [fsi.FullName] = new KeventFileData(fsi, fsi.LastAccessTime, fsi.LastWriteTime);
+ PostEvent(filename, fsw, fa, changedFsi);
+ }
+ } catch (Exception) {
+ // The file system infos were changed while we processed them
+ }
+
+
+ }
+ }
+
+ private void PostEvent (string filename, FileSystemWatcher fsw, FileAction fa, FileSystemInfo changedFsi) {
+ RenamedEventArgs renamed = null;
+ if (fa == 0)
+ return;
+
+ if (fsw.IncludeSubdirectories && fa == FileAction.Added) {
+ if (changedFsi is DirectoryInfo) {
+ KeventData newdirdata = new KeventData ();
+ newdirdata.FSW = fsw;
+ newdirdata.Directory = changedFsi.FullName;
+ newdirdata.FileMask = fsw.MangledFilter;
+ newdirdata.IncludeSubdirs = fsw.IncludeSubdirectories;
+
+ newdirdata.Enabled = true;
+ lock (this) {
+ StartMonitoringDirectory (newdirdata);
+ }
+ }
+ }
+
+ if (!fsw.Pattern.IsMatch(filename))
+ return;
+
+ lock (fsw) {
+ fsw.DispatchEvents (fa, filename, ref renamed);
+ if (fsw.Waiting) {
+ fsw.Waiting = false;
+ System.Threading.Monitor.PulseAll (fsw);
+ }
+ }
+ }
+
+ [DllImport ("libc")]
+ extern static int open(string path, int flags, int mode_t);
+
+ [DllImport ("libc")]
+ extern static int close(int fd);
+
+ [DllImport ("libc")]
+ extern static int kqueue();
+
+ [DllImport ("libc")]
+ extern static int kevent(int kqueue, ref kevent ev, int nchanges, ref kevent evtlist, int nevents, ref timespec ts);
+ }
+}
+