Cleanup in signal.c and related tests
[mono.git] / mcs / class / Mono.Posix / Mono.Unix / UnixPath.cs
index ebaadd0a7c67bf1a46e20ca16b69e6fc9b1adf14..e577edb74d4508f668dcc99a7bf282508160f843 100644 (file)
@@ -4,7 +4,7 @@
 // Authors:
 //   Jonathan Pryor (jonpryor@vt.edu)
 //
-// (C) 2004 Jonathan Pryor
+// (C) 2004-2006 Jonathan Pryor
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
@@ -39,42 +39,58 @@ namespace Mono.Unix {
 
                public static readonly char DirectorySeparatorChar = '/';
                public static readonly char AltDirectorySeparatorChar = '/';
-               public static readonly char[] InvalidPathChars = new char[]{};
                public static readonly char PathSeparator = ':';
                public static readonly char VolumeSeparatorChar = '/';
 
+               private static readonly char[] _InvalidPathChars = new char[]{};
+
+               public static char[] GetInvalidPathChars ()
+               {
+                       return (char[]) _InvalidPathChars.Clone ();
+               }
+
                public static string Combine (string path1, params string[] paths)
                {
                        if (path1 == null)
                                throw new ArgumentNullException ("path1");
                        if (paths == null)
                                throw new ArgumentNullException ("paths");
-                       if (path1.IndexOfAny (InvalidPathChars) != -1)
+                       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);
                }
 
@@ -85,6 +101,8 @@ namespace Mono.Unix {
                        int lastDir = path.LastIndexOf (DirectorySeparatorChar);
                        if (lastDir > 0)
                                return path.Substring (0, lastDir);
+                       if (lastDir == 0)
+                               return "/";
                        return "";
                }
 
@@ -111,7 +129,7 @@ namespace Mono.Unix {
                        if (path == null)
                                throw new ArgumentNullException ("path");
                        if (!IsPathRooted (path))
-                               path = UnixDirectory.GetCurrentDirectory() + DirectorySeparatorChar + path;
+                               path = UnixDirectoryInfo.GetCurrentDirectory() + DirectorySeparatorChar + path;
 
                        return path;
                }
@@ -191,33 +209,61 @@ 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 = Syscall.readlink (path, buf);
-                               if (r < 0) {
-                                       Error e;
-                                       switch (e = Syscall.GetLastError()) {
-                                       case Error.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 UnixEncoding.Instance.GetString (buf, 0, checked ((int) r));
+                       } while (true);
+               }
+
+               public static string TryReadLinkAt (int dirfd, string path)
+               {
+                       byte[] buf = new byte[256];
+                       do {
+                               long r = Native.Syscall.readlinkat (dirfd, 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);
                }
 
+               public static string ReadLink (string path)
+               {
+                       string target = TryReadLink (path);
+                       if (target == null)
+                               UnixMarshal.ThrowExceptionForLastError (); 
+                       return target;
+               }
+
+               public static string ReadLinkAt (int dirfd, string path)
+               {
+                       string target = TryReadLinkAt (dirfd, path);
+                       if (target == null)
+                               UnixMarshal.ThrowExceptionForLastError (); 
+                       return target;
+               }
+
                public static bool IsPathRooted (string path)
                {
                        if (path == null || path.Length == 0)
@@ -229,8 +275,10 @@ namespace Mono.Unix {
                {
                        if (path == null)
                                throw new ArgumentNullException ();
-                       if (path.IndexOfAny (UnixPath.InvalidPathChars) != -1)
-                               throw new ArgumentException ("Invalid characters in path.");
+                       if (path.Length == 0)
+                               throw new ArgumentException ("Path cannot contain a zero-length string", "path");
+                       if (path.IndexOfAny (_InvalidPathChars) != -1)
+                               throw new ArgumentException ("Invalid characters in path.", "path");
                }
        }
 }