예제 #1
0
파일: KeventWatcher.cs 프로젝트: iainx/mono
        kevent[] CreateChangeList(ref List <int> FdList)
        {
            if (FdList.Count == 0)
            {
                return(emptyEventList);
            }

            var changes = new List <kevent> ();

            foreach (int fd in FdList)
            {
                var change = new kevent {
                    ident  = (UIntPtr)fd,
                    filter = EventFilter.Vnode,
                    flags  = EventFlags.Add | EventFlags.Enable | EventFlags.Clear,
                    fflags = FilterFlags.VNodeDelete | FilterFlags.VNodeExtend |
                             FilterFlags.VNodeRename | FilterFlags.VNodeAttrib |
                             FilterFlags.VNodeLink | FilterFlags.VNodeRevoke |
                             FilterFlags.VNodeWrite,
                    data  = IntPtr.Zero,
                    udata = IntPtr.Zero
                };

                changes.Add(change);
            }
            FdList.Clear();

            return(changes.ToArray());
        }
예제 #2
0
		void Setup ()
		{	
			var initialFds = new List<int> ();

			// fsw.FullPath may end in '/', see https://bugzilla.xamarin.com/show_bug.cgi?id=5747
			if (fsw.FullPath != "/" && fsw.FullPath.EndsWith ("/", StringComparison.Ordinal))
				fullPathNoLastSlash = fsw.FullPath.Substring (0, fsw.FullPath.Length - 1);
			else
				fullPathNoLastSlash = fsw.FullPath;
				
			// GetFilenameFromFd() returns the *realpath* which can be different than fsw.FullPath because symlinks.
			// If so, introduce a fixup step.
			int fd = open (fullPathNoLastSlash, O_EVTONLY, 0);
			var resolvedFullPath = GetFilenameFromFd (fd);
			close (fd);

			if (resolvedFullPath != fullPathNoLastSlash)
				fixupPath = resolvedFullPath;
			else
				fixupPath = null;

			Scan (fullPathNoLastSlash, false, ref initialFds);

			var immediate_timeout = new timespec { tv_sec = (IntPtr)0, tv_usec = (IntPtr)0 };
			var eventBuffer = new kevent[0]; // we don't want to take any events from the queue at this point
			var changes = CreateChangeList (ref initialFds);

			int numEvents = kevent (conn, changes, changes.Length, eventBuffer, eventBuffer.Length, ref immediate_timeout);

			if (numEvents == -1) {
				var errMsg = String.Format ("kevent() error at initial event registration, error code = '{0}'", Marshal.GetLastWin32Error ());
				throw new IOException (errMsg);
			}
		}
예제 #3
0
 private void Monitor()
 {
     while (!KeventWatcher.stop)
     {
         kevent ev = default(kevent);
         ev.udata = IntPtr.Zero;
         kevent kevent = default(kevent);
         kevent.udata = IntPtr.Zero;
         timespec timespec = default(timespec);
         timespec.tv_sec  = 0;
         timespec.tv_usec = 0;
         int num;
         lock (this)
         {
             num = KeventWatcher.kevent(KeventWatcher.conn, ref kevent, 0, ref ev, 1, ref timespec);
         }
         if (num > 0)
         {
             KeventData data = (KeventData)KeventWatcher.requests[ev.ident];
             KeventWatcher.StopMonitoringDirectory(data);
             KeventWatcher.StartMonitoringDirectory(data);
             this.ProcessEvent(ev);
         }
         else
         {
             Thread.Sleep(500);
         }
     }
     lock (this)
     {
         KeventWatcher.thread = null;
         KeventWatcher.stop   = false;
     }
 }
예제 #4
0
        void Monitor()
        {
            while (!stop)
            {
                kevent ev = new kevent();
                ev.udata = IntPtr.Zero;
                kevent nullev = new kevent();
                nullev.udata = IntPtr.Zero;
                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];
                    StopMonitoringDirectory(data);
                    StartMonitoringDirectory(data);
                    ProcessEvent(ev);
                }
                else
                {
                    System.Threading.Thread.Sleep(500);
                }
            }

            lock (this) {
                thread = null;
                stop   = false;
            }
        }
예제 #5
0
 private void Monitor()
 {
     while (!stop)
     {
         kevent evtlist = default(kevent);
         evtlist.udata = IntPtr.Zero;
         kevent ev = default(kevent);
         ev.udata = IntPtr.Zero;
         timespec ts = default(timespec);
         ts.tv_sec  = 0;
         ts.tv_usec = 0;
         int num;
         lock (this)
         {
             num = kevent(conn, ref ev, 0, ref evtlist, 1, ref ts);
         }
         if (num > 0)
         {
             KeventData data = (KeventData)requests[evtlist.ident];
             StopMonitoringDirectory(data);
             StartMonitoringDirectory(data);
             ProcessEvent(evtlist);
         }
         else
         {
             Thread.Sleep(500);
         }
     }
     lock (this)
     {
         thread = null;
         stop   = false;
     }
 }
예제 #6
0
        void Setup()
        {
            var initialFds = new List <int> ();

            // fsw.FullPath may end in '/', see https://bugzilla.xamarin.com/show_bug.cgi?id=5747
            if (fsw.FullPath != "/" && fsw.FullPath.EndsWith("/", StringComparison.Ordinal))
            {
                fullPathNoLastSlash = fsw.FullPath.Substring(0, fsw.FullPath.Length - 1);
            }
            else
            {
                fullPathNoLastSlash = fsw.FullPath;
            }

            // realpath() returns the *realpath* which can be different than fsw.FullPath because symlinks.
            // If so, introduce a fixup step.
            var sb = new StringBuilder(__DARWIN_MAXPATHLEN);

            if (realpath(fsw.FullPath, sb) == IntPtr.Zero)
            {
                var errMsg = String.Format("realpath({0}) failed, error code = '{1}'", fsw.FullPath, Marshal.GetLastWin32Error());
                throw new IOException(errMsg);
            }
            var resolvedFullPath = sb.ToString();

            if (resolvedFullPath != fullPathNoLastSlash)
            {
                fixupPath = resolvedFullPath;
            }
            else
            {
                fixupPath = null;
            }

            Scan(fullPathNoLastSlash, false, ref initialFds);

            var immediate_timeout = new timespec {
                tv_sec = (IntPtr)0, tv_nsec = (IntPtr)0
            };
            var eventBuffer = new kevent[0];             // we don't want to take any events from the queue at this point
            var changes     = CreateChangeList(ref initialFds);

            int numEvents;
            int errno = 0;

            do
            {
                numEvents = kevent(conn, changes, changes.Length, eventBuffer, eventBuffer.Length, ref immediate_timeout);
                if (numEvents == -1)
                {
                    errno = Marshal.GetLastWin32Error();
                }
            } while (numEvents == -1 && errno == EINTR);

            if (numEvents == -1)
            {
                var errMsg = String.Format("kevent() error at initial event registration, error code = '{0}'", errno);
                throw new IOException(errMsg);
            }
        }
예제 #7
0
        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();

            ev.udata = IntPtr.Zero;
            timespec nullts = new timespec();

            nullts.tv_sec  = 0;
            nullts.tv_usec = 0;
            if (fd > 0)
            {
                ev.ident  = fd;
                ev.filter = EventFilter.Vnode;
                ev.flags  = EventFlags.Add | EventFlags.Enable | EventFlags.OneShot;
                ev.fflags =                 // 20 | 2 | 1 | 8;
                            FilterFlags.VNodeDelete |
                            FilterFlags.VNodeWrite |
                            FilterFlags.VNodeAttrib |
                            // The following two values are the equivalent of the original value "20", but we suspect the original author meant
                            // 0x20, we will review later with some test cases
                            FilterFlags.VNodeLink |
                            FilterFlags.VNodeExtend;
                ev.data  = 0;
                ev.udata = Marshal.StringToHGlobalAuto(data.Directory);
                kevent outev = new kevent();
                outev.udata = IntPtr.Zero;
                kevent(conn, ref ev, 1, ref outev, 0, ref nullts);
                data.ev       = ev;
                requests [fd] = data;
            }

            if (!data.IncludeSubdirs)
            {
                return;
            }
        }
예제 #8
0
        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();

            ev.udata = IntPtr.Zero;
            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  = Marshal.StringToHGlobalAuto(data.Directory);
                kevent outev = new kevent();
                outev.udata = IntPtr.Zero;
                kevent(conn, ref ev, 1, ref outev, 0, ref nullts);
                data.ev       = ev;
                requests [fd] = data;
            }

            if (!data.IncludeSubdirs)
            {
                return;
            }
        }
예제 #9
0
        private static void StartMonitoringDirectory(KeventData data)
        {
            DirectoryInfo directoryInfo = new DirectoryInfo(data.Directory);

            if (data.DirEntries == null)
            {
                data.DirEntries = new Hashtable();
                FileSystemInfo[] fileSystemInfos = directoryInfo.GetFileSystemInfos();
                foreach (FileSystemInfo fileSystemInfo in fileSystemInfos)
                {
                    data.DirEntries.Add(fileSystemInfo.FullName, new KeventFileData(fileSystemInfo, fileSystemInfo.LastAccessTime, fileSystemInfo.LastWriteTime));
                }
            }
            int    num = open(data.Directory, 0, 0);
            kevent ev  = default(kevent);

            ev.udata = IntPtr.Zero;
            timespec ts = default(timespec);

            ts.tv_sec  = 0;
            ts.tv_usec = 0;
            if (num > 0)
            {
                ev.ident  = num;
                ev.filter = -4;
                ev.flags  = 21;
                ev.fflags = 31u;
                ev.data   = 0;
                ev.udata  = Marshal.StringToHGlobalAuto(data.Directory);
                kevent evtlist = default(kevent);
                evtlist.udata = IntPtr.Zero;
                kevent(conn, ref ev, 1, ref evtlist, 0, ref ts);
                data.ev       = ev;
                requests[num] = data;
            }
            if (data.IncludeSubdirs)
            {
            }
        }
예제 #10
0
        void Setup()
        {
            var initialFds = new List <int> ();

            // GetFilenameFromFd() returns the *realpath* which can be different than fsw.FullPath because symlinks.
            // If so, introduce a fixup step.
            int fd = open(fsw.FullPath, O_EVTONLY, 0);
            var resolvedFullPath = GetFilenameFromFd(fd);

            close(fd);

            if (resolvedFullPath != fsw.FullPath)
            {
                fixupPath = resolvedFullPath;
            }
            else
            {
                fixupPath = null;
            }

            Scan(fsw.FullPath, false, ref initialFds);

            var immediate_timeout = new timespec {
                tv_sec = (IntPtr)0, tv_usec = (IntPtr)0
            };
            var eventBuffer = new kevent[0];             // we don't want to take any events from the queue at this point
            var changes     = CreateChangeList(ref initialFds);

            int numEvents = kevent(conn, changes, changes.Length, eventBuffer, eventBuffer.Length, ref immediate_timeout);

            if (numEvents == -1)
            {
                var errMsg = String.Format("kevent() error at initial event registration, error code = '{0}'", Marshal.GetLastWin32Error());
                throw new IOException(errMsg);
            }
        }
예제 #11
0
파일: KeventWatcher.cs 프로젝트: av8/mono
		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();
			ev.udata = IntPtr.Zero;
			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 = Marshal.StringToHGlobalAuto (data.Directory);
				kevent outev = new kevent();
				outev.udata = IntPtr.Zero;
				kevent (conn, ref ev, 1, ref outev, 0, ref nullts);
				data.ev = ev;
				requests [fd] = data;
			}
			
			if (!data.IncludeSubdirs)
				return;

		}
예제 #12
0
        void Monitor()
        {
            var timeout = new timespec {
                tv_sec = (IntPtr)0, tv_usec = (IntPtr)500000000
            };
            var             eventBuffer = new kevent[32];
            var             newFds      = new List <int> ();
            List <PathData> removeQueue = new List <PathData> ();
            List <string>   rescanQueue = new List <string> ();

            while (!requestStop)
            {
                var changes = CreateChangeList(ref newFds);

                int numEvents = kevent(conn, changes, changes.Length, eventBuffer, eventBuffer.Length, ref timeout);

                if (numEvents == -1)
                {
                    var errMsg = String.Format("kevent() error, error code = '{0}'", Marshal.GetLastWin32Error());
                    fsw.OnError(new ErrorEventArgs(new IOException(errMsg)));
                }

                if (numEvents == 0)
                {
                    continue;
                }

                for (var i = 0; i < numEvents; i++)
                {
                    var kevt     = eventBuffer [i];
                    var pathData = fdsDict [(int)kevt.ident];

                    if ((kevt.flags & EventFlags.Error) == EventFlags.Error)
                    {
                        var errMsg = String.Format("kevent() error watching path '{0}', error code = '{1}'", pathData.Path, kevt.data);
                        fsw.OnError(new ErrorEventArgs(new IOException(errMsg)));
                        continue;
                    }

                    if ((kevt.fflags & FilterFlags.VNodeDelete) == FilterFlags.VNodeDelete || (kevt.fflags & FilterFlags.VNodeRevoke) == FilterFlags.VNodeRevoke)
                    {
                        removeQueue.Add(pathData);
                    }

                    else if ((kevt.fflags & FilterFlags.VNodeWrite) == FilterFlags.VNodeWrite)
                    {
                        if (pathData.IsDirectory)
                        {
                            rescanQueue.Add(pathData.Path);
                        }
                        else
                        {
                            PostEvent(FileAction.Modified, pathData.Path);
                        }
                    }

                    else if ((kevt.fflags & FilterFlags.VNodeRename) == FilterFlags.VNodeRename)
                    {
                        var newFilename = GetFilenameFromFd(pathData.Fd);

                        if (newFilename.StartsWith(fsw.FullPath))
                        {
                            Rename(pathData, newFilename);
                        }
                        else                         //moved outside of our watched dir so stop watching
                        {
                            RemoveTree(pathData);
                        }
                    }

                    else if ((kevt.fflags & FilterFlags.VNodeAttrib) == FilterFlags.VNodeAttrib || (kevt.fflags & FilterFlags.VNodeExtend) == FilterFlags.VNodeExtend)
                    {
                        PostEvent(FileAction.Modified, pathData.Path);
                    }
                }

                removeQueue.ForEach(Remove);
                removeQueue.Clear();

                rescanQueue.ForEach(path => {
                    Scan(path, true, ref newFds);
                });
                rescanQueue.Clear();
            }
        }
예제 #13
0
		void Monitor ()
		{
			var eventBuffer = new kevent[32];
			var newFds = new List<int> ();
			List<PathData> removeQueue = new List<PathData> ();
			List<string> rescanQueue = new List<string> ();

			int retries = 0; 

			while (!requestStop) {
				var changes = CreateChangeList (ref newFds);

				// We are calling an icall, so have to marshal manually
				// Marshal in
				int ksize = Marshal.SizeOf<kevent> ();
				var changesNative = Marshal.AllocHGlobal (ksize * changes.Length);
				for (int i = 0; i < changes.Length; ++i)
					Marshal.StructureToPtr (changes [i], changesNative + (i * ksize), false);
				var eventBufferNative = Marshal.AllocHGlobal (ksize * eventBuffer.Length);

				int numEvents = kevent_notimeout (ref conn, changesNative, changes.Length, eventBufferNative, eventBuffer.Length);

				// Marshal out
				Marshal.FreeHGlobal (changesNative);
				for (int i = 0; i < numEvents; ++i)
					eventBuffer [i] = Marshal.PtrToStructure<kevent> (eventBufferNative + (i * ksize));
				Marshal.FreeHGlobal (eventBufferNative);

				if (numEvents == -1) {
					// Stop () signals us to stop by closing the connection
					if (requestStop)
						break;
					if (++retries == 3)
						throw new IOException (String.Format (
							"persistent kevent() error, error code = '{0}'", Marshal.GetLastWin32Error ()));

					continue;
				}
				retries = 0;

				for (var i = 0; i < numEvents; i++) {
					var kevt = eventBuffer [i];

					if (!fdsDict.ContainsKey ((int)kevt.ident))
						// The event is for a file that was removed
						continue;

					var pathData = fdsDict [(int)kevt.ident];

					if ((kevt.flags & EventFlags.Error) == EventFlags.Error) {
						var errMsg = String.Format ("kevent() error watching path '{0}', error code = '{1}'", pathData.Path, kevt.data);
						fsw.DispatchErrorEvents (new ErrorEventArgs (new IOException (errMsg)));
						continue;
					}
						
					if ((kevt.fflags & FilterFlags.VNodeDelete) == FilterFlags.VNodeDelete || (kevt.fflags & FilterFlags.VNodeRevoke) == FilterFlags.VNodeRevoke) {
						if (pathData.Path == fullPathNoLastSlash)
							// The root path is deleted; exit silently
							return;
								
						removeQueue.Add (pathData);
						continue;
					}

					if ((kevt.fflags & FilterFlags.VNodeRename) == FilterFlags.VNodeRename) {
							UpdatePath (pathData);
					} 

					if ((kevt.fflags & FilterFlags.VNodeWrite) == FilterFlags.VNodeWrite) {
						if (pathData.IsDirectory) //TODO: Check if dirs trigger Changed events on .NET
							rescanQueue.Add (pathData.Path);
						else
							PostEvent (FileAction.Modified, pathData.Path);
					}
						
					if ((kevt.fflags & FilterFlags.VNodeAttrib) == FilterFlags.VNodeAttrib || (kevt.fflags & FilterFlags.VNodeExtend) == FilterFlags.VNodeExtend)
						PostEvent (FileAction.Modified, pathData.Path);
				}

				removeQueue.ForEach (Remove);
				removeQueue.Clear ();

				rescanQueue.ForEach (path => {
					Scan (path, true, ref newFds);
				});
				rescanQueue.Clear ();
			}
		}
예제 #14
0
		kevent[] CreateChangeList (ref List<int> FdList)
		{
			if (FdList.Count == 0)
				return emptyEventList;

			var changes = new List<kevent> ();
			foreach (int fd in FdList) {
				var change = new kevent {

					ident = (UIntPtr)fd,
					filter = EventFilter.Vnode,
					flags = EventFlags.Add | EventFlags.Enable | EventFlags.Clear,
					fflags = FilterFlags.VNodeDelete | FilterFlags.VNodeExtend |
						FilterFlags.VNodeRename | FilterFlags.VNodeAttrib |
						FilterFlags.VNodeLink | FilterFlags.VNodeRevoke |
						FilterFlags.VNodeWrite,
					data = IntPtr.Zero,
					udata = IntPtr.Zero
				};

				changes.Add (change);
			}
			FdList.Clear ();

			return changes.ToArray ();
		}
예제 #15
0
		void Setup ()
		{	
			var initialFds = new List<int> ();

			// fsw.FullPath may end in '/', see https://bugzilla.xamarin.com/show_bug.cgi?id=5747
			if (fsw.FullPath != "/" && fsw.FullPath.EndsWith ("/", StringComparison.Ordinal))
				fullPathNoLastSlash = fsw.FullPath.Substring (0, fsw.FullPath.Length - 1);
			else
				fullPathNoLastSlash = fsw.FullPath;
				
			// GetFilenameFromFd() returns the *realpath* which can be different than fsw.FullPath because symlinks.
			// If so, introduce a fixup step.
			int fd = open (fullPathNoLastSlash, O_EVTONLY, 0);
			var resolvedFullPath = GetFilenameFromFd (fd);
			close (fd);

			if (resolvedFullPath != fullPathNoLastSlash)
				fixupPath = resolvedFullPath;
			else
				fixupPath = null;

			Scan (fullPathNoLastSlash, false, ref initialFds);

			var immediate_timeout = new timespec { tv_sec = (IntPtr)0, tv_nsec = (IntPtr)0 };
			var eventBuffer = new kevent[0]; // we don't want to take any events from the queue at this point
			var changes = CreateChangeList (ref initialFds);

			int numEvents = kevent (conn, changes, changes.Length, eventBuffer, eventBuffer.Length, ref immediate_timeout);

			if (numEvents == -1) {
				var errMsg = String.Format ("kevent() error at initial event registration, error code = '{0}'", Marshal.GetLastWin32Error ());
				throw new IOException (errMsg);
			}
		}
예제 #16
0
		void Monitor ()
		{
			var timeout = new timespec { tv_sec = (IntPtr)0, tv_usec = (IntPtr)500000000 };
			var eventBuffer = new kevent[32];
			var newFds = new List<int> ();
			List<PathData> removeQueue = new List<PathData> ();
			List<string> rescanQueue = new List<string> ();

			int retries = 0; 

			while (!requestStop) {
				var changes = CreateChangeList (ref newFds);

				int numEvents = kevent (conn, changes, changes.Length, eventBuffer, eventBuffer.Length, ref timeout);

				if (numEvents == -1) {
					if (++retries == 3)
						throw new IOException (String.Format (
							"persistent kevent() error, error code = '{0}'", Marshal.GetLastWin32Error ()));

					continue;
				}

				retries = 0;

				for (var i = 0; i < numEvents; i++) {
					var kevt = eventBuffer [i];
					var pathData = fdsDict [(int)kevt.ident];

					if ((kevt.flags & EventFlags.Error) == EventFlags.Error) {
						var errMsg = String.Format ("kevent() error watching path '{0}', error code = '{1}'", pathData.Path, kevt.data);
						fsw.DispatchErrorEvents (new ErrorEventArgs (new IOException (errMsg)));
						continue;
					}
						
					if ((kevt.fflags & FilterFlags.VNodeDelete) == FilterFlags.VNodeDelete || (kevt.fflags & FilterFlags.VNodeRevoke) == FilterFlags.VNodeRevoke) {
						removeQueue.Add (pathData);
						continue;
					}

					if ((kevt.fflags & FilterFlags.VNodeRename) == FilterFlags.VNodeRename) {
							UpdatePath (pathData);
					} 

					if ((kevt.fflags & FilterFlags.VNodeWrite) == FilterFlags.VNodeWrite) {
						if (pathData.IsDirectory) //TODO: Check if dirs trigger Changed events on .NET
							rescanQueue.Add (pathData.Path);
						else
							PostEvent (FileAction.Modified, pathData.Path);
					}
						
					if ((kevt.fflags & FilterFlags.VNodeAttrib) == FilterFlags.VNodeAttrib || (kevt.fflags & FilterFlags.VNodeExtend) == FilterFlags.VNodeExtend)
						PostEvent (FileAction.Modified, pathData.Path);
				}

				removeQueue.ForEach (Remove);
				removeQueue.Clear ();

				rescanQueue.ForEach (path => {
					Scan (path, true, ref newFds);
				});
				rescanQueue.Clear ();
			}
		}
예제 #17
0
        void Monitor()
        {
            var timeout = new timespec {
                tv_sec = (IntPtr)0, tv_usec = (IntPtr)500000000
            };
            var             eventBuffer = new kevent[32];
            var             newFds      = new List <int> ();
            List <PathData> removeQueue = new List <PathData> ();
            List <string>   rescanQueue = new List <string> ();

            int retries = 0;

            while (!requestStop)
            {
                var changes = CreateChangeList(ref newFds);

                int numEvents = kevent(conn, changes, changes.Length, eventBuffer, eventBuffer.Length, ref timeout);

                if (numEvents == -1)
                {
                    if (++retries == 3)
                    {
                        throw new IOException(String.Format(
                                                  "persistent kevent() error, error code = '{0}'", Marshal.GetLastWin32Error()));
                    }

                    continue;
                }

                retries = 0;

                for (var i = 0; i < numEvents; i++)
                {
                    var kevt     = eventBuffer [i];
                    var pathData = fdsDict [(int)kevt.ident];

                    if ((kevt.flags & EventFlags.Error) == EventFlags.Error)
                    {
                        var errMsg = String.Format("kevent() error watching path '{0}', error code = '{1}'", pathData.Path, kevt.data);
                        fsw.DispatchErrorEvents(new ErrorEventArgs(new IOException(errMsg)));
                        continue;
                    }

                    if ((kevt.fflags & FilterFlags.VNodeDelete) == FilterFlags.VNodeDelete || (kevt.fflags & FilterFlags.VNodeRevoke) == FilterFlags.VNodeRevoke)
                    {
                        removeQueue.Add(pathData);
                        continue;
                    }

                    if ((kevt.fflags & FilterFlags.VNodeRename) == FilterFlags.VNodeRename)
                    {
                        UpdatePath(pathData);
                    }

                    if ((kevt.fflags & FilterFlags.VNodeWrite) == FilterFlags.VNodeWrite)
                    {
                        if (pathData.IsDirectory)                         //TODO: Check if dirs trigger Changed events on .NET
                        {
                            rescanQueue.Add(pathData.Path);
                        }
                        else
                        {
                            PostEvent(FileAction.Modified, pathData.Path);
                        }
                    }

                    if ((kevt.fflags & FilterFlags.VNodeAttrib) == FilterFlags.VNodeAttrib || (kevt.fflags & FilterFlags.VNodeExtend) == FilterFlags.VNodeExtend)
                    {
                        PostEvent(FileAction.Modified, pathData.Path);
                    }
                }

                removeQueue.ForEach(Remove);
                removeQueue.Clear();

                rescanQueue.ForEach(path => {
                    Scan(path, true, ref newFds);
                });
                rescanQueue.Clear();
            }
        }
예제 #18
0
 private void ProcessEvent(kevent ev)
 {
     lock (this)
     {
         KeventData keventData = (KeventData)KeventWatcher.requests[ev.ident];
         if (keventData.Enabled)
         {
             string            text          = string.Empty;
             FileSystemWatcher fsw           = keventData.FSW;
             DirectoryInfo     directoryInfo = new DirectoryInfo(keventData.Directory);
             FileSystemInfo    changedFsi    = null;
             try
             {
                 foreach (FileSystemInfo fileSystemInfo in directoryInfo.GetFileSystemInfos())
                 {
                     if (keventData.DirEntries.ContainsKey(fileSystemInfo.FullName) && fileSystemInfo is FileInfo)
                     {
                         KeventFileData keventFileData = (KeventFileData)keventData.DirEntries[fileSystemInfo.FullName];
                         if (keventFileData.LastWriteTime != fileSystemInfo.LastWriteTime)
                         {
                             text = fileSystemInfo.Name;
                             FileAction fa = FileAction.Modified;
                             keventData.DirEntries[fileSystemInfo.FullName] = new KeventFileData(fileSystemInfo, fileSystemInfo.LastAccessTime, fileSystemInfo.LastWriteTime);
                             if (fsw.IncludeSubdirectories && fileSystemInfo is DirectoryInfo)
                             {
                                 keventData.Directory             = text;
                                 KeventWatcher.requests[ev.ident] = keventData;
                                 this.ProcessEvent(ev);
                             }
                             this.PostEvent(text, fsw, fa, changedFsi);
                         }
                     }
                 }
             }
             catch (Exception)
             {
             }
             try
             {
                 bool flag = true;
                 while (flag)
                 {
                     foreach (object obj in keventData.DirEntries.Values)
                     {
                         KeventFileData keventFileData2 = (KeventFileData)obj;
                         if (!File.Exists(keventFileData2.fsi.FullName) && !Directory.Exists(keventFileData2.fsi.FullName))
                         {
                             text = keventFileData2.fsi.Name;
                             FileAction fa = FileAction.Removed;
                             keventData.DirEntries.Remove(keventFileData2.fsi.FullName);
                             this.PostEvent(text, fsw, fa, changedFsi);
                             break;
                         }
                     }
                     flag = false;
                 }
             }
             catch (Exception)
             {
             }
             try
             {
                 foreach (FileSystemInfo fileSystemInfo2 in directoryInfo.GetFileSystemInfos())
                 {
                     if (!keventData.DirEntries.ContainsKey(fileSystemInfo2.FullName))
                     {
                         changedFsi = fileSystemInfo2;
                         text       = fileSystemInfo2.Name;
                         FileAction fa = FileAction.Added;
                         keventData.DirEntries[fileSystemInfo2.FullName] = new KeventFileData(fileSystemInfo2, fileSystemInfo2.LastAccessTime, fileSystemInfo2.LastWriteTime);
                         this.PostEvent(text, fsw, fa, changedFsi);
                     }
                 }
             }
             catch (Exception)
             {
             }
         }
     }
 }
예제 #19
0
        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)
                            {
                                filename = fsi.Name;
                                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.Name;
                                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.Name;
                            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
                }
            }
        }
예제 #20
0
파일: KeventWatcher.cs 프로젝트: av8/mono
		extern static int kevent(int kqueue, ref kevent ev, int nchanges, ref kevent evtlist,  int nevents, ref timespec ts);
예제 #21
0
파일: KeventWatcher.cs 프로젝트: av8/mono
		void Monitor ()
		{
		
			while (!stop) {
				kevent ev = new kevent();
				ev.udata = IntPtr.Zero;
				kevent nullev = new kevent();
				nullev.udata = IntPtr.Zero;
				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];
					StopMonitoringDirectory (data);
					StartMonitoringDirectory (data);
					ProcessEvent (ev);
				} else {
					System.Threading.Thread.Sleep (500);
				}
			}

			lock (this) {
				thread = null;
				stop = false;
			}
		}
예제 #22
0
		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();
			ev.udata = IntPtr.Zero;
			timespec nullts = new timespec();
			nullts.tv_sec = 0;
			nullts.tv_usec = 0;
			if (fd > 0) {
				ev.ident = fd;
				ev.filter = EventFilter.Vnode;
				ev.flags = EventFlags.Add | EventFlags.Enable | EventFlags.OneShot;
				ev.fflags = // 20 | 2 | 1 | 8;
					FilterFlags.VNodeDelete |
					FilterFlags.VNodeWrite |
					FilterFlags.VNodeAttrib |
					// The following two values are the equivalent of the original value "20", but we suspect the original author meant
					// 0x20, we will review later with some test cases
					FilterFlags.VNodeLink |
					FilterFlags.VNodeExtend;
				ev.data = 0;
				ev.udata = Marshal.StringToHGlobalAuto (data.Directory);
				kevent outev = new kevent();
				outev.udata = IntPtr.Zero;
				kevent (conn, ref ev, 1, ref outev, 0, ref nullts);
				data.ev = ev;
				requests [fd] = data;
			}
			
			if (!data.IncludeSubdirs)
				return;

		}
예제 #23
0
 static int kevent(int kqueue, ref kevent ev, int nchanges, ref kevent evtlist, int nevents, ref timespec ts)
 {
     throw new System.NotImplementedException();
 }
예제 #24
0
 private void ProcessEvent(kevent ev)
 {
     lock (this)
     {
         KeventData keventData = (KeventData)requests[ev.ident];
         if (keventData.Enabled)
         {
             string            empty         = string.Empty;
             FileSystemWatcher fSW           = keventData.FSW;
             FileAction        fileAction    = (FileAction)0;
             DirectoryInfo     directoryInfo = new DirectoryInfo(keventData.Directory);
             FileSystemInfo    changedFsi    = null;
             try
             {
                 FileSystemInfo[] fileSystemInfos = directoryInfo.GetFileSystemInfos();
                 foreach (FileSystemInfo fileSystemInfo in fileSystemInfos)
                 {
                     if (keventData.DirEntries.ContainsKey(fileSystemInfo.FullName) && fileSystemInfo is FileInfo)
                     {
                         KeventFileData keventFileData = (KeventFileData)keventData.DirEntries[fileSystemInfo.FullName];
                         if (keventFileData.LastWriteTime != fileSystemInfo.LastWriteTime)
                         {
                             empty      = fileSystemInfo.Name;
                             fileAction = FileAction.Modified;
                             keventData.DirEntries[fileSystemInfo.FullName] = new KeventFileData(fileSystemInfo, fileSystemInfo.LastAccessTime, fileSystemInfo.LastWriteTime);
                             if (fSW.IncludeSubdirectories && fileSystemInfo is DirectoryInfo)
                             {
                                 keventData.Directory = empty;
                                 requests[ev.ident]   = keventData;
                                 ProcessEvent(ev);
                             }
                             PostEvent(empty, fSW, fileAction, changedFsi);
                         }
                     }
                 }
             }
             catch (Exception)
             {
             }
             try
             {
                 bool flag = true;
                 while (flag)
                 {
                     foreach (KeventFileData value in keventData.DirEntries.Values)
                     {
                         if (!File.Exists(value.fsi.FullName) && !Directory.Exists(value.fsi.FullName))
                         {
                             empty      = value.fsi.Name;
                             fileAction = FileAction.Removed;
                             keventData.DirEntries.Remove(value.fsi.FullName);
                             PostEvent(empty, fSW, fileAction, changedFsi);
                             break;
                         }
                     }
                     flag = false;
                 }
             }
             catch (Exception)
             {
             }
             try
             {
                 FileSystemInfo[] fileSystemInfos2 = directoryInfo.GetFileSystemInfos();
                 foreach (FileSystemInfo fileSystemInfo2 in fileSystemInfos2)
                 {
                     if (!keventData.DirEntries.ContainsKey(fileSystemInfo2.FullName))
                     {
                         changedFsi = fileSystemInfo2;
                         empty      = fileSystemInfo2.Name;
                         fileAction = FileAction.Added;
                         keventData.DirEntries[fileSystemInfo2.FullName] = new KeventFileData(fileSystemInfo2, fileSystemInfo2.LastAccessTime, fileSystemInfo2.LastWriteTime);
                         PostEvent(empty, fSW, fileAction, changedFsi);
                     }
                 }
             }
             catch (Exception)
             {
             }
         }
     }
 }
예제 #25
0
파일: KeventWatcher.cs 프로젝트: av8/mono
		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) {
								filename = fsi.Name;
								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.Name;
								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.Name;
							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
				}
				

			}
		}
예제 #26
0
        void Monitor()
        {
            var             eventBuffer = new kevent[32];
            var             newFds      = new List <int> ();
            List <PathData> removeQueue = new List <PathData> ();
            List <string>   rescanQueue = new List <string> ();

            int retries = 0;

            while (!requestStop)
            {
                var changes = CreateChangeList(ref newFds);

                // We are calling an icall, so have to marshal manually
                // Marshal in
                int ksize         = Marshal.SizeOf <kevent> ();
                var changesNative = Marshal.AllocHGlobal(ksize * changes.Length);
                for (int i = 0; i < changes.Length; ++i)
                {
                    Marshal.StructureToPtr(changes [i], changesNative + (i * ksize), false);
                }
                var eventBufferNative = Marshal.AllocHGlobal(ksize * eventBuffer.Length);

                int numEvents = kevent_notimeout(ref conn, changesNative, changes.Length, eventBufferNative, eventBuffer.Length);

                // Marshal out
                Marshal.FreeHGlobal(changesNative);
                for (int i = 0; i < numEvents; ++i)
                {
                    eventBuffer [i] = Marshal.PtrToStructure <kevent> (eventBufferNative + (i * ksize));
                }
                Marshal.FreeHGlobal(eventBufferNative);

                if (numEvents == -1)
                {
                    // Stop () signals us to stop by closing the connection
                    if (requestStop)
                    {
                        break;
                    }
                    int errno = Marshal.GetLastWin32Error();
                    if (errno != EINTR && ++retries == 3)
                    {
                        throw new IOException(String.Format(
                                                  "persistent kevent() error, error code = '{0}'", errno));
                    }

                    continue;
                }
                retries = 0;

                for (var i = 0; i < numEvents; i++)
                {
                    var kevt = eventBuffer [i];

                    if (!fdsDict.ContainsKey((int)kevt.ident))
                    {
                        // The event is for a file that was removed
                        continue;
                    }

                    var pathData = fdsDict [(int)kevt.ident];

                    if ((kevt.flags & EventFlags.Error) == EventFlags.Error)
                    {
                        var errMsg = String.Format("kevent() error watching path '{0}', error code = '{1}'", pathData.Path, kevt.data);
                        fsw.DispatchErrorEvents(new ErrorEventArgs(new IOException(errMsg)));
                        continue;
                    }

                    if ((kevt.fflags & FilterFlags.VNodeDelete) == FilterFlags.VNodeDelete || (kevt.fflags & FilterFlags.VNodeRevoke) == FilterFlags.VNodeRevoke)
                    {
                        if (pathData.Path == fullPathNoLastSlash)
                        {
                            // The root path is deleted; exit silently
                            return;
                        }

                        removeQueue.Add(pathData);
                        continue;
                    }

                    if ((kevt.fflags & FilterFlags.VNodeRename) == FilterFlags.VNodeRename)
                    {
                        UpdatePath(pathData);
                    }

                    if ((kevt.fflags & FilterFlags.VNodeWrite) == FilterFlags.VNodeWrite)
                    {
                        if (pathData.IsDirectory)                         //TODO: Check if dirs trigger Changed events on .NET
                        {
                            rescanQueue.Add(pathData.Path);
                        }
                        else
                        {
                            PostEvent(FileAction.Modified, pathData.Path);
                        }
                    }

                    if ((kevt.fflags & FilterFlags.VNodeAttrib) == FilterFlags.VNodeAttrib || (kevt.fflags & FilterFlags.VNodeExtend) == FilterFlags.VNodeExtend)
                    {
                        PostEvent(FileAction.Modified, pathData.Path);
                    }
                }

                removeQueue.ForEach(Remove);
                removeQueue.Clear();

                rescanQueue.ForEach(path => {
                    Scan(path, true, ref newFds);
                });
                rescanQueue.Clear();
            }
        }
예제 #27
0
		void Setup ()
		{	
			var initialFds = new List<int> ();

			// fsw.FullPath may end in '/', see https://bugzilla.xamarin.com/show_bug.cgi?id=5747
			if (fsw.FullPath != "/" && fsw.FullPath.EndsWith ("/", StringComparison.Ordinal))
				fullPathNoLastSlash = fsw.FullPath.Substring (0, fsw.FullPath.Length - 1);
			else
				fullPathNoLastSlash = fsw.FullPath;
				
			// realpath() returns the *realpath* which can be different than fsw.FullPath because symlinks.
			// If so, introduce a fixup step.
			var sb = new StringBuilder (__DARWIN_MAXPATHLEN);
			if (realpath(fsw.FullPath, sb) == IntPtr.Zero) {
				var errMsg = String.Format ("realpath({0}) failed, error code = '{1}'", fsw.FullPath, Marshal.GetLastWin32Error ());
				throw new IOException (errMsg);
			}
			var resolvedFullPath = sb.ToString();

			if (resolvedFullPath != fullPathNoLastSlash)
				fixupPath = resolvedFullPath;
			else
				fixupPath = null;

			Scan (fullPathNoLastSlash, false, ref initialFds);

			var immediate_timeout = new timespec { tv_sec = (IntPtr)0, tv_nsec = (IntPtr)0 };
			var eventBuffer = new kevent[0]; // we don't want to take any events from the queue at this point
			var changes = CreateChangeList (ref initialFds);

			int numEvents;
			int errno = 0;
			do {
				numEvents = kevent (conn, changes, changes.Length, eventBuffer, eventBuffer.Length, ref immediate_timeout);
				if (numEvents == -1) {
					errno = Marshal.GetLastWin32Error ();
				}
			} while (numEvents == -1 && errno == EINTR);

			if (numEvents == -1) {
				var errMsg = String.Format ("kevent() error at initial event registration, error code = '{0}'", errno);
				throw new IOException (errMsg);
			}
		}
예제 #28
0
		void Setup ()
		{	
			var initialFds = new List<int> ();

			// GetFilenameFromFd() returns the *realpath* which can be different than fsw.FullPath because symlinks.
			// If so, introduce a fixup step.
			int fd = open (fsw.FullPath, O_EVTONLY, 0);
			var resolvedFullPath = GetFilenameFromFd (fd);
			close (fd);

			if (resolvedFullPath != fsw.FullPath)
				fixupPath = resolvedFullPath;
			else
				fixupPath = null;

			Scan (fsw.FullPath, false, ref initialFds);

			var immediate_timeout = new timespec { tv_sec = (IntPtr)0, tv_usec = (IntPtr)0 };
			var eventBuffer = new kevent[0]; // we don't want to take any events from the queue at this point
			var changes = CreateChangeList (ref initialFds);

			int numEvents = kevent (conn, changes, changes.Length, eventBuffer, eventBuffer.Length, ref immediate_timeout);

			if (numEvents == -1) {
				var errMsg = String.Format ("kevent() error at initial event registration, error code = '{0}'", Marshal.GetLastWin32Error ());
				throw new IOException (errMsg);
			}
		}
예제 #29
0
 extern static int kevent(int kqueue, ref kevent ev, int nchanges, ref kevent evtlist, int nevents, ref timespec ts);
예제 #30
0
		void Monitor ()
		{
			var timeout = new timespec { tv_sec = (IntPtr)0, tv_usec = (IntPtr)500000000 };
			var eventBuffer = new kevent[32];
			var newFds = new List<int> ();
			List<PathData> removeQueue = new List<PathData> ();
			List<string> rescanQueue = new List<string> ();

			while (!requestStop) {
				var changes = CreateChangeList (ref newFds);

				int numEvents = kevent (conn, changes, changes.Length, eventBuffer, eventBuffer.Length, ref timeout);

				if (numEvents == -1) {
					var errMsg = String.Format ("kevent() error, error code = '{0}'", Marshal.GetLastWin32Error ());
					fsw.OnError (new ErrorEventArgs (new IOException (errMsg)));
				}

				if (numEvents == 0)
					continue;

				for (var i = 0; i < numEvents; i++) {
					var kevt = eventBuffer [i];
					var pathData = fdsDict [(int)kevt.ident];

					if ((kevt.flags & EventFlags.Error) == EventFlags.Error) {
						var errMsg = String.Format ("kevent() error watching path '{0}', error code = '{1}'", pathData.Path, kevt.data);
						fsw.OnError (new ErrorEventArgs (new IOException (errMsg)));
						continue;
					}

					if ((kevt.fflags & FilterFlags.VNodeDelete) == FilterFlags.VNodeDelete || (kevt.fflags & FilterFlags.VNodeRevoke) == FilterFlags.VNodeRevoke)
						removeQueue.Add (pathData);

					else if ((kevt.fflags & FilterFlags.VNodeWrite) == FilterFlags.VNodeWrite) {
						if (pathData.IsDirectory)
							rescanQueue.Add (pathData.Path);
						else
							PostEvent (FileAction.Modified, pathData.Path);
					} 

					else if ((kevt.fflags & FilterFlags.VNodeRename) == FilterFlags.VNodeRename) {
						var newFilename = GetFilenameFromFd (pathData.Fd);

						if (newFilename.StartsWith (fsw.FullPath))
							Rename (pathData, newFilename);
						else //moved outside of our watched dir so stop watching
								RemoveTree (pathData);
					} 

					else if ((kevt.fflags & FilterFlags.VNodeAttrib) == FilterFlags.VNodeAttrib || (kevt.fflags & FilterFlags.VNodeExtend) == FilterFlags.VNodeExtend)
						PostEvent (FileAction.Modified, pathData.Path);
				}

				removeQueue.ForEach (Remove);
				removeQueue.Clear ();

				rescanQueue.ForEach (path => {
					Scan (path, true, ref newFds);
				});
				rescanQueue.Clear ();
			}
		}
예제 #31
0
파일: KeventWatcher.cs 프로젝트: iainx/mono
        void Monitor()
        {
            var             eventBuffer = new kevent[32];
            var             newFds      = new List <int> ();
            List <PathData> removeQueue = new List <PathData> ();
            List <string>   rescanQueue = new List <string> ();

            int retries = 0;

            while (!requestStop)
            {
                var changes = CreateChangeList(ref newFds);

                int numEvents = kevent_notimeout(conn, changes, changes.Length, eventBuffer, eventBuffer.Length, IntPtr.Zero);

                if (numEvents == -1)
                {
                    // Stop () signals us to stop by closing the connection
                    if (requestStop)
                    {
                        break;
                    }
                    if (++retries == 3)
                    {
                        throw new IOException(String.Format(
                                                  "persistent kevent() error, error code = '{0}'", Marshal.GetLastWin32Error()));
                    }

                    continue;
                }

                retries = 0;

                for (var i = 0; i < numEvents; i++)
                {
                    var kevt = eventBuffer [i];

                    if (!fdsDict.ContainsKey((int)kevt.ident))
                    {
                        // The event is for a file that was removed
                        continue;
                    }

                    var pathData = fdsDict [(int)kevt.ident];

                    if ((kevt.flags & EventFlags.Error) == EventFlags.Error)
                    {
                        var errMsg = String.Format("kevent() error watching path '{0}', error code = '{1}'", pathData.Path, kevt.data);
                        fsw.DispatchErrorEvents(new ErrorEventArgs(new IOException(errMsg)));
                        continue;
                    }

                    if ((kevt.fflags & FilterFlags.VNodeDelete) == FilterFlags.VNodeDelete || (kevt.fflags & FilterFlags.VNodeRevoke) == FilterFlags.VNodeRevoke)
                    {
                        if (pathData.Path == fullPathNoLastSlash)
                        {
                            // The root path is deleted; exit silently
                            return;
                        }

                        removeQueue.Add(pathData);
                        continue;
                    }

                    if ((kevt.fflags & FilterFlags.VNodeRename) == FilterFlags.VNodeRename)
                    {
                        UpdatePath(pathData);
                    }

                    if ((kevt.fflags & FilterFlags.VNodeWrite) == FilterFlags.VNodeWrite)
                    {
                        if (pathData.IsDirectory)                         //TODO: Check if dirs trigger Changed events on .NET
                        {
                            rescanQueue.Add(pathData.Path);
                        }
                        else
                        {
                            PostEvent(FileAction.Modified, pathData.Path);
                        }
                    }

                    if ((kevt.fflags & FilterFlags.VNodeAttrib) == FilterFlags.VNodeAttrib || (kevt.fflags & FilterFlags.VNodeExtend) == FilterFlags.VNodeExtend)
                    {
                        PostEvent(FileAction.Modified, pathData.Path);
                    }
                }

                removeQueue.ForEach(Remove);
                removeQueue.Clear();

                rescanQueue.ForEach(path => {
                    Scan(path, true, ref newFds);
                });
                rescanQueue.Clear();
            }
        }
		static int kevent(int kqueue, ref kevent ev, int nchanges, ref kevent evtlist,  int nevents, ref timespec ts)
		{
			throw new System.NotImplementedException();
		}