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);
}
int lastDir = path.LastIndexOf (DirectorySeparatorChar);
if (lastDir > 0)
return path.Substring (0, lastDir);
+ if (lastDir == 0)
+ return "/";
return "";
}
// 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 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)