Cleanup in signal.c and related tests
[mono.git] / mcs / class / Mono.Posix / Mono.Unix / UnixPath.cs
index a7836db0bf2528f28d40338a57ce69cbe3f4d1f3..e577edb74d4508f668dcc99a7bf282508160f843 100644 (file)
@@ -58,29 +58,39 @@ namespace Mono.Unix {
                        if (path1.IndexOfAny (_InvalidPathChars) != -1)
                                throw new ArgumentException ("Illegal characters in path", "path1");
 
-                       int len = path1.Length + 1;
+                       int len = path1.Length;
+                       int start = -1;
                        for (int i = 0; i < paths.Length; ++i) {
                                if (paths [i] == null)
-                                       throw new ArgumentNullException ("paths");
+                                       throw new ArgumentNullException ("paths[" + i + "]");
+                               if (paths [i].IndexOfAny (_InvalidPathChars) != -1)
+                                       throw new ArgumentException ("Illegal characters in path", "paths[" + i + "]");
+                               if (IsPathRooted (paths [i])) {
+                                       len = 0;
+                                       start = i;
+                               }
                                len += paths [i].Length + 1;
                        }
 
                        StringBuilder sb = new StringBuilder (len);
-                       sb.Append (path1);
-                       for (int i = 0; i < paths.Length; ++i)
+                       if (start == -1) {
+                               sb.Append (path1);
+                               start = 0;
+                       }
+                       for (int i = start; i < paths.Length; ++i)
                                Combine (sb, paths [i]);
                        return sb.ToString ();
                }
 
                private static void Combine (StringBuilder path, string part)
                {
-                       if (part.IndexOfAny (_InvalidPathChars) != -1)
-                               throw new ArgumentException ("Illegal characters in path", "path1");
-                       char end = path [path.Length-1];
-                       if (end != DirectorySeparatorChar && 
-                                       end != AltDirectorySeparatorChar && 
-                                       end != VolumeSeparatorChar)
-                               path.Append (DirectorySeparatorChar);
+                       if (path.Length > 0 && part.Length > 0) {
+                               char end = path [path.Length-1];
+                               if (end != DirectorySeparatorChar && 
+                                               end != AltDirectorySeparatorChar && 
+                                               end != VolumeSeparatorChar)
+                                       path.Append (DirectorySeparatorChar);
+                       }
                        path.Append (part);
                }
 
@@ -91,6 +101,8 @@ namespace Mono.Unix {
                        int lastDir = path.LastIndexOf (DirectorySeparatorChar);
                        if (lastDir > 0)
                                return path.Substring (0, lastDir);
+                       if (lastDir == 0)
+                               return "/";
                        return "";
                }
 
@@ -197,69 +209,59 @@ namespace Mono.Unix {
 
                // Read the specified symbolic link.  If the file isn't a symbolic link,
                // return null; otherwise, return the contents of the symbolic link.
-               //
-               // readlink(2) is horribly evil, as there is no way to query how big the
-               // symlink contents are.  Consequently, it's trial and error...
                internal static string ReadSymbolicLink (string path)
                {
-                       StringBuilder buf = new StringBuilder (256);
+                       string target = TryReadLink (path);
+                       if (target == null) {
+                               Native.Errno errno = Native.Stdlib.GetLastError ();
+                               if (errno != Native.Errno.EINVAL)
+                                       UnixMarshal.ThrowExceptionForError (errno);
+                       }
+                       return target;
+               }
+
+               public static string TryReadLink (string path)
+               {
+                       byte[] buf = new byte[256];
                        do {
-                               int r = Native.Syscall.readlink (path, buf);
-                               if (r < 0) {
-                                       Native.Errno e;
-                                       switch (e = Native.Stdlib.GetLastError()) {
-                                       case Native.Errno.EINVAL:
-                                               // path isn't a symbolic link
-                                               return null;
-                                       default:
-                                               UnixMarshal.ThrowExceptionForError (e);
-                                               break;
-                                       }
-                               }
-                               else if (r == buf.Capacity) {
-                                       buf.Capacity *= 2;
-                               }
+                               long r = Native.Syscall.readlink (path, buf);
+                               if (r < 0)
+                                       return null;
+                               else if (r == buf.Length)
+                                       buf = new byte[checked (buf.LongLength * 2)];
                                else
-                                       return buf.ToString (0, r);
+                                       return UnixEncoding.Instance.GetString (buf, 0, checked ((int) r));
                        } while (true);
                }
 
-               // Read the specified symbolic link.  If the file isn't a symbolic link,
-               // return null; otherwise, return the contents of the symbolic link.
-               //
-               // readlink(2) is horribly evil, as there is no way to query how big the
-               // symlink contents are.  Consequently, it's trial and error...
-               private static string ReadSymbolicLink (string path, out Native.Errno errno)
+               public static string TryReadLinkAt (int dirfd, string path)
                {
-                       errno = (Native.Errno) 0;
-                       StringBuilder buf = new StringBuilder (256);
+                       byte[] buf = new byte[256];
                        do {
-                               int r = Native.Syscall.readlink (path, buf);
-                               if (r < 0) {
-                                       errno = Native.Stdlib.GetLastError ();
+                               long r = Native.Syscall.readlinkat (dirfd, path, buf);
+                               if (r < 0)
                                        return null;
-                               }
-                               else if (r == buf.Capacity) {
-                                       buf.Capacity *= 2;
-                               }
+                               else if (r == buf.Length)
+                                       buf = new byte[checked (buf.LongLength * 2)];
                                else
-                                       return buf.ToString (0, r);
+                                       return UnixEncoding.Instance.GetString (buf, 0, checked ((int) r));
                        } while (true);
                }
 
-               public static string TryReadLink (string path)
+               public static string ReadLink (string path)
                {
-                       Native.Errno errno;
-                       return ReadSymbolicLink (path, out errno);
+                       string target = TryReadLink (path);
+                       if (target == null)
+                               UnixMarshal.ThrowExceptionForLastError (); 
+                       return target;
                }
 
-               public static string ReadLink (string path)
+               public static string ReadLinkAt (int dirfd, string path)
                {
-                       Native.Errno errno;
-                       path = ReadSymbolicLink (path, out errno);
-                       if (errno != 0)
-                               UnixMarshal.ThrowExceptionForError (errno);
-                       return path;
+                       string target = TryReadLinkAt (dirfd, path);
+                       if (target == null)
+                               UnixMarshal.ThrowExceptionForLastError (); 
+                       return target;
                }
 
                public static bool IsPathRooted (string path)