// 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
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);
}
int lastDir = path.LastIndexOf (DirectorySeparatorChar);
if (lastDir > 0)
return path.Substring (0, lastDir);
+ if (lastDir == 0)
+ return "/";
return "";
}
if (path == null)
throw new ArgumentNullException ("path");
if (!IsPathRooted (path))
- path = UnixDirectory.GetCurrentDirectory() + DirectorySeparatorChar + path;
+ path = UnixDirectoryInfo.GetCurrentDirectory() + DirectorySeparatorChar + path;
return path;
}
// 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)
{
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");
}
}
}