Fix problems with overlong directory names: phase #1
[mono.git] / mcs / class / Mono.Posix / Mono.Unix / UnixStream.cs
index eabec2bbdfc6651dadfe86f49d3d37b21fae637f..64795781531b8325ed254853ce3e1351b9599e31 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
@@ -52,17 +52,15 @@ namespace Mono.Unix {
                        this.fileDescriptor = fileDescriptor;
                        this.owner = ownsHandle;
                        
-                       long offset = Syscall.lseek (fileDescriptor, 0, SeekFlags.SEEK_CUR);
+                       long offset = Native.Syscall.lseek (fileDescriptor, 0, Native.SeekFlags.SEEK_CUR);
                        if (offset != -1)
                                canSeek = true;
-                       unsafe {
-                               long read = Syscall.read (fileDescriptor, null, 0);
-                               if (read != -1)
-                                       canRead = true;
-                               long write = Syscall.write (fileDescriptor, null, 0);
-                               if (write != -1)
-                                       canWrite = true;  
-                       }
+                       long read = Native.Syscall.read (fileDescriptor, IntPtr.Zero, 0);
+                       if (read != -1)
+                               canRead = true;
+                       long write = Native.Syscall.write (fileDescriptor, IntPtr.Zero, 0);
+                       if (write != -1)
+                               canWrite = true;  
                }
 
                private void AssertNotDisposed ()
@@ -71,7 +69,7 @@ namespace Mono.Unix {
                                throw new ObjectDisposedException ("Invalid File Descriptor");
                }
 
-               public int FileDescriptor {
+               public int Handle {
                        get {return fileDescriptor;}
                }
 
@@ -92,10 +90,8 @@ namespace Mono.Unix {
                                AssertNotDisposed ();
                                if (!CanSeek)
                                        throw new NotSupportedException ("File descriptor doesn't support seeking");
-                               Stat stat;
-                               int r = Syscall.fstat (fileDescriptor, out stat);
-                               UnixMarshal.ThrowExceptionForLastErrorIf (r);
-                               return (long) stat.st_size;
+                               RefreshStat ();
+                               return stat.st_size;
                        }
                }
 
@@ -104,7 +100,7 @@ namespace Mono.Unix {
                                AssertNotDisposed ();
                                if (!CanSeek)
                                        throw new NotSupportedException ("The stream does not support seeking");
-                               long pos = Syscall.lseek (fileDescriptor, 0, SeekFlags.SEEK_CUR);
+                               long pos = Native.Syscall.lseek (fileDescriptor, 0, Native.SeekFlags.SEEK_CUR);
                                if (pos == -1)
                                        UnixMarshal.ThrowExceptionForLastError ();
                                return (long) pos;
@@ -114,83 +110,89 @@ namespace Mono.Unix {
                        }
                }
 
-               public FilePermissions Permissions {
+               [CLSCompliant (false)]
+               public Native.FilePermissions Protection {
                        get {
-                               Stat stat;
-                               int r = Syscall.fstat (fileDescriptor, out stat);
-                               UnixMarshal.ThrowExceptionForLastErrorIf (r);
+                               RefreshStat ();
                                return stat.st_mode;
                        }
                        set {
-                               int r = Syscall.fchmod (fileDescriptor, value);
+                               // we can't change file type with fchmod, so clear out that portion
+                               value &= ~Native.FilePermissions.S_IFMT;
+                               int r = Native.Syscall.fchmod (fileDescriptor, value);
                                UnixMarshal.ThrowExceptionForLastErrorIf (r);
                        }
                }
 
-               public void AdviseNormalAccess (long offset, long len)
-               {
-                       UnixFile.AdviseNormalAccess (fileDescriptor, offset, len);
-               }
-
-               public void AdviseNormalAccess ()
-               {
-                       UnixFile.AdviseNormalAccess (fileDescriptor);
-               }
-
-               public void AdviseSequentialAccess (long offset, long len)
-               {
-                       UnixFile.AdviseSequentialAccess (fileDescriptor, offset, len);
+               public FileTypes FileType {
+                       get {
+                               int type = (int) Protection;
+                               return (FileTypes) (type & (int) UnixFileSystemInfo.AllFileTypes);
+                       }
+                       // no set as fchmod(2) won't accept changing the file type.
                }
 
-               public void AdviseSequentialAccess ()
-               {
-                       UnixFile.AdviseSequentialAccess (fileDescriptor);
+               public FileAccessPermissions FileAccessPermissions {
+                       get {
+                               int perms = (int) Protection;
+                               return (FileAccessPermissions) (perms & (int) FileAccessPermissions.AllPermissions);
+                       }
+                       set {
+                               int perms = (int) Protection;
+                               perms &= (int) ~FileAccessPermissions.AllPermissions;
+                               perms |= (int) value;
+                               Protection = (Native.FilePermissions) perms;
+                       }
                }
 
-               public void AdviseRandomAccess (long offset, long len)
-               {
-                       UnixFile.AdviseRandomAccess (fileDescriptor, offset, len);
+               public FileSpecialAttributes FileSpecialAttributes {
+                       get {
+                               int attrs = (int) Protection;
+                               return (FileSpecialAttributes) (attrs & (int) UnixFileSystemInfo.AllSpecialAttributes);
+                       }
+                       set {
+                               int perms = (int) Protection;
+                               perms &= (int) ~UnixFileSystemInfo.AllSpecialAttributes;
+                               perms |= (int) value;
+                               Protection = (Native.FilePermissions) perms;
+                       }
                }
 
-               public void AdviseRandomAccess ()
-               {
-                       UnixFile.AdviseRandomAccess (fileDescriptor);
+               public UnixUserInfo OwnerUser {
+                       get {RefreshStat (); return new UnixUserInfo (stat.st_uid);}
                }
-
-               public void AdviseNeedAccess (long offset, long len)
-               {
-                       UnixFile.AdviseNeedAccess (fileDescriptor, offset, len);
+                                                                                                
+               public long OwnerUserId {
+                       get {RefreshStat (); return stat.st_uid;}
                }
-
-               public void AdviseNeedAccess ()
-               {
-                       UnixFile.AdviseNeedAccess (fileDescriptor);
+                                                                                                
+               public UnixGroupInfo OwnerGroup {
+                       get {RefreshStat (); return new UnixGroupInfo (stat.st_gid);}
                }
-
-               public void AdviseNoAccess (long offset, long len)
-               {
-                       UnixFile.AdviseNoAccess (fileDescriptor, offset, len);
+                                                                                                
+               public long OwnerGroupId {
+                       get {RefreshStat (); return stat.st_gid;}
                }
 
-               public void AdviseNoAccess ()
+               private void RefreshStat ()
                {
-                       UnixFile.AdviseNoAccess (fileDescriptor);
+                       AssertNotDisposed ();
+                       int r = Native.Syscall.fstat (fileDescriptor, out stat);
+                       UnixMarshal.ThrowExceptionForLastErrorIf (r);
                }
 
-               public void AdviseOnceAccess (long offset, long len)
+               public void AdviseFileAccessPattern (FileAccessPattern pattern, long offset, long len)
                {
-                       UnixFile.AdviseOnceAccess (fileDescriptor, offset, len);
+                       FileHandleOperations.AdviseFileAccessPattern (fileDescriptor, pattern, offset, len);
                }
 
-               public void AdviseOnceAccess ()
+               public void AdviseFileAccessPattern (FileAccessPattern pattern)
                {
-                       UnixFile.AdviseOnceAccess (fileDescriptor);
+                       AdviseFileAccessPattern (pattern, 0, 0);
                }
 
                public override void Flush ()
                {
-                       int r = Syscall.fsync (fileDescriptor);
-                       UnixMarshal.ThrowExceptionForLastErrorIf (r);
                }
 
                public override unsafe int Read ([In, Out] byte[] buffer, int offset, int count)
@@ -203,7 +205,7 @@ namespace Mono.Unix {
                        long r = 0;
                        fixed (byte* buf = &buffer[offset]) {
                                do {
-                                       r = Syscall.read (fileDescriptor, buf, (ulong) count);
+                                       r = Native.Syscall.read (fileDescriptor, buf, (ulong) count);
                                } while (UnixMarshal.ShouldRetrySyscall ((int) r));
                        }
                        if (r == -1)
@@ -236,7 +238,7 @@ namespace Mono.Unix {
                        long r = 0;
                        fixed (byte* buf = &buffer[offset]) {
                                do {
-                                       r = Syscall.pread (fileDescriptor, buf, (ulong) count, fileOffset);
+                                       r = Native.Syscall.pread (fileDescriptor, buf, (ulong) count, fileOffset);
                                } while (UnixMarshal.ShouldRetrySyscall ((int) r));
                        }
                        if (r == -1)
@@ -252,14 +254,14 @@ namespace Mono.Unix {
                        if (offset > int.MaxValue)
                                throw new ArgumentOutOfRangeException ("offset", "too large");
                                        
-                       SeekFlags sf = SeekFlags.SEEK_CUR;
+                       Native.SeekFlags sf = Native.SeekFlags.SEEK_CUR;
                        switch (origin) {
-                               case SeekOrigin.Begin:   sf = SeekFlags.SEEK_SET; break;
-                               case SeekOrigin.Current: sf = SeekFlags.SEEK_CUR; break;
-                               case SeekOrigin.End:     sf = SeekFlags.SEEK_END; break;
+                               case SeekOrigin.Begin:   sf = Native.SeekFlags.SEEK_SET; break;
+                               case SeekOrigin.Current: sf = Native.SeekFlags.SEEK_CUR; break;
+                               case SeekOrigin.End:     sf = Native.SeekFlags.SEEK_END; break;
                        }
 
-                       long pos = Syscall.lseek (fileDescriptor, offset, sf);
+                       long pos = Native.Syscall.lseek (fileDescriptor, offset, sf);
                        if (pos == -1)
                                UnixMarshal.ThrowExceptionForLastError ();
                        return (long) pos;
@@ -275,7 +277,7 @@ namespace Mono.Unix {
                        
                        int r;
                        do {
-                               r = Syscall.ftruncate (fileDescriptor, value);
+                               r = Native.Syscall.ftruncate (fileDescriptor, value);
                        } while (UnixMarshal.ShouldRetrySyscall (r));
                        UnixMarshal.ThrowExceptionForLastErrorIf (r);
                }
@@ -290,7 +292,7 @@ namespace Mono.Unix {
                        long r = 0;
                        fixed (byte* buf = &buffer[offset]) {
                                do {
-                                       r = Syscall.write (fileDescriptor, buf, (ulong) count);
+                                       r = Native.Syscall.write (fileDescriptor, buf, (ulong) count);
                                } while (UnixMarshal.ShouldRetrySyscall ((int) r));
                        }
                        if (r == -1)
@@ -308,7 +310,7 @@ namespace Mono.Unix {
                        long r = 0;
                        fixed (byte* buf = &buffer[offset]) {
                                do {
-                                       r = Syscall.pwrite (fileDescriptor, buf, (ulong) count, fileOffset);
+                                       r = Native.Syscall.pwrite (fileDescriptor, buf, (ulong) count, fileOffset);
                                } while (UnixMarshal.ShouldRetrySyscall ((int) r));
                        }
                        if (r == -1)
@@ -320,26 +322,29 @@ namespace Mono.Unix {
                        SendTo (output, (ulong) output.Length);
                }
 
+               [CLSCompliant (false)]
                public void SendTo (UnixStream output, ulong count)
                {
-                       SendTo (output.FileDescriptor, count);
+                       SendTo (output.Handle, count);
                }
 
+               [CLSCompliant (false)]
                public void SendTo (int out_fd, ulong count)
                {
                        if (!CanWrite)
                                throw new NotSupportedException ("Unable to write to the current file descriptor");
                        long offset = Position;
-                       long r = Syscall.sendfile (out_fd, fileDescriptor, ref offset, count);
+                       long r = Native.Syscall.sendfile (out_fd, fileDescriptor, ref offset, count);
                        if (r == -1)
                                UnixMarshal.ThrowExceptionForLastError ();
                }
                
-               public void SetOwner (uint user, uint group)
+               public void SetOwner (long user, long group)
                {
                        AssertNotDisposed ();
 
-                       int r = Syscall.fchown (fileDescriptor, user, group);
+                       int r = Native.Syscall.fchown (fileDescriptor, 
+                                       Convert.ToUInt32 (user), Convert.ToUInt32 (group));
                        UnixMarshal.ThrowExceptionForLastErrorIf (r);
                }
 
@@ -347,8 +352,8 @@ namespace Mono.Unix {
                {
                        AssertNotDisposed ();
 
-                       uint uid = UnixUser.GetUserId (user);
-                       uint gid = UnixGroup.GetGroupId (group);
+                       long uid = new UnixUserInfo (user).UserId;
+                       long gid = new UnixGroupInfo (group).GroupId;
                        SetOwner (uid, gid);
                }
 
@@ -356,20 +361,20 @@ namespace Mono.Unix {
                {
                        AssertNotDisposed ();
 
-                       Passwd pw = Syscall.getpwnam (user);
+                       Native.Passwd pw = Native.Syscall.getpwnam (user);
                        if (pw == null)
                                throw new ArgumentException (Locale.GetText ("invalid username"), "user");
-                       uint uid = pw.pw_uid;
-                       uint gid = pw.pw_gid;
+                       long uid = pw.pw_uid;
+                       long gid = pw.pw_gid;
                        SetOwner (uid, gid);
                }
 
-               public long GetConfigurationValue (PathConf name)
+               [CLSCompliant (false)]
+               public long GetConfigurationValue (Native.PathconfName name)
                {
                        AssertNotDisposed ();
-                       Syscall.SetLastError ((Error) 0);
-                       long r = Syscall.fpathconf (fileDescriptor, name);
-                       if (r == -1 && Syscall.GetLastError() != (Error) 0)
+                       long r = Native.Syscall.fpathconf (fileDescriptor, name);
+                       if (r == -1 && Native.Syscall.GetLastError() != (Native.Errno) 0)
                                UnixMarshal.ThrowExceptionForLastError ();
                        return r;
                }
@@ -385,12 +390,17 @@ namespace Mono.Unix {
                                return;
                                
                        Flush ();
+
+                       if (!owner)
+                               return;
+
                        int r;
                        do {
-                               r = Syscall.close (fileDescriptor);
+                               r = Native.Syscall.close (fileDescriptor);
                        } while (UnixMarshal.ShouldRetrySyscall (r));
                        UnixMarshal.ThrowExceptionForLastErrorIf (r);
                        fileDescriptor = InvalidFileDescriptor;
+                       GC.SuppressFinalize (this);
                }
                
                void IDisposable.Dispose ()
@@ -407,6 +417,7 @@ namespace Mono.Unix {
                private bool canWrite = false;
                private bool owner = true;
                private int fileDescriptor = InvalidFileDescriptor;
+               private Native.Stat stat;
        }
 }