* Mono.Posix.dll.sources: Add UnixDriveInfo and UnixPath.
authorJonathan Pryor <jpryor@novell.com>
Tue, 28 Dec 2004 19:54:39 +0000 (19:54 -0000)
committerJonathan Pryor <jpryor@novell.com>
Tue, 28 Dec 2004 19:54:39 +0000 (19:54 -0000)
  * CdeclFunctions.cs: Correct the comments for AMD64
  * UnixDirectoryInfo.cs: override Name; add Parent & Root properties;
    Correct Path usage (s/Path/FullPath/g).
  * UnixDriveInfo.cs: Added.  Based on .NET 2.0 System.IO.DriveInfo docs,
    provides statvfs(2) and getfsfile(3) information about a mounted volume.
    GetDrives() wraps getfsent(3), thus parsing /etc/fstab.
  * UnixFile.cs: Use UnixConver.ToOpenFlags, deleting the local version.
  * UnixFileInfo.cs: Use UnixConver.ToOpenFlags, deleting the local version;
    override Name; add DirectoryName and Directory properties;
  * UnixFileSystemInfo.cs: Make more .NET-like, using FullPath and
    OriginalPath protected members, abstract Name property; Add
    CreateSymbolicLink; Remove ReadLink (it's now
    UnixSymbolicLinkInfo.Contents); Use lstat(2) for Create(string), so we
    properly detect Symbolic Links.
  * UnixPath.cs: Added; Path manipulation utility functions.
  * UnixSymbolicLinkInfo.cs:
    - Seal the class;
    - override new abstract member Name;
    - rename ReadLink to ContentsPath (and Contents) properties
      (why "Contents"?  Because readlink(2) says "readlink places the
      contents of the symbolic link in the buffer...")
    - Add CreateSymbolicLinkTo(), which creates a symlink to the specified
      "normal" file

svn path=/trunk/mcs/; revision=38140

mcs/class/Mono.Posix/ChangeLog
mcs/class/Mono.Posix/Mono.Posix.dll.sources
mcs/class/Mono.Posix/Mono.Unix/CdeclFunction.cs
mcs/class/Mono.Posix/Mono.Unix/ChangeLog
mcs/class/Mono.Posix/Mono.Unix/UnixDirectoryInfo.cs
mcs/class/Mono.Posix/Mono.Unix/UnixDriveInfo.cs [new file with mode: 0644]
mcs/class/Mono.Posix/Mono.Unix/UnixFile.cs
mcs/class/Mono.Posix/Mono.Unix/UnixFileInfo.cs
mcs/class/Mono.Posix/Mono.Unix/UnixFileSystemInfo.cs
mcs/class/Mono.Posix/Mono.Unix/UnixPath.cs [new file with mode: 0644]
mcs/class/Mono.Posix/Mono.Unix/UnixSymbolicLinkInfo.cs

index dd5a6b95479ee3153bb12c82c1e265fe28bbd840..27eb5dc598a57450b3f11013e202b955d98fe4d9 100644 (file)
@@ -1,3 +1,7 @@
+2004-12-28  Jonathan Pryor  <jonpryor@vt.edu>
+
+       * Mono.Posix.dll.sources: Add UnixDriveInfo and UnixPath.
+
 2004-11-22  Raja R Harinath  <rharinath@novell.com>
 
        * Makefile (CLEAN_FILES): Clean up make-map.exe and the duplicated
index a1cac12b72130e9bd1fc521390fdf37131122bd8..17996c0a75a905c4aad4b77124bf905d45abd52c 100644 (file)
@@ -10,7 +10,9 @@
 ./Mono.Unix/UnixConvert.cs
 ./Mono.Unix/UnixDirectory.cs
 ./Mono.Unix/UnixDirectoryInfo.cs
+./Mono.Unix/UnixDriveInfo.cs
 ./Mono.Unix/UnixEnvironment.cs
+./Mono.Unix/UnixEndPoint.cs
 ./Mono.Unix/UnixFile.cs
 ./Mono.Unix/UnixFileInfo.cs
 ./Mono.Unix/UnixFileSystemInfo.cs
 ./Mono.Unix/UnixGroupInfo.cs
 ./Mono.Unix/UnixIOException.cs
 ./Mono.Unix/UnixMarshal.cs
+./Mono.Unix/UnixPath.cs
 ./Mono.Unix/UnixProcess.cs
 ./Mono.Unix/UnixStream.cs
 ./Mono.Unix/UnixSymbolicLinkInfo.cs
 ./Mono.Unix/UnixUser.cs
 ./Mono.Unix/UnixUserInfo.cs
-./Mono.Unix/UnixEndPoint.cs
 ./Mono.Posix/Catalog.cs
 ./Mono.Posix/PeerCred.cs
 ./Mono.Posix/Syscall.cs
index 04c7227f5fd3463c4519e44b235fc9857d1e16dd..39d2d3a28e7c0edf9155e519acc79b1b2e8a3d1f 100644 (file)
@@ -46,7 +46,7 @@ namespace Mono.Unix {
        //
        // Then call the Invoke method with the appropriate number of arguments:
        //
-       //              printf.Invoke (new object[]{"hello, %s\n", "world!"});
+       //    printf.Invoke (new object[]{"hello, %s\n", "world!"});
        //
        // In the background a P/Invoke definition for the method with the
        // requested argument types will be generated and invoked, invoking the
@@ -54,15 +54,19 @@ namespace Mono.Unix {
        // calls with the same argument list do not generate new code, speeding up
        // the call sequence.
        //
-       // Invoking Cdecl functions is not portable across all platforms.  In
-       // particular, AMD64 requires that the caller set EAX to the number of
-       // floating point arguments passed in the SSE registers.  This is only
-       // required for variable argument/stdarg functions; consequently, Mono's JIT
-       // doesn't set EAX properly which can lead to failures.  See:
+       // Invoking Cdecl functions is not guaranteed to be portable across all 
+       // platforms.  For example, AMD64 requires that the caller set EAX to the 
+       // number of floating point arguments passed in the SSE registers.  This 
+       // is only required for variable argument/cdecl functions; consequently, 
+       // the overload technique used by this class wouldn't normally work.  
+       // Mono's AMD64 JIT works around this by always setting EAX on P/Invoke
+       // invocations, allowing CdeclFunction to work properly, but it will not
+       // necessarily always work.  See also: 
        //
        //     http://lwn.net/Articles/5201/?format=printable
        //
-       // Consequently, Cdecl functions should be avoided on most platforms.
+       // Due to potential portability issues, cdecl functions should be avoided 
+       // on most platforms.
        //
        // This class is intended to be thread-safe.
        public sealed class CdeclFunction
index c99b833f455ee7a42d59243e49a10c1948c1aaac..b56c783caf09f51b0d7d08f3a7603b69b7a24304 100644 (file)
@@ -1,3 +1,29 @@
+2004-12-28  Jonathan Pryor <jonpryor@vt.edu>
+
+       * CdeclFunctions.cs: Correct the comments for AMD64
+       * UnixDirectoryInfo.cs: override Name; add Parent & Root properties; 
+         Correct Path usage (s/Path/FullPath/g).
+       * UnixDriveInfo.cs: Added.  Based on .NET 2.0 System.IO.DriveInfo docs,
+         provides statvfs(2) and getfsfile(3) information about a mounted volume.
+         GetDrives() wraps getfsent(3), thus parsing /etc/fstab.
+       * UnixFile.cs: Use UnixConver.ToOpenFlags, deleting the local version.
+       * UnixFileInfo.cs: Use UnixConver.ToOpenFlags, deleting the local version;
+         override Name; add DirectoryName and Directory properties; 
+       * UnixFileSystemInfo.cs: Make more .NET-like, using FullPath and
+         OriginalPath protected members, abstract Name property; Add
+         CreateSymbolicLink; Remove ReadLink (it's now 
+         UnixSymbolicLinkInfo.Contents); Use lstat(2) for Create(string), so we
+         properly detect Symbolic Links.
+       * UnixPath.cs: Added; Path manipulation utility functions.
+       * UnixSymbolicLinkInfo.cs: 
+         - Seal the class; 
+         - override new abstract member Name; 
+         - rename ReadLink to ContentsPath (and Contents) properties 
+           (why "Contents"?  Because readlink(2) says "readlink places the 
+           contents of the symbolic link in the buffer...")
+         - Add CreateSymbolicLinkTo(), which creates a symlink to the specified
+           "normal" file
+
 2004-12-28  Jonathan Pryor <jonpryor@vt.edu>
 
        * Stdlib.cs: Add syslog(3) to XPrintfFunctions; Add additional printf(3) 
index ae97037cdcb9b608e5f83652a2ceb3b76cddb4f9..29c533a42bd388c2dbf7b04b7256faf0d553e6c2 100644 (file)
@@ -35,7 +35,7 @@ using Mono.Unix;
 
 namespace Mono.Unix {
 
-       public class UnixDirectoryInfo : UnixFileSystemInfo
+       public sealed class UnixDirectoryInfo : UnixFileSystemInfo
        {
                public UnixDirectoryInfo (string path)
                        : base (path)
@@ -47,9 +47,36 @@ namespace Mono.Unix {
                {
                }
 
+               public override string Name {
+                       get {
+                               string r = UnixPath.GetFileName (FullPath);
+                               if (r == null || r == "")
+                                       return FullPath;
+                               return r;
+                       }
+               }
+
+               public UnixDirectoryInfo Parent {
+                       get {
+                               string dirname = UnixPath.GetDirectoryName (FullPath);
+                               if (dirname == null)
+                                       return null;
+                               return new UnixDirectoryInfo (dirname);
+                       }
+               }
+
+               public UnixDirectoryInfo Root {
+                       get {
+                               string root = UnixPath.GetPathRoot (FullPath);
+                               if (root == null)
+                                       return null;
+                               return new UnixDirectoryInfo (root);
+                       }
+               }
+
                public void Create (FilePermissions mode)
                {
-                       int r = Syscall.mkdir (Path, mode);
+                       int r = Syscall.mkdir (FullPath, mode);
                        UnixMarshal.ThrowExceptionForLastErrorIf (r);
                        base.Refresh ();
                }
@@ -76,14 +103,14 @@ namespace Mono.Unix {
                                                e.Delete ();
                                }
                        }
-                       int r = Syscall.rmdir (Path);
+                       int r = Syscall.rmdir (FullPath);
                        UnixMarshal.ThrowExceptionForLastErrorIf (r);
                        base.Refresh ();
                }
 
                public Dirent[] GetEntries ()
                {
-                       IntPtr dirp = Syscall.opendir (Path);
+                       IntPtr dirp = Syscall.opendir (FullPath);
                        if (dirp == IntPtr.Zero)
                                UnixMarshal.ThrowExceptionForLastError ();
 
@@ -123,7 +150,7 @@ namespace Mono.Unix {
 
                public Dirent[] GetEntries (Regex regex)
                {
-                       IntPtr dirp = Syscall.opendir (Path);
+                       IntPtr dirp = Syscall.opendir (FullPath);
                        if (dirp == IntPtr.Zero)
                                UnixMarshal.ThrowExceptionForLastError ();
 
diff --git a/mcs/class/Mono.Posix/Mono.Unix/UnixDriveInfo.cs b/mcs/class/Mono.Posix/Mono.Unix/UnixDriveInfo.cs
new file mode 100644 (file)
index 0000000..8eacd5c
--- /dev/null
@@ -0,0 +1,169 @@
+//
+// Mono.Unix/UnixDriveInfo.cs
+//
+// Authors:
+//   Jonathan Pryor (jonpryor@vt.edu)
+//
+// (C) 2004 Jonathan Pryor
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections;
+using System.IO;
+using Mono.Unix;
+
+namespace Mono.Unix {
+
+       public enum UnixDriveType {
+               Unknown,
+               NoRootDirectory,
+               Removable,
+               Fixed,
+               Network,
+               CDRom,
+               Ram
+       }
+
+       // All methods & properties can throw IOException
+       public sealed class UnixDriveInfo
+       {
+               private Statvfs stat;
+               private Fstab   fstab;
+
+               public UnixDriveInfo (string mountPoint)
+               {
+                       if (mountPoint == null)
+                               throw new ArgumentNullException ("mountPoint");
+                       fstab = Syscall.getfsfile (mountPoint);
+                       if (fstab == null)
+                               throw new ArgumentException ("mountPoint isn't valid: " + mountPoint);
+                       // throws ArgumentException if driveName isn't valid
+                       // though .NET also has a DriveNotFoundException class, so maybe that's
+                       // more appropriate?
+               }
+
+               public static UnixDriveInfo GetForSpecialFile (string specialFile)
+               {
+                       if (specialFile == null)
+                               throw new ArgumentNullException ("specialFile");
+                       Fstab f = Syscall.getfsspec (specialFile);
+                       if (f == null)
+                               throw new ArgumentException ("specialFile isn't valid: " + specialFile);
+                       return new UnixDriveInfo (f);
+               }
+
+               private UnixDriveInfo (Fstab fstab)
+               {
+                       this.fstab = fstab;
+               }
+
+               public long AvailableFreeSpace {
+                       get {Refresh (); return (long) (stat.f_bavail * stat.f_bsize);}
+               }
+
+               public string DriveFormat {
+                       get {return fstab.fs_vfstype;}
+               }
+
+               public UnixDriveType DriveType {
+                       get {return UnixDriveType.Unknown;}
+               }
+
+               // this throws no exceptions
+               public bool IsReady {
+                       get {return Refresh (false);}
+               }
+
+               public string Name {
+                       get {return fstab.fs_file;}
+               }
+
+               public UnixDirectoryInfo RootDirectory {
+                       get {return new UnixDirectoryInfo (fstab.fs_file);}
+               }
+
+               public long TotalFreeSpace {
+                       get {Refresh (); return (long) (stat.f_bfree * stat.f_bsize);}
+               }
+
+               public long TotalSize {
+                       get {Refresh (); return (long) (stat.f_frsize * stat.f_blocks);}
+               }
+
+               // also throws SecurityException if caller lacks perms
+               public string VolumeLabel {
+                       get {return fstab.fs_spec;}
+                       // set {}
+               }
+
+               public ulong MaximumFilenameLength {
+                       get {Refresh (); return stat.f_namemax;}
+               }
+
+               public static UnixDriveInfo[] GetDrives ()
+               {
+                       // throws IOException, UnauthorizedAccessException (no permission)
+                       Syscall.SetLastError ((Error) 0);
+                       int r = Syscall.setfsent ();
+                       if (r != 1)
+                               throw new IOException ("Error calling setfsent(3)");
+                       ArrayList entries = new ArrayList ();
+                       try {
+                               Fstab fs;
+                               while ((fs = Syscall.getfsent()) != null) {
+                                       // avoid virtual entries, such as "swap"
+                                       if (fs.fs_file.StartsWith ("/"))
+                                               entries.Add (new UnixDriveInfo (fs));
+                               }
+                       }
+                       finally {
+                               Syscall.endfsent ();
+                       }
+                       return (UnixDriveInfo[]) entries.ToArray (typeof(UnixDriveInfo));
+               }
+
+               public override string ToString ()
+               {
+                       return VolumeLabel;
+               }
+
+               private void Refresh ()
+               {
+                       Refresh (true);
+               }
+
+               private bool Refresh (bool throwException)
+               {
+                       int r = Syscall.statvfs (fstab.fs_file, out stat);
+                       if (r == -1 && throwException) {
+                               Error e = Syscall.GetLastError ();
+                               throw new IOException (UnixMarshal.GetErrorDescription (e),
+                                       UnixMarshal.CreateExceptionForError (e));
+                       }
+                       else if (r == -1)
+                               return false;
+                       return true;
+               }
+       }
+}
+
+// vim: noexpandtab
index f2d65af295fa16bf6f56c62379da820116cb2fb9..0b1fdee4cf401680ddd5e051646763057ae8bed7 100644 (file)
@@ -173,7 +173,7 @@ namespace Mono.Unix {
 
                public static UnixStream Open (string path, FileMode mode)
                {
-                       OpenFlags flags = ToOpenFlags (mode, FileAccess.ReadWrite);
+                       OpenFlags flags = UnixConvert.ToOpenFlags (mode, FileAccess.ReadWrite);
                        int fd = Syscall.open (path, flags);
                        if (fd < 0)
                                UnixMarshal.ThrowExceptionForLastError ();
@@ -182,7 +182,7 @@ namespace Mono.Unix {
 
                public static UnixStream Open (string path, FileMode mode, FileAccess access)
                {
-                       OpenFlags flags = ToOpenFlags (mode, access);
+                       OpenFlags flags = UnixConvert.ToOpenFlags (mode, access);
                        int fd = Syscall.open (path, flags);
                        if (fd < 0)
                                UnixMarshal.ThrowExceptionForLastError ();
@@ -191,7 +191,7 @@ namespace Mono.Unix {
 
                public static UnixStream Open (string path, FileMode mode, FileAccess access, FilePermissions perms)
                {
-                       OpenFlags flags = ToOpenFlags (mode, access);
+                       OpenFlags flags = UnixConvert.ToOpenFlags (mode, access);
                        int fd = Syscall.open (path, flags, perms);
                        if (fd < 0)
                                UnixMarshal.ThrowExceptionForLastError ();
@@ -256,54 +256,6 @@ namespace Mono.Unix {
                        SetLinkOwner (path, uid, gid);
                }
 
-               public static OpenFlags ToOpenFlags (FileMode mode, FileAccess access)
-               {
-                       OpenFlags flags = 0;
-                       switch (mode) {
-                       case FileMode.CreateNew:
-                               flags = OpenFlags.O_CREAT | OpenFlags.O_EXCL;
-                               break;
-                       case FileMode.Create:
-                               flags = OpenFlags.O_CREAT | OpenFlags.O_TRUNC;
-                               break;
-                       case FileMode.Open:
-                               // do nothing
-                               break;
-                       case FileMode.OpenOrCreate:
-                               flags = OpenFlags.O_CREAT;
-                               break;
-                       case FileMode.Truncate:
-                               flags = OpenFlags.O_TRUNC;
-                               break;
-                       case FileMode.Append:
-                               flags = OpenFlags.O_APPEND;
-                               break;
-                       default:
-                               throw new ArgumentException (Locale.GetText ("Unsupported mode value"), "mode");
-                       }
-
-                       // Is O_LARGEFILE supported?
-                       int _v;
-                       if (UnixConvert.TryFromOpenFlags (OpenFlags.O_LARGEFILE, out _v))
-                               flags |= OpenFlags.O_LARGEFILE;
-
-                       switch (access) {
-                       case FileAccess.Read:
-                               flags |= OpenFlags.O_RDONLY;
-                               break;
-                       case FileAccess.Write:
-                               flags |= OpenFlags.O_WRONLY;
-                               break;
-                       case FileAccess.ReadWrite:
-                               flags |= OpenFlags.O_RDWR;
-                               break;
-                       default:
-                               throw new ArgumentException (Locale.GetText ("Unsupported access value"), "access");
-                       }
-
-                       return flags;
-               }
-
                public static void AdviseNormalAccess (int fd, long offset, long len)
                {
                        int r = Syscall.posix_fadvise (fd, offset, len,
index 09a1666ad920a1292080c834f63b88e66d9512d5..5a12445768f93657fb92056610337c037c1bf0d8 100644 (file)
@@ -33,7 +33,7 @@ using Mono.Unix;
 
 namespace Mono.Unix {
 
-       public class UnixFileInfo : UnixFileSystemInfo
+       public sealed class UnixFileInfo : UnixFileSystemInfo
        {
                public UnixFileInfo (string path)
                        : base (path)
@@ -45,9 +45,21 @@ namespace Mono.Unix {
                {
                }
 
+               public override string Name {
+                       get {return UnixPath.GetFileName (FullPath);}
+               }
+
+               public string DirectoryName {
+                       get {return UnixPath.GetDirectoryName (FullPath);}
+               }
+
+               public UnixDirectoryInfo Directory {
+                       get {return new UnixDirectoryInfo (DirectoryName);}
+               }
+
                public override void Delete ()
                {
-                       int r = Syscall.unlink (Path);
+                       int r = Syscall.unlink (FullPath);
                        UnixMarshal.ThrowExceptionForLastErrorIf (r);
                        base.Refresh ();
                }
@@ -62,7 +74,7 @@ namespace Mono.Unix {
 
                public UnixStream Create (FilePermissions mode)
                {
-                       int fd = Syscall.creat (Path, mode);
+                       int fd = Syscall.creat (FullPath, mode);
                        if (fd < 0)
                                UnixMarshal.ThrowExceptionForLastError ();
                        base.Refresh ();
@@ -71,7 +83,7 @@ namespace Mono.Unix {
 
                public UnixStream Open (OpenFlags flags)
                {
-                       int fd = Syscall.open (Path, flags);
+                       int fd = Syscall.open (FullPath, flags);
                        if (fd < 0)
                                UnixMarshal.ThrowExceptionForLastError ();
                        return new UnixStream (fd);
@@ -79,7 +91,7 @@ namespace Mono.Unix {
 
                public UnixStream Open (OpenFlags flags, FilePermissions mode)
                {
-                       int fd = Syscall.open (Path, flags, mode);
+                       int fd = Syscall.open (FullPath, flags, mode);
                        if (fd < 0)
                                UnixMarshal.ThrowExceptionForLastError ();
                        return new UnixStream (fd);
@@ -87,8 +99,8 @@ namespace Mono.Unix {
 
                public UnixStream Open (FileMode mode)
                {
-                       OpenFlags flags = ToOpenFlags (mode, FileAccess.ReadWrite);
-                       int fd = Syscall.open (Path, flags);
+                       OpenFlags flags = UnixConvert.ToOpenFlags (mode, FileAccess.ReadWrite);
+                       int fd = Syscall.open (FullPath, flags);
                        if (fd < 0)
                                UnixMarshal.ThrowExceptionForLastError ();
                        return new UnixStream (fd);
@@ -96,8 +108,8 @@ namespace Mono.Unix {
 
                public UnixStream Open (FileMode mode, FileAccess access)
                {
-                       OpenFlags flags = ToOpenFlags (mode, access);
-                       int fd = Syscall.open (Path, flags);
+                       OpenFlags flags = UnixConvert.ToOpenFlags (mode, access);
+                       int fd = Syscall.open (FullPath, flags);
                        if (fd < 0)
                                UnixMarshal.ThrowExceptionForLastError ();
                        return new UnixStream (fd);
@@ -105,8 +117,8 @@ namespace Mono.Unix {
 
                public UnixStream Open (FileMode mode, FileAccess access, FilePermissions perms)
                {
-                       OpenFlags flags = ToOpenFlags (mode, access);
-                       int fd = Syscall.open (Path, flags, perms);
+                       OpenFlags flags = UnixConvert.ToOpenFlags (mode, access);
+                       int fd = Syscall.open (FullPath, flags, perms);
                        if (fd < 0)
                                UnixMarshal.ThrowExceptionForLastError ();
                        return new UnixStream (fd);
@@ -121,55 +133,6 @@ namespace Mono.Unix {
                {
                        return Open (FileMode.OpenOrCreate, FileAccess.Write);
                }
-
-               public static OpenFlags ToOpenFlags (FileMode mode, FileAccess access)
-               {
-                       OpenFlags flags = 0;
-                       switch (mode) {
-                       case FileMode.CreateNew:
-                               flags = OpenFlags.O_CREAT | OpenFlags.O_EXCL;
-                               break;
-                       case FileMode.Create:
-                               flags = OpenFlags.O_CREAT | OpenFlags.O_TRUNC;
-                               break;
-                       case FileMode.Open:
-                               // do nothing
-                               break;
-                       case FileMode.OpenOrCreate:
-                               flags = OpenFlags.O_CREAT;
-                               break;
-                       case FileMode.Truncate:
-                               flags = OpenFlags.O_TRUNC;
-                               break;
-                       case FileMode.Append:
-                               flags = OpenFlags.O_APPEND;
-                               break;
-                       default:
-                               throw new ArgumentOutOfRangeException ("mode", mode, 
-                                               Locale.GetText ("Unsupported mode value"));
-                       }
-
-                       int _ignored;
-                       if (UnixConvert.TryFromOpenFlags (OpenFlags.O_LARGEFILE, out _ignored))
-                               flags |= OpenFlags.O_LARGEFILE;
-
-                       switch (access) {
-                       case FileAccess.Read:
-                               flags |= OpenFlags.O_RDONLY;
-                               break;
-                       case FileAccess.Write:
-                               flags |= OpenFlags.O_WRONLY;
-                               break;
-                       case FileAccess.ReadWrite:
-                               flags |= OpenFlags.O_RDWR;
-                               break;
-                       default:
-                               throw new ArgumentOutOfRangeException ("access", access,
-                                               Locale.GetText ("Unsupported access value"));
-                       }
-
-                       return flags;
-               }
        }
 }
 
index 5b0b3ca18197f054fbc2332d34b6af4deba0b676..8b173c1bb4688728254a6b1bf88f3995e266662d 100644 (file)
@@ -36,25 +36,34 @@ namespace Mono.Unix {
        public abstract class UnixFileSystemInfo
        {
                private Stat stat;
-               private string path;
+               private string fullPath;
+               private string originalPath;
                private bool valid = false;
 
                protected UnixFileSystemInfo (string path)
                {
-                       this.path = path;
+                       UnixPath.CheckPath (path);
+                       this.originalPath = path;
+                       this.fullPath = UnixPath.GetFullPath (path);
                        Refresh (true);
                }
 
                internal UnixFileSystemInfo (String path, Stat stat)
                {
-                       this.path = path;
+                       this.originalPath = path;
+                       this.fullPath = UnixPath.GetFullPath (path);
                        this.stat = stat;
                        this.valid = true;
                }
 
-               protected string Path {
-                       get {return path;}
-                       set {path = value;}
+               protected string FullPath {
+                       get {return fullPath;}
+                       set {fullPath = value;}
+               }
+
+               protected string OriginalPath {
+                       get {return originalPath;}
+                       set {originalPath = value;}
                }
 
                private void AssertValid ()
@@ -64,9 +73,15 @@ namespace Mono.Unix {
                                throw new InvalidOperationException ("Path doesn't exist!");
                }
 
+               public virtual string FullName {
+                       get {return FullPath;}
+               }
+
+               public abstract string Name {get;}
+
                public bool Exists {
                        get {
-                               int r = Syscall.access (path, AccessMode.F_OK);
+                               int r = Syscall.access (FullPath, AccessMode.F_OK);
                                if (r == 0)
                                        return true;
                                return false;
@@ -192,42 +207,29 @@ namespace Mono.Unix {
 
                public bool CanAccess (AccessMode mode)
                {
-                       int r = Syscall.access (path, mode);
+                       int r = Syscall.access (FullPath, mode);
                        return r == 0;
                }
 
+               public UnixSymbolicLinkInfo CreateSymbolicLink (string path)
+               {
+                       int r = Syscall.symlink (FullName, path);
+                       UnixMarshal.ThrowExceptionForLastErrorIf (r);
+                       return new UnixSymbolicLinkInfo (path);
+               }
+
                public abstract void Delete ();
 
                public long GetConfigurationValue (PathConf name)
                {
                        Syscall.SetLastError ((Error) 0);
-                       long r = Syscall.pathconf (Path, name);
+                       long r = Syscall.pathconf (FullPath, name);
                        if (r == -1 && Syscall.GetLastError() != (Error) 0)
                                UnixMarshal.ThrowExceptionForLastError ();
                        return r;
                }
 
-               // TODO: Should ReadLink be in UnixSymbolicLinkInfo?
-               public string ReadLink ()
-               {
-                       string r = TryReadLink ();
-                       if (r == null)
-                               UnixMarshal.ThrowExceptionForLastError ();
-                       return r;
-               }
-
-               public string TryReadLink ()
-               {
-                       // Who came up with readlink(2)?  There doesn't seem to be a way to
-                       // properly handle it.
-                       StringBuilder sb = new StringBuilder (512);
-                       int r = Syscall.readlink (path, sb);
-                       if (r == -1)
-                               return null;
-                       return sb.ToString().Substring (0, r);
-               }
-
-               public new void Refresh ()
+               public void Refresh ()
                {
                        Refresh (true);
                }
@@ -236,7 +238,7 @@ namespace Mono.Unix {
                {
                        if (valid && !force)
                                return;
-                       int r = Syscall.stat (path, out this.stat);
+                       int r = Syscall.lstat (FullPath, out this.stat);
                        valid = r == 0;
                }
 
@@ -244,20 +246,20 @@ namespace Mono.Unix {
                {
                        int r;
                        do {
-                               r = Syscall.truncate (path, length);
+                               r = Syscall.truncate (FullPath, length);
                        }       while (UnixMarshal.ShouldRetrySyscall (r));
                        UnixMarshal.ThrowExceptionForLastErrorIf (r);
                }
 
                public void SetPermissions (FilePermissions perms)
                {
-                       int r = Syscall.chmod (path, perms);
+                       int r = Syscall.chmod (FullPath, perms);
                        UnixMarshal.ThrowExceptionForLastErrorIf (r);
                }
 
                public virtual void SetOwner (uint owner, uint group)
                {
-                       int r = Syscall.chown (path, owner, group);
+                       int r = Syscall.chown (FullPath, owner, group);
                        UnixMarshal.ThrowExceptionForLastErrorIf (r);
                }
 
@@ -281,12 +283,15 @@ namespace Mono.Unix {
 
                public override string ToString ()
                {
-                       return path;
+                       return FullPath;
                }
 
                internal static UnixFileSystemInfo Create (string path)
                {
-                       Stat stat = UnixFile.GetFileStatus (path);
+                       Stat stat;
+                       int r = Syscall.lstat (path, out stat);
+                       UnixMarshal.ThrowExceptionForLastErrorIf (r);
+
                        if (IsType (stat.st_mode, FilePermissions.S_IFDIR))
                                return new UnixDirectoryInfo (path, stat);
                        else if (IsType (stat.st_mode, FilePermissions.S_IFLNK))
diff --git a/mcs/class/Mono.Posix/Mono.Unix/UnixPath.cs b/mcs/class/Mono.Posix/Mono.Unix/UnixPath.cs
new file mode 100644 (file)
index 0000000..679c2c1
--- /dev/null
@@ -0,0 +1,204 @@
+//
+// Mono.Unix/UnixPath.cs
+//
+// Authors:
+//   Jonathan Pryor (jonpryor@vt.edu)
+//
+// (C) 2004 Jonathan Pryor
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections;
+using System.Text;
+using Mono.Unix;
+
+namespace Mono.Unix {
+
+       public sealed class UnixPath
+       {
+               private UnixPath () {}
+
+               public static readonly char DirectorySeparatorChar = '/';
+               public static readonly char AltDirectorySeparatorChar = '/';
+               public static readonly char[] InvalidPathChars = new char[]{'\0'};
+               public static readonly char PathSeparator = ':';
+               public static readonly char VolumeSeparatorChar = '/';
+
+               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)
+                               throw new ArgumentException ("Illegal characters in path", "path1");
+
+                       int len = path1.Length + 1;
+                       for (int i = 0; i < paths.Length; ++i) {
+                               if (paths [i] == null)
+                                       throw new ArgumentNullException ("paths");
+                               len += paths [i].Length + 1;
+                       }
+
+                       StringBuilder sb = new StringBuilder (len);
+                       sb.Append (path1);
+                       for (int i = 0; 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);
+                       path.Append (part);
+               }
+
+               public static string GetDirectoryName (string path)
+               {
+                       CheckPath (path);
+
+                       int lastDir = path.LastIndexOf (DirectorySeparatorChar);
+                       if (lastDir > 0)
+                               return path.Substring (0, lastDir);
+                       return "";
+               }
+
+               public static string GetFileName (string path)
+               {
+                       if (path == null || path.Length == 0)
+                               return path;
+
+                       int lastDir = path.LastIndexOf (DirectorySeparatorChar);
+                       if (lastDir >= 0)
+                               return path.Substring (lastDir+1);
+
+                       return path;
+               }
+
+               public static string GetFullPath (string path)
+               {
+                       path = _GetFullPath (path);
+                       string [] dirs;
+                       int lastIndex;
+                       GetPathComponents (path, out dirs, out lastIndex);
+                       return string.Join ("/", dirs, 0, lastIndex);
+               }
+
+               private static string _GetFullPath (string path)
+               {
+                       if (path == null)
+                               throw new ArgumentNullException ("path");
+                       if (!IsPathRooted (path))
+                               path = UnixDirectory.GetCurrentDirectory() + DirectorySeparatorChar + path;
+
+                       return path;
+               }
+
+               private static void GetPathComponents (string path, 
+                       out string[] components, out int lastIndex)
+               {
+                       string [] dirs = path.Split (DirectorySeparatorChar);
+                       int target = 0;
+                       for (int i = 0; i < dirs.Length; ++i) {
+                               if (dirs [i] == "." || (i != 0 && dirs [i] == string.Empty)) continue;
+                               else if (dirs [i] == "..") {
+                                       if (target != 0) --target;
+                               }
+                               else
+                                       dirs [target++] = dirs [i];
+                       }
+                       components = dirs;
+                       lastIndex = target;
+               }
+
+               public static string GetPathRoot (string path)
+               {
+                       if (path == null)
+                               return null;
+                       if (!IsPathRooted (path))
+                               return "";
+                       return "/";
+               }
+
+               public static string GetRealPath (string path)
+               {
+                       path = _GetFullPath (path);
+                       string [] dirs;
+                       int lastIndex;
+                       GetPathComponents (path, out dirs, out lastIndex);
+                       StringBuilder realPath = new StringBuilder ();
+                       for (int i = 0; i < dirs.Length; ++i) {
+                               realPath.Append ("/").Append (dirs [i]);
+                               string p = _GetRealPath (realPath.ToString());
+                               realPath.Remove (0, realPath.Length);
+                               realPath.Append (p);
+                       }
+                       return realPath.ToString ();
+               }
+
+               private static string _GetRealPath (string path)
+               {
+                       StringBuilder buf = new StringBuilder (1024);
+                       int r;
+                       do {
+                               r = Syscall.readlink (path, buf);
+                               if (r == -1) {
+                                       Error e;
+                                       switch (e = Syscall.GetLastError()) {
+                                       case Error.EINVAL:
+                                               // path isn't a symbolic link
+                                               return path;
+                                       default:
+                                               UnixMarshal.ThrowExceptionForError (e);
+                                               break;
+                                       }
+                               }
+                               path = buf.ToString ();
+                       } while (r == 0);
+
+                       return path;
+               }
+
+               public static bool IsPathRooted (string path)
+               {
+                       if (path == null || path.Length == 0)
+                               return false;
+                       return path [0] == DirectorySeparatorChar;
+               }
+
+               internal static void CheckPath (string path)
+               {
+                       if (path == null)
+                               throw new ArgumentNullException ();
+                       if (path.IndexOfAny (UnixPath.InvalidPathChars) != -1)
+                               throw new ArgumentException ("Invalid characters in path.");
+               }
+       }
+}
+
+// vim: noexpandtab
index 322f7069f4cc625c311e2af2f374802ddddb6ef4..ea0336da1540db4829bc4437bd49348535edcd21 100644 (file)
@@ -33,7 +33,7 @@ using Mono.Unix;
 
 namespace Mono.Unix {
 
-       public class UnixSymbolicLinkInfo : UnixFileSystemInfo
+       public sealed class UnixSymbolicLinkInfo : UnixFileSystemInfo
        {
                public UnixSymbolicLinkInfo (string path)
                        : base (path)
@@ -45,18 +45,75 @@ namespace Mono.Unix {
                {
                }
 
+               public override string Name {
+                       get {return UnixPath.GetFileName (FullPath);}
+               }
+
+               // maximum number of bytes read from the symbolic link
+               public static readonly int ContentsLength = 1024;
+
+               public UnixFileSystemInfo Contents {
+                       get {
+                               return UnixFileSystemInfo.Create (ContentsPath);
+                       }
+               }
+
+               public string ContentsPath {
+                       get {
+                               return ReadLink ();
+                       }
+               }
+
+               public bool HasContents {
+                       get {
+                               return TryReadLink () != null;
+                       }
+               }
+
+               public void CreateSymbolicLinkTo (string path)
+               {
+                       int r = Syscall.symlink (path, OriginalPath);
+                       UnixMarshal.ThrowExceptionForLastErrorIf (r);
+               }
+
+               public void CreateSymbolicLinkTo (UnixFileSystemInfo path)
+               {
+                       int r = Syscall.symlink (path.FullName, OriginalPath);
+                       UnixMarshal.ThrowExceptionForLastErrorIf (r);
+               }
+
                public override void Delete ()
                {
-                       int r = Syscall.unlink (Path);
+                       int r = Syscall.unlink (FullPath);
                        UnixMarshal.ThrowExceptionForLastErrorIf (r);
                        base.Refresh ();
                }
 
                public override void SetOwner (uint owner, uint group)
                {
-                       int r = Syscall.lchown (Path, owner, group);
+                       int r = Syscall.lchown (FullPath, owner, group);
                        UnixMarshal.ThrowExceptionForLastErrorIf (r);
                }
+
+               // TODO: Should ReadLink be in UnixSymbolicLinkInfo?
+               private string ReadLink ()
+               {
+                       string r = TryReadLink ();
+                       if (r == null)
+                               UnixMarshal.ThrowExceptionForLastError ();
+                       return r;
+               }
+
+               private string TryReadLink ()
+               {
+                       // Who came up with readlink(2)?  There doesn't seem to be a way to
+                       // properly handle it.
+                       StringBuilder sb = new StringBuilder (ContentsLength+1);
+                       int r = Syscall.readlink (FullPath, sb, (ulong) ContentsLength);
+                       if (r == -1)
+                               return null;
+                       return sb.ToString().Substring (0, r);
+               }
        }
 }