Merge pull request #2417 from razzfazz/guard_substr
[mono.git] / mcs / class / System / System.IO / KeventWatcher.cs
index 6875dbdc476ba75d94cb00d9c93aeef7c45295b2..778671764ea91a8f8b9bcc563e60b0b68d9d0fdd 100644 (file)
@@ -150,7 +150,7 @@ namespace System.IO {
        [StructLayout(LayoutKind.Sequential)]
        struct timespec {
                public IntPtr tv_sec;
-               public IntPtr tv_usec;
+               public IntPtr tv_nsec;
        }
 
        class PathData
@@ -300,11 +300,14 @@ namespace System.IO {
                        else
                                fullPathNoLastSlash = fsw.FullPath;
                                
-                       // GetFilenameFromFd() returns the *realpath* which can be different than fsw.FullPath because symlinks.
+                       // realpath() 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);
+                       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;
@@ -313,14 +316,21 @@ namespace System.IO {
 
                        Scan (fullPathNoLastSlash, false, ref initialFds);
 
-                       var immediate_timeout = new timespec { tv_sec = (IntPtr)0, tv_usec = (IntPtr)0 };
+                       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);
+                       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}'", Marshal.GetLastWin32Error ());
+                               var errMsg = String.Format ("kevent() error at initial event registration, error code = '{0}'", errno);
                                throw new IOException (errMsg);
                        }
                }
@@ -384,9 +394,10 @@ namespace System.IO {
                                        // Stop () signals us to stop by closing the connection
                                        if (requestStop)
                                                break;
-                                       if (++retries == 3)
+                                       int errno = Marshal.GetLastWin32Error ();
+                                       if (errno != EINTR && ++retries == 3)
                                                throw new IOException (String.Format (
-                                                       "persistent kevent() error, error code = '{0}'", Marshal.GetLastWin32Error ()));
+                                                       "persistent kevent() error, error code = '{0}'", errno));
 
                                        continue;
                                }
@@ -646,6 +657,7 @@ namespace System.IO {
                const int O_EVTONLY = 0x8000;
                const int F_GETPATH = 50;
                const int __DARWIN_MAXPATHLEN = 1024;
+               const int EINTR = 4;
                static readonly kevent[] emptyEventList = new System.IO.kevent[0];
                int maxFds = Int32.MaxValue;
 
@@ -665,19 +677,22 @@ namespace System.IO {
                string fixupPath = null;
                string fullPathNoLastSlash = null;
 
-               [DllImport ("libc", EntryPoint="fcntl", CharSet=CharSet.Auto, SetLastError=true)]
+               [DllImport ("libc", CharSet=CharSet.Auto, SetLastError=true)]
                static extern int fcntl (int file_names_by_descriptor, int cmd, StringBuilder sb);
 
-               [DllImport ("libc")]
+               [DllImport ("libc", CharSet=CharSet.Auto, SetLastError=true)]
+               static extern IntPtr realpath (string pathname, StringBuilder sb);
+
+               [DllImport ("libc", SetLastError=true)]
                extern static int open (string path, int flags, int mode_t);
 
                [DllImport ("libc")]
                extern static int close (int fd);
 
-               [DllImport ("libc")]
+               [DllImport ("libc", SetLastError=true)]
                extern static int kqueue ();
 
-               [DllImport ("libc")]
+               [DllImport ("libc", SetLastError=true)]
                extern static int kevent (int kq, [In]kevent[] ev, int nchanges, [Out]kevent[] evtlist, int nevents, [In] ref timespec time);
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]