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 { // Token: 0x0200011E RID: 286 internal class InotifyWatcher : IFileWatcher { // Token: 0x06000A25 RID: 2597 RVA: 0x0001BA38 File Offset: 0x00019C38 private InotifyWatcher() { } // Token: 0x06000A27 RID: 2599 RVA: 0x0001BA4C File Offset: 0x00019C4C public static bool GetInstance(out IFileWatcher watcher, bool gamin) { if (InotifyWatcher.failed) { watcher = null; return false; } if (InotifyWatcher.instance != null) { watcher = InotifyWatcher.instance; return true; } InotifyWatcher.FD = InotifyWatcher.GetInotifyInstance(); if ((long)InotifyWatcher.FD == -1L) { InotifyWatcher.failed = true; watcher = null; return false; } InotifyWatcher.watches = Hashtable.Synchronized(new Hashtable()); InotifyWatcher.requests = Hashtable.Synchronized(new Hashtable()); InotifyWatcher.instance = new InotifyWatcher(); watcher = InotifyWatcher.instance; return true; } // Token: 0x06000A28 RID: 2600 RVA: 0x0001BAD4 File Offset: 0x00019CD4 public void StartDispatching(FileSystemWatcher fsw) { ParentInotifyData parentInotifyData; lock (this) { if ((long)InotifyWatcher.FD == -1L) { InotifyWatcher.FD = InotifyWatcher.GetInotifyInstance(); } if (InotifyWatcher.thread == null) { InotifyWatcher.thread = new Thread(new ThreadStart(this.Monitor)); InotifyWatcher.thread.IsBackground = true; InotifyWatcher.thread.Start(); } parentInotifyData = (ParentInotifyData)InotifyWatcher.watches[fsw]; } if (parentInotifyData == null) { InotifyData inotifyData = new InotifyData(); inotifyData.FSW = fsw; inotifyData.Directory = fsw.FullPath; parentInotifyData = new ParentInotifyData(); parentInotifyData.IncludeSubdirs = fsw.IncludeSubdirectories; parentInotifyData.Enabled = true; parentInotifyData.children = new ArrayList(); parentInotifyData.data = inotifyData; InotifyWatcher.watches[fsw] = parentInotifyData; try { InotifyWatcher.StartMonitoringDirectory(inotifyData, false); lock (this) { InotifyWatcher.AppendRequestData(inotifyData); InotifyWatcher.stop = false; } } catch { } } } // Token: 0x06000A29 RID: 2601 RVA: 0x0001BC2C File Offset: 0x00019E2C private static void AppendRequestData(InotifyData data) { int watch = data.Watch; object obj = InotifyWatcher.requests[watch]; if (obj == null) { InotifyWatcher.requests[data.Watch] = data; } else if (obj is InotifyData) { ArrayList arrayList = new ArrayList(); arrayList.Add(obj); arrayList.Add(data); InotifyWatcher.requests[data.Watch] = arrayList; } else { ArrayList arrayList = (ArrayList)obj; arrayList.Add(data); } } // Token: 0x06000A2A RID: 2602 RVA: 0x0001BCC0 File Offset: 0x00019EC0 private static bool RemoveRequestData(InotifyData data) { int watch = data.Watch; object obj = InotifyWatcher.requests[watch]; if (obj == null) { return true; } if (obj is InotifyData) { if (obj == data) { InotifyWatcher.requests.Remove(watch); return true; } return false; } else { ArrayList arrayList = (ArrayList)obj; arrayList.Remove(data); if (arrayList.Count == 0) { InotifyWatcher.requests.Remove(watch); return true; } return false; } } // Token: 0x06000A2B RID: 2603 RVA: 0x0001BD40 File Offset: 0x00019F40 private static InotifyMask GetMaskFromFilters(NotifyFilters filters) { InotifyMask inotifyMask = InotifyMask.Create | InotifyMask.Delete | InotifyMask.DeleteSelf | InotifyMask.AddMask; if ((filters & NotifyFilters.Attributes) != (NotifyFilters)0) { inotifyMask |= InotifyMask.Attrib; } if ((filters & NotifyFilters.Security) != (NotifyFilters)0) { inotifyMask |= InotifyMask.Attrib; } if ((filters & NotifyFilters.Size) != (NotifyFilters)0) { inotifyMask |= InotifyMask.Attrib; inotifyMask |= InotifyMask.Modify; } if ((filters & NotifyFilters.LastAccess) != (NotifyFilters)0) { inotifyMask |= InotifyMask.Attrib; inotifyMask |= InotifyMask.Access; inotifyMask |= InotifyMask.Modify; } if ((filters & NotifyFilters.LastWrite) != (NotifyFilters)0) { inotifyMask |= InotifyMask.Attrib; inotifyMask |= InotifyMask.Modify; } if ((filters & NotifyFilters.FileName) != (NotifyFilters)0) { inotifyMask |= InotifyMask.MovedFrom; inotifyMask |= InotifyMask.MovedTo; } if ((filters & NotifyFilters.DirectoryName) != (NotifyFilters)0) { inotifyMask |= InotifyMask.MovedFrom; inotifyMask |= InotifyMask.MovedTo; } return inotifyMask; } // Token: 0x06000A2C RID: 2604 RVA: 0x0001BDD0 File Offset: 0x00019FD0 private static void StartMonitoringDirectory(InotifyData data, bool justcreated) { InotifyMask maskFromFilters = InotifyWatcher.GetMaskFromFilters(data.FSW.NotifyFilter); int num = InotifyWatcher.AddDirectoryWatch(InotifyWatcher.FD, data.Directory, maskFromFilters); if (num != -1) { FileSystemWatcher fsw = data.FSW; data.Watch = num; ParentInotifyData parentInotifyData = (ParentInotifyData)InotifyWatcher.watches[fsw]; if (parentInotifyData.IncludeSubdirs) { foreach (string text in Directory.GetDirectories(data.Directory)) { InotifyData inotifyData = new InotifyData(); inotifyData.FSW = fsw; inotifyData.Directory = text; if (justcreated) { FileSystemWatcher fileSystemWatcher = fsw; lock (fileSystemWatcher) { RenamedEventArgs renamedEventArgs = null; if (fsw.Pattern.IsMatch(text)) { fsw.DispatchEvents(FileAction.Added, text, ref renamedEventArgs); if (fsw.Waiting) { fsw.Waiting = false; global::System.Threading.Monitor.PulseAll(fsw); } } } } try { InotifyWatcher.StartMonitoringDirectory(inotifyData, justcreated); InotifyWatcher.AppendRequestData(inotifyData); parentInotifyData.children.Add(inotifyData); } catch { } } } if (justcreated) { foreach (string text2 in Directory.GetFiles(data.Directory)) { FileSystemWatcher fileSystemWatcher2 = fsw; lock (fileSystemWatcher2) { RenamedEventArgs renamedEventArgs2 = null; if (fsw.Pattern.IsMatch(text2)) { fsw.DispatchEvents(FileAction.Added, text2, ref renamedEventArgs2); fsw.DispatchEvents(FileAction.Modified, text2, ref renamedEventArgs2); if (fsw.Waiting) { fsw.Waiting = false; global::System.Threading.Monitor.PulseAll(fsw); } } } } } return; } int lastWin32Error = Marshal.GetLastWin32Error(); if (lastWin32Error == 4) { string text3 = "(unknown)"; try { using (StreamReader streamReader = new StreamReader("/proc/sys/fs/inotify/max_user_watches")) { text3 = streamReader.ReadLine(); } } catch { } string text4 = string.Format("The per-user inotify watches limit of {0} has been reached. If you're experiencing problems with your application, increase that limit in /proc/sys/fs/inotify/max_user_watches.", text3); throw new global::System.ComponentModel.Win32Exception(lastWin32Error, text4); } throw new global::System.ComponentModel.Win32Exception(lastWin32Error); } // Token: 0x06000A2D RID: 2605 RVA: 0x0001C074 File Offset: 0x0001A274 public void StopDispatching(FileSystemWatcher fsw) { lock (this) { ParentInotifyData parentInotifyData = (ParentInotifyData)InotifyWatcher.watches[fsw]; if (parentInotifyData != null) { if (InotifyWatcher.RemoveRequestData(parentInotifyData.data)) { InotifyWatcher.StopMonitoringDirectory(parentInotifyData.data); } InotifyWatcher.watches.Remove(fsw); if (InotifyWatcher.watches.Count == 0) { InotifyWatcher.stop = true; IntPtr fd = InotifyWatcher.FD; InotifyWatcher.FD = (IntPtr)(-1); InotifyWatcher.Close(fd); } if (parentInotifyData.IncludeSubdirs) { foreach (object obj in parentInotifyData.children) { InotifyData inotifyData = (InotifyData)obj; if (InotifyWatcher.RemoveRequestData(inotifyData)) { InotifyWatcher.StopMonitoringDirectory(inotifyData); } } } } } } // Token: 0x06000A2E RID: 2606 RVA: 0x0001C1A0 File Offset: 0x0001A3A0 private static void StopMonitoringDirectory(InotifyData data) { InotifyWatcher.RemoveWatch(InotifyWatcher.FD, data.Watch); } // Token: 0x06000A2F RID: 2607 RVA: 0x0001C1B4 File Offset: 0x0001A3B4 private void Monitor() { byte[] array = new byte[4096]; while (!InotifyWatcher.stop) { int num = InotifyWatcher.ReadFromFD(InotifyWatcher.FD, array, (IntPtr)array.Length); if (num != -1) { lock (this) { this.ProcessEvents(array, num); } } } lock (this) { InotifyWatcher.thread = null; InotifyWatcher.stop = false; } } // Token: 0x06000A30 RID: 2608 RVA: 0x0001C26C File Offset: 0x0001A46C private static int ReadEvent(byte[] source, int off, int size, out InotifyEvent evt) { evt = default(InotifyEvent); if (size <= 0 || off > size - 16) { return -1; } int num; if (BitConverter.IsLittleEndian) { evt.WatchDescriptor = (int)source[off] + ((int)source[off + 1] << 8) + ((int)source[off + 2] << 16) + ((int)source[off + 3] << 24); evt.Mask = (InotifyMask)((int)source[off + 4] + ((int)source[off + 5] << 8) + ((int)source[off + 6] << 16) + ((int)source[off + 7] << 24)); num = (int)source[off + 12] + ((int)source[off + 13] << 8) + ((int)source[off + 14] << 16) + ((int)source[off + 15] << 24); } else { evt.WatchDescriptor = (int)source[off + 3] + ((int)source[off + 2] << 8) + ((int)source[off + 1] << 16) + ((int)source[off] << 24); evt.Mask = (InotifyMask)((int)source[off + 7] + ((int)source[off + 6] << 8) + ((int)source[off + 5] << 16) + ((int)source[off + 4] << 24)); num = (int)source[off + 15] + ((int)source[off + 14] << 8) + ((int)source[off + 13] << 16) + ((int)source[off + 12] << 24); } if (num > 0) { if (off > size - 16 - num) { return -1; } string @string = Encoding.UTF8.GetString(source, off + 16, num); evt.Name = @string.Trim(new char[1]); } else { evt.Name = null; } return 16 + num; } // Token: 0x06000A31 RID: 2609 RVA: 0x0001C3C4 File Offset: 0x0001A5C4 private static IEnumerable GetEnumerator(object source) { if (source == null) { yield break; } if (source is InotifyData) { yield return source; } if (source is ArrayList) { ArrayList list = (ArrayList)source; for (int i = 0; i < list.Count; i++) { yield return list[i]; } } yield break; } // Token: 0x06000A32 RID: 2610 RVA: 0x0001C3F0 File Offset: 0x0001A5F0 private void ProcessEvents(byte[] buffer, int length) { ArrayList arrayList = null; int num = 0; RenamedEventArgs renamedEventArgs = null; while (length > num) { InotifyEvent inotifyEvent; int num2 = InotifyWatcher.ReadEvent(buffer, num, length, out inotifyEvent); if (num2 <= 0) { break; } num += num2; InotifyMask inotifyMask = inotifyEvent.Mask; bool flag = (inotifyMask & InotifyMask.Directory) != (InotifyMask)0U; inotifyMask &= InotifyWatcher.Interesting; if (inotifyMask != (InotifyMask)0U) { foreach (object obj in InotifyWatcher.GetEnumerator(InotifyWatcher.requests[inotifyEvent.WatchDescriptor])) { InotifyData inotifyData = (InotifyData)obj; ParentInotifyData parentInotifyData = (ParentInotifyData)InotifyWatcher.watches[inotifyData.FSW]; if (inotifyData != null && parentInotifyData.Enabled) { string directory = inotifyData.Directory; string text = inotifyEvent.Name; if (text == null) { text = directory; } FileSystemWatcher fsw = inotifyData.FSW; FileAction fileAction = (FileAction)0; if ((inotifyMask & (InotifyMask.Modify | InotifyMask.Attrib)) != (InotifyMask)0U) { fileAction = FileAction.Modified; } else if ((inotifyMask & InotifyMask.Create) != (InotifyMask)0U) { fileAction = FileAction.Added; } else if ((inotifyMask & InotifyMask.Delete) != (InotifyMask)0U) { fileAction = FileAction.Removed; } else if ((inotifyMask & InotifyMask.DeleteSelf) != (InotifyMask)0U) { if (inotifyData.Watch != parentInotifyData.data.Watch) { continue; } fileAction = FileAction.Removed; } else { if ((inotifyMask & InotifyMask.MoveSelf) != (InotifyMask)0U) { continue; } if ((inotifyMask & InotifyMask.MovedFrom) != (InotifyMask)0U) { InotifyEvent inotifyEvent2; int num3 = InotifyWatcher.ReadEvent(buffer, num, length, out inotifyEvent2); if (num3 == -1 || (inotifyEvent2.Mask & InotifyMask.MovedTo) == (InotifyMask)0U || inotifyEvent.WatchDescriptor != inotifyEvent2.WatchDescriptor) { fileAction = FileAction.Removed; } else { num += num3; fileAction = FileAction.RenamedNewName; renamedEventArgs = new RenamedEventArgs(WatcherChangeTypes.Renamed, inotifyData.Directory, inotifyEvent2.Name, inotifyEvent.Name); if (inotifyEvent.Name != inotifyData.Directory && !fsw.Pattern.IsMatch(inotifyEvent.Name)) { text = inotifyEvent2.Name; } } } else if ((inotifyMask & InotifyMask.MovedTo) != (InotifyMask)0U) { fileAction = FileAction.Added; } } if (fsw.IncludeSubdirectories) { string fullPath = fsw.FullPath; string text2 = inotifyData.Directory; if (text2 != fullPath) { int length2 = fullPath.Length; int num4 = 1; if (length2 > 1 && fullPath[length2 - 1] == Path.DirectorySeparatorChar) { num4 = 0; } string text3 = text2.Substring(fullPath.Length + num4); text2 = Path.Combine(text2, text); text = Path.Combine(text3, text); } else { text2 = Path.Combine(fullPath, text); } if (fileAction == FileAction.Added && flag) { if (arrayList == null) { arrayList = new ArrayList(2); } arrayList.Add(new InotifyData { FSW = fsw, Directory = text2 }); } if (fileAction == FileAction.RenamedNewName && flag) { string oldFullPath = renamedEventArgs.OldFullPath; string fullPath2 = renamedEventArgs.FullPath; int length3 = oldFullPath.Length; foreach (object obj2 in parentInotifyData.children) { InotifyData inotifyData2 = (InotifyData)obj2; if (inotifyData2.Directory.StartsWith(oldFullPath, StringComparison.Ordinal)) { inotifyData2.Directory = fullPath2 + inotifyData2.Directory.Substring(length3); } } } } if (fileAction == FileAction.Removed && text == inotifyData.Directory) { int num5 = parentInotifyData.children.IndexOf(inotifyData); if (num5 != -1) { parentInotifyData.children.RemoveAt(num5); if (!fsw.Pattern.IsMatch(Path.GetFileName(text))) { continue; } } } if (!(text != inotifyData.Directory) || fsw.Pattern.IsMatch(Path.GetFileName(text))) { FileSystemWatcher fileSystemWatcher = fsw; lock (fileSystemWatcher) { fsw.DispatchEvents(fileAction, text, ref renamedEventArgs); if (fileAction == FileAction.RenamedNewName) { renamedEventArgs = null; } if (fsw.Waiting) { fsw.Waiting = false; global::System.Threading.Monitor.PulseAll(fsw); } } } } } } } if (arrayList != null) { foreach (object obj3 in arrayList) { InotifyData inotifyData3 = (InotifyData)obj3; try { InotifyWatcher.StartMonitoringDirectory(inotifyData3, true); InotifyWatcher.AppendRequestData(inotifyData3); ((ParentInotifyData)InotifyWatcher.watches[inotifyData3.FSW]).children.Add(inotifyData3); } catch { } } arrayList.Clear(); } } // Token: 0x06000A33 RID: 2611 RVA: 0x0001C99C File Offset: 0x0001AB9C private static int AddDirectoryWatch(IntPtr fd, string directory, InotifyMask mask) { mask |= InotifyMask.Directory; return InotifyWatcher.AddWatch(fd, directory, mask); } // Token: 0x06000A34 RID: 2612 [DllImport("libc", EntryPoint = "close")] internal static extern int Close(IntPtr fd); // Token: 0x06000A35 RID: 2613 [DllImport("libc", EntryPoint = "read")] private static extern int ReadFromFD(IntPtr fd, byte[] buffer, IntPtr length); // Token: 0x06000A36 RID: 2614 [MethodImpl(MethodImplOptions.InternalCall)] private static extern IntPtr GetInotifyInstance(); // Token: 0x06000A37 RID: 2615 [MethodImpl(MethodImplOptions.InternalCall)] private static extern int AddWatch(IntPtr fd, string name, InotifyMask mask); // Token: 0x06000A38 RID: 2616 [MethodImpl(MethodImplOptions.InternalCall)] private static extern IntPtr RemoveWatch(IntPtr fd, int wd); // Token: 0x0400039B RID: 923 private static bool failed; // Token: 0x0400039C RID: 924 private static InotifyWatcher instance; // Token: 0x0400039D RID: 925 private static Hashtable watches; // Token: 0x0400039E RID: 926 private static Hashtable requests; // Token: 0x0400039F RID: 927 private static IntPtr FD; // Token: 0x040003A0 RID: 928 private static Thread thread; // Token: 0x040003A1 RID: 929 private static bool stop; // Token: 0x040003A2 RID: 930 private static InotifyMask Interesting = InotifyMask.Modify | InotifyMask.Attrib | InotifyMask.MovedFrom | InotifyMask.MovedTo | InotifyMask.Create | InotifyMask.Delete | InotifyMask.DeleteSelf; } }