huge refactoring

This commit is contained in:
BlubbFish 2019-11-26 18:15:10 +01:00
parent 6b5d3e07cc
commit 2f0ae844d0
56 changed files with 15671 additions and 15714 deletions

View File

@ -1,3 +1,5 @@
using System;
// //
// Consts.cs.in // Consts.cs.in
// //
@ -30,107 +32,107 @@
static partial class Consts static partial class Consts
{ {
public const string MonoCorlibVersion = "@MONO_CORLIB_VERSION@"; public const String MonoCorlibVersion = "@MONO_CORLIB_VERSION@";
} }
#if !NETCORE #if !NETCORE
static partial class Consts static partial class Consts
{ {
// //
// Use these assembly version constants to make code more maintainable. // Use these assembly version constants to make code more maintainable.
// //
public const string MonoVersion = "@MONO_VERSION@"; public const String MonoVersion = "@MONO_VERSION@";
public const string MonoCompany = "Mono development team"; public const String MonoCompany = "Mono development team";
public const string MonoProduct = "Mono Common Language Infrastructure"; public const String MonoProduct = "Mono Common Language Infrastructure";
public const string MonoCopyright = "(c) Various Mono authors"; public const String MonoCopyright = "(c) Various Mono authors";
#if MOBILE #if MOBILE
// Versions of .NET Framework for Silverlight 4.0 // Versions of .NET Framework for Silverlight 4.0
public const string FxVersion = "2.0.5.0"; public const string FxVersion = "2.0.5.0";
public const string VsVersion = "9.0.0.0"; // unused, but needed for compilation public const string VsVersion = "9.0.0.0"; // unused, but needed for compilation
public const string FxFileVersion = "4.0.50524.0"; public const string FxFileVersion = "4.0.50524.0";
public const string EnvironmentVersion = FxFileVersion; public const string EnvironmentVersion = FxFileVersion;
public const string VsFileVersion = "9.0.50727.42"; // unused, but needed for compilation public const string VsFileVersion = "9.0.50727.42"; // unused, but needed for compilation
#elif NET_4_6 #elif NET_4_6
public const string FxVersion = "4.0.0.0"; public const String FxVersion = "4.0.0.0";
public const string FxFileVersion = "4.6.57.0"; public const String FxFileVersion = "4.6.57.0";
public const string EnvironmentVersion = "4.0.30319.42000"; public const String EnvironmentVersion = "4.0.30319.42000";
public const string VsVersion = "0.0.0.0"; // Useless ? public const String VsVersion = "0.0.0.0"; // Useless ?
public const string VsFileVersion = "11.0.0.0"; // TODO: public const String VsFileVersion = "11.0.0.0"; // TODO:
#elif NET_4_5 #elif NET_4_5
public const string FxVersion = "4.0.0.0"; public const string FxVersion = "4.0.0.0";
public const string FxFileVersion = "4.0.30319.17020"; public const string FxFileVersion = "4.0.30319.17020";
public const string EnvironmentVersion = FxFileVersion; public const string EnvironmentVersion = FxFileVersion;
public const string VsVersion = "0.0.0.0"; // Useless ? public const string VsVersion = "0.0.0.0"; // Useless ?
public const string VsFileVersion = "11.0.0.0"; // TODO: public const string VsFileVersion = "11.0.0.0"; // TODO:
#elif NETCORE #elif NETCORE
public const string FxVersion = ""; public const string FxVersion = "";
public const string FxFileVersion = ""; public const string FxFileVersion = "";
public const string EnvironmentVersion = FxFileVersion; public const string EnvironmentVersion = FxFileVersion;
public const string VsVersion = ""; public const string VsVersion = "";
public const string VsFileVersion = ""; public const string VsFileVersion = "";
#elif NET_4_0 #elif NET_4_0
#error Profile NET_4_0 is not supported. #error Profile NET_4_0 is not supported.
#elif NET_3_5 #elif NET_3_5
#error Profile NET_3_5 is not supported. #error Profile NET_3_5 is not supported.
#elif NET_3_0 #elif NET_3_0
#error Profile NET_3_0 is not supported. #error Profile NET_3_0 is not supported.
#elif NET_2_0 #elif NET_2_0
#error Profile NET_2_0 is not supported. #error Profile NET_2_0 is not supported.
#elif NET_1_1 #elif NET_1_1
#error Profile NET_1_1 is not supported. #error Profile NET_1_1 is not supported.
#elif NET_1_0 #elif NET_1_0
#error Profile NET_1_0 is not supported. #error Profile NET_1_0 is not supported.
#else #else
#error No profile symbols defined. #error No profile symbols defined.
#endif #endif
#if MOBILE #if MOBILE
const string PublicKeyToken = "7cec85d7bea7798e"; const string PublicKeyToken = "7cec85d7bea7798e";
#else #else
const string PublicKeyToken = "b77a5c561934e089"; const String PublicKeyToken = "b77a5c561934e089";
#endif #endif
// //
// Use these assembly name constants to make code more maintainable. // Use these assembly name constants to make code more maintainable.
// //
public const string AssemblyI18N = "I18N, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756"; public const String AssemblyI18N = "I18N, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756";
public const string AssemblyMicrosoft_JScript = "Microsoft.JScript, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"; public const String AssemblyMicrosoft_JScript = "Microsoft.JScript, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
public const string AssemblyMicrosoft_VisualStudio = "Microsoft.VisualStudio, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"; public const String AssemblyMicrosoft_VisualStudio = "Microsoft.VisualStudio, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
public const string AssemblyMicrosoft_VisualStudio_Web = "Microsoft.VisualStudio.Web, Version=" + VsVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"; public const String AssemblyMicrosoft_VisualStudio_Web = "Microsoft.VisualStudio.Web, Version=" + VsVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
public const string AssemblyMicrosoft_VSDesigner = "Microsoft.VSDesigner, Version=" + VsVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"; public const String AssemblyMicrosoft_VSDesigner = "Microsoft.VSDesigner, Version=" + VsVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
public const string AssemblyMono_Http = "Mono.Http, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756"; public const String AssemblyMono_Http = "Mono.Http, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756";
public const string AssemblyMono_Posix = "Mono.Posix, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756"; public const String AssemblyMono_Posix = "Mono.Posix, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756";
public const string AssemblyMono_Security = "Mono.Security, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756"; public const String AssemblyMono_Security = "Mono.Security, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756";
public const string AssemblyMono_Messaging_RabbitMQ = "Mono.Messaging.RabbitMQ, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756"; public const String AssemblyMono_Messaging_RabbitMQ = "Mono.Messaging.RabbitMQ, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756";
public const string AssemblyCorlib = "mscorlib, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=" + PublicKeyToken; public const String AssemblyCorlib = "mscorlib, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=" + PublicKeyToken;
public const string AssemblySystem = "System, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=" + PublicKeyToken; public const String AssemblySystem = "System, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=" + PublicKeyToken;
public const string AssemblySystem_Data = "System.Data, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b77a5c561934e089"; public const String AssemblySystem_Data = "System.Data, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b77a5c561934e089";
public const string AssemblySystem_Design = "System.Design, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"; public const String AssemblySystem_Design = "System.Design, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
public const string AssemblySystem_DirectoryServices = "System.DirectoryServices, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"; public const String AssemblySystem_DirectoryServices = "System.DirectoryServices, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
public const string AssemblySystem_Drawing = "System.Drawing, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"; public const String AssemblySystem_Drawing = "System.Drawing, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
public const string AssemblySystem_Drawing_Design = "System.Drawing.Design, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"; public const String AssemblySystem_Drawing_Design = "System.Drawing.Design, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
public const string AssemblySystem_Messaging = "System.Messaging, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"; public const String AssemblySystem_Messaging = "System.Messaging, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
public const string AssemblySystem_Security = "System.Security, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"; public const String AssemblySystem_Security = "System.Security, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
public const string AssemblySystem_ServiceProcess = "System.ServiceProcess, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"; public const String AssemblySystem_ServiceProcess = "System.ServiceProcess, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
public const string AssemblySystem_Web = "System.Web, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"; public const String AssemblySystem_Web = "System.Web, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
public const string AssemblySystem_Windows_Forms = "System.Windows.Forms, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b77a5c561934e089"; public const String AssemblySystem_Windows_Forms = "System.Windows.Forms, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b77a5c561934e089";
public const string AssemblySystem_2_0 = "System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"; public const String AssemblySystem_2_0 = "System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
public const string AssemblySystemCore_3_5 = "System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"; public const String AssemblySystemCore_3_5 = "System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
public const string AssemblySystem_Core = "System.Core, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=" + PublicKeyToken; public const String AssemblySystem_Core = "System.Core, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=" + PublicKeyToken;
public const string WindowsBase_3_0 = "WindowsBase, Version=3.0.0.0, PublicKeyToken=31bf3856ad364e35"; public const String WindowsBase_3_0 = "WindowsBase, Version=3.0.0.0, PublicKeyToken=31bf3856ad364e35";
public const string AssemblyWindowsBase = "WindowsBase, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"; public const String AssemblyWindowsBase = "WindowsBase, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35";
public const string AssemblyPresentationCore_3_5 = "PresentationCore, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"; public const String AssemblyPresentationCore_3_5 = "PresentationCore, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35";
public const string AssemblyPresentationCore_4_0 = "PresentationCore, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"; public const String AssemblyPresentationCore_4_0 = "PresentationCore, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35";
public const string AssemblyPresentationFramework_3_5 = "PresentationFramework, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"; public const String AssemblyPresentationFramework_3_5 = "PresentationFramework, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35";
public const string AssemblySystemServiceModel_3_0 = "System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"; public const String AssemblySystemServiceModel_3_0 = "System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
} }
#endif #endif

View File

@ -35,17 +35,11 @@ using System;
internal sealed class Locale { internal sealed class Locale {
private Locale () private Locale ()
{ {
} }
public static string GetText (string msg) public static String GetText(String msg) => msg;
{
return msg;
}
public static string GetText (string fmt, params object [] args) public static String GetText(String fmt, params Object[] args) => String.Format(fmt, args);
{
return String.Format (fmt, args);
}
} }

View File

@ -31,56 +31,62 @@
// //
using System; using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Mono.Posix { namespace Mono.Posix {
[Obsolete ("Use Mono.Unix.Catalog")] [Obsolete ("Use Mono.Unix.Catalog")]
public class Catalog { public class Catalog {
[DllImport("intl")] [DllImport("intl")]
static extern IntPtr bindtextdomain (IntPtr domainname, IntPtr dirname); [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
[DllImport("intl")] static extern IntPtr bindtextdomain (IntPtr domainname, IntPtr dirname);
static extern IntPtr bind_textdomain_codeset (IntPtr domainname, [DllImport("intl")]
IntPtr codeset); [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
[DllImport("intl")] static extern IntPtr bind_textdomain_codeset (IntPtr domainname,
static extern IntPtr textdomain (IntPtr domainname); IntPtr codeset);
[DllImport("intl")]
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
static extern IntPtr textdomain (IntPtr domainname);
public static void Init (String package, String localedir) public static void Init (String package, String localedir)
{ {
IntPtr ipackage = Marshal.StringToHGlobalAuto (package); IntPtr ipackage = Marshal.StringToHGlobalAuto (package);
IntPtr ilocaledir = Marshal.StringToHGlobalAuto (localedir); IntPtr ilocaledir = Marshal.StringToHGlobalAuto (localedir);
IntPtr iutf8 = Marshal.StringToHGlobalAuto ("UTF-8"); IntPtr iutf8 = Marshal.StringToHGlobalAuto ("UTF-8");
bindtextdomain (ipackage, ilocaledir); _ = bindtextdomain(ipackage, ilocaledir);
bind_textdomain_codeset (ipackage, iutf8); _ = bind_textdomain_codeset(ipackage, iutf8);
textdomain (ipackage); _ = textdomain(ipackage);
Marshal.FreeHGlobal (ipackage); Marshal.FreeHGlobal (ipackage);
Marshal.FreeHGlobal (ilocaledir); Marshal.FreeHGlobal (ilocaledir);
Marshal.FreeHGlobal (iutf8); Marshal.FreeHGlobal (iutf8);
} }
[DllImport("intl")] [DllImport("intl")]
static extern IntPtr gettext (IntPtr instring); [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
static extern IntPtr gettext (IntPtr instring);
public static String GetString (String s) public static String GetString (String s)
{ {
IntPtr ints = Marshal.StringToHGlobalAuto (s); IntPtr ints = Marshal.StringToHGlobalAuto (s);
String t = Marshal.PtrToStringAuto (gettext (ints)); String t = Marshal.PtrToStringAuto (gettext (ints));
Marshal.FreeHGlobal (ints); Marshal.FreeHGlobal (ints);
return t; return t;
} }
[DllImport("intl")] [DllImport("intl")]
static extern IntPtr ngettext (IntPtr singular, IntPtr plural, Int32 n); [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
static extern IntPtr ngettext (IntPtr singular, IntPtr plural, Int32 n);
public static String GetPluralString (String s, String p, Int32 n) public static String GetPluralString (String s, String p, Int32 n)
{ {
IntPtr ints = Marshal.StringToHGlobalAuto (s); IntPtr ints = Marshal.StringToHGlobalAuto (s);
IntPtr intp = Marshal.StringToHGlobalAuto (p); IntPtr intp = Marshal.StringToHGlobalAuto (p);
String t = Marshal.PtrToStringAnsi (ngettext (ints, intp, n)); String t = Marshal.PtrToStringAnsi (ngettext (ints, intp, n));
Marshal.FreeHGlobal (ints); Marshal.FreeHGlobal (ints);
Marshal.FreeHGlobal (intp); Marshal.FreeHGlobal (intp);
return t; return t;
} }
} }
} }

View File

@ -34,48 +34,36 @@ using System.Net.Sockets;
namespace Mono.Posix namespace Mono.Posix
{ {
#pragma warning disable 649 #pragma warning disable 649
internal struct PeerCredData { internal struct PeerCredData {
public int pid; public Int32 pid;
public int uid; public Int32 uid;
public int gid; public Int32 gid;
} }
#pragma warning restore 649 #pragma warning restore 649
[Obsolete ("Use Mono.Unix.PeerCred")] [Obsolete ("Use Mono.Unix.PeerCred")]
public class PeerCred public class PeerCred
{ {
/* Make sure this doesn't clash with anything in /* Make sure this doesn't clash with anything in
* SocketOptionName, and keep it synchronised with the * SocketOptionName, and keep it synchronised with the
* runtime * runtime
*/ */
private const int so_peercred=10001; private const Int32 so_peercred =10001;
private PeerCredData data; private PeerCredData data;
public PeerCred (Socket sock) { public PeerCred (Socket sock) {
if (sock.AddressFamily != AddressFamily.Unix) { if (sock.AddressFamily != AddressFamily.Unix) {
throw new ArgumentException ("Only Unix sockets are supported", "sock"); throw new ArgumentException ("Only Unix sockets are supported", "sock");
} }
data = (PeerCredData)sock.GetSocketOption (SocketOptionLevel.Socket, (SocketOptionName)so_peercred); this.data = (PeerCredData)sock.GetSocketOption (SocketOptionLevel.Socket, (SocketOptionName)so_peercred);
} }
public int ProcessID { public Int32 ProcessID => this.data.pid;
get {
return(data.pid);
}
}
public int UserID { public Int32 UserID => this.data.uid;
get {
return(data.uid);
}
}
public int GroupID { public Int32 GroupID => this.data.gid;
get { }
return(data.gid);
}
}
}
} }

File diff suppressed because it is too large Load Diff

View File

@ -34,85 +34,79 @@ using System.Text;
namespace Mono.Posix namespace Mono.Posix
{ {
[Serializable] [Serializable]
[Obsolete ("Use Mono.Unix.UnixEndPoint")] [Obsolete ("Use Mono.Unix.UnixEndPoint")]
public class UnixEndPoint : EndPoint public class UnixEndPoint : EndPoint
{ {
string filename; String filename;
public UnixEndPoint (string filename) public UnixEndPoint (String filename)
{ {
if (filename == null) if (filename == null) {
throw new ArgumentNullException ("filename"); throw new ArgumentNullException ("filename");
}
if (filename == "") if (filename == "") {
throw new ArgumentException ("Cannot be empty.", "filename"); throw new ArgumentException ("Cannot be empty.", "filename");
this.filename = filename; }
}
public string Filename { this.filename = filename;
get { }
return(filename);
}
set {
filename=value;
}
}
public override AddressFamily AddressFamily { public String Filename {
get { return AddressFamily.Unix; } get => this.filename;
} set => this.filename = value;
}
public override EndPoint Create (SocketAddress socketAddress) public override AddressFamily AddressFamily => AddressFamily.Unix;
{
/*
* Should also check this
*
int addr = (int) AddressFamily.Unix;
if (socketAddress [0] != (addr & 0xFF))
throw new ArgumentException ("socketAddress is not a unix socket address.");
if (socketAddress [1] != ((addr & 0xFF00) >> 8)) public override EndPoint Create (SocketAddress socketAddress)
throw new ArgumentException ("socketAddress is not a unix socket address."); {
*/ /*
* Should also check this
*
int addr = (int) AddressFamily.Unix;
if (socketAddress [0] != (addr & 0xFF))
throw new ArgumentException ("socketAddress is not a unix socket address.");
byte [] bytes = new byte [socketAddress.Size - 2]; if (socketAddress [1] != ((addr & 0xFF00) >> 8))
for (int i = 0; i < bytes.Length; i++) { throw new ArgumentException ("socketAddress is not a unix socket address.");
bytes [i] = socketAddress [i + 2]; */
}
string name = Encoding.Default.GetString (bytes); Byte[] bytes = new Byte[socketAddress.Size - 2];
return new UnixEndPoint (name); for (Int32 i = 0; i < bytes.Length; i++) {
} bytes [i] = socketAddress [i + 2];
}
public override SocketAddress Serialize () String name = Encoding.Default.GetString (bytes);
{ return new UnixEndPoint (name);
byte [] bytes = Encoding.Default.GetBytes (filename); }
SocketAddress sa = new SocketAddress (AddressFamily, bytes.Length + 2);
// sa [0] -> family low byte, sa [1] -> family high byte
for (int i = 0; i < bytes.Length; i++)
sa [i + 2] = bytes [i];
return sa; public override SocketAddress Serialize ()
} {
Byte[] bytes = Encoding.Default.GetBytes (this.filename);
SocketAddress sa = new SocketAddress (this.AddressFamily, bytes.Length + 2);
// sa [0] -> family low byte, sa [1] -> family high byte
for (Int32 i = 0; i < bytes.Length; i++) {
sa [i + 2] = bytes [i];
}
public override string ToString() { return sa;
return(filename); }
}
public override int GetHashCode () public override String ToString() => this.filename;
{
return filename.GetHashCode ();
}
public override bool Equals (object o) public override Int32 GetHashCode() => this.filename.GetHashCode();
{
UnixEndPoint other = o as UnixEndPoint;
if (other == null)
return false;
return (other.filename == filename); public override Boolean Equals (Object o)
} {
} UnixEndPoint other = o as UnixEndPoint;
if (other == null) {
return false;
}
return other.filename == this.filename;
}
}
} }

View File

@ -39,129 +39,111 @@ using System.Runtime.Serialization.Formatters.Binary;
namespace Mono.Remoting.Channels.Unix namespace Mono.Remoting.Channels.Unix
{ {
internal class UnixBinaryClientFormatterSink : IClientFormatterSink, IMessageSink, IClientChannelSink, IChannelSinkBase internal class UnixBinaryClientFormatterSink : IClientFormatterSink, IMessageSink, IClientChannelSink, IChannelSinkBase
{ {
UnixBinaryCore _binaryCore = UnixBinaryCore.DefaultInstance; UnixBinaryCore _binaryCore = UnixBinaryCore.DefaultInstance;
IClientChannelSink _nextInChain; IClientChannelSink _nextInChain;
public UnixBinaryClientFormatterSink (IClientChannelSink nextSink) public UnixBinaryClientFormatterSink(IClientChannelSink nextSink) => this._nextInChain = nextSink;
{
_nextInChain = nextSink;
}
internal UnixBinaryCore BinaryCore internal UnixBinaryCore BinaryCore {
{ get => this._binaryCore;
get { return _binaryCore; } set => this._binaryCore = value;
set { _binaryCore = value; } }
}
public IClientChannelSink NextChannelSink public IClientChannelSink NextChannelSink => this._nextInChain;
{
get {
return _nextInChain;
}
}
public IMessageSink NextSink public IMessageSink NextSink =>
{ // This is the last sink in the IMessageSink sink chain
get { null;
// This is the last sink in the IMessageSink sink chain
return null;
}
}
public IDictionary Properties public IDictionary Properties => null;
{
get {
return null;
}
}
public void AsyncProcessRequest (IClientChannelSinkStack sinkStack, public void AsyncProcessRequest(IClientChannelSinkStack sinkStack,
IMessage msg, IMessage msg,
ITransportHeaders headers, ITransportHeaders headers,
Stream stream) Stream stream) =>
{ // never called because the formatter sink is
// never called because the formatter sink is // always the first in the chain
// always the first in the chain throw new NotSupportedException("UnixBinaryClientFormatterSink must be the first sink in the IClientChannelSink chain");
throw new NotSupportedException("UnixBinaryClientFormatterSink must be the first sink in the IClientChannelSink chain");
}
public void AsyncProcessResponse (IClientResponseChannelSinkStack sinkStack, public void AsyncProcessResponse (IClientResponseChannelSinkStack sinkStack,
object state, Object state,
ITransportHeaders headers, ITransportHeaders headers,
Stream stream) Stream stream)
{ {
IMessage replyMessage = (IMessage)_binaryCore.Deserializer.DeserializeMethodResponse (stream, null, (IMethodCallMessage)state); IMessage replyMessage = (IMessage)this._binaryCore.Deserializer.DeserializeMethodResponse (stream, null, (IMethodCallMessage)state);
sinkStack.DispatchReplyMessage (replyMessage); sinkStack.DispatchReplyMessage (replyMessage);
} }
public Stream GetRequestStream (IMessage msg, public Stream GetRequestStream(IMessage msg,
ITransportHeaders headers) ITransportHeaders headers) =>
{ // never called
// never called throw new NotSupportedException();
throw new NotSupportedException ();
}
public void ProcessMessage (IMessage msg, public void ProcessMessage(IMessage msg,
ITransportHeaders requestHeaders, ITransportHeaders requestHeaders,
Stream requestStream, Stream requestStream,
out ITransportHeaders responseHeaders, out ITransportHeaders responseHeaders,
out Stream responseStream) out Stream responseStream) =>
{ // never called because the formatter sink is
// never called because the formatter sink is // always the first in the chain
// always the first in the chain throw new NotSupportedException();
throw new NotSupportedException ();
}
public IMessageCtrl AsyncProcessMessage (IMessage msg, public IMessageCtrl AsyncProcessMessage (IMessage msg,
IMessageSink replySink) IMessageSink replySink)
{ {
ITransportHeaders transportHeaders = new TransportHeaders(); ITransportHeaders transportHeaders = new TransportHeaders();
Stream stream = _nextInChain.GetRequestStream(msg, transportHeaders); Stream stream = this._nextInChain.GetRequestStream(msg, transportHeaders);
if (stream == null) stream = new MemoryStream (); if (stream == null) {
stream = new MemoryStream ();
}
_binaryCore.Serializer.Serialize (stream, msg, null); this._binaryCore.Serializer.Serialize (stream, msg, null);
if (stream is MemoryStream) stream.Position = 0; if (stream is MemoryStream) {
stream.Position = 0;
}
ClientChannelSinkStack stack = new ClientChannelSinkStack(replySink); ClientChannelSinkStack stack = new ClientChannelSinkStack(replySink);
stack.Push (this, msg); stack.Push (this, msg);
_nextInChain.AsyncProcessRequest (stack, msg, transportHeaders, stream); this._nextInChain.AsyncProcessRequest (stack, msg, transportHeaders, stream);
// FIXME: No idea about how to implement IMessageCtrl // FIXME: No idea about how to implement IMessageCtrl
return null; return null;
} }
public IMessage SyncProcessMessage (IMessage msg) public IMessage SyncProcessMessage (IMessage msg)
{ {
try { try {
ITransportHeaders call_headers = new TransportHeaders(); ITransportHeaders call_headers = new TransportHeaders();
call_headers["__RequestUri"] = ((IMethodCallMessage)msg).Uri; call_headers["__RequestUri"] = ((IMethodCallMessage)msg).Uri;
call_headers["Content-Type"] = "application/octet-stream"; call_headers["Content-Type"] = "application/octet-stream";
Stream call_stream = _nextInChain.GetRequestStream(msg, call_headers); Stream call_stream = this._nextInChain.GetRequestStream(msg, call_headers);
if (call_stream == null) call_stream = new MemoryStream (); if (call_stream == null) {
call_stream = new MemoryStream ();
}
// Serialize msg to the stream // Serialize msg to the stream
_binaryCore.Serializer.Serialize (call_stream, msg, null); this._binaryCore.Serializer.Serialize (call_stream, msg, null);
if (call_stream is MemoryStream) call_stream.Position = 0; if (call_stream is MemoryStream) {
call_stream.Position = 0;
}
Stream response_stream;
ITransportHeaders response_headers;
_nextInChain.ProcessMessage (msg, call_headers, call_stream, out response_headers, this._nextInChain.ProcessMessage(msg, call_headers, call_stream, out ITransportHeaders response_headers,
out response_stream); out Stream response_stream);
// Deserialize response_stream // Deserialize response_stream
return (IMessage) _binaryCore.Deserializer.DeserializeMethodResponse (response_stream, null, (IMethodCallMessage)msg); return (IMessage)this._binaryCore.Deserializer.DeserializeMethodResponse (response_stream, null, (IMethodCallMessage)msg);
} catch (Exception e) { } catch (Exception e) {
return new ReturnMessage (e, (IMethodCallMessage)msg); return new ReturnMessage (e, (IMethodCallMessage)msg);
} }
} }
} }
} }

View File

@ -33,48 +33,38 @@ using System.Runtime.Remoting.Channels;
namespace Mono.Remoting.Channels.Unix namespace Mono.Remoting.Channels.Unix
{ {
internal class UnixBinaryClientFormatterSinkProvider: IClientFormatterSinkProvider, IClientChannelSinkProvider internal class UnixBinaryClientFormatterSinkProvider: IClientFormatterSinkProvider, IClientChannelSinkProvider
{ {
IClientChannelSinkProvider next = null; IClientChannelSinkProvider next = null;
UnixBinaryCore _binaryCore; UnixBinaryCore _binaryCore;
static string[] allowedProperties = new string [] { "includeVersions", "strictBinding" }; static System.String[] allowedProperties = new System.String[] { "includeVersions", "strictBinding" };
public UnixBinaryClientFormatterSinkProvider () public UnixBinaryClientFormatterSinkProvider() => this._binaryCore = UnixBinaryCore.DefaultInstance;
{
_binaryCore = UnixBinaryCore.DefaultInstance;
}
public UnixBinaryClientFormatterSinkProvider (IDictionary properties, public UnixBinaryClientFormatterSinkProvider(IDictionary properties,
ICollection providerData) ICollection providerData) => this._binaryCore = new UnixBinaryCore(this, properties, allowedProperties);
{
_binaryCore = new UnixBinaryCore (this, properties, allowedProperties);
}
public IClientChannelSinkProvider Next public IClientChannelSinkProvider Next {
{ get => this.next;
get {
return next;
}
set { set => this.next = value;
next = value; }
}
}
public IClientChannelSink CreateSink (IChannelSender channel, public IClientChannelSink CreateSink (IChannelSender channel,
string url, System.String url,
object remoteChannelData) System.Object remoteChannelData)
{ {
IClientChannelSink next_sink = null; IClientChannelSink next_sink = null;
UnixBinaryClientFormatterSink result; UnixBinaryClientFormatterSink result;
if (next != null) if (this.next != null) {
next_sink = next.CreateSink (channel, url, remoteChannelData); next_sink = this.next.CreateSink (channel, url, remoteChannelData);
}
result = new UnixBinaryClientFormatterSink (next_sink); result = new UnixBinaryClientFormatterSink (next_sink);
result.BinaryCore = _binaryCore; result.BinaryCore = this._binaryCore;
return result; return result;
} }
} }
} }

View File

@ -35,114 +35,116 @@ using System.Runtime.Remoting.Messaging;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters; using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary; using System.Runtime.Serialization.Formatters.Binary;
using System.Diagnostics.CodeAnalysis;
namespace Mono.Remoting.Channels.Unix namespace Mono.Remoting.Channels.Unix
{ {
internal class UnixBinaryCore internal class UnixBinaryCore
{ {
BinaryFormatter _serializationFormatter; BinaryFormatter _serializationFormatter;
BinaryFormatter _deserializationFormatter; BinaryFormatter _deserializationFormatter;
bool _includeVersions = true; Boolean _includeVersions = true;
bool _strictBinding = false; Boolean _strictBinding = false;
IDictionary _properties; IDictionary _properties;
public static UnixBinaryCore DefaultInstance = new UnixBinaryCore (); public static UnixBinaryCore DefaultInstance = new UnixBinaryCore ();
public UnixBinaryCore (object owner, IDictionary properties, string[] allowedProperties) public UnixBinaryCore (Object owner, IDictionary properties, String[] allowedProperties)
{ {
_properties = properties; this._properties = properties;
foreach(DictionaryEntry property in properties) foreach(DictionaryEntry property in properties)
{ {
string key = (string) property.Key; String key = (String) property.Key;
if (Array.IndexOf (allowedProperties, key) == -1) if (Array.IndexOf (allowedProperties, key) == -1) {
throw new RemotingException (owner.GetType().Name + " does not recognize '" + key + "' configuration property"); throw new RemotingException (owner.GetType().Name + " does not recognize '" + key + "' configuration property");
}
switch (key) switch (key)
{ {
case "includeVersions": case "includeVersions":
_includeVersions = Convert.ToBoolean (property.Value); this._includeVersions = Convert.ToBoolean (property.Value);
break; break;
case "strictBinding": case "strictBinding":
_strictBinding = Convert.ToBoolean (property.Value); this._strictBinding = Convert.ToBoolean (property.Value);
break; break;
} }
} }
Init (); this.Init ();
} }
public UnixBinaryCore () public UnixBinaryCore ()
{ {
_properties = new Hashtable (); this._properties = new Hashtable ();
Init (); this.Init ();
} }
public void Init () public void Init ()
{ {
RemotingSurrogateSelector surrogateSelector = new RemotingSurrogateSelector (); RemotingSurrogateSelector surrogateSelector = new RemotingSurrogateSelector ();
StreamingContext context = new StreamingContext (StreamingContextStates.Remoting, null); StreamingContext context = new StreamingContext (StreamingContextStates.Remoting, null);
_serializationFormatter = new BinaryFormatter (surrogateSelector, context); this._serializationFormatter = new BinaryFormatter (surrogateSelector, context);
_deserializationFormatter = new BinaryFormatter (null, context); this._deserializationFormatter = new BinaryFormatter (null, context);
if (!_includeVersions) if (!this._includeVersions)
{ {
_serializationFormatter.AssemblyFormat = FormatterAssemblyStyle.Simple; this._serializationFormatter.AssemblyFormat = FormatterAssemblyStyle.Simple;
_deserializationFormatter.AssemblyFormat = FormatterAssemblyStyle.Simple; this._deserializationFormatter.AssemblyFormat = FormatterAssemblyStyle.Simple;
} }
if (!_strictBinding) if (!this._strictBinding)
{ {
_serializationFormatter.Binder = SimpleBinder.Instance; this._serializationFormatter.Binder = SimpleBinder.Instance;
_deserializationFormatter.Binder = SimpleBinder.Instance; this._deserializationFormatter.Binder = SimpleBinder.Instance;
} }
} }
public BinaryFormatter Serializer public BinaryFormatter Serializer => this._serializationFormatter;
{
get { return _serializationFormatter; }
}
public BinaryFormatter Deserializer public BinaryFormatter Deserializer => this._deserializationFormatter;
{
get { return _deserializationFormatter; }
}
public IDictionary Properties public IDictionary Properties => this._properties;
{ }
get { return _properties; }
}
}
internal class SimpleBinder: SerializationBinder internal class SimpleBinder: SerializationBinder
{ {
public static SimpleBinder Instance = new SimpleBinder (); public static SimpleBinder Instance = new SimpleBinder ();
public override Type BindToType (String assemblyName, string typeName) [SuppressMessage("Microsoft.Design", "CS0618", Justification = "Someone do shit")]
{ public override Type BindToType (String assemblyName, String typeName)
Assembly asm; {
Assembly asm;
if (assemblyName.IndexOf (',') != -1) if (assemblyName.IndexOf (',') != -1)
{ {
// Try using the full name // Try using the full name
try try
{ {
asm = Assembly.Load (assemblyName); asm = Assembly.Load (assemblyName);
if (asm == null) return null; if (asm == null) {
Type t = asm.GetType (typeName); return null;
if (t != null) return t; }
}
catch {}
}
// Try using the simple name Type t = asm.GetType (typeName);
asm = Assembly.LoadWithPartialName (assemblyName); if (t != null) {
if (asm == null) return null; return t;
return asm.GetType (typeName, true); }
} }
} catch {}
}
// Try using the simple name
asm = Assembly.LoadWithPartialName (assemblyName);
if (asm == null) {
return null;
}
return asm.GetType (typeName, true);
}
}
} }

View File

@ -40,124 +40,123 @@ using System.Runtime.InteropServices;
namespace Mono.Remoting.Channels.Unix { namespace Mono.Remoting.Channels.Unix {
internal class UnixBinaryServerFormatterSink : IServerChannelSink, IChannelSinkBase internal class UnixBinaryServerFormatterSink : IServerChannelSink, IChannelSinkBase
{ {
UnixBinaryCore _binaryCore = UnixBinaryCore.DefaultInstance; UnixBinaryCore _binaryCore = UnixBinaryCore.DefaultInstance;
IServerChannelSink next_sink; IServerChannelSink next_sink;
IChannelReceiver receiver; IChannelReceiver receiver;
public UnixBinaryServerFormatterSink (IServerChannelSink nextSink, IChannelReceiver receiver) public UnixBinaryServerFormatterSink (IServerChannelSink nextSink, IChannelReceiver receiver)
{ {
this.next_sink = nextSink; this.next_sink = nextSink;
this.receiver = receiver; this.receiver = receiver;
} }
internal UnixBinaryCore BinaryCore internal UnixBinaryCore BinaryCore {
{ get => this._binaryCore;
get { return _binaryCore; } set => this._binaryCore = value;
set { _binaryCore = value; } }
}
public IServerChannelSink NextChannelSink { public IServerChannelSink NextChannelSink => this.next_sink;
get {
return next_sink;
}
}
public IDictionary Properties { public IDictionary Properties => null;
get {
return null;
}
}
public void AsyncProcessResponse (IServerResponseChannelSinkStack sinkStack, object state, public void AsyncProcessResponse (IServerResponseChannelSinkStack sinkStack, Object state,
IMessage message, ITransportHeaders headers, Stream stream) IMessage message, ITransportHeaders headers, Stream stream)
{ {
ITransportHeaders responseHeaders = new TransportHeaders(); ITransportHeaders responseHeaders = new TransportHeaders();
if (sinkStack != null) stream = sinkStack.GetResponseStream (message, responseHeaders); if (sinkStack != null) {
if (stream == null) stream = new MemoryStream(); stream = sinkStack.GetResponseStream (message, responseHeaders);
}
_binaryCore.Serializer.Serialize (stream, message, null); if (stream == null) {
if (stream is MemoryStream) stream.Position = 0; stream = new MemoryStream();
}
sinkStack.AsyncProcessResponse (message, responseHeaders, stream); this._binaryCore.Serializer.Serialize (stream, message, null);
} if (stream is MemoryStream) {
stream.Position = 0;
}
public Stream GetResponseStream (IServerResponseChannelSinkStack sinkStack, object state, sinkStack.AsyncProcessResponse (message, responseHeaders, stream);
IMessage msg, ITransportHeaders headers) }
{
return null;
}
public ServerProcessing ProcessMessage (IServerChannelSinkStack sinkStack, public Stream GetResponseStream(IServerResponseChannelSinkStack sinkStack, Object state,
IMessage requestMsg, ITransportHeaders requestHeaders, Stream requestStream, IMessage msg, ITransportHeaders headers) => null;
out IMessage responseMsg, out ITransportHeaders responseHeaders, out Stream responseStream)
{
sinkStack.Push (this, null);
ServerProcessing res;
try public ServerProcessing ProcessMessage (IServerChannelSinkStack sinkStack,
{ IMessage requestMsg, ITransportHeaders requestHeaders, Stream requestStream,
string url = (string)requestHeaders["__RequestUri"]; out IMessage responseMsg, out ITransportHeaders responseHeaders, out Stream responseStream)
string uri; {
receiver.Parse (url, out uri); sinkStack.Push (this, null);
if (uri == null) uri = url; ServerProcessing res;
MethodCallHeaderHandler mhh = new MethodCallHeaderHandler(uri); try
requestMsg = (IMessage) _binaryCore.Deserializer.Deserialize (requestStream, new HeaderHandler(mhh.HandleHeaders)); {
String url = (String)requestHeaders["__RequestUri"];
_ = this.receiver.Parse(url, out String uri);
if (uri == null) {
uri = url;
}
res = next_sink.ProcessMessage (sinkStack, requestMsg, requestHeaders, null, out responseMsg, out responseHeaders, out responseStream); MethodCallHeaderHandler mhh = new MethodCallHeaderHandler(uri);
} requestMsg = (IMessage)this._binaryCore.Deserializer.Deserialize (requestStream, new HeaderHandler(mhh.HandleHeaders));
catch (Exception ex)
{
responseMsg = new ReturnMessage (ex, (IMethodCallMessage)requestMsg);
res = ServerProcessing.Complete;
responseHeaders = null;
responseStream = null;
}
if (res == ServerProcessing.Complete) res = this.next_sink.ProcessMessage (sinkStack, requestMsg, requestHeaders, null, out responseMsg, out responseHeaders, out responseStream);
{ }
for (int n=0; n<3; n++) { catch (Exception ex)
responseStream = null; {
responseHeaders = new TransportHeaders(); responseMsg = new ReturnMessage (ex, (IMethodCallMessage)requestMsg);
res = ServerProcessing.Complete;
responseHeaders = null;
responseStream = null;
}
if (sinkStack != null) responseStream = sinkStack.GetResponseStream (responseMsg, responseHeaders); if (res == ServerProcessing.Complete)
if (responseStream == null) responseStream = new MemoryStream(); {
for (Int32 n =0; n<3; n++) {
responseStream = null;
responseHeaders = new TransportHeaders();
try { if (sinkStack != null) {
_binaryCore.Serializer.Serialize (responseStream, responseMsg); responseStream = sinkStack.GetResponseStream (responseMsg, responseHeaders);
break; }
} catch (Exception ex) {
if (n == 2) throw ex;
else responseMsg = new ReturnMessage (ex, (IMethodCallMessage)requestMsg);
}
}
if (responseStream is MemoryStream) responseStream.Position = 0; if (responseStream == null) {
responseStream = new MemoryStream();
}
try {
this._binaryCore.Serializer.Serialize (responseStream, responseMsg);
break;
} catch (Exception ex) {
if (n == 2) {
throw ex;
} else {
responseMsg = new ReturnMessage (ex, (IMethodCallMessage)requestMsg);
}
}
}
sinkStack.Pop (this); if (responseStream is MemoryStream) {
} responseStream.Position = 0;
return res; }
}
} _ = sinkStack.Pop(this);
}
return res;
}
internal class MethodCallHeaderHandler }
{
string _uri;
public MethodCallHeaderHandler (string uri) internal class MethodCallHeaderHandler
{ {
_uri = uri; String _uri;
}
public object HandleHeaders (Header[] headers) public MethodCallHeaderHandler(String uri) => this._uri = uri;
{
return _uri; public Object HandleHeaders(Header[] headers) => this._uri;
} }
}
} }

View File

@ -35,51 +35,41 @@ using System.Runtime.Remoting.Channels;
namespace Mono.Remoting.Channels.Unix namespace Mono.Remoting.Channels.Unix
{ {
internal class UnixBinaryServerFormatterSinkProvider: IServerFormatterSinkProvider, IServerChannelSinkProvider internal class UnixBinaryServerFormatterSinkProvider: IServerFormatterSinkProvider, IServerChannelSinkProvider
{ {
IServerChannelSinkProvider next = null; IServerChannelSinkProvider next = null;
UnixBinaryCore _binaryCore; UnixBinaryCore _binaryCore;
internal static string[] AllowedProperties = new string [] { "includeVersions", "strictBinding" }; internal static System.String[] AllowedProperties = new System.String[] { "includeVersions", "strictBinding" };
public UnixBinaryServerFormatterSinkProvider () public UnixBinaryServerFormatterSinkProvider() => this._binaryCore = UnixBinaryCore.DefaultInstance;
{
_binaryCore = UnixBinaryCore.DefaultInstance;
}
public UnixBinaryServerFormatterSinkProvider (IDictionary properties, ICollection providerData) public UnixBinaryServerFormatterSinkProvider(IDictionary properties, ICollection providerData) => this._binaryCore = new UnixBinaryCore(this, properties, AllowedProperties);
{
_binaryCore = new UnixBinaryCore (this, properties, AllowedProperties);
}
public IServerChannelSinkProvider Next public IServerChannelSinkProvider Next {
{ get => this.next;
get {
return next;
}
set { set => this.next = value;
next = value; }
}
}
public IServerChannelSink CreateSink (IChannelReceiver channel) public IServerChannelSink CreateSink (IChannelReceiver channel)
{ {
IServerChannelSink next_sink = null; IServerChannelSink next_sink = null;
UnixBinaryServerFormatterSink result; UnixBinaryServerFormatterSink result;
if (next != null) if (this.next != null) {
next_sink = next.CreateSink (channel); next_sink = this.next.CreateSink (channel);
}
result = new UnixBinaryServerFormatterSink (next_sink, channel); result = new UnixBinaryServerFormatterSink (next_sink, channel);
result.BinaryCore = _binaryCore; result.BinaryCore = this._binaryCore;
return result; return result;
} }
public void GetChannelData (IChannelDataStore channelData) public void GetChannelData (IChannelDataStore channelData)
{ {
// Nothing to add here // Nothing to add here
} }
} }
} }

View File

@ -40,104 +40,109 @@ namespace Mono.Remoting.Channels.Unix
{ {
private UnixClientChannel _clientChannel; private UnixClientChannel _clientChannel;
private UnixServerChannel _serverChannel = null; private UnixServerChannel _serverChannel = null;
private string _name = "unix"; private String _name = "unix";
private int _priority = 1; private Int32 _priority = 1;
public UnixChannel (): this (null) public UnixChannel (): this (null)
{ {
} }
public UnixChannel (string path) public UnixChannel (String path)
{ {
Hashtable ht = new Hashtable(); Hashtable ht = new Hashtable();
ht["path"] = path; ht["path"] = path;
Init(ht, null, null); this.Init(ht, null, null);
} }
void Init (IDictionary properties, IClientChannelSinkProvider clientSink, IServerChannelSinkProvider serverSink) void Init (IDictionary properties, IClientChannelSinkProvider clientSink, IServerChannelSinkProvider serverSink)
{ {
_clientChannel = new UnixClientChannel (properties,clientSink); this._clientChannel = new UnixClientChannel (properties,clientSink);
if(properties["path"] != null) if(properties["path"] != null) {
_serverChannel = new UnixServerChannel(properties, serverSink); this._serverChannel = new UnixServerChannel(properties, serverSink);
}
object val = properties ["name"]; Object val = properties ["name"];
if (val != null) _name = val as string; if (val != null) {
this._name = val as String;
}
val = properties ["priority"]; val = properties ["priority"];
if (val != null) _priority = Convert.ToInt32 (val); if (val != null) {
} this._priority = Convert.ToInt32 (val);
}
}
public UnixChannel (IDictionary properties, public UnixChannel(IDictionary properties,
IClientChannelSinkProvider clientSinkProvider, IClientChannelSinkProvider clientSinkProvider,
IServerChannelSinkProvider serverSinkProvider) IServerChannelSinkProvider serverSinkProvider) => this.Init(properties, clientSinkProvider, serverSinkProvider);
public IMessageSink CreateMessageSink(String url, Object remoteChannelData, out String objectURI) => this._clientChannel.CreateMessageSink(url, remoteChannelData, out objectURI);
public String ChannelName => this._name;
public Int32 ChannelPriority => this._priority;
public void StartListening (Object data)
{ {
Init (properties, clientSinkProvider, serverSinkProvider); if (this._serverChannel != null) {
} this._serverChannel.StartListening (data);
}
}
public IMessageSink CreateMessageSink(string url, object remoteChannelData, out string objectURI) public void StopListening (Object data)
{ {
return _clientChannel.CreateMessageSink(url, remoteChannelData, out objectURI); if (this._serverChannel != null) {
} this._serverChannel.StopListening(data);
}
}
public string ChannelName public String[] GetUrlsForUri (String uri)
{ {
get { return _name; } if (this._serverChannel != null) {
} return this._serverChannel.GetUrlsForUri(uri);
} else {
return null;
}
}
public int ChannelPriority public Object ChannelData
{
get { return _priority; }
}
public void StartListening (object data)
{
if (_serverChannel != null) _serverChannel.StartListening (data);
}
public void StopListening (object data)
{
if (_serverChannel != null) _serverChannel.StopListening(data);
}
public string[] GetUrlsForUri (string uri)
{
if (_serverChannel != null) return _serverChannel.GetUrlsForUri(uri);
else return null;
}
public object ChannelData
{ {
get get
{ {
if (_serverChannel != null) return _serverChannel.ChannelData; if (this._serverChannel != null) {
else return null; return this._serverChannel.ChannelData;
} } else {
return null;
}
}
} }
public string Parse (string url, out string objectURI) public String Parse(String url, out String objectURI) => UnixChannel.ParseUnixURL(url, out objectURI);
{
return UnixChannel.ParseUnixURL (url, out objectURI);
}
internal static string ParseUnixURL (string url, out string objectURI) internal static String ParseUnixURL (String url, out String objectURI)
{ {
// format: "unix:///path/to/unix/socket?/path/to/object" // format: "unix:///path/to/unix/socket?/path/to/object"
objectURI = null; objectURI = null;
if (!url.StartsWith ("unix://")) return null; if (!url.StartsWith ("unix://")) {
return null;
}
int i = url.IndexOf ('?'); Int32 i = url.IndexOf ('?');
if (i == -1) return url.Substring (7); if (i == -1) {
return url.Substring (7);
}
objectURI = url.Substring (i+1); objectURI = url.Substring (i+1);
if (objectURI.Length == 0) if (objectURI.Length == 0) {
objectURI = null; objectURI = null;
}
return url.Substring (7, i - 7); return url.Substring (7, i - 7);
} }
} }
} }

View File

@ -40,95 +40,94 @@ namespace Mono.Remoting.Channels.Unix
{ {
public class UnixClientChannel : IChannelSender, IChannel public class UnixClientChannel : IChannelSender, IChannel
{ {
int priority = 1; Int32 priority = 1;
string name = "unix"; String name = "unix";
IClientChannelSinkProvider _sinkProvider; IClientChannelSinkProvider _sinkProvider;
public UnixClientChannel () public UnixClientChannel ()
{ {
_sinkProvider = new UnixBinaryClientFormatterSinkProvider (); this._sinkProvider = new UnixBinaryClientFormatterSinkProvider ();
_sinkProvider.Next = new UnixClientTransportSinkProvider (); this._sinkProvider.Next = new UnixClientTransportSinkProvider ();
} }
public UnixClientChannel (IDictionary properties, IClientChannelSinkProvider sinkProvider) public UnixClientChannel (IDictionary properties, IClientChannelSinkProvider sinkProvider)
{ {
object val = properties ["name"]; Object val = properties ["name"];
if (val != null) name = val as string; if (val != null) {
this.name = val as String;
}
val = properties ["priority"]; val = properties ["priority"];
if (val != null) priority = Convert.ToInt32 (val); if (val != null) {
this.priority = Convert.ToInt32 (val);
}
if (sinkProvider != null) if (sinkProvider != null)
{ {
_sinkProvider = sinkProvider; this._sinkProvider = sinkProvider;
// add the unix provider at the end of the chain // add the unix provider at the end of the chain
IClientChannelSinkProvider prov = sinkProvider; IClientChannelSinkProvider prov = sinkProvider;
while (prov.Next != null) prov = prov.Next; while (prov.Next != null) {
prov.Next = new UnixClientTransportSinkProvider (); prov = prov.Next;
}
prov.Next = new UnixClientTransportSinkProvider ();
// Note: a default formatter is added only when // Note: a default formatter is added only when
// no sink providers are specified in the config file. // no sink providers are specified in the config file.
} }
else else
{ {
_sinkProvider = new UnixBinaryClientFormatterSinkProvider (); this._sinkProvider = new UnixBinaryClientFormatterSinkProvider ();
_sinkProvider.Next = new UnixClientTransportSinkProvider (); this._sinkProvider.Next = new UnixClientTransportSinkProvider ();
} }
} }
public UnixClientChannel (string name, IClientChannelSinkProvider sinkProvider) public UnixClientChannel (String name, IClientChannelSinkProvider sinkProvider)
{ {
this.name = name; this.name = name;
_sinkProvider = sinkProvider; this._sinkProvider = sinkProvider;
// add the unix provider at the end of the chain // add the unix provider at the end of the chain
IClientChannelSinkProvider prov = sinkProvider; IClientChannelSinkProvider prov = sinkProvider;
while (prov.Next != null) prov = prov.Next; while (prov.Next != null) {
prov.Next = new UnixClientTransportSinkProvider (); prov = prov.Next;
}
prov.Next = new UnixClientTransportSinkProvider ();
} }
public string ChannelName public String ChannelName => this.name;
{
get {
return name;
}
}
public int ChannelPriority public Int32 ChannelPriority => this.priority;
{
get {
return priority;
}
}
public IMessageSink CreateMessageSink (string url, public IMessageSink CreateMessageSink (String url,
object remoteChannelData, Object remoteChannelData,
out string objectURI) out String objectURI)
{ {
if (url != null && Parse (url, out objectURI) != null) if (url != null && this.Parse (url, out objectURI) != null) {
return (IMessageSink) _sinkProvider.CreateSink (this, url, remoteChannelData); return (IMessageSink)this._sinkProvider.CreateSink (this, url, remoteChannelData);
}
if (remoteChannelData != null) { if (remoteChannelData != null) {
IChannelDataStore ds = remoteChannelData as IChannelDataStore; IChannelDataStore ds = remoteChannelData as IChannelDataStore;
if (ds != null && ds.ChannelUris.Length > 0) if (ds != null && ds.ChannelUris.Length > 0) {
url = ds.ChannelUris [0]; url = ds.ChannelUris [0];
else { } else {
objectURI = null; objectURI = null;
return null; return null;
} }
} }
if (Parse (url, out objectURI) == null) if (this.Parse (url, out objectURI) == null) {
return null; return null;
}
return (IMessageSink) _sinkProvider.CreateSink (this, url, remoteChannelData); return (IMessageSink)this._sinkProvider.CreateSink (this, url, remoteChannelData);
} }
public string Parse (string url, out string objectURI) public String Parse(String url, out String objectURI) => UnixChannel.ParseUnixURL(url, out objectURI);
{ }
return UnixChannel.ParseUnixURL (url, out objectURI);
}
}
} }

View File

@ -38,156 +38,156 @@ using System.Runtime.Remoting;
namespace Mono.Remoting.Channels.Unix namespace Mono.Remoting.Channels.Unix
{ {
internal class UnixClientTransportSink : IClientChannelSink internal class UnixClientTransportSink : IClientChannelSink
{ {
string _path; String _path;
public UnixClientTransportSink (string url) public UnixClientTransportSink (String url)
{ {
string objectUri; this._path = UnixChannel.ParseUnixURL(url, out String objectUri);
_path = UnixChannel.ParseUnixURL (url, out objectUri); }
}
public IDictionary Properties public IDictionary Properties => null;
{
get
{
return null;
}
}
public IClientChannelSink NextChannelSink public IClientChannelSink NextChannelSink =>
{ // we are the last one
get null;
{
// we are the last one
return null;
}
}
public void AsyncProcessRequest (IClientChannelSinkStack sinkStack, IMessage msg, public void AsyncProcessRequest (IClientChannelSinkStack sinkStack, IMessage msg,
ITransportHeaders headers, Stream requestStream) ITransportHeaders headers, Stream requestStream)
{ {
UnixConnection connection = null; UnixConnection connection = null;
bool isOneWay = RemotingServices.IsOneWay (((IMethodMessage)msg).MethodBase); Boolean isOneWay = RemotingServices.IsOneWay (((IMethodMessage)msg).MethodBase);
try try
{ {
if (headers == null) headers = new TransportHeaders(); if (headers == null) {
headers ["__RequestUri"] = ((IMethodMessage)msg).Uri; headers = new TransportHeaders();
}
// Sends the stream using a connection from the pool headers ["__RequestUri"] = ((IMethodMessage)msg).Uri;
// and creates a WorkItem that will wait for the
// response of the server
connection = UnixConnectionPool.GetConnection (_path); // Sends the stream using a connection from the pool
UnixMessageIO.SendMessageStream (connection.Stream, requestStream, headers, connection.Buffer); // and creates a WorkItem that will wait for the
connection.Stream.Flush (); // response of the server
if (!isOneWay) connection = UnixConnectionPool.GetConnection (this._path);
{ UnixMessageIO.SendMessageStream (connection.Stream, requestStream, headers, connection.Buffer);
sinkStack.Push (this, connection); connection.Stream.Flush ();
ThreadPool.QueueUserWorkItem (new WaitCallback(data => {
try {
ReadAsyncUnixMessage (data);
} catch {}
}), sinkStack);
}
else
connection.Release();
}
catch
{
if (connection != null) connection.Release();
if (!isOneWay) throw;
}
}
private void ReadAsyncUnixMessage(object data) if (!isOneWay)
{ {
// This method is called by a new thread to asynchronously sinkStack.Push (this, connection);
// read the response to a request _ = ThreadPool.QueueUserWorkItem(new WaitCallback(data => {
try {
this.ReadAsyncUnixMessage(data);
} catch { }
}), sinkStack);
}
else {
connection.Release();
}
}
catch
{
if (connection != null) {
connection.Release();
}
// The stack was provided as state data in QueueUserWorkItem if (!isOneWay) {
IClientChannelSinkStack stack = (IClientChannelSinkStack)data; throw;
}
}
}
// The first sink in the stack is this sink. Pop it and private void ReadAsyncUnixMessage(Object data)
// get the status data, which is the UnixConnection used to send {
// the request // This method is called by a new thread to asynchronously
UnixConnection connection = (UnixConnection)stack.Pop(this); // read the response to a request
try // The stack was provided as state data in QueueUserWorkItem
{ IClientChannelSinkStack stack = (IClientChannelSinkStack)data;
ITransportHeaders responseHeaders;
// Read the response, blocking if necessary // The first sink in the stack is this sink. Pop it and
MessageStatus status = UnixMessageIO.ReceiveMessageStatus (connection.Stream, connection.Buffer); // get the status data, which is the UnixConnection used to send
// the request
UnixConnection connection = (UnixConnection)stack.Pop(this);
if (status != MessageStatus.MethodMessage) try
throw new RemotingException ("Unknown response message from server"); {
Stream responseStream = UnixMessageIO.ReceiveMessageStream (connection.Stream, out responseHeaders, connection.Buffer); // Read the response, blocking if necessary
MessageStatus status = UnixMessageIO.ReceiveMessageStatus(connection.Stream, connection.Buffer);
// Free the connection, so it can be reused if (status != MessageStatus.MethodMessage) {
connection.Release(); throw new RemotingException ("Unknown response message from server");
connection = null; }
// Ok, proceed with the other sinks Stream responseStream = UnixMessageIO.ReceiveMessageStream (connection.Stream, out ITransportHeaders responseHeaders, connection.Buffer);
stack.AsyncProcessResponse (responseHeaders, responseStream);
}
catch
{
if (connection != null) connection.Release();
throw;
}
}
public void AsyncProcessResponse (IClientResponseChannelSinkStack sinkStack, // Free the connection, so it can be reused
object state, ITransportHeaders headers, connection.Release();
Stream stream) connection = null;
{
// Should never be called
throw new NotSupportedException();
}
public Stream GetRequestStream (IMessage msg, ITransportHeaders headers) // Ok, proceed with the other sinks
{ stack.AsyncProcessResponse (responseHeaders, responseStream);
return null; }
} catch
{
if (connection != null) {
connection.Release();
}
public void ProcessMessage (IMessage msg, throw;
ITransportHeaders requestHeaders, }
Stream requestStream, }
out ITransportHeaders responseHeaders,
out Stream responseStream)
{
UnixConnection connection = null;
try
{
if (requestHeaders == null) requestHeaders = new TransportHeaders();
requestHeaders ["__RequestUri"] = ((IMethodMessage)msg).Uri;
// Sends the message public void AsyncProcessResponse(IClientResponseChannelSinkStack sinkStack,
connection = UnixConnectionPool.GetConnection (_path); Object state, ITransportHeaders headers,
UnixMessageIO.SendMessageStream (connection.Stream, requestStream, requestHeaders, connection.Buffer); Stream stream) =>
connection.Stream.Flush (); // Should never be called
throw new NotSupportedException();
// Reads the response public Stream GetRequestStream(IMessage msg, ITransportHeaders headers) => null;
MessageStatus status = UnixMessageIO.ReceiveMessageStatus (connection.Stream, connection.Buffer);
if (status != MessageStatus.MethodMessage) public void ProcessMessage (IMessage msg,
throw new RemotingException ("Unknown response message from server"); ITransportHeaders requestHeaders,
Stream requestStream,
out ITransportHeaders responseHeaders,
out Stream responseStream)
{
UnixConnection connection = null;
try
{
if (requestHeaders == null) {
requestHeaders = new TransportHeaders();
}
responseStream = UnixMessageIO.ReceiveMessageStream (connection.Stream, out responseHeaders, connection.Buffer); requestHeaders ["__RequestUri"] = ((IMethodMessage)msg).Uri;
}
finally
{
if (connection != null)
connection.Release();
}
}
} // Sends the message
connection = UnixConnectionPool.GetConnection (this._path);
UnixMessageIO.SendMessageStream (connection.Stream, requestStream, requestHeaders, connection.Buffer);
connection.Stream.Flush ();
// Reads the response
MessageStatus status = UnixMessageIO.ReceiveMessageStatus (connection.Stream, connection.Buffer);
if (status != MessageStatus.MethodMessage) {
throw new RemotingException ("Unknown response message from server");
}
responseStream = UnixMessageIO.ReceiveMessageStream (connection.Stream, out responseHeaders, connection.Buffer);
}
finally
{
if (connection != null) {
connection.Release();
}
}
}
}
} }

View File

@ -40,23 +40,15 @@ namespace Mono.Remoting.Channels.Unix
// what should we do here ? // what should we do here ?
} }
public IClientChannelSinkProvider Next public IClientChannelSinkProvider Next {
{ get => null;
get
{
return null;
}
set set {
{ // ignore, we are always the last in the chain
// ignore, we are always the last in the chain }
}
}
public IClientChannelSink CreateSink (IChannelSender channel, string url,
object remoteChannelData)
{
return new UnixClientTransportSink (url);
}
} }
public IClientChannelSink CreateSink(IChannelSender channel, String url,
Object remoteChannelData) => new UnixClientTransportSink(url);
}
} }

View File

@ -37,275 +37,254 @@ using Mono.Unix;
namespace Mono.Remoting.Channels.Unix namespace Mono.Remoting.Channels.Unix
{ {
// This is a pool of Unix connections. Connections requested // This is a pool of Unix connections. Connections requested
// by the TCP channel are pooled after their use, and can // by the TCP channel are pooled after their use, and can
// be reused later. Connections are automaticaly closed // be reused later. Connections are automaticaly closed
// if not used after some time, specified in KeepAliveSeconds. // if not used after some time, specified in KeepAliveSeconds.
// The number of allowed open connections can also be specified // The number of allowed open connections can also be specified
// in MaxOpenConnections. The limit is per host. // in MaxOpenConnections. The limit is per host.
// If a thread requests a connection and the limit has been // If a thread requests a connection and the limit has been
// reached, the thread is suspended until one is released. // reached, the thread is suspended until one is released.
internal class UnixConnectionPool internal class UnixConnectionPool
{ {
// Table of pools. There is a HostConnectionPool // Table of pools. There is a HostConnectionPool
// instance for each host // instance for each host
static Hashtable _pools = new Hashtable(); static Hashtable _pools = new Hashtable();
static int _maxOpenConnections = int.MaxValue; static Int32 _maxOpenConnections = Int32.MaxValue;
static int _keepAliveSeconds = 15; static Int32 _keepAliveSeconds = 15;
static Thread _poolThread; static Thread _poolThread;
static UnixConnectionPool() static UnixConnectionPool()
{ {
// This thread will close unused connections // This thread will close unused connections
_poolThread = new Thread (new ThreadStart (ConnectionCollector)); _poolThread = new Thread (new ThreadStart (ConnectionCollector));
_poolThread.Start(); _poolThread.Start();
_poolThread.IsBackground = true; _poolThread.IsBackground = true;
} }
public static void Shutdown () public static void Shutdown ()
{ {
if (_poolThread != null) if (_poolThread != null) {
_poolThread.Abort(); _poolThread.Abort();
} }
}
public static int MaxOpenConnections public static Int32 MaxOpenConnections {
{ get => _maxOpenConnections;
get { return _maxOpenConnections; } set {
set if(value < 1) {
{ throw new RemotingException("MaxOpenConnections must be greater than zero");
if (value < 1) throw new RemotingException ("MaxOpenConnections must be greater than zero"); }
_maxOpenConnections = value;
}
}
public static int KeepAliveSeconds _maxOpenConnections = value;
{ }
get { return _keepAliveSeconds; } }
set { _keepAliveSeconds = value; }
}
public static UnixConnection GetConnection (string path) public static Int32 KeepAliveSeconds {
{ get => _keepAliveSeconds;
HostConnectionPool hostPool; set => _keepAliveSeconds = value;
}
lock (_pools) public static UnixConnection GetConnection (String path)
{ {
hostPool = (HostConnectionPool) _pools[path]; HostConnectionPool hostPool;
if (hostPool == null)
{
hostPool = new HostConnectionPool(path);
_pools[path] = hostPool;
}
}
return hostPool.GetConnection(); lock (_pools)
} {
hostPool = (HostConnectionPool) _pools[path];
if (hostPool == null)
{
hostPool = new HostConnectionPool(path);
_pools[path] = hostPool;
}
}
private static void ConnectionCollector () return hostPool.GetConnection();
{ }
while (true)
{
Thread.Sleep(3000);
lock (_pools)
{
ICollection values = _pools.Values;
foreach (HostConnectionPool pool in values)
pool.PurgeConnections();
}
}
}
}
internal class ReusableUnixClient : UnixClient private static void ConnectionCollector ()
{ {
public ReusableUnixClient (string path): base (path) while (true)
{ {
} Thread.Sleep(3000);
lock (_pools)
{
ICollection values = _pools.Values;
foreach (HostConnectionPool pool in values) {
pool.PurgeConnections();
}
}
}
}
}
public bool IsAlive internal class ReusableUnixClient : UnixClient
{ {
get public ReusableUnixClient (String path): base (path)
{ {
// This Poll will return true if there is data pending to }
// be read. It prob. means that a client object using this
// connection got an exception and did not finish to read
// the data. It can also mean that the connection has been
// closed in the server. In both cases, the connection cannot
// be reused.
return !Client.Poll (0, SelectMode.SelectRead);
}
}
}
internal class UnixConnection public Boolean IsAlive =>
{ // This Poll will return true if there is data pending to
DateTime _controlTime; // be read. It prob. means that a client object using this
Stream _stream; // connection got an exception and did not finish to read
ReusableUnixClient _client; // the data. It can also mean that the connection has been
HostConnectionPool _pool; // closed in the server. In both cases, the connection cannot
byte[] _buffer; // be reused.
!this.Client.Poll(0, SelectMode.SelectRead);
}
public UnixConnection (HostConnectionPool pool, ReusableUnixClient client) internal class UnixConnection
{ {
_pool = pool; DateTime _controlTime;
_client = client; Stream _stream;
_stream = new BufferedStream (client.GetStream()); ReusableUnixClient _client;
_controlTime = DateTime.UtcNow; HostConnectionPool _pool;
_buffer = new byte[UnixMessageIO.DefaultStreamBufferSize]; Byte[] _buffer;
}
public Stream Stream public UnixConnection (HostConnectionPool pool, ReusableUnixClient client)
{ {
get { return _stream; } this._pool = pool;
} this._client = client;
this._stream = new BufferedStream (client.GetStream());
this._controlTime = DateTime.UtcNow;
this._buffer = new Byte[UnixMessageIO.DefaultStreamBufferSize];
}
public DateTime ControlTime public Stream Stream => this._stream;
{
get { return _controlTime; }
set { _controlTime = value; }
}
public bool IsAlive public DateTime ControlTime {
{ get => this._controlTime;
get { return _client.IsAlive; } set => this._controlTime = value;
} }
// This is a "thread safe" buffer that can be used by public Boolean IsAlive => this._client.IsAlive;
// UnixClientTransportSink to read or send data to the stream.
// The buffer is "thread safe" since only one thread can
// use a connection at a given time.
public byte[] Buffer
{
get { return _buffer; }
}
// Returns the connection to the pool // This is a "thread safe" buffer that can be used by
public void Release() // UnixClientTransportSink to read or send data to the stream.
{ // The buffer is "thread safe" since only one thread can
_pool.ReleaseConnection (this); // use a connection at a given time.
} public Byte[] Buffer => this._buffer;
public void Close() // Returns the connection to the pool
{ public void Release() => this._pool.ReleaseConnection(this);
_client.Close();
}
}
internal class HostConnectionPool public void Close() => this._client.Close();
{ }
ArrayList _pool = new ArrayList();
int _activeConnections = 0;
string _path; internal class HostConnectionPool
{
ArrayList _pool = new ArrayList();
Int32 _activeConnections = 0;
public HostConnectionPool (string path) String _path;
{
_path = path;
}
public UnixConnection GetConnection () public HostConnectionPool(String path) => this._path = path;
{
UnixConnection connection = null;
lock (_pool)
{
do
{
if (_pool.Count > 0)
{
// There are available connections
connection = (UnixConnection)_pool[_pool.Count - 1]; public UnixConnection GetConnection ()
_pool.RemoveAt(_pool.Count - 1); {
if (!connection.IsAlive) { UnixConnection connection = null;
CancelConnection (connection); lock (this._pool)
connection = null; {
continue; do
} {
} if (this._pool.Count > 0)
{
// There are available connections
if (connection == null && _activeConnections < UnixConnectionPool.MaxOpenConnections) connection = (UnixConnection)this._pool[this._pool.Count - 1];
{ this._pool.RemoveAt(this._pool.Count - 1);
// No connections available, but the max connections if (!connection.IsAlive) {
// has not been reached yet, so a new one can be created this.CancelConnection (connection);
// Create the connection outside the lock connection = null;
break; continue;
} }
}
// No available connections in the pool if (connection == null && this._activeConnections < UnixConnectionPool.MaxOpenConnections)
// Wait for somewone to release one. {
// No connections available, but the max connections
// has not been reached yet, so a new one can be created
// Create the connection outside the lock
break;
}
if (connection == null) // No available connections in the pool
{ // Wait for somewone to release one.
Monitor.Wait(_pool);
}
}
while (connection == null);
}
if (connection == null) if (connection == null)
return CreateConnection (); {
else _ = Monitor.Wait(this._pool);
return connection; }
} }
while (connection == null);
}
private UnixConnection CreateConnection() if (connection == null) {
{ return this.CreateConnection ();
try } else {
{ return connection;
ReusableUnixClient client = new ReusableUnixClient (_path); }
UnixConnection entry = new UnixConnection(this, client); }
_activeConnections++;
return entry;
}
catch (Exception ex)
{
throw new RemotingException (ex.Message);
}
}
public void ReleaseConnection (UnixConnection entry) private UnixConnection CreateConnection()
{ {
lock (_pool) try
{ {
entry.ControlTime = DateTime.UtcNow; // Initialize timeout ReusableUnixClient client = new ReusableUnixClient (this._path);
_pool.Add (entry); UnixConnection entry = new UnixConnection(this, client);
Monitor.Pulse (_pool); this._activeConnections++;
} return entry;
} }
catch (Exception ex)
{
throw new RemotingException (ex.Message);
}
}
private void CancelConnection(UnixConnection entry) public void ReleaseConnection (UnixConnection entry)
{ {
try lock (this._pool)
{ {
entry.Stream.Close(); entry.ControlTime = DateTime.UtcNow; // Initialize timeout
_activeConnections--; _ = this._pool.Add(entry);
} Monitor.Pulse (this._pool);
catch }
{ }
}
}
public void PurgeConnections() private void CancelConnection(UnixConnection entry)
{ {
lock (_pool) try
{ {
for (int n=0; n < _pool.Count; n++) entry.Stream.Close();
{ this._activeConnections--;
UnixConnection entry = (UnixConnection)_pool[n]; }
if ( (DateTime.UtcNow - entry.ControlTime).TotalSeconds > UnixConnectionPool.KeepAliveSeconds) catch
{ {
CancelConnection (entry); }
_pool.RemoveAt(n); }
n--;
}
}
}
}
} public void PurgeConnections()
{
lock (this._pool)
{
for (Int32 n =0; n < this._pool.Count; n++)
{
UnixConnection entry = (UnixConnection)this._pool[n];
if ( (DateTime.UtcNow - entry.ControlTime).TotalSeconds > UnixConnectionPool.KeepAliveSeconds)
{
this.CancelConnection (entry);
this._pool.RemoveAt(n);
n--;
}
}
}
}
}
} }

View File

@ -38,246 +38,265 @@ using System.Runtime.Remoting;
namespace Mono.Remoting.Channels.Unix namespace Mono.Remoting.Channels.Unix
{ {
enum MessageStatus { MethodMessage = 0, CancelSignal = 1, Unknown = 10} enum MessageStatus { MethodMessage = 0, CancelSignal = 1, Unknown = 10}
internal class UnixMessageIO internal class UnixMessageIO
{ {
static byte[][] _msgHeaders = static Byte[][] _msgHeaders =
{ {
new byte[] { (byte)'.', (byte)'N', (byte)'E', (byte)'T', 1, 0 }, new Byte[] { (Byte)'.', (Byte)'N', (Byte)'E', (Byte)'T', 1, 0 },
new byte[] { 255, 255, 255, 255, 255, 255 } new Byte[] { 255, 255, 255, 255, 255, 255 }
}; };
public static int DefaultStreamBufferSize = 1000; public static Int32 DefaultStreamBufferSize = 1000;
// Identifies an incoming message // Identifies an incoming message
public static MessageStatus ReceiveMessageStatus (Stream networkStream, byte[] buffer) public static MessageStatus ReceiveMessageStatus (Stream networkStream, Byte[] buffer)
{ {
try { try {
StreamRead (networkStream, buffer, 6); _ = StreamRead(networkStream, buffer, 6);
} catch (Exception ex) { } catch (Exception ex) {
throw new RemotingException ("Unix transport error.", ex); throw new RemotingException ("Unix transport error.", ex);
} }
try try
{ {
bool[] isOnTrack = new bool[_msgHeaders.Length]; Boolean[] isOnTrack = new Boolean[_msgHeaders.Length];
bool atLeastOneOnTrack = true; Boolean atLeastOneOnTrack = true;
int i = 0; Int32 i = 0;
while (atLeastOneOnTrack) while (atLeastOneOnTrack)
{ {
atLeastOneOnTrack = false; atLeastOneOnTrack = false;
byte c = buffer [i]; Byte c = buffer [i];
for (int n = 0; n<_msgHeaders.Length; n++) for (Int32 n = 0; n<_msgHeaders.Length; n++)
{ {
if (i > 0 && !isOnTrack[n]) continue; if (i > 0 && !isOnTrack[n]) {
continue;
}
isOnTrack[n] = (c == _msgHeaders[n][i]); isOnTrack[n] = c == _msgHeaders[n][i];
if (isOnTrack[n] && (i == _msgHeaders[n].Length-1)) return (MessageStatus) n; if (isOnTrack[n] && i == _msgHeaders[n].Length-1) {
atLeastOneOnTrack = atLeastOneOnTrack || isOnTrack[n]; return (MessageStatus) n;
} }
i++;
}
return MessageStatus.Unknown;
}
catch (Exception ex) {
throw new RemotingException ("Unix transport error.", ex);
}
}
static bool StreamRead (Stream networkStream, byte[] buffer, int count) atLeastOneOnTrack = atLeastOneOnTrack || isOnTrack[n];
{ }
int nr = 0; i++;
do { }
int pr = networkStream.Read (buffer, nr, count - nr); return MessageStatus.Unknown;
if (pr == 0) }
throw new RemotingException ("Connection closed"); catch (Exception ex) {
nr += pr; throw new RemotingException ("Unix transport error.", ex);
} while (nr < count); }
return true; }
}
public static void SendMessageStream (Stream networkStream, Stream data, ITransportHeaders requestHeaders, byte[] buffer) static Boolean StreamRead (Stream networkStream, Byte[] buffer, Int32 count)
{ {
if (buffer == null) buffer = new byte[DefaultStreamBufferSize]; Int32 nr = 0;
do {
Int32 pr = networkStream.Read (buffer, nr, count - nr);
if (pr == 0) {
throw new RemotingException ("Connection closed");
}
// Writes the message start header nr += pr;
byte[] dotnetHeader = _msgHeaders[(int) MessageStatus.MethodMessage]; } while (nr < count);
networkStream.Write(dotnetHeader, 0, dotnetHeader.Length); return true;
}
// Writes header tag (0x0000 if request stream, 0x0002 if response stream) public static void SendMessageStream (Stream networkStream, Stream data, ITransportHeaders requestHeaders, Byte[] buffer)
if(requestHeaders["__RequestUri"]!=null) buffer [0] = (byte) 0; {
else buffer[0] = (byte) 2; if (buffer == null) {
buffer [1] = (byte) 0 ; buffer = new Byte[DefaultStreamBufferSize];
}
// Writes ID // Writes the message start header
buffer [2] = (byte) 0; Byte[] dotnetHeader = _msgHeaders[(Int32) MessageStatus.MethodMessage];
networkStream.Write(dotnetHeader, 0, dotnetHeader.Length);
// Writes assemblyID???? // Writes header tag (0x0000 if request stream, 0x0002 if response stream)
buffer [3] = (byte) 0; if(requestHeaders["__RequestUri"]!=null) {
buffer [0] = (Byte) 0;
} else {
buffer[0] = (Byte) 2;
}
// Writes the length of the stream being sent (not including the headers) buffer [1] = (Byte) 0 ;
int num = (int)data.Length;
buffer [4] = (byte) num;
buffer [5] = (byte) (num >> 8);
buffer [6] = (byte) (num >> 16);
buffer [7] = (byte) (num >> 24);
networkStream.Write(buffer, 0, 8);
// Writes the message headers // Writes ID
SendHeaders (networkStream, requestHeaders, buffer); buffer [2] = (Byte) 0;
// Writes the stream // Writes assemblyID????
if (data is MemoryStream) buffer [3] = (Byte) 0;
{
// The copy of the stream can be optimized. The internal
// buffer of MemoryStream can be used.
MemoryStream memStream = (MemoryStream)data;
networkStream.Write (memStream.GetBuffer(), 0, (int)memStream.Length);
}
else
{
int nread = data.Read (buffer, 0, buffer.Length);
while (nread > 0)
{
networkStream.Write (buffer, 0, nread);
nread = data.Read (buffer, 0, buffer.Length);
}
}
}
static byte[] msgUriTransportKey = new byte[] { 4, 0, 1, 1 }; // Writes the length of the stream being sent (not including the headers)
static byte[] msgContentTypeTransportKey = new byte[] { 6, 0, 1, 1 }; Int32 num = (Int32)data.Length;
static byte[] msgDefaultTransportKey = new byte[] { 1, 0, 1 }; buffer [4] = (Byte) num;
static byte[] msgHeaderTerminator = new byte[] { 0, 0 }; buffer [5] = (Byte) (num >> 8);
buffer [6] = (Byte) (num >> 16);
buffer [7] = (Byte) (num >> 24);
networkStream.Write(buffer, 0, 8);
private static void SendHeaders(Stream networkStream, ITransportHeaders requestHeaders, byte[] buffer) // Writes the message headers
{ SendHeaders (networkStream, requestHeaders, buffer);
// Writes the headers as a sequence of strings
if (networkStream != null)
{
IEnumerator e = requestHeaders.GetEnumerator();
while (e.MoveNext())
{
DictionaryEntry hdr = (DictionaryEntry)e.Current;
switch (hdr.Key.ToString())
{
case "__RequestUri":
networkStream.Write (msgUriTransportKey, 0, 4);
break;
case "Content-Type":
networkStream.Write (msgContentTypeTransportKey, 0, 4);
break;
default:
networkStream.Write (msgDefaultTransportKey, 0, 3);
SendString (networkStream, hdr.Key.ToString(), buffer);
networkStream.WriteByte (1);
break;
}
SendString (networkStream, hdr.Value.ToString(), buffer);
}
}
networkStream.Write (msgHeaderTerminator, 0, 2); // End of headers
}
public static ITransportHeaders ReceiveHeaders (Stream networkStream, byte[] buffer) // Writes the stream
{ if (data is MemoryStream)
StreamRead (networkStream, buffer, 2); {
// The copy of the stream can be optimized. The internal
// buffer of MemoryStream can be used.
MemoryStream memStream = (MemoryStream)data;
networkStream.Write (memStream.GetBuffer(), 0, (Int32)memStream.Length);
}
else
{
Int32 nread = data.Read (buffer, 0, buffer.Length);
while (nread > 0)
{
networkStream.Write (buffer, 0, nread);
nread = data.Read (buffer, 0, buffer.Length);
}
}
}
byte headerType = buffer [0]; static Byte[] msgUriTransportKey = new Byte[] { 4, 0, 1, 1 };
TransportHeaders headers = new TransportHeaders (); static Byte[] msgContentTypeTransportKey = new Byte[] { 6, 0, 1, 1 };
static Byte[] msgDefaultTransportKey = new Byte[] { 1, 0, 1 };
static Byte[] msgHeaderTerminator = new Byte[] { 0, 0 };
while (headerType != 0) private static void SendHeaders(Stream networkStream, ITransportHeaders requestHeaders, Byte[] buffer)
{ {
string key; // Writes the headers as a sequence of strings
StreamRead (networkStream, buffer, 1); // byte 1 if (networkStream != null)
switch (headerType) {
{ IEnumerator e = requestHeaders.GetEnumerator();
case 4: key = "__RequestUri"; break; while (e.MoveNext())
case 6: key = "Content-Type"; break; {
case 1: key = ReceiveString (networkStream, buffer); break; DictionaryEntry hdr = (DictionaryEntry)e.Current;
default: throw new NotSupportedException ("Unknown header code: " + headerType); switch (hdr.Key.ToString())
} {
StreamRead (networkStream, buffer, 1); // byte 1 case "__RequestUri":
headers[key] = ReceiveString (networkStream, buffer); networkStream.Write (msgUriTransportKey, 0, 4);
break;
case "Content-Type":
networkStream.Write (msgContentTypeTransportKey, 0, 4);
break;
default:
networkStream.Write (msgDefaultTransportKey, 0, 3);
SendString (networkStream, hdr.Key.ToString(), buffer);
networkStream.WriteByte (1);
break;
}
SendString (networkStream, hdr.Value.ToString(), buffer);
}
}
networkStream.Write (msgHeaderTerminator, 0, 2); // End of headers
}
StreamRead (networkStream, buffer, 2); public static ITransportHeaders ReceiveHeaders (Stream networkStream, Byte[] buffer)
headerType = buffer [0]; {
} _ = StreamRead(networkStream, buffer, 2);
return headers; Byte headerType = buffer [0];
} TransportHeaders headers = new TransportHeaders ();
public static Stream ReceiveMessageStream (Stream networkStream, out ITransportHeaders headers, byte[] buffer) while (headerType != 0)
{ {
headers = null; String key;
_ = StreamRead(networkStream, buffer, 1); // byte 1
switch (headerType)
{
case 4: key = "__RequestUri"; break;
case 6: key = "Content-Type"; break;
case 1: key = ReceiveString (networkStream, buffer); break;
default: throw new NotSupportedException ("Unknown header code: " + headerType);
}
_ = StreamRead(networkStream, buffer, 1); // byte 1
headers[key] = ReceiveString (networkStream, buffer);
if (buffer == null) buffer = new byte[DefaultStreamBufferSize]; _ = StreamRead(networkStream, buffer, 2);
headerType = buffer [0];
}
// Reads header tag: 0 -> Stream with headers or 2 -> Response Stream return headers;
// + }
// Gets the length of the data stream
StreamRead (networkStream, buffer, 8);
int byteCount = (buffer [4] | (buffer [5] << 8) | public static Stream ReceiveMessageStream (Stream networkStream, out ITransportHeaders headers, Byte[] buffer)
(buffer [6] << 16) | (buffer [7] << 24)); {
headers = null;
// Reads the headers if (buffer == null) {
headers = ReceiveHeaders (networkStream, buffer); buffer = new Byte[DefaultStreamBufferSize];
}
byte[] resultBuffer = new byte[byteCount]; // Reads header tag: 0 -> Stream with headers or 2 -> Response Stream
StreamRead (networkStream, resultBuffer, byteCount); // +
// Gets the length of the data stream
_ = StreamRead(networkStream, buffer, 8);
return new MemoryStream (resultBuffer); Int32 byteCount = buffer [4] | (buffer [5] << 8) |
} (buffer [6] << 16) | (buffer [7] << 24);
private static void SendString (Stream networkStream, string str, byte[] buffer) // Reads the headers
{ headers = ReceiveHeaders (networkStream, buffer);
// Allocates a buffer. Use the internal buffer if it is
// big enough. If not, create a new one.
int maxBytes = Encoding.UTF8.GetMaxByteCount(str.Length)+4; //+4 bytes for storing the string length Byte[] resultBuffer = new Byte[byteCount];
if (maxBytes > buffer.Length) _ = StreamRead(networkStream, resultBuffer, byteCount);
buffer = new byte[maxBytes];
int num = Encoding.UTF8.GetBytes (str, 0, str.Length, buffer, 4); return new MemoryStream (resultBuffer);
}
// store number of bytes (not number of chars!) private static void SendString (Stream networkStream, String str, Byte[] buffer)
{
// Allocates a buffer. Use the internal buffer if it is
// big enough. If not, create a new one.
buffer [0] = (byte) num; Int32 maxBytes = Encoding.UTF8.GetMaxByteCount(str.Length)+4; //+4 bytes for storing the string length
buffer [1] = (byte) (num >> 8); if (maxBytes > buffer.Length) {
buffer [2] = (byte) (num >> 16); buffer = new Byte[maxBytes];
buffer [3] = (byte) (num >> 24); }
// Write the string bytes Int32 num = Encoding.UTF8.GetBytes (str, 0, str.Length, buffer, 4);
networkStream.Write (buffer, 0, num + 4);
}
private static string ReceiveString (Stream networkStream, byte[] buffer) // store number of bytes (not number of chars!)
{
StreamRead (networkStream, buffer, 4);
// Reads the number of bytes (not chars!) buffer [0] = (Byte) num;
buffer [1] = (Byte) (num >> 8);
buffer [2] = (Byte) (num >> 16);
buffer [3] = (Byte) (num >> 24);
int byteCount = (buffer [0] | (buffer [1] << 8) | // Write the string bytes
(buffer [2] << 16) | (buffer [3] << 24)); networkStream.Write (buffer, 0, num + 4);
}
if (byteCount == 0) return string.Empty; private static String ReceiveString (Stream networkStream, Byte[] buffer)
{
_ = StreamRead(networkStream, buffer, 4);
// Allocates a buffer of the correct size. Use the // Reads the number of bytes (not chars!)
// internal buffer if it is big enough
if (byteCount > buffer.Length) Int32 byteCount = buffer [0] | (buffer [1] << 8) |
buffer = new byte[byteCount]; (buffer [2] << 16) | (buffer [3] << 24);
// Reads the string if (byteCount == 0) {
return String.Empty;
}
StreamRead (networkStream, buffer, byteCount); // Allocates a buffer of the correct size. Use the
char[] chars = Encoding.UTF8.GetChars (buffer, 0, byteCount); // internal buffer if it is big enough
return new string (chars); if (byteCount > buffer.Length) {
} buffer = new Byte[byteCount];
}
} // Reads the string
_ = StreamRead(networkStream, buffer, byteCount);
Char[] chars = Encoding.UTF8.GetChars (buffer, 0, byteCount);
return new String(chars);
}
}
} }

View File

@ -43,17 +43,17 @@ namespace Mono.Remoting.Channels.Unix
{ {
public class UnixServerChannel : IChannelReceiver, IChannel public class UnixServerChannel : IChannelReceiver, IChannel
{ {
string path = null; String path = null;
string name = "unix"; String name = "unix";
int priority = 1; Int32 priority = 1;
bool supressChannelData = false; Boolean supressChannelData = false;
Thread server_thread = null; Thread server_thread = null;
UnixListener listener; UnixListener listener;
UnixServerTransportSink sink; UnixServerTransportSink sink;
ChannelDataStore channel_data; ChannelDataStore channel_data;
int _maxConcurrentConnections = 100; Int32 _maxConcurrentConnections = 100;
ArrayList _activeConnections = new ArrayList(); ArrayList _activeConnections = new ArrayList();
@ -64,28 +64,28 @@ namespace Mono.Remoting.Channels.Unix
serverSinkProvider = new UnixBinaryServerFormatterSinkProvider (); serverSinkProvider = new UnixBinaryServerFormatterSinkProvider ();
} }
// Gets channel data from the chain of channel providers // Gets channel data from the chain of channel providers
channel_data = new ChannelDataStore (null); this.channel_data = new ChannelDataStore (null);
IServerChannelSinkProvider provider = serverSinkProvider; IServerChannelSinkProvider provider = serverSinkProvider;
while (provider != null) while (provider != null)
{ {
provider.GetChannelData(channel_data); provider.GetChannelData(this.channel_data);
provider = provider.Next; provider = provider.Next;
} }
// Creates the sink chain that will process all incoming messages // Creates the sink chain that will process all incoming messages
IServerChannelSink next_sink = ChannelServices.CreateServerChannelSinkChain (serverSinkProvider, this); IServerChannelSink next_sink = ChannelServices.CreateServerChannelSinkChain (serverSinkProvider, this);
sink = new UnixServerTransportSink (next_sink); this.sink = new UnixServerTransportSink (next_sink);
StartListening (null); this.StartListening (null);
} }
public UnixServerChannel (string path) public UnixServerChannel (String path)
{ {
this.path = path; this.path = path;
Init (null); this.Init (null);
} }
public UnixServerChannel (IDictionary properties, public UnixServerChannel (IDictionary properties,
@ -93,90 +93,80 @@ namespace Mono.Remoting.Channels.Unix
{ {
foreach(DictionaryEntry property in properties) foreach(DictionaryEntry property in properties)
{ {
switch((string)property.Key) switch((String)property.Key)
{ {
case "path": case "path":
path = property.Value as string; this.path = property.Value as String;
break; break;
case "priority": case "priority":
priority = Convert.ToInt32(property.Value); this.priority = Convert.ToInt32(property.Value);
break; break;
case "supressChannelData": case "supressChannelData":
supressChannelData = Convert.ToBoolean (property.Value); this.supressChannelData = Convert.ToBoolean (property.Value);
break; break;
} }
} }
Init (serverSinkProvider); this.Init (serverSinkProvider);
} }
public UnixServerChannel (string name, string path, public UnixServerChannel (String name, String path,
IServerChannelSinkProvider serverSinkProvider) IServerChannelSinkProvider serverSinkProvider)
{ {
this.name = name; this.name = name;
this.path = path; this.path = path;
Init (serverSinkProvider); this.Init (serverSinkProvider);
} }
public UnixServerChannel (string name, string path) public UnixServerChannel (String name, String path)
{ {
this.name = name; this.name = name;
this.path = path; this.path = path;
Init (null); this.Init (null);
} }
public object ChannelData public Object ChannelData
{ {
get { get {
if (supressChannelData) return null; if (this.supressChannelData) {
else return channel_data; return null;
} } else {
return this.channel_data;
}
}
} }
public string ChannelName public String ChannelName => this.name;
public Int32 ChannelPriority => this.priority;
public String GetChannelUri() => "unix://" + this.path;
public String[] GetUrlsForUri (String uri)
{ {
get { if (!uri.StartsWith ("/")) {
return name; uri = "/" + uri;
} }
String[] chnl_uris = this.channel_data.ChannelUris;
String[] result = new String [chnl_uris.Length];
for (Int32 i = 0; i < chnl_uris.Length; i++) {
result [i] = chnl_uris [i] + "?" + uri;
}
return result;
} }
public int ChannelPriority public String Parse(String url, out String objectURI) => UnixChannel.ParseUnixURL(url, out objectURI);
{
get {
return priority;
}
}
public string GetChannelUri () void WaitForConnections ()
{
return "unix://" + path;
}
public string[] GetUrlsForUri (string uri)
{
if (!uri.StartsWith ("/")) uri = "/" + uri;
string [] chnl_uris = channel_data.ChannelUris;
string [] result = new String [chnl_uris.Length];
for (int i = 0; i < chnl_uris.Length; i++)
result [i] = chnl_uris [i] + "?" + uri;
return result;
}
public string Parse (string url, out string objectURI)
{
return UnixChannel.ParseUnixURL (url, out objectURI);
}
void WaitForConnections ()
{ {
try try
{ {
while (true) while (true)
{ {
Socket client = listener.AcceptSocket (); Socket client = this.listener.AcceptSocket ();
CreateListenerConnection (client); this.CreateListenerConnection (client);
} }
} }
catch catch
@ -185,71 +175,77 @@ namespace Mono.Remoting.Channels.Unix
internal void CreateListenerConnection (Socket client) internal void CreateListenerConnection (Socket client)
{ {
lock (_activeConnections) lock (this._activeConnections)
{ {
if (_activeConnections.Count >= _maxConcurrentConnections) if (this._activeConnections.Count >= this._maxConcurrentConnections) {
Monitor.Wait (_activeConnections); _ = Monitor.Wait(this._activeConnections);
}
if (server_thread == null) return; // Server was stopped while waiting if (this.server_thread == null) {
return; // Server was stopped while waiting
}
ClientConnection reader = new ClientConnection (this, client, sink); ClientConnection reader = new ClientConnection (this, client, this.sink);
Thread thread = new Thread (new ThreadStart (reader.ProcessMessages)); Thread thread = new Thread (new ThreadStart (reader.ProcessMessages));
thread.Start(); thread.Start();
thread.IsBackground = true; thread.IsBackground = true;
_activeConnections.Add (thread); _ = this._activeConnections.Add(thread);
} }
} }
internal void ReleaseConnection (Thread thread) internal void ReleaseConnection (Thread thread)
{ {
lock (_activeConnections) lock (this._activeConnections)
{ {
_activeConnections.Remove (thread); this._activeConnections.Remove (thread);
Monitor.Pulse (_activeConnections); Monitor.Pulse (this._activeConnections);
} }
} }
public void StartListening (object data) public void StartListening (Object data)
{ {
listener = new UnixListener (path); this.listener = new UnixListener (this.path);
Mono.Unix.Native.Syscall.chmod (path, _ = Mono.Unix.Native.Syscall.chmod(this.path,
Mono.Unix.Native.FilePermissions.S_IRUSR | Mono.Unix.Native.FilePermissions.S_IRUSR |
Mono.Unix.Native.FilePermissions.S_IWUSR | Mono.Unix.Native.FilePermissions.S_IWUSR |
Mono.Unix.Native.FilePermissions.S_IRGRP | Mono.Unix.Native.FilePermissions.S_IRGRP |
Mono.Unix.Native.FilePermissions.S_IWGRP | Mono.Unix.Native.FilePermissions.S_IWGRP |
Mono.Unix.Native.FilePermissions.S_IROTH | Mono.Unix.Native.FilePermissions.S_IROTH |
Mono.Unix.Native.FilePermissions.S_IWOTH); Mono.Unix.Native.FilePermissions.S_IWOTH);
if (server_thread == null) if (this.server_thread == null)
{ {
listener.Start (); this.listener.Start ();
string[] uris = new String [1]; String[] uris = new String [1];
uris = new String [1]; uris = new String [1];
uris [0] = GetChannelUri (); uris [0] = this.GetChannelUri ();
channel_data.ChannelUris = uris; this.channel_data.ChannelUris = uris;
server_thread = new Thread (new ThreadStart (WaitForConnections)); this.server_thread = new Thread (new ThreadStart (this.WaitForConnections));
server_thread.IsBackground = true; this.server_thread.IsBackground = true;
server_thread.Start (); this.server_thread.Start ();
} }
} }
public void StopListening (object data) public void StopListening (Object data)
{ {
if (server_thread == null) return; if (this.server_thread == null) {
return;
}
lock (_activeConnections) lock (this._activeConnections)
{ {
server_thread.Abort (); this.server_thread.Abort ();
server_thread = null; this.server_thread = null;
listener.Stop (); this.listener.Stop ();
foreach (Thread thread in _activeConnections) foreach (Thread thread in this._activeConnections) {
thread.Abort(); thread.Abort();
}
_activeConnections.Clear(); this._activeConnections.Clear();
Monitor.PulseAll (_activeConnections); Monitor.PulseAll (this._activeConnections);
} }
} }
} }
@ -261,46 +257,41 @@ namespace Mono.Remoting.Channels.Unix
Stream _stream; Stream _stream;
UnixServerChannel _serverChannel; UnixServerChannel _serverChannel;
byte[] _buffer = new byte[UnixMessageIO.DefaultStreamBufferSize]; Byte[] _buffer = new Byte[UnixMessageIO.DefaultStreamBufferSize];
public ClientConnection (UnixServerChannel serverChannel, Socket client, UnixServerTransportSink sink) public ClientConnection (UnixServerChannel serverChannel, Socket client, UnixServerTransportSink sink)
{ {
_serverChannel = serverChannel; this._serverChannel = serverChannel;
_client = client; this._client = client;
_sink = sink; this._sink = sink;
} }
public Socket Client { public Socket Client => this._client;
get { return _client; }
}
public byte[] Buffer public Byte[] Buffer => this._buffer;
public void ProcessMessages()
{ {
get { return _buffer; } Byte[] buffer = new Byte[256];
} this._stream = new BufferedStream (new NetworkStream (this._client));
public void ProcessMessages()
{
byte[] buffer = new byte[256];
_stream = new BufferedStream (new NetworkStream (_client));
try try
{ {
bool end = false; Boolean end = false;
while (!end) while (!end)
{ {
MessageStatus type = UnixMessageIO.ReceiveMessageStatus (_stream, buffer); MessageStatus type = UnixMessageIO.ReceiveMessageStatus (this._stream, buffer);
switch (type) switch (type)
{ {
case MessageStatus.MethodMessage: case MessageStatus.MethodMessage:
_sink.InternalProcessMessage (this, _stream); this._sink.InternalProcessMessage (this, this._stream);
break; break;
case MessageStatus.Unknown: case MessageStatus.Unknown:
case MessageStatus.CancelSignal: case MessageStatus.CancelSignal:
end = true; end = true;
break; break;
} }
} }
} }
@ -310,21 +301,15 @@ namespace Mono.Remoting.Channels.Unix
} }
finally finally
{ {
try { try {
_serverChannel.ReleaseConnection (Thread.CurrentThread); this._serverChannel.ReleaseConnection (Thread.CurrentThread);
_stream.Close(); this._stream.Close();
_client.Close (); this._client.Close ();
} catch { } catch {
} }
} }
} }
public bool IsLocal public Boolean IsLocal => true;
{ }
get
{
return true;
}
}
}
} }

View File

@ -35,102 +35,80 @@ using System.Runtime.Remoting.Messaging;
using System.IO; using System.IO;
using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Channels;
namespace Mono.Remoting.Channels.Unix namespace Mono.Remoting.Channels.Unix {
{ internal class UnixServerTransportSink : IServerChannelSink, IChannelSinkBase {
internal class UnixServerTransportSink : IServerChannelSink, IChannelSinkBase IServerChannelSink next_sink;
{
IServerChannelSink next_sink;
public UnixServerTransportSink (IServerChannelSink next) public UnixServerTransportSink(IServerChannelSink next) => this.next_sink = next;
{
next_sink = next; public IServerChannelSink NextChannelSink => this.next_sink;
}
public IDictionary Properties {
public IServerChannelSink NextChannelSink get {
{ if(this.next_sink != null) {
get return this.next_sink.Properties;
{ } else {
return next_sink; return null;
}
}
public IDictionary Properties
{
get
{
if (next_sink != null) return next_sink.Properties;
else return null;
}
}
public void AsyncProcessResponse (IServerResponseChannelSinkStack sinkStack, object state,
IMessage msg, ITransportHeaders headers, Stream responseStream)
{
ClientConnection connection = (ClientConnection)state;
NetworkStream stream = new NetworkStream (connection.Client);
UnixMessageIO.SendMessageStream (stream, responseStream, headers, connection.Buffer);
stream.Flush ();
stream.Close ();
}
public Stream GetResponseStream (IServerResponseChannelSinkStack sinkStack, object state,
IMessage msg, ITransportHeaders headers)
{
return null;
}
public ServerProcessing ProcessMessage (IServerChannelSinkStack sinkStack,
IMessage requestMsg,
ITransportHeaders requestHeaders,
Stream requestStream,
out IMessage responseMsg,
out ITransportHeaders responseHeaders,
out Stream responseStream)
{
// this is the first sink, and UnixServerChannel does not call it.
throw new NotSupportedException ();
}
internal void InternalProcessMessage (ClientConnection connection, Stream stream)
{
// Reads the headers and the request stream
Stream requestStream;
ITransportHeaders requestHeaders;
requestStream = UnixMessageIO.ReceiveMessageStream (stream, out requestHeaders, connection.Buffer);
/* try {
PeerCred cred = connection.Client.PeerCredential;
requestHeaders["__uid"] = cred.UserID;
} catch (Exception e) {
Console.WriteLine ("Couldn't get the peer cred: " + e);
}
*/
// Pushes the connection object together with the sink. This information
// will be used for sending the response in an async call.
ServerChannelSinkStack sinkStack = new ServerChannelSinkStack();
sinkStack.Push(this, connection);
ITransportHeaders responseHeaders;
Stream responseStream;
IMessage responseMsg;
ServerProcessing proc = next_sink.ProcessMessage(sinkStack, null, requestHeaders, requestStream, out responseMsg, out responseHeaders, out responseStream);
switch (proc)
{
case ServerProcessing.Complete:
UnixMessageIO.SendMessageStream (stream, responseStream, responseHeaders, connection.Buffer);
stream.Flush ();
break;
case ServerProcessing.Async:
case ServerProcessing.OneWay:
break;
}
} }
}
} }
public void AsyncProcessResponse(IServerResponseChannelSinkStack sinkStack, Object state,
IMessage msg, ITransportHeaders headers, Stream responseStream) {
ClientConnection connection = (ClientConnection)state;
NetworkStream stream = new NetworkStream(connection.Client);
UnixMessageIO.SendMessageStream(stream, responseStream, headers, connection.Buffer);
stream.Flush();
stream.Close();
}
public Stream GetResponseStream(IServerResponseChannelSinkStack sinkStack, Object state,
IMessage msg, ITransportHeaders headers) => null;
public ServerProcessing ProcessMessage(IServerChannelSinkStack sinkStack,
IMessage requestMsg,
ITransportHeaders requestHeaders,
Stream requestStream,
out IMessage responseMsg,
out ITransportHeaders responseHeaders,
out Stream responseStream) =>
// this is the first sink, and UnixServerChannel does not call it.
throw new NotSupportedException();
internal void InternalProcessMessage(ClientConnection connection, Stream stream) {
// Reads the headers and the request stream
Stream requestStream;
requestStream = UnixMessageIO.ReceiveMessageStream(stream, out ITransportHeaders requestHeaders, connection.Buffer);
/* try {
PeerCred cred = connection.Client.PeerCredential;
requestHeaders["__uid"] = cred.UserID;
} catch (Exception e) {
Console.WriteLine ("Couldn't get the peer cred: " + e);
}
*/
// Pushes the connection object together with the sink. This information
// will be used for sending the response in an async call.
ServerChannelSinkStack sinkStack = new ServerChannelSinkStack();
sinkStack.Push(this, connection);
ServerProcessing proc = this.next_sink.ProcessMessage(sinkStack, null, requestHeaders, requestStream, out IMessage responseMsg, out ITransportHeaders responseHeaders, out Stream responseStream);
switch(proc) {
case ServerProcessing.Complete:
UnixMessageIO.SendMessageStream(stream, responseStream, responseHeaders, connection.Buffer);
stream.Flush();
break;
case ServerProcessing.Async:
case ServerProcessing.OneWay:
break;
}
}
}
} }

View File

@ -35,154 +35,158 @@ using System.Text;
namespace Mono.Unix.Native { namespace Mono.Unix.Native {
// This class represents a single unmanaged function with "cdecl" calling // This class represents a single unmanaged function with "cdecl" calling
// convention -- that is, it can accept a variable number of arguments which // convention -- that is, it can accept a variable number of arguments which
// are passed on the runtime stack. // are passed on the runtime stack.
// //
// To use, create an instance: // To use, create an instance:
// //
// CdeclFunction printf = new CdeclFunction ("the library", // CdeclFunction printf = new CdeclFunction ("the library",
// "the function name", /* optional */ typeof (ReturnType)); // "the function name", /* optional */ typeof (ReturnType));
// //
// Then call the Invoke method with the appropriate number of arguments: // 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 // In the background a P/Invoke definition for the method with the
// requested argument types will be generated and invoked, invoking the // requested argument types will be generated and invoked, invoking the
// unmanaged function. The generated methods are cached, so that subsequent // unmanaged function. The generated methods are cached, so that subsequent
// calls with the same argument list do not generate new code, speeding up // calls with the same argument list do not generate new code, speeding up
// the call sequence. // the call sequence.
// //
// Invoking Cdecl functions is not guaranteed to be portable across all // Invoking Cdecl functions is not guaranteed to be portable across all
// platforms. For example, AMD64 requires that the caller set EAX to the // platforms. For example, AMD64 requires that the caller set EAX to the
// number of floating point arguments passed in the SSE registers. This // number of floating point arguments passed in the SSE registers. This
// is only required for variable argument/cdecl functions; consequently, // is only required for variable argument/cdecl functions; consequently,
// the overload technique used by this class wouldn't normally work. // 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 // Mono's AMD64 JIT works around this by always setting EAX on P/Invoke
// invocations, allowing CdeclFunction to work properly, but it will not // invocations, allowing CdeclFunction to work properly, but it will not
// necessarily always work. See also: // necessarily always work. See also:
// //
// http://lwn.net/Articles/5201/?format=printable // http://lwn.net/Articles/5201/?format=printable
// //
// Due to potential portability issues, cdecl functions should be avoided // Due to potential portability issues, cdecl functions should be avoided
// on most platforms. // on most platforms.
// //
// This class is intended to be thread-safe. // This class is intended to be thread-safe.
public sealed class CdeclFunction public sealed class CdeclFunction
{ {
// The readonly fields (1) shouldn't be modified, and (2) should only be // The readonly fields (1) shouldn't be modified, and (2) should only be
// used when `overloads' is locked. // used when `overloads' is locked.
private readonly string library; private readonly String library;
private readonly string method; private readonly String method;
private readonly Type returnType; private readonly Type returnType;
private readonly AssemblyName assemblyName; private readonly AssemblyName assemblyName;
private readonly AssemblyBuilder assemblyBuilder; private readonly AssemblyBuilder assemblyBuilder;
private readonly ModuleBuilder moduleBuilder; private readonly ModuleBuilder moduleBuilder;
private Hashtable overloads; private readonly Hashtable overloads;
public CdeclFunction (string library, string method) public CdeclFunction (String library, String method)
: this (library, method, typeof(void)) : this (library, method, typeof(void))
{ {
} }
public CdeclFunction (string library, string method, Type returnType) public CdeclFunction (String library, String method, Type returnType)
{ {
this.library = library; this.library = library;
this.method = method; this.method = method;
this.returnType = returnType; this.returnType = returnType;
this.overloads = new Hashtable (); this.overloads = new Hashtable ();
this.assemblyName = new AssemblyName (); this.assemblyName = new AssemblyName {
this.assemblyName.Name = "Mono.Posix.Imports." + library; Name = "Mono.Posix.Imports." + library
this.assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly ( };
assemblyName, AssemblyBuilderAccess.Run); this.assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly (
this.moduleBuilder = assemblyBuilder.DefineDynamicModule (assemblyName.Name); this.assemblyName, AssemblyBuilderAccess.Run);
} this.moduleBuilder = this.assemblyBuilder.DefineDynamicModule (this.assemblyName.Name);
}
public object Invoke (object[] parameters) public Object Invoke (Object[] parameters)
{ {
Type[] parameterTypes = GetParameterTypes (parameters); Type[] parameterTypes = GetParameterTypes (parameters);
MethodInfo m = CreateMethod (parameterTypes); MethodInfo m = this.CreateMethod (parameterTypes);
return m.Invoke (null, parameters); return m.Invoke (null, parameters);
} }
private MethodInfo CreateMethod (Type[] parameterTypes) private MethodInfo CreateMethod (Type[] parameterTypes)
{ {
string typeName = GetTypeName (parameterTypes); String typeName = this.GetTypeName (parameterTypes);
lock (overloads) { lock (this.overloads) {
MethodInfo mi = (MethodInfo) overloads [typeName]; MethodInfo mi = (MethodInfo)this.overloads [typeName];
if (mi != null) { if (mi != null) {
return mi; return mi;
} }
TypeBuilder tb = CreateType (typeName); TypeBuilder tb = this.CreateType (typeName);
/* MethodBuilder mb = */ tb.DefinePInvokeMethod ( /* MethodBuilder mb = */
method, _ = tb.DefinePInvokeMethod(
library, this.method,
MethodAttributes.PinvokeImpl | MethodAttributes.Static | MethodAttributes.Public, this.library,
CallingConventions.Standard, MethodAttributes.PinvokeImpl | MethodAttributes.Static | MethodAttributes.Public,
returnType, CallingConventions.Standard,
parameterTypes, this.returnType,
CallingConvention.Cdecl, parameterTypes,
CharSet.Ansi); CallingConvention.Cdecl,
mi = tb.CreateType ().GetMethod (method); CharSet.Ansi);
overloads.Add (typeName, mi); mi = tb.CreateType ().GetMethod (this.method);
return mi; this.overloads.Add (typeName, mi);
} return mi;
} }
}
private TypeBuilder CreateType (string typeName) private TypeBuilder CreateType(String typeName) => this.moduleBuilder.DefineType(typeName, TypeAttributes.Public);
{
return moduleBuilder.DefineType (typeName, TypeAttributes.Public);
}
private static Type GetMarshalType (Type t) private static Type GetMarshalType (Type t)
{ {
switch (Type.GetTypeCode (t)) { switch (Type.GetTypeCode (t)) {
// types < sizeof(int) are marshaled as ints // types < sizeof(int) are marshaled as ints
case TypeCode.Boolean: case TypeCode.Char: case TypeCode.SByte: case TypeCode.Boolean: case TypeCode.Char: case TypeCode.SByte:
case TypeCode.Int16: case TypeCode.Int32: case TypeCode.Int16: case TypeCode.Int32:
return typeof(int); return typeof(Int32);
case TypeCode.Byte: case TypeCode.UInt16: case TypeCode.UInt32: case TypeCode.Byte: case TypeCode.UInt16: case TypeCode.UInt32:
return typeof(uint); return typeof(UInt32);
case TypeCode.Int64: case TypeCode.Int64:
return typeof(long); return typeof(Int64);
case TypeCode.UInt64: case TypeCode.UInt64:
return typeof(ulong); return typeof(UInt64);
case TypeCode.Single: case TypeCode.Double: case TypeCode.Single: case TypeCode.Double:
return typeof(double); return typeof(Double);
default: default:
return t; return t;
} }
} }
private string GetTypeName (Type[] parameterTypes) private String GetTypeName (Type[] parameterTypes)
{ {
StringBuilder sb = new StringBuilder (); StringBuilder sb = new StringBuilder ();
sb.Append ("[").Append (library).Append ("] ").Append (method); _ = sb.Append("[").Append(this.library).Append("] ").Append(this.method);
sb.Append ("("); _ = sb.Append("(");
if (parameterTypes.Length > 0) if (parameterTypes.Length > 0) {
sb.Append (parameterTypes [0]); _ = sb.Append(parameterTypes[0]);
for (int i = 1; i < parameterTypes.Length; ++i) }
sb.Append (",").Append (parameterTypes [i]);
sb.Append (") : ").Append (returnType.FullName); for (Int32 i = 1; i < parameterTypes.Length; ++i) {
_ = sb.Append(",").Append(parameterTypes[i]);
}
return sb.ToString (); _ = sb.Append(") : ").Append(this.returnType.FullName);
}
private static Type[] GetParameterTypes (object[] parameters) return sb.ToString ();
{ }
Type[] parameterTypes = new Type [parameters.Length];
for (int i = 0; i < parameters.Length; ++i) private static Type[] GetParameterTypes (Object[] parameters)
parameterTypes [i] = GetMarshalType (parameters [i].GetType ()); {
return parameterTypes; Type[] parameterTypes = new Type [parameters.Length];
} for (Int32 i = 0; i < parameters.Length; ++i) {
} parameterTypes [i] = GetMarshalType (parameters [i].GetType ());
}
return parameterTypes;
}
}
} }

View File

@ -32,48 +32,42 @@ using Mono.Unix;
namespace Mono.Unix.Native { namespace Mono.Unix.Native {
class FileNameMarshaler : ICustomMarshaler { class FileNameMarshaler : ICustomMarshaler {
private static FileNameMarshaler Instance = new FileNameMarshaler (); private static readonly FileNameMarshaler Instance = new FileNameMarshaler ();
public static ICustomMarshaler GetInstance (string s) [System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE0060:Nicht verwendete Parameter entfernen", Justification = "<Ausstehend>")]
{ public static ICustomMarshaler GetInstance(String s) => Instance;
return Instance;
}
public void CleanUpManagedData (object o) public void CleanUpManagedData (Object o)
{ {
} }
public void CleanUpNativeData (IntPtr pNativeData) public void CleanUpNativeData(IntPtr pNativeData) =>
{ // Console.WriteLine ("# FileNameMarshaler.CleanUpManagedData ({0:x})", pNativeData);
// Console.WriteLine ("# FileNameMarshaler.CleanUpManagedData ({0:x})", pNativeData); UnixMarshal.FreeHeap(pNativeData);
UnixMarshal.FreeHeap (pNativeData);
}
public int GetNativeDataSize () public Int32 GetNativeDataSize() => IntPtr.Size;
{
return IntPtr.Size;
}
public IntPtr MarshalManagedToNative (object obj) public IntPtr MarshalManagedToNative (Object obj)
{ {
string s = obj as string; if(!(obj is String s)) {
if (s == null) return IntPtr.Zero;
return IntPtr.Zero; }
IntPtr p = UnixMarshal.StringToHeap (s, UnixEncoding.Instance);
// Console.WriteLine ("# FileNameMarshaler.MarshalNativeToManaged for `{0}'={1:x}", s, p);
return p;
}
public object MarshalNativeToManaged (IntPtr pNativeData) IntPtr p = UnixMarshal.StringToHeap (s, UnixEncoding.Instance);
{ // Console.WriteLine ("# FileNameMarshaler.MarshalNativeToManaged for `{0}'={1:x}", s, p);
string s = UnixMarshal.PtrToString (pNativeData, UnixEncoding.Instance); return p;
// Console.WriteLine ("# FileNameMarshaler.MarshalNativeToManaged ({0:x})=`{1}'", }
// pNativeData, s);
return s; public Object MarshalNativeToManaged (IntPtr pNativeData)
} {
} String s = UnixMarshal.PtrToString (pNativeData, UnixEncoding.Instance);
// Console.WriteLine ("# FileNameMarshaler.MarshalNativeToManaged ({0:x})=`{1}'",
// pNativeData, s);
return s;
}
}
} }
// vim: noexpandtab // vim: noexpandtab

View File

@ -30,31 +30,23 @@
using System; using System;
[AttributeUsage ( [AttributeUsage (
AttributeTargets.Class | AttributeTargets.Class |
AttributeTargets.Delegate | AttributeTargets.Delegate |
AttributeTargets.Enum | AttributeTargets.Enum |
AttributeTargets.Field | AttributeTargets.Field |
AttributeTargets.Struct)] AttributeTargets.Struct)]
internal class MapAttribute : Attribute { internal class MapAttribute : Attribute {
private string nativeType; public MapAttribute ()
private string suppressFlags; {
}
public MapAttribute () public MapAttribute(String nativeType) => this.NativeType = nativeType;
{
}
public MapAttribute (string nativeType) public String NativeType {
{ get;
this.nativeType = nativeType; }
}
public string NativeType { public String SuppressFlags { get;
get {return nativeType;} set; }
}
public string SuppressFlags {
get {return suppressFlags;}
set {suppressFlags = value;}
}
} }

View File

@ -14,470 +14,458 @@ using Mono.Unix.Android;
namespace Mono.Unix.Native { namespace Mono.Unix.Native {
[CLSCompliant (false)] //[CLSCompliant (false)]
public sealed /* static */ partial class NativeConvert public sealed /* static */ partial class NativeConvert
{ {
// //
// Non-generated exports // Non-generated exports
// //
#if MONODROID #if MONODROID
[DllImport (LIB, EntryPoint="Mono_Posix_FromRealTimeSignum")] [DllImport (LIB, EntryPoint="Mono_Posix_FromRealTimeSignum")]
static extern int HelperFromRealTimeSignum (Int32 offset, out Int32 rval); static extern int HelperFromRealTimeSignum (Int32 offset, out Int32 rval);
static int FromRealTimeSignum (Int32 offset, out Int32 rval) static int FromRealTimeSignum (Int32 offset, out Int32 rval)
{ {
if (!AndroidUtils.AreRealTimeSignalsSafe ()) if (!AndroidUtils.AreRealTimeSignalsSafe ())
throw new PlatformNotSupportedException ("Real-time signals are not supported on this Android architecture"); throw new PlatformNotSupportedException ("Real-time signals are not supported on this Android architecture");
return HelperFromRealTimeSignum (offset, out rval); return HelperFromRealTimeSignum (offset, out rval);
} }
#else #else
[DllImport (LIB, EntryPoint="Mono_Posix_FromRealTimeSignum")] [DllImport (LIB, EntryPoint="Mono_Posix_FromRealTimeSignum")]
private static extern int FromRealTimeSignum (Int32 offset, out Int32 rval); private static extern Int32 FromRealTimeSignum (Int32 offset, out Int32 rval);
#endif #endif
// convert a realtime signal to os signal // convert a realtime signal to os signal
public static int FromRealTimeSignum (RealTimeSignum sig) public static Int32 FromRealTimeSignum (RealTimeSignum sig)
{ {
int sigNum; if(FromRealTimeSignum(sig.Offset, out Int32 sigNum) == -1) {
if (FromRealTimeSignum (sig.Offset, out sigNum) == -1) ThrowArgumentException(sig.Offset);
ThrowArgumentException (sig.Offset); }
return sigNum;
}
// convert an offset to an rt signum return sigNum;
public static RealTimeSignum ToRealTimeSignum (int offset) }
{
return new RealTimeSignum (offset);
}
// convert from octal representation. // convert an offset to an rt signum
public static FilePermissions FromOctalPermissionString (string value) public static RealTimeSignum ToRealTimeSignum(Int32 offset) => new RealTimeSignum(offset);
{
uint n = Convert.ToUInt32 (value, 8);
return ToFilePermissions (n);
}
public static string ToOctalPermissionString (FilePermissions value) // convert from octal representation.
{ public static FilePermissions FromOctalPermissionString (String value)
string s = Convert.ToString ((int) (value & ~FilePermissions.S_IFMT), 8); {
return new string ('0', 4-s.Length) + s; UInt32 n = Convert.ToUInt32 (value, 8);
} return ToFilePermissions (n);
}
public static FilePermissions FromUnixPermissionString (string value) public static String ToOctalPermissionString (FilePermissions value)
{ {
if (value == null) String s = Convert.ToString ((Int32) (value & ~FilePermissions.S_IFMT), 8);
throw new ArgumentNullException ("value"); return new String('0', 4-s.Length) + s;
if (value.Length != 9 && value.Length != 10) }
throw new ArgumentException ("value", "must contain 9 or 10 characters");
int i = 0; public static FilePermissions FromUnixPermissionString (String value)
FilePermissions perms = new FilePermissions (); {
if (value == null) {
throw new ArgumentNullException ("value");
}
if (value.Length == 10) { if (value.Length != 9 && value.Length != 10) {
perms |= GetUnixPermissionDevice (value [i]); throw new ArgumentException ("value", "must contain 9 or 10 characters");
++i; }
}
perms |= GetUnixPermissionGroup ( Int32 i = 0;
value [i++], FilePermissions.S_IRUSR, FilePermissions perms = new FilePermissions ();
value [i++], FilePermissions.S_IWUSR,
value [i++], FilePermissions.S_IXUSR,
's', 'S', FilePermissions.S_ISUID);
perms |= GetUnixPermissionGroup ( if (value.Length == 10) {
value [i++], FilePermissions.S_IRGRP, perms |= GetUnixPermissionDevice (value [i]);
value [i++], FilePermissions.S_IWGRP, ++i;
value [i++], FilePermissions.S_IXGRP, }
's', 'S', FilePermissions.S_ISGID);
perms |= GetUnixPermissionGroup ( perms |= GetUnixPermissionGroup (
value [i++], FilePermissions.S_IROTH, value [i++], FilePermissions.S_IRUSR,
value [i++], FilePermissions.S_IWOTH, value [i++], FilePermissions.S_IWUSR,
value [i++], FilePermissions.S_IXOTH, value [i++], FilePermissions.S_IXUSR,
't', 'T', FilePermissions.S_ISVTX); 's', 'S', FilePermissions.S_ISUID);
return perms; perms |= GetUnixPermissionGroup (
} value [i++], FilePermissions.S_IRGRP,
value [i++], FilePermissions.S_IWGRP,
value [i++], FilePermissions.S_IXGRP,
's', 'S', FilePermissions.S_ISGID);
private static FilePermissions GetUnixPermissionDevice (char value) perms |= GetUnixPermissionGroup (
{ value [i++], FilePermissions.S_IROTH,
switch (value) { value [i++], FilePermissions.S_IWOTH,
case 'd': return FilePermissions.S_IFDIR; value [i++], FilePermissions.S_IXOTH,
case 'c': return FilePermissions.S_IFCHR; 't', 'T', FilePermissions.S_ISVTX);
case 'b': return FilePermissions.S_IFBLK;
case '-': return FilePermissions.S_IFREG;
case 'p': return FilePermissions.S_IFIFO;
case 'l': return FilePermissions.S_IFLNK;
case 's': return FilePermissions.S_IFSOCK;
}
throw new ArgumentException ("value", "invalid device specification: " +
value);
}
private static FilePermissions GetUnixPermissionGroup ( return perms;
char read, FilePermissions readb, }
char write, FilePermissions writeb,
char exec, FilePermissions execb,
char xboth, char xbitonly, FilePermissions xbit)
{
FilePermissions perms = new FilePermissions ();
if (read == 'r')
perms |= readb;
if (write == 'w')
perms |= writeb;
if (exec == 'x')
perms |= execb;
else if (exec == xbitonly)
perms |= xbit;
else if (exec == xboth)
perms |= (execb | xbit);
return perms;
}
// Create ls(1) drwxrwxrwx permissions display private static FilePermissions GetUnixPermissionDevice (Char value)
public static string ToUnixPermissionString (FilePermissions value) {
{ switch (value) {
char [] access = new char[] { case 'd': return FilePermissions.S_IFDIR;
'-', // device case 'c': return FilePermissions.S_IFCHR;
'-', '-', '-', // owner case 'b': return FilePermissions.S_IFBLK;
'-', '-', '-', // group case '-': return FilePermissions.S_IFREG;
'-', '-', '-', // other case 'p': return FilePermissions.S_IFIFO;
}; case 'l': return FilePermissions.S_IFLNK;
bool have_device = true; case 's': return FilePermissions.S_IFSOCK;
switch (value & FilePermissions.S_IFMT) { }
case FilePermissions.S_IFDIR: access [0] = 'd'; break; throw new ArgumentException ("value", "invalid device specification: " +
case FilePermissions.S_IFCHR: access [0] = 'c'; break; value);
case FilePermissions.S_IFBLK: access [0] = 'b'; break; }
case FilePermissions.S_IFREG: access [0] = '-'; break;
case FilePermissions.S_IFIFO: access [0] = 'p'; break;
case FilePermissions.S_IFLNK: access [0] = 'l'; break;
case FilePermissions.S_IFSOCK: access [0] = 's'; break;
default: have_device = false; break;
}
SetUnixPermissionGroup (value, access, 1,
FilePermissions.S_IRUSR, FilePermissions.S_IWUSR, FilePermissions.S_IXUSR,
's', 'S', FilePermissions.S_ISUID);
SetUnixPermissionGroup (value, access, 4,
FilePermissions.S_IRGRP, FilePermissions.S_IWGRP, FilePermissions.S_IXGRP,
's', 'S', FilePermissions.S_ISGID);
SetUnixPermissionGroup (value, access, 7,
FilePermissions.S_IROTH, FilePermissions.S_IWOTH, FilePermissions.S_IXOTH,
't', 'T', FilePermissions.S_ISVTX);
return have_device
? new string (access)
: new string (access, 1, 9);
}
private static void SetUnixPermissionGroup (FilePermissions value, private static FilePermissions GetUnixPermissionGroup (
char[] access, int index, Char read, FilePermissions readb,
FilePermissions read, FilePermissions write, FilePermissions exec, Char write, FilePermissions writeb,
char both, char setonly, FilePermissions setxbit) Char exec, FilePermissions execb,
{ Char xboth, Char xbitonly, FilePermissions xbit)
if (UnixFileSystemInfo.IsSet (value, read)) {
access [index] = 'r'; FilePermissions perms = new FilePermissions ();
if (UnixFileSystemInfo.IsSet (value, write)) if (read == 'r') {
access [index+1] = 'w'; perms |= readb;
access [index+2] = GetSymbolicMode (value, exec, both, setonly, setxbit); }
}
// Implement the GNU ls(1) permissions spec; see `info coreutils ls`, if (write == 'w') {
// section 10.1.2, the `-l' argument information. perms |= writeb;
private static char GetSymbolicMode (FilePermissions value, }
FilePermissions xbit, char both, char setonly, FilePermissions setxbit)
{
bool is_x = UnixFileSystemInfo.IsSet (value, xbit);
bool is_sx = UnixFileSystemInfo.IsSet (value, setxbit);
if (is_x && is_sx) if (exec == 'x') {
return both; perms |= execb;
if (is_sx) } else if (exec == xbitonly) {
return setonly; perms |= xbit;
if (is_x) } else if (exec == xboth) {
return 'x'; perms |= execb | xbit;
return '-'; }
}
public static readonly DateTime UnixEpoch = return perms;
new DateTime (year:1970, month:1, day:1, hour:0, minute:0, second:0, kind:DateTimeKind.Utc); }
public static readonly DateTime LocalUnixEpoch =
new DateTime (1970, 1, 1);
public static readonly TimeSpan LocalUtcOffset =
TimeZone.CurrentTimeZone.GetUtcOffset (DateTime.UtcNow);
public static DateTime ToDateTime (long time) // Create ls(1) drwxrwxrwx permissions display
{ public static String ToUnixPermissionString (FilePermissions value)
return FromTimeT (time); {
} Char[] access = new Char[] {
'-', // device
'-', '-', '-', // owner
'-', '-', '-', // group
'-', '-', '-', // other
};
Boolean have_device = true;
switch (value & FilePermissions.S_IFMT) {
case FilePermissions.S_IFDIR: access [0] = 'd'; break;
case FilePermissions.S_IFCHR: access [0] = 'c'; break;
case FilePermissions.S_IFBLK: access [0] = 'b'; break;
case FilePermissions.S_IFREG: access [0] = '-'; break;
case FilePermissions.S_IFIFO: access [0] = 'p'; break;
case FilePermissions.S_IFLNK: access [0] = 'l'; break;
case FilePermissions.S_IFSOCK: access [0] = 's'; break;
default: have_device = false; break;
}
SetUnixPermissionGroup (value, access, 1,
FilePermissions.S_IRUSR, FilePermissions.S_IWUSR, FilePermissions.S_IXUSR,
's', 'S', FilePermissions.S_ISUID);
SetUnixPermissionGroup (value, access, 4,
FilePermissions.S_IRGRP, FilePermissions.S_IWGRP, FilePermissions.S_IXGRP,
's', 'S', FilePermissions.S_ISGID);
SetUnixPermissionGroup (value, access, 7,
FilePermissions.S_IROTH, FilePermissions.S_IWOTH, FilePermissions.S_IXOTH,
't', 'T', FilePermissions.S_ISVTX);
return have_device
? new String(access)
: new String(access, 1, 9);
}
public static DateTime ToDateTime (long time, long nanoTime) private static void SetUnixPermissionGroup (FilePermissions value,
{ Char[] access, Int32 index,
return FromTimeT (time).AddMilliseconds (nanoTime / 1000); FilePermissions read, FilePermissions write, FilePermissions exec,
} Char both, Char setonly, FilePermissions setxbit)
{
if (UnixFileSystemInfo.IsSet (value, read)) {
access [index] = 'r';
}
public static long FromDateTime (DateTime time) if (UnixFileSystemInfo.IsSet (value, write)) {
{ access [index+1] = 'w';
return ToTimeT (time); }
}
public static DateTime FromTimeT (long time) access [index+2] = GetSymbolicMode (value, exec, both, setonly, setxbit);
{ }
return UnixEpoch.AddSeconds (time).ToLocalTime ();
}
public static long ToTimeT (DateTime time) // Implement the GNU ls(1) permissions spec; see `info coreutils ls`,
{ // section 10.1.2, the `-l' argument information.
if (time.Kind == DateTimeKind.Unspecified) private static Char GetSymbolicMode (FilePermissions value,
throw new ArgumentException ("DateTimeKind.Unspecified is not supported. Use Local or Utc times.", "time"); FilePermissions xbit, Char both, Char setonly, FilePermissions setxbit)
{
Boolean is_x = UnixFileSystemInfo.IsSet (value, xbit);
Boolean is_sx = UnixFileSystemInfo.IsSet (value, setxbit);
if (time.Kind == DateTimeKind.Local) return is_x && is_sx ? both : is_sx ? setonly : is_x ? 'x' : '-';
time = time.ToUniversalTime (); }
return (long) (time - UnixEpoch).TotalSeconds; public static readonly DateTime UnixEpoch =
} new DateTime (year:1970, month:1, day:1, hour:0, minute:0, second:0, kind:DateTimeKind.Utc);
public static readonly DateTime LocalUnixEpoch =
new DateTime (1970, 1, 1);
public static readonly TimeSpan LocalUtcOffset =
TimeZone.CurrentTimeZone.GetUtcOffset (DateTime.UtcNow);
public static OpenFlags ToOpenFlags (FileMode mode, FileAccess access) public static DateTime ToDateTime(Int64 time) => FromTimeT(time);
{
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? public static DateTime ToDateTime(Int64 time, Int64 nanoTime) => FromTimeT(time).AddMilliseconds(nanoTime / 1000);
int _v;
if (TryFromOpenFlags (OpenFlags.O_LARGEFILE, out _v))
flags |= OpenFlags.O_LARGEFILE;
switch (access) { public static Int64 FromDateTime(DateTime time) => ToTimeT(time);
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 (Locale.GetText ("Unsupported access value"), "access");
}
return flags; public static DateTime FromTimeT(Int64 time) => UnixEpoch.AddSeconds(time).ToLocalTime();
}
public static string ToFopenMode (FileAccess access) public static Int64 ToTimeT (DateTime time)
{ {
switch (access) { if (time.Kind == DateTimeKind.Unspecified) {
case FileAccess.Read: return "rb"; throw new ArgumentException ("DateTimeKind.Unspecified is not supported. Use Local or Utc times.", "time");
case FileAccess.Write: return "wb"; }
case FileAccess.ReadWrite: return "r+b";
default: throw new ArgumentOutOfRangeException ("access");
}
}
public static string ToFopenMode (FileMode mode) if (time.Kind == DateTimeKind.Local) {
{ time = time.ToUniversalTime ();
switch (mode) { }
case FileMode.CreateNew: case FileMode.Create: return "w+b";
case FileMode.Open: case FileMode.OpenOrCreate: return "r+b";
case FileMode.Truncate: return "w+b";
case FileMode.Append: return "a+b";
default: throw new ArgumentOutOfRangeException ("mode");
}
}
private static readonly string[][] fopen_modes = new string[][]{ return (Int64) (time - UnixEpoch).TotalSeconds;
// Read Write ReadWrite }
/* FileMode.CreateNew: */ new string[]{"Can't Read+Create", "wb", "w+b"},
/* FileMode.Create: */ new string[]{"Can't Read+Create", "wb", "w+b"},
/* FileMode.Open: */ new string[]{"rb", "wb", "r+b"},
/* FileMode.OpenOrCreate: */ new string[]{"rb", "wb", "r+b"},
/* FileMode.Truncate: */ new string[]{"Cannot Truncate and Read","wb", "w+b"},
/* FileMode.Append: */ new string[]{"Cannot Append and Read", "ab", "a+b"},
};
public static string ToFopenMode (FileMode mode, FileAccess access) public static OpenFlags ToOpenFlags (FileMode mode, FileAccess access)
{ {
int fm = -1, fa = -1; OpenFlags flags = 0;
switch (mode) { switch (mode) {
case FileMode.CreateNew: fm = 0; break; case FileMode.CreateNew:
case FileMode.Create: fm = 1; break; flags = OpenFlags.O_CREAT | OpenFlags.O_EXCL;
case FileMode.Open: fm = 2; break; break;
case FileMode.OpenOrCreate: fm = 3; break; case FileMode.Create:
case FileMode.Truncate: fm = 4; break; flags = OpenFlags.O_CREAT | OpenFlags.O_TRUNC;
case FileMode.Append: fm = 5; break; break;
} case FileMode.Open:
switch (access) { // do nothing
case FileAccess.Read: fa = 0; break; break;
case FileAccess.Write: fa = 1; break; case FileMode.OpenOrCreate:
case FileAccess.ReadWrite: fa = 2; break; 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");
}
if (fm == -1) // Is O_LARGEFILE supported?
throw new ArgumentOutOfRangeException ("mode"); if(TryFromOpenFlags(OpenFlags.O_LARGEFILE, out _)) {
if (fa == -1) flags |= OpenFlags.O_LARGEFILE;
throw new ArgumentOutOfRangeException ("access"); }
string fopen_mode = fopen_modes [fm][fa]; switch (access) {
if (fopen_mode [0] != 'r' && fopen_mode [0] != 'w' && fopen_mode [0] != 'a') case FileAccess.Read:
throw new ArgumentException (fopen_mode); flags |= OpenFlags.O_RDONLY;
return fopen_mode; break;
} case FileAccess.Write:
flags |= OpenFlags.O_WRONLY;
break;
case FileAccess.ReadWrite:
flags |= OpenFlags.O_RDWR;
break;
default:
throw new ArgumentOutOfRangeException (Locale.GetText ("Unsupported access value"), "access");
}
[DllImport (LIB, EntryPoint="Mono_Posix_FromStat")] return flags;
private static extern int FromStat (ref Stat source, IntPtr destination); }
public static bool TryCopy (ref Stat source, IntPtr destination) public static String ToFopenMode (FileAccess access)
{ {
return FromStat (ref source, destination) == 0; switch (access) {
} case FileAccess.Read: return "rb";
case FileAccess.Write: return "wb";
case FileAccess.ReadWrite: return "r+b";
default: throw new ArgumentOutOfRangeException ("access");
}
}
[DllImport (LIB, EntryPoint="Mono_Posix_ToStat")] public static String ToFopenMode (FileMode mode)
private static extern int ToStat (IntPtr source, out Stat destination); {
switch (mode) {
case FileMode.CreateNew: case FileMode.Create: return "w+b";
case FileMode.Open: case FileMode.OpenOrCreate: return "r+b";
case FileMode.Truncate: return "w+b";
case FileMode.Append: return "a+b";
default: throw new ArgumentOutOfRangeException ("mode");
}
}
public static bool TryCopy (IntPtr source, out Stat destination) private static readonly String[][] fopen_modes = new String[][]{
{ // Read Write ReadWrite
return ToStat (source, out destination) == 0; /* FileMode.CreateNew: */ new String[]{"Can't Read+Create", "wb", "w+b"},
} /* FileMode.Create: */ new String[]{"Can't Read+Create", "wb", "w+b"},
/* FileMode.Open: */ new String[]{"rb", "wb", "r+b"},
/* FileMode.OpenOrCreate: */ new String[]{"rb", "wb", "r+b"},
/* FileMode.Truncate: */ new String[]{"Cannot Truncate and Read","wb", "w+b"},
/* FileMode.Append: */ new String[]{"Cannot Append and Read", "ab", "a+b"},
};
[DllImport (LIB, EntryPoint="Mono_Posix_FromStatvfs")] public static String ToFopenMode (FileMode mode, FileAccess access)
private static extern int FromStatvfs (ref Statvfs source, IntPtr destination); {
Int32 fm = -1, fa = -1;
switch (mode) {
case FileMode.CreateNew: fm = 0; break;
case FileMode.Create: fm = 1; break;
case FileMode.Open: fm = 2; break;
case FileMode.OpenOrCreate: fm = 3; break;
case FileMode.Truncate: fm = 4; break;
case FileMode.Append: fm = 5; break;
}
switch (access) {
case FileAccess.Read: fa = 0; break;
case FileAccess.Write: fa = 1; break;
case FileAccess.ReadWrite: fa = 2; break;
}
public static bool TryCopy (ref Statvfs source, IntPtr destination) if (fm == -1) {
{ throw new ArgumentOutOfRangeException ("mode");
return FromStatvfs (ref source, destination) == 0; }
}
[DllImport (LIB, EntryPoint="Mono_Posix_ToStatvfs")] if (fa == -1) {
private static extern int ToStatvfs (IntPtr source, out Statvfs destination); throw new ArgumentOutOfRangeException ("access");
}
public static bool TryCopy (IntPtr source, out Statvfs destination) String fopen_mode = fopen_modes [fm][fa];
{ if (fopen_mode [0] != 'r' && fopen_mode [0] != 'w' && fopen_mode [0] != 'a') {
return ToStatvfs (source, out destination) == 0; throw new ArgumentException (fopen_mode);
} }
[DllImport (LIB, EntryPoint="Mono_Posix_FromInAddr")] return fopen_mode;
private static extern int FromInAddr (ref InAddr source, IntPtr destination); }
public static bool TryCopy (ref InAddr source, IntPtr destination) [DllImport (LIB, EntryPoint="Mono_Posix_FromStat")]
{ private static extern Int32 FromStat (ref Stat source, IntPtr destination);
return FromInAddr (ref source, destination) == 0;
}
[DllImport (LIB, EntryPoint="Mono_Posix_ToInAddr")] public static Boolean TryCopy(ref Stat source, IntPtr destination) => FromStat(ref source, destination) == 0;
private static extern int ToInAddr (IntPtr source, out InAddr destination);
public static bool TryCopy (IntPtr source, out InAddr destination) [DllImport (LIB, EntryPoint="Mono_Posix_ToStat")]
{ private static extern Int32 ToStat (IntPtr source, out Stat destination);
return ToInAddr (source, out destination) == 0;
}
[DllImport (LIB, EntryPoint="Mono_Posix_FromIn6Addr")] public static Boolean TryCopy(IntPtr source, out Stat destination) => ToStat(source, out destination) == 0;
private static extern int FromIn6Addr (ref In6Addr source, IntPtr destination);
public static bool TryCopy (ref In6Addr source, IntPtr destination) [DllImport (LIB, EntryPoint="Mono_Posix_FromStatvfs")]
{ private static extern Int32 FromStatvfs (ref Statvfs source, IntPtr destination);
return FromIn6Addr (ref source, destination) == 0;
}
[DllImport (LIB, EntryPoint="Mono_Posix_ToIn6Addr")] public static Boolean TryCopy(ref Statvfs source, IntPtr destination) => FromStatvfs(ref source, destination) == 0;
private static extern int ToIn6Addr (IntPtr source, out In6Addr destination);
public static bool TryCopy (IntPtr source, out In6Addr destination) [DllImport (LIB, EntryPoint="Mono_Posix_ToStatvfs")]
{ private static extern Int32 ToStatvfs (IntPtr source, out Statvfs destination);
return ToIn6Addr (source, out destination) == 0;
}
public static InAddr ToInAddr (System.Net.IPAddress address) public static Boolean TryCopy(IntPtr source, out Statvfs destination) => ToStatvfs(source, out destination) == 0;
{
if (address == null)
throw new ArgumentNullException ("address");
if (address.AddressFamily != System.Net.Sockets.AddressFamily.InterNetwork)
throw new ArgumentException ("address", "address.AddressFamily != System.Net.Sockets.AddressFamily.InterNetwork");
return new InAddr (address.GetAddressBytes ());
}
public static System.Net.IPAddress ToIPAddress (InAddr address) [DllImport (LIB, EntryPoint="Mono_Posix_FromInAddr")]
{ private static extern Int32 FromInAddr (ref InAddr source, IntPtr destination);
var bytes = new byte[4];
address.CopyTo (bytes, 0);
return new System.Net.IPAddress (bytes);
}
public static In6Addr ToIn6Addr (System.Net.IPAddress address) public static Boolean TryCopy(ref InAddr source, IntPtr destination) => FromInAddr(ref source, destination) == 0;
{
if (address == null)
throw new ArgumentNullException ("address");
if (address.AddressFamily != System.Net.Sockets.AddressFamily.InterNetworkV6)
throw new ArgumentException ("address", "address.AddressFamily != System.Net.Sockets.AddressFamily.InterNetworkV6");
return new In6Addr (address.GetAddressBytes ());
}
public static System.Net.IPAddress ToIPAddress (In6Addr address) [DllImport (LIB, EntryPoint="Mono_Posix_ToInAddr")]
{ private static extern Int32 ToInAddr (IntPtr source, out InAddr destination);
var bytes = new byte[16];
address.CopyTo (bytes, 0);
return new System.Net.IPAddress (bytes);
}
[DllImport (LIB, EntryPoint="Mono_Posix_FromSockaddr")] public static Boolean TryCopy(IntPtr source, out InAddr destination) => ToInAddr(source, out destination) == 0;
private static extern unsafe int FromSockaddr (_SockaddrHeader* source, IntPtr destination);
public static unsafe bool TryCopy (Sockaddr source, IntPtr destination) [DllImport (LIB, EntryPoint="Mono_Posix_FromIn6Addr")]
{ private static extern Int32 FromIn6Addr (ref In6Addr source, IntPtr destination);
if (source == null)
throw new ArgumentNullException ("source");
byte[] array = Sockaddr.GetDynamicData (source);
// SockaddrStorage has to be handled extra because the native code assumes that SockaddrStorage input is used in-place
if (source.type == (SockaddrType.SockaddrStorage | SockaddrType.MustBeWrapped)) {
Marshal.Copy (array, 0, destination, (int) source.GetDynamicLength ());
return true;
}
fixed (SockaddrType* addr = &Sockaddr.GetAddress (source).type)
fixed (byte* data = array) {
var dyn = new _SockaddrDynamic (source, data, useMaxLength: false);
return FromSockaddr (Sockaddr.GetNative (&dyn, addr), destination) == 0;
}
}
[DllImport (LIB, EntryPoint="Mono_Posix_ToSockaddr")] public static Boolean TryCopy(ref In6Addr source, IntPtr destination) => FromIn6Addr(ref source, destination) == 0;
private static extern unsafe int ToSockaddr (IntPtr source, long size, _SockaddrHeader* destination);
public static unsafe bool TryCopy (IntPtr source, long size, Sockaddr destination) [DllImport (LIB, EntryPoint="Mono_Posix_ToIn6Addr")]
{ private static extern Int32 ToIn6Addr (IntPtr source, out In6Addr destination);
if (destination == null)
throw new ArgumentNullException ("destination"); public static Boolean TryCopy(IntPtr source, out In6Addr destination) => ToIn6Addr(source, out destination) == 0;
byte[] array = Sockaddr.GetDynamicData (destination);
fixed (SockaddrType* addr = &Sockaddr.GetAddress (destination).type) public static InAddr ToInAddr (System.Net.IPAddress address)
fixed (byte* data = Sockaddr.GetDynamicData (destination)) { {
var dyn = new _SockaddrDynamic (destination, data, useMaxLength: true); if (address == null) {
var r = ToSockaddr (source, size, Sockaddr.GetNative (&dyn, addr)); throw new ArgumentNullException ("address");
dyn.Update (destination); }
// SockaddrStorage has to be handled extra because the native code assumes that SockaddrStorage input is used in-place
if (r == 0 && destination.type == (SockaddrType.SockaddrStorage | SockaddrType.MustBeWrapped)) { if (address.AddressFamily != System.Net.Sockets.AddressFamily.InterNetwork) {
Marshal.Copy (source, array, 0, (int) destination.GetDynamicLength ()); throw new ArgumentException ("address", "address.AddressFamily != System.Net.Sockets.AddressFamily.InterNetwork");
} }
return r == 0;
} return new InAddr (address.GetAddressBytes ());
} }
}
public static System.Net.IPAddress ToIPAddress (InAddr address)
{
Byte[] bytes = new Byte[4];
address.CopyTo (bytes, 0);
return new System.Net.IPAddress (bytes);
}
public static In6Addr ToIn6Addr (System.Net.IPAddress address)
{
if (address == null) {
throw new ArgumentNullException ("address");
}
if (address.AddressFamily != System.Net.Sockets.AddressFamily.InterNetworkV6) {
throw new ArgumentException ("address", "address.AddressFamily != System.Net.Sockets.AddressFamily.InterNetworkV6");
}
return new In6Addr (address.GetAddressBytes ());
}
public static System.Net.IPAddress ToIPAddress (In6Addr address)
{
Byte[] bytes = new Byte[16];
address.CopyTo (bytes, 0);
return new System.Net.IPAddress (bytes);
}
[DllImport (LIB, EntryPoint="Mono_Posix_FromSockaddr")]
private static extern unsafe Int32 FromSockaddr (_SockaddrHeader* source, IntPtr destination);
public static unsafe Boolean TryCopy (Sockaddr source, IntPtr destination)
{
if (source == null) {
throw new ArgumentNullException ("source");
}
Byte[] array = Sockaddr.GetDynamicData (source);
// SockaddrStorage has to be handled extra because the native code assumes that SockaddrStorage input is used in-place
if (source.type == (SockaddrType.SockaddrStorage | SockaddrType.MustBeWrapped)) {
Marshal.Copy (array, 0, destination, (Int32) source.GetDynamicLength ());
return true;
}
fixed (SockaddrType* addr = &Sockaddr.GetAddress (source).type)
fixed (Byte* data = array) {
_SockaddrDynamic dyn = new _SockaddrDynamic (source, data, useMaxLength: false);
return FromSockaddr (Sockaddr.GetNative (&dyn, addr), destination) == 0;
}
}
[DllImport (LIB, EntryPoint="Mono_Posix_ToSockaddr")]
private static extern unsafe Int32 ToSockaddr (IntPtr source, Int64 size, _SockaddrHeader* destination);
public static unsafe Boolean TryCopy (IntPtr source, Int64 size, Sockaddr destination)
{
if (destination == null) {
throw new ArgumentNullException ("destination");
}
Byte[] array = Sockaddr.GetDynamicData (destination);
fixed (SockaddrType* addr = &Sockaddr.GetAddress (destination).type)
fixed (Byte* data = Sockaddr.GetDynamicData (destination)) {
_SockaddrDynamic dyn = new _SockaddrDynamic (destination, data, useMaxLength: true);
Int32 r = ToSockaddr (source, size, Sockaddr.GetNative (&dyn, addr));
dyn.Update (destination);
// SockaddrStorage has to be handled extra because the native code assumes that SockaddrStorage input is used in-place
if (r == 0 && destination.type == (SockaddrType.SockaddrStorage | SockaddrType.MustBeWrapped)) {
Marshal.Copy (source, array, 0, (Int32) destination.GetDynamicLength ());
}
return r == 0;
}
}
}
} }
// vim: noexpandtab // vim: noexpandtab

File diff suppressed because it is too large Load Diff

View File

@ -25,57 +25,39 @@
// //
using System; using System;
using System.Runtime.InteropServices;
using System.Threading;
namespace Mono.Unix.Native { namespace Mono.Unix.Native {
public struct RealTimeSignum public struct RealTimeSignum
: IEquatable <RealTimeSignum> : IEquatable <RealTimeSignum>
{ {
private int rt_offset; private static readonly Int32 MaxOffset = UnixSignal.GetSIGRTMAX () - UnixSignal.GetSIGRTMIN () - 1;
private static readonly int MaxOffset = UnixSignal.GetSIGRTMAX () - UnixSignal.GetSIGRTMIN () - 1; public static readonly RealTimeSignum MinValue = new RealTimeSignum (0);
public static readonly RealTimeSignum MinValue = new RealTimeSignum (0); public static readonly RealTimeSignum MaxValue = new RealTimeSignum (MaxOffset);
public static readonly RealTimeSignum MaxValue = new RealTimeSignum (MaxOffset);
public RealTimeSignum (int offset) public RealTimeSignum (Int32 offset)
{ {
if (offset < 0) if (offset < 0) {
throw new ArgumentOutOfRangeException ("Offset cannot be negative"); throw new ArgumentOutOfRangeException ("Offset cannot be negative");
if (offset > MaxOffset) }
throw new ArgumentOutOfRangeException ("Offset greater than maximum supported SIGRT");
rt_offset = offset;
}
public int Offset { if (offset > MaxOffset) {
get { return rt_offset; } throw new ArgumentOutOfRangeException ("Offset greater than maximum supported SIGRT");
} }
public override int GetHashCode () this.Offset = offset;
{ }
return rt_offset.GetHashCode ();
}
public override bool Equals (object obj) public Int32 Offset { get; }
{
if ((obj == null) || (obj.GetType () != GetType ()))
return false;
return Equals ((RealTimeSignum)obj);
}
public bool Equals (RealTimeSignum value) public override Int32 GetHashCode() => this.Offset.GetHashCode();
{
return Offset == value.Offset;
}
public static bool operator== (RealTimeSignum lhs, RealTimeSignum rhs) public override Boolean Equals(Object obj) => obj == null || obj.GetType() != this.GetType() ? false : this.Equals((RealTimeSignum)obj);
{
return lhs.Equals (rhs);
}
public static bool operator!= (RealTimeSignum lhs, RealTimeSignum rhs) public Boolean Equals(RealTimeSignum value) => this.Offset == value.Offset;
{
return !lhs.Equals (rhs); public static Boolean operator ==(RealTimeSignum lhs, RealTimeSignum rhs) => lhs.Equals(rhs);
}
} public static Boolean operator !=(RealTimeSignum lhs, RealTimeSignum rhs) => !lhs.Equals(rhs);
}
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -28,111 +28,125 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// //
using System; using System;
using System.Diagnostics.CodeAnalysis;
namespace Mono.Unix.Native { namespace Mono.Unix.Native {
[AttributeUsage (AttributeTargets.Field)] [AttributeUsage (AttributeTargets.Field)]
internal class blkcnt_tAttribute : MapAttribute { [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
internal class blkcnt_tAttribute : MapAttribute {
public blkcnt_tAttribute () : base ("blkcnt_t") public blkcnt_tAttribute () : base ("blkcnt_t")
{ {
} }
} }
[AttributeUsage (AttributeTargets.Field)] [AttributeUsage (AttributeTargets.Field)]
internal class blksize_tAttribute : MapAttribute { [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
internal class blksize_tAttribute : MapAttribute {
public blksize_tAttribute () : base ("blksize_t") public blksize_tAttribute () : base ("blksize_t")
{ {
} }
} }
[AttributeUsage (AttributeTargets.Field)] [AttributeUsage (AttributeTargets.Field)]
internal class dev_tAttribute : MapAttribute { [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
internal class dev_tAttribute : MapAttribute {
public dev_tAttribute () : base ("dev_t") public dev_tAttribute () : base ("dev_t")
{ {
} }
} }
[AttributeUsage (AttributeTargets.Field)] [AttributeUsage (AttributeTargets.Field)]
internal class gid_tAttribute : MapAttribute { [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
internal class gid_tAttribute : MapAttribute {
public gid_tAttribute () : base ("gid_t") public gid_tAttribute () : base ("gid_t")
{ {
} }
} }
[AttributeUsage (AttributeTargets.Field)] [AttributeUsage (AttributeTargets.Field)]
internal class fsblkcnt_tAttribute : MapAttribute { [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
internal class fsblkcnt_tAttribute : MapAttribute {
public fsblkcnt_tAttribute () : base ("fsblkcnt_t") public fsblkcnt_tAttribute () : base ("fsblkcnt_t")
{ {
} }
} }
[AttributeUsage (AttributeTargets.Field)] [AttributeUsage (AttributeTargets.Field)]
internal class fsfilcnt_tAttribute : MapAttribute { [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
internal class fsfilcnt_tAttribute : MapAttribute {
public fsfilcnt_tAttribute () : base ("fsfilcnt_t") public fsfilcnt_tAttribute () : base ("fsfilcnt_t")
{ {
} }
} }
[AttributeUsage (AttributeTargets.Field)] [AttributeUsage (AttributeTargets.Field)]
internal class ino_tAttribute : MapAttribute { [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
internal class ino_tAttribute : MapAttribute {
public ino_tAttribute () : base ("ino_t") public ino_tAttribute () : base ("ino_t")
{ {
} }
} }
[AttributeUsage (AttributeTargets.Field)] [AttributeUsage (AttributeTargets.Field)]
internal class nlink_tAttribute : MapAttribute { [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
internal class nlink_tAttribute : MapAttribute {
public nlink_tAttribute () : base ("nlink_t") public nlink_tAttribute () : base ("nlink_t")
{ {
} }
} }
[AttributeUsage (AttributeTargets.Field)] [AttributeUsage (AttributeTargets.Field)]
internal class off_tAttribute : MapAttribute { [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
internal class off_tAttribute : MapAttribute {
public off_tAttribute () : base ("off_t") public off_tAttribute () : base ("off_t")
{ {
} }
} }
[AttributeUsage (AttributeTargets.Field)] [AttributeUsage (AttributeTargets.Field)]
internal class pid_tAttribute : MapAttribute { [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
internal class pid_tAttribute : MapAttribute {
public pid_tAttribute () : base ("pid_t") public pid_tAttribute () : base ("pid_t")
{ {
} }
} }
[AttributeUsage (AttributeTargets.Field)] [AttributeUsage (AttributeTargets.Field)]
internal class suseconds_tAttribute : MapAttribute { [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
internal class suseconds_tAttribute : MapAttribute {
public suseconds_tAttribute () : base ("suseconds_t") public suseconds_tAttribute () : base ("suseconds_t")
{ {
} }
} }
[AttributeUsage (AttributeTargets.Field)] [AttributeUsage (AttributeTargets.Field)]
internal class uid_tAttribute : MapAttribute { [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
internal class uid_tAttribute : MapAttribute {
public uid_tAttribute () : base ("uid_t") public uid_tAttribute () : base ("uid_t")
{ {
} }
} }
[AttributeUsage (AttributeTargets.Field)] [AttributeUsage (AttributeTargets.Field)]
internal class time_tAttribute : MapAttribute { [SuppressMessage("Microsoft.Design","IDE1006", Justification = "Can not change name!")]
internal class time_tAttribute : MapAttribute {
public time_tAttribute () : base ("time_t") public time_tAttribute () : base ("time_t")
{ {
} }
} }
} }

View File

@ -36,88 +36,82 @@ using System.Text;
namespace Mono.Unix namespace Mono.Unix
{ {
[Serializable] [Serializable]
public class AbstractUnixEndPoint : EndPoint public class AbstractUnixEndPoint : EndPoint
{ {
string path; String path;
public AbstractUnixEndPoint (string path) public AbstractUnixEndPoint (String path)
{ {
if (path == null) if (path == null) {
throw new ArgumentNullException ("path"); throw new ArgumentNullException ("path");
}
if (path == "") if (path == "") {
throw new ArgumentException ("Cannot be empty.", "path"); throw new ArgumentException ("Cannot be empty.", "path");
this.path = path; }
}
public string Path { this.path = path;
get { }
return(path);
}
set {
path=value;
}
}
public override AddressFamily AddressFamily { public String Path {
get { return AddressFamily.Unix; } get => this.path;
} set => this.path = value;
}
public override EndPoint Create (SocketAddress socketAddress) public override AddressFamily AddressFamily => AddressFamily.Unix;
{
/*
* Should also check this
*
int addr = (int) AddressFamily.Unix;
if (socketAddress [0] != (addr & 0xFF))
throw new ArgumentException ("socketAddress is not a unix socket address.");
if (socketAddress [1] != ((addr & 0xFF00) >> 8)) public override EndPoint Create (SocketAddress socketAddress)
throw new ArgumentException ("socketAddress is not a unix socket address."); {
*/ /*
* Should also check this
*
int addr = (int) AddressFamily.Unix;
if (socketAddress [0] != (addr & 0xFF))
throw new ArgumentException ("socketAddress is not a unix socket address.");
byte [] bytes = new byte [socketAddress.Size - 2 - 1]; if (socketAddress [1] != ((addr & 0xFF00) >> 8))
for (int i = 0; i < bytes.Length; i++) { throw new ArgumentException ("socketAddress is not a unix socket address.");
bytes [i] = socketAddress [2 + 1 + i]; */
}
string name = Encoding.Default.GetString (bytes); Byte[] bytes = new Byte[socketAddress.Size - 2 - 1];
return new AbstractUnixEndPoint (name); for (Int32 i = 0; i < bytes.Length; i++) {
} bytes [i] = socketAddress [2 + 1 + i];
}
public override SocketAddress Serialize () String name = Encoding.Default.GetString (bytes);
{ return new AbstractUnixEndPoint (name);
byte [] bytes = Encoding.Default.GetBytes (path); }
SocketAddress sa = new SocketAddress (AddressFamily, 2 + 1 + bytes.Length);
//NULL prefix denotes the abstract namespace, see unix(7)
//in this case, there is no NULL suffix
sa [2] = 0;
// sa [0] -> family low byte, sa [1] -> family high byte public override SocketAddress Serialize ()
for (int i = 0; i < bytes.Length; i++) {
sa [i + 2 + 1] = bytes [i]; Byte[] bytes = Encoding.Default.GetBytes (this.path);
SocketAddress sa = new SocketAddress (this.AddressFamily, 2 + 1 + bytes.Length);
//NULL prefix denotes the abstract namespace, see unix(7)
//in this case, there is no NULL suffix
sa [2] = 0;
return sa; // sa [0] -> family low byte, sa [1] -> family high byte
} for (Int32 i = 0; i < bytes.Length; i++) {
sa [i + 2 + 1] = bytes [i];
}
public override string ToString() { return sa;
return(path); }
}
public override int GetHashCode () public override String ToString() => this.path;
{
return path.GetHashCode ();
}
public override bool Equals (object o) public override Int32 GetHashCode() => this.path.GetHashCode();
{
AbstractUnixEndPoint other = o as AbstractUnixEndPoint;
if (other == null)
return false;
return (other.path == path); public override Boolean Equals (Object o)
} {
} AbstractUnixEndPoint other = o as AbstractUnixEndPoint;
if (other == null) {
return false;
}
return other.path == this.path;
}
}
} }

View File

@ -33,104 +33,112 @@
// //
using System; using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Mono.Unix { namespace Mono.Unix {
public class Catalog { public class Catalog {
private Catalog () {} private Catalog () {}
[DllImport("intl", CallingConvention=CallingConvention.Cdecl)] [DllImport("intl", CallingConvention=CallingConvention.Cdecl)]
static extern IntPtr bindtextdomain (IntPtr domainname, IntPtr dirname); [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
[DllImport("intl", CallingConvention=CallingConvention.Cdecl)] static extern IntPtr bindtextdomain (IntPtr domainname, IntPtr dirname);
static extern IntPtr bind_textdomain_codeset (IntPtr domainname, [DllImport("intl", CallingConvention=CallingConvention.Cdecl)]
IntPtr codeset); [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
[DllImport("intl", CallingConvention=CallingConvention.Cdecl)] static extern IntPtr bind_textdomain_codeset (IntPtr domainname,
static extern IntPtr textdomain (IntPtr domainname); IntPtr codeset);
[DllImport("intl", CallingConvention=CallingConvention.Cdecl)]
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
static extern IntPtr textdomain (IntPtr domainname);
public static void Init (String package, String localedir) public static void Init (String package, String localedir)
{ {
IntPtr ipackage, ilocaledir, iutf8; MarshalStrings(package, out IntPtr ipackage, localedir, out IntPtr ilocaledir,
MarshalStrings (package, out ipackage, localedir, out ilocaledir, "UTF-8", out IntPtr iutf8);
"UTF-8", out iutf8); try {
try { if (bindtextdomain (ipackage, ilocaledir) == IntPtr.Zero) {
if (bindtextdomain (ipackage, ilocaledir) == IntPtr.Zero) throw new UnixIOException (Native.Errno.ENOMEM);
throw new UnixIOException (Native.Errno.ENOMEM); }
if (bind_textdomain_codeset (ipackage, iutf8) == IntPtr.Zero)
throw new UnixIOException (Native.Errno.ENOMEM);
if (textdomain (ipackage) == IntPtr.Zero)
throw new UnixIOException (Native.Errno.ENOMEM);
}
finally {
UnixMarshal.FreeHeap (ipackage);
UnixMarshal.FreeHeap (ilocaledir);
UnixMarshal.FreeHeap (iutf8);
}
}
private static void MarshalStrings (string s1, out IntPtr p1, if (bind_textdomain_codeset (ipackage, iutf8) == IntPtr.Zero) {
string s2, out IntPtr p2, string s3, out IntPtr p3) throw new UnixIOException (Native.Errno.ENOMEM);
{ }
p1 = p2 = p3 = IntPtr.Zero;
bool cleanup = true; if (textdomain (ipackage) == IntPtr.Zero) {
throw new UnixIOException (Native.Errno.ENOMEM);
}
}
finally {
UnixMarshal.FreeHeap (ipackage);
UnixMarshal.FreeHeap (ilocaledir);
UnixMarshal.FreeHeap (iutf8);
}
}
try { private static void MarshalStrings (String s1, out IntPtr p1,
p1 = UnixMarshal.StringToHeap (s1); String s2, out IntPtr p2, String s3, out IntPtr p3)
p2 = UnixMarshal.StringToHeap (s2); {
if (s3 != null) p1 = p2 = p3 = IntPtr.Zero;
p3 = UnixMarshal.StringToHeap (s3);
cleanup = false;
}
finally {
if (cleanup) {
UnixMarshal.FreeHeap (p1);
UnixMarshal.FreeHeap (p2);
UnixMarshal.FreeHeap (p3);
}
}
}
[DllImport("intl", CallingConvention=CallingConvention.Cdecl)] Boolean cleanup = true;
static extern IntPtr gettext (IntPtr instring);
public static String GetString (String s) try {
{ p1 = UnixMarshal.StringToHeap (s1);
IntPtr ints = UnixMarshal.StringToHeap (s); p2 = UnixMarshal.StringToHeap (s2);
try { if (s3 != null) {
// gettext(3) returns the input pointer if no translation is found p3 = UnixMarshal.StringToHeap (s3);
IntPtr r = gettext (ints); }
if (r != ints)
return UnixMarshal.PtrToStringUnix (r);
return s;
}
finally {
UnixMarshal.FreeHeap (ints);
}
}
[DllImport("intl", CallingConvention=CallingConvention.Cdecl)] cleanup = false;
static extern IntPtr ngettext (IntPtr singular, IntPtr plural, Int32 n); }
finally {
if (cleanup) {
UnixMarshal.FreeHeap (p1);
UnixMarshal.FreeHeap (p2);
UnixMarshal.FreeHeap (p3);
}
}
}
public static String GetPluralString (String s, String p, Int32 n) [DllImport("intl", CallingConvention=CallingConvention.Cdecl)]
{ [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
IntPtr ints, intp, _ignore; static extern IntPtr gettext (IntPtr instring);
MarshalStrings (s, out ints, p, out intp, null, out _ignore);
try { public static String GetString (String s)
// ngettext(3) returns an input pointer if no translation is found {
IntPtr r = ngettext (ints, intp, n); IntPtr ints = UnixMarshal.StringToHeap (s);
if (r == ints) try {
return s; // gettext(3) returns the input pointer if no translation is found
if (r == intp) IntPtr r = gettext (ints);
return p; if (r != ints) {
return UnixMarshal.PtrToStringUnix (r); return UnixMarshal.PtrToStringUnix (r);
} }
finally {
UnixMarshal.FreeHeap (ints); return s;
UnixMarshal.FreeHeap (intp); }
} finally {
} UnixMarshal.FreeHeap (ints);
} }
}
[DllImport("intl", CallingConvention=CallingConvention.Cdecl)]
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
static extern IntPtr ngettext (IntPtr singular, IntPtr plural, Int32 n);
public static String GetPluralString (String s, String p, Int32 n)
{
MarshalStrings(s, out IntPtr ints, p, out IntPtr intp, null, out IntPtr _ignore);
try {
// ngettext(3) returns an input pointer if no translation is found
IntPtr r = ngettext (ints, intp, n);
return r == ints ? s : r == intp ? p : UnixMarshal.PtrToStringUnix (r);
} finally {
UnixMarshal.FreeHeap (ints);
UnixMarshal.FreeHeap (intp);
}
}
}
} }

View File

@ -31,13 +31,13 @@ using Mono.Unix;
namespace Mono.Unix { namespace Mono.Unix {
public enum FileAccessPattern { public enum FileAccessPattern {
Normal = Native.PosixFadviseAdvice.POSIX_FADV_NORMAL, Normal = Native.PosixFadviseAdvice.POSIX_FADV_NORMAL,
Sequential = Native.PosixFadviseAdvice.POSIX_FADV_SEQUENTIAL, Sequential = Native.PosixFadviseAdvice.POSIX_FADV_SEQUENTIAL,
Random = Native.PosixFadviseAdvice.POSIX_FADV_RANDOM, Random = Native.PosixFadviseAdvice.POSIX_FADV_RANDOM,
NoReuse = Native.PosixFadviseAdvice.POSIX_FADV_NOREUSE, NoReuse = Native.PosixFadviseAdvice.POSIX_FADV_NOREUSE,
PreLoad = Native.PosixFadviseAdvice.POSIX_FADV_WILLNEED, PreLoad = Native.PosixFadviseAdvice.POSIX_FADV_WILLNEED,
FlushCache = Native.PosixFadviseAdvice.POSIX_FADV_DONTNEED, FlushCache = Native.PosixFadviseAdvice.POSIX_FADV_DONTNEED,
} }
} }

View File

@ -31,23 +31,23 @@ using Mono.Unix;
namespace Mono.Unix { namespace Mono.Unix {
[Flags] [Flags]
public enum FileAccessPermissions { public enum FileAccessPermissions {
UserReadWriteExecute = (int) Native.FilePermissions.S_IRWXU, UserReadWriteExecute = (Int32) Native.FilePermissions.S_IRWXU,
UserRead = (int) Native.FilePermissions.S_IRUSR, UserRead = (Int32) Native.FilePermissions.S_IRUSR,
UserWrite = (int) Native.FilePermissions.S_IWUSR, UserWrite = (Int32) Native.FilePermissions.S_IWUSR,
UserExecute = (int) Native.FilePermissions.S_IXUSR, UserExecute = (Int32) Native.FilePermissions.S_IXUSR,
GroupReadWriteExecute = (int) Native.FilePermissions.S_IRWXG, GroupReadWriteExecute = (Int32) Native.FilePermissions.S_IRWXG,
GroupRead = (int) Native.FilePermissions.S_IRGRP, GroupRead = (Int32) Native.FilePermissions.S_IRGRP,
GroupWrite = (int) Native.FilePermissions.S_IWGRP, GroupWrite = (Int32) Native.FilePermissions.S_IWGRP,
GroupExecute = (int) Native.FilePermissions.S_IXGRP, GroupExecute = (Int32) Native.FilePermissions.S_IXGRP,
OtherReadWriteExecute = (int) Native.FilePermissions.S_IRWXO, OtherReadWriteExecute = (Int32) Native.FilePermissions.S_IRWXO,
OtherRead = (int) Native.FilePermissions.S_IROTH, OtherRead = (Int32) Native.FilePermissions.S_IROTH,
OtherWrite = (int) Native.FilePermissions.S_IWOTH, OtherWrite = (Int32) Native.FilePermissions.S_IWOTH,
OtherExecute = (int) Native.FilePermissions.S_IXOTH, OtherExecute = (Int32) Native.FilePermissions.S_IXOTH,
DefaultPermissions = (int) Native.FilePermissions.DEFFILEMODE, DefaultPermissions = (Int32) Native.FilePermissions.DEFFILEMODE,
AllPermissions = (int) Native.FilePermissions.ACCESSPERMS, AllPermissions = (Int32) Native.FilePermissions.ACCESSPERMS,
} }
} }

View File

@ -27,56 +27,53 @@
// //
using System; using System;
using System.Diagnostics.CodeAnalysis;
using System.IO; using System.IO;
using System.Text; using System.Text;
using Mono.Unix; using Mono.Unix;
namespace Mono.Unix { namespace Mono.Unix {
public sealed /* static */ class FileHandleOperations public sealed /* static */ class FileHandleOperations
{ {
private FileHandleOperations () {} private FileHandleOperations () {}
public static void AdviseFileAccessPattern (int fd, FileAccessPattern pattern, long offset, long len) public static void AdviseFileAccessPattern (Int32 fd, FileAccessPattern pattern, Int64 offset, Int64 len)
{ {
int r = Native.Syscall.posix_fadvise (fd, offset, len, Int32 r = Native.Syscall.posix_fadvise (fd, offset, len,
(Native.PosixFadviseAdvice) pattern); (Native.PosixFadviseAdvice) pattern);
UnixMarshal.ThrowExceptionForLastErrorIf (r); UnixMarshal.ThrowExceptionForLastErrorIf (r);
} }
public static void AdviseFileAccessPattern (int fd, FileAccessPattern pattern) public static void AdviseFileAccessPattern(Int32 fd, FileAccessPattern pattern) => AdviseFileAccessPattern(fd, pattern, 0, 0);
{
AdviseFileAccessPattern (fd, pattern, 0, 0);
}
public static void AdviseFileAccessPattern (FileStream file, FileAccessPattern pattern, long offset, long len) [SuppressMessage("Microsoft.Design", "CS0618", Justification = "Someone do shit")]
{ public static void AdviseFileAccessPattern (FileStream file, FileAccessPattern pattern, Int64 offset, Int64 len)
if (file == null) {
throw new ArgumentNullException ("file"); if (file == null) {
int r = Native.Syscall.posix_fadvise (file.Handle.ToInt32(), offset, len, throw new ArgumentNullException ("file");
(Native.PosixFadviseAdvice) pattern); }
UnixMarshal.ThrowExceptionForLastErrorIf (r);
}
public static void AdviseFileAccessPattern (FileStream file, FileAccessPattern pattern) Int32 r = Native.Syscall.posix_fadvise (file.Handle.ToInt32(), offset, len,
{ (Native.PosixFadviseAdvice) pattern);
AdviseFileAccessPattern (file, pattern, 0, 0); UnixMarshal.ThrowExceptionForLastErrorIf (r);
} }
public static void AdviseFileAccessPattern (UnixStream stream, FileAccessPattern pattern, long offset, long len) public static void AdviseFileAccessPattern(FileStream file, FileAccessPattern pattern) => AdviseFileAccessPattern(file, pattern, 0, 0);
{
if (stream == null)
throw new ArgumentNullException ("stream");
int r = Native.Syscall.posix_fadvise (stream.Handle, offset, len,
(Native.PosixFadviseAdvice) pattern);
UnixMarshal.ThrowExceptionForLastErrorIf (r);
}
public static void AdviseFileAccessPattern (UnixStream stream, FileAccessPattern pattern) public static void AdviseFileAccessPattern (UnixStream stream, FileAccessPattern pattern, Int64 offset, Int64 len)
{ {
AdviseFileAccessPattern (stream, pattern, 0, 0); if (stream == null) {
} throw new ArgumentNullException ("stream");
} }
Int32 r = Native.Syscall.posix_fadvise (stream.Handle, offset, len,
(Native.PosixFadviseAdvice) pattern);
UnixMarshal.ThrowExceptionForLastErrorIf (r);
}
public static void AdviseFileAccessPattern(UnixStream stream, FileAccessPattern pattern) => AdviseFileAccessPattern(stream, pattern, 0, 0);
}
} }
// vim: noexpandtab // vim: noexpandtab

View File

@ -31,11 +31,11 @@ using Mono.Unix;
namespace Mono.Unix { namespace Mono.Unix {
[Flags] [Flags]
public enum FileSpecialAttributes { public enum FileSpecialAttributes {
SetUserId = (int) Native.FilePermissions.S_ISUID, SetUserId = (Int32) Native.FilePermissions.S_ISUID,
SetGroupId = (int) Native.FilePermissions.S_ISGID, SetGroupId = (Int32) Native.FilePermissions.S_ISGID,
Sticky = (int) Native.FilePermissions.S_ISVTX, Sticky = (Int32) Native.FilePermissions.S_ISVTX,
} }
} }

View File

@ -31,14 +31,15 @@ using Mono.Unix;
namespace Mono.Unix { namespace Mono.Unix {
public enum FileTypes { public enum FileTypes {
Directory = (int) Native.FilePermissions.S_IFDIR, Directory = (Int32) Native.FilePermissions.S_IFDIR,
CharacterDevice = (int) Native.FilePermissions.S_IFCHR, CharacterDevice = (Int32) Native.FilePermissions.S_IFCHR,
BlockDevice = (int) Native.FilePermissions.S_IFBLK, BlockDevice = (Int32) Native.FilePermissions.S_IFBLK,
RegularFile = (int) Native.FilePermissions.S_IFREG, RegularFile = (Int32) Native.FilePermissions.S_IFREG,
Fifo = (int) Native.FilePermissions.S_IFIFO, Fifo = (Int32) Native.FilePermissions.S_IFIFO,
SymbolicLink = (int) Native.FilePermissions.S_IFLNK, SymbolicLink = (Int32) Native.FilePermissions.S_IFLNK,
Socket = (int) Native.FilePermissions.S_IFSOCK, Socket = (Int32) Native.FilePermissions.S_IFSOCK,
} }
} }

View File

@ -34,48 +34,36 @@ using System.Net.Sockets;
namespace Mono.Unix namespace Mono.Unix
{ {
#pragma warning disable 649 #pragma warning disable 649
internal struct PeerCredData { internal struct PeerCredData {
public int pid; public Int32 pid;
public int uid; public Int32 uid;
public int gid; public Int32 gid;
} }
#pragma warning restore 649 #pragma warning restore 649
public class PeerCred public class PeerCred
{ {
/* Make sure this doesn't clash with anything in /* Make sure this doesn't clash with anything in
* SocketOptionName, and keep it synchronised with the * SocketOptionName, and keep it synchronised with the
* runtime * runtime
*/ */
private const int so_peercred=10001; private const Int32 so_peercred =10001;
private PeerCredData data; private PeerCredData data;
public PeerCred (Socket sock) { public PeerCred (Socket sock) {
if (sock.AddressFamily != AddressFamily.Unix) { if (sock.AddressFamily != AddressFamily.Unix) {
throw new ArgumentException ("Only Unix sockets are supported", "sock"); throw new ArgumentException ("Only Unix sockets are supported", "sock");
} }
data = (PeerCredData) this.data = (PeerCredData)
sock.GetSocketOption (SocketOptionLevel.Socket, (SocketOptionName)so_peercred); sock.GetSocketOption (SocketOptionLevel.Socket, (SocketOptionName)so_peercred);
} }
public int ProcessID { public Int32 ProcessID => this.data.pid;
get {
return(data.pid);
}
}
public int UserID { public Int32 UserID => this.data.uid;
get {
return(data.uid);
}
}
public int GroupID { public Int32 GroupID => this.data.gid;
get { }
return(data.gid);
}
}
}
} }

View File

@ -34,373 +34,424 @@ using Mono.Unix;
namespace Mono.Unix { namespace Mono.Unix {
public class StdioFileStream : Stream public class StdioFileStream : Stream
{ {
public static readonly IntPtr InvalidFileStream = IntPtr.Zero; public static readonly IntPtr InvalidFileStream = IntPtr.Zero;
public static readonly IntPtr StandardInput = Native.Stdlib.stdin; public static readonly IntPtr StandardInput = Native.Stdlib.stdin;
public static readonly IntPtr StandardOutput = Native.Stdlib.stdout; public static readonly IntPtr StandardOutput = Native.Stdlib.stdout;
public static readonly IntPtr StandardError = Native.Stdlib.stderr; public static readonly IntPtr StandardError = Native.Stdlib.stderr;
public StdioFileStream (IntPtr fileStream) public StdioFileStream (IntPtr fileStream)
: this (fileStream, true) {} : this (fileStream, true) {}
public StdioFileStream (IntPtr fileStream, bool ownsHandle) public StdioFileStream(IntPtr fileStream, Boolean ownsHandle) => this.InitStream(fileStream, ownsHandle);
{
InitStream (fileStream, ownsHandle);
}
public StdioFileStream (IntPtr fileStream, FileAccess access) public StdioFileStream (IntPtr fileStream, FileAccess access)
: this (fileStream, access, true) {} : this (fileStream, access, true) {}
public StdioFileStream (IntPtr fileStream, FileAccess access, bool ownsHandle) public StdioFileStream (IntPtr fileStream, FileAccess access, Boolean ownsHandle)
{ {
InitStream (fileStream, ownsHandle); this.InitStream (fileStream, ownsHandle);
InitCanReadWrite (access); this.InitCanReadWrite (access);
} }
public StdioFileStream (string path) public StdioFileStream (String path)
{ {
if (path == null) if (path == null) {
throw new ArgumentNullException ("path"); throw new ArgumentNullException ("path");
InitStream (Fopen (path, "rb"), true); }
}
public StdioFileStream (string path, string mode) this.InitStream (Fopen (path, "rb"), true);
{ }
if (path == null)
throw new ArgumentNullException ("path");
InitStream (Fopen (path, mode), true);
}
public StdioFileStream (string path, FileMode mode) public StdioFileStream (String path, String mode)
{ {
if (path == null) if (path == null) {
throw new ArgumentNullException ("path"); throw new ArgumentNullException ("path");
InitStream (Fopen (path, ToFopenMode (path, mode)), true); }
}
public StdioFileStream (string path, FileAccess access) this.InitStream (Fopen (path, mode), true);
{ }
if (path == null)
throw new ArgumentNullException ("path");
InitStream (Fopen (path, ToFopenMode (path, access)), true);
InitCanReadWrite (access);
}
public StdioFileStream (string path, FileMode mode, FileAccess access) public StdioFileStream (String path, FileMode mode)
{ {
if (path == null) if (path == null) {
throw new ArgumentNullException ("path"); throw new ArgumentNullException ("path");
InitStream (Fopen (path, ToFopenMode (path, mode, access)), true); }
InitCanReadWrite (access);
}
private static IntPtr Fopen (string path, string mode) this.InitStream (Fopen (path, ToFopenMode (path, mode)), true);
{ }
if (path.Length == 0)
throw new ArgumentException ("path");
if (mode == null)
throw new ArgumentNullException ("mode");
IntPtr f = Native.Stdlib.fopen (path, mode);
if (f == IntPtr.Zero)
throw new DirectoryNotFoundException ("path",
UnixMarshal.CreateExceptionForLastError ());
return f;
}
private void InitStream (IntPtr fileStream, bool ownsHandle) public StdioFileStream (String path, FileAccess access)
{ {
if (InvalidFileStream == fileStream) if (path == null) {
throw new ArgumentException (Locale.GetText ("Invalid file stream"), "fileStream"); throw new ArgumentNullException ("path");
}
this.file = fileStream; this.InitStream (Fopen (path, ToFopenMode (path, access)), true);
this.owner = ownsHandle; this.InitCanReadWrite (access);
}
try { public StdioFileStream (String path, FileMode mode, FileAccess access)
long offset = Native.Stdlib.fseek (file, 0, Native.SeekFlags.SEEK_CUR); {
if (offset != -1) if (path == null) {
canSeek = true; throw new ArgumentNullException ("path");
Native.Stdlib.fread (IntPtr.Zero, 0, 0, file); }
if (Native.Stdlib.ferror (file) == 0)
canRead = true;
Native.Stdlib.fwrite (IntPtr.Zero, 0, 0, file);
if (Native.Stdlib.ferror (file) == 0)
canWrite = true;
Native.Stdlib.clearerr (file);
}
catch (Exception) {
throw new ArgumentException (Locale.GetText ("Invalid file stream"), "fileStream");
}
GC.KeepAlive (this);
}
private void InitCanReadWrite (FileAccess access) this.InitStream (Fopen (path, ToFopenMode (path, mode, access)), true);
{ this.InitCanReadWrite (access);
canRead = canRead && }
(access == FileAccess.Read || access == FileAccess.ReadWrite);
canWrite = canWrite &&
(access == FileAccess.Write || access == FileAccess.ReadWrite);
}
private static string ToFopenMode (string file, FileMode mode) private static IntPtr Fopen (String path, String mode)
{ {
string cmode = Native.NativeConvert.ToFopenMode (mode); if (path.Length == 0) {
AssertFileMode (file, mode); throw new ArgumentException ("path");
return cmode; }
}
private static string ToFopenMode (string file, FileAccess access) if (mode == null) {
{ throw new ArgumentNullException ("mode");
return Native.NativeConvert.ToFopenMode (access); }
}
private static string ToFopenMode (string file, FileMode mode, FileAccess access) IntPtr f = Native.Stdlib.fopen (path, mode);
{ if (f == IntPtr.Zero) {
string cmode = Native.NativeConvert.ToFopenMode (mode, access); throw new DirectoryNotFoundException ("path",
bool exists = AssertFileMode (file, mode); UnixMarshal.CreateExceptionForLastError ());
// HACK: for open-or-create & read, mode is "rb", which doesn't create }
// files. If the file doesn't exist, we need to use "w+b" to ensure
// file creation.
if (mode == FileMode.OpenOrCreate && access == FileAccess.Read && !exists)
cmode = "w+b";
return cmode;
}
private static bool AssertFileMode (string file, FileMode mode) return f;
{ }
bool exists = FileExists (file);
if (mode == FileMode.CreateNew && exists)
throw new IOException ("File exists and FileMode.CreateNew specified");
if ((mode == FileMode.Open || mode == FileMode.Truncate) && !exists)
throw new FileNotFoundException ("File doesn't exist and FileMode.Open specified", file);
return exists;
}
private static bool FileExists (string file) private void InitStream (IntPtr fileStream, Boolean ownsHandle)
{ {
bool found = false; if (InvalidFileStream == fileStream) {
IntPtr f = Native.Stdlib.fopen (file, "r"); throw new ArgumentException (Locale.GetText ("Invalid file stream"), "fileStream");
found = f != IntPtr.Zero; }
if (f != IntPtr.Zero)
Native.Stdlib.fclose (f);
return found;
}
private void AssertNotDisposed () this.file = fileStream;
{ this.owner = ownsHandle;
if (file == InvalidFileStream)
throw new ObjectDisposedException ("Invalid File Stream");
GC.KeepAlive (this);
}
public IntPtr Handle { try {
get { Int64 offset = Native.Stdlib.fseek (this.file, 0, Native.SeekFlags.SEEK_CUR);
AssertNotDisposed (); if (offset != -1) {
GC.KeepAlive (this); this.canSeek = true;
return file; }
}
}
public override bool CanRead { _ = Native.Stdlib.fread(IntPtr.Zero, 0, 0, this.file);
get {return canRead;} if (Native.Stdlib.ferror (this.file) == 0) {
} this.canRead = true;
}
public override bool CanSeek { _ = Native.Stdlib.fwrite(IntPtr.Zero, 0, 0, this.file);
get {return canSeek;} if (Native.Stdlib.ferror (this.file) == 0) {
} this.canWrite = true;
}
public override bool CanWrite { _ = Native.Stdlib.clearerr(this.file);
get {return canWrite;} }
} catch (Exception) {
throw new ArgumentException (Locale.GetText ("Invalid file stream"), "fileStream");
}
GC.KeepAlive (this);
}
public override long Length { private void InitCanReadWrite (FileAccess access)
get { {
AssertNotDisposed (); this.canRead = this.canRead &&
if (!CanSeek) (access == FileAccess.Read || access == FileAccess.ReadWrite);
throw new NotSupportedException ("File Stream doesn't support seeking"); this.canWrite = this.canWrite &&
long curPos = Native.Stdlib.ftell (file); (access == FileAccess.Write || access == FileAccess.ReadWrite);
if (curPos == -1) }
throw new NotSupportedException ("Unable to obtain current file position");
int r = Native.Stdlib.fseek (file, 0, Native.SeekFlags.SEEK_END);
UnixMarshal.ThrowExceptionForLastErrorIf (r);
long endPos = Native.Stdlib.ftell (file); private static String ToFopenMode (String file, FileMode mode)
if (endPos == -1) {
UnixMarshal.ThrowExceptionForLastError (); String cmode = Native.NativeConvert.ToFopenMode (mode);
_ = AssertFileMode(file, mode);
return cmode;
}
r = Native.Stdlib.fseek (file, curPos, Native.SeekFlags.SEEK_SET); private static String ToFopenMode(String file, FileAccess access) => Native.NativeConvert.ToFopenMode(access);
UnixMarshal.ThrowExceptionForLastErrorIf (r);
GC.KeepAlive (this); private static String ToFopenMode (String file, FileMode mode, FileAccess access)
return endPos; {
} String cmode = Native.NativeConvert.ToFopenMode (mode, access);
} Boolean exists = AssertFileMode (file, mode);
// HACK: for open-or-create & read, mode is "rb", which doesn't create
// files. If the file doesn't exist, we need to use "w+b" to ensure
// file creation.
if (mode == FileMode.OpenOrCreate && access == FileAccess.Read && !exists) {
cmode = "w+b";
}
public override long Position { return cmode;
get { }
AssertNotDisposed ();
if (!CanSeek)
throw new NotSupportedException ("The stream does not support seeking");
long pos = Native.Stdlib.ftell (file);
if (pos == -1)
UnixMarshal.ThrowExceptionForLastError ();
GC.KeepAlive (this);
return (long) pos;
}
set {
AssertNotDisposed ();
Seek (value, SeekOrigin.Begin);
}
}
public void SaveFilePosition (Native.FilePosition pos) private static Boolean AssertFileMode (String file, FileMode mode)
{ {
AssertNotDisposed (); Boolean exists = FileExists (file);
int r = Native.Stdlib.fgetpos (file, pos); if (mode == FileMode.CreateNew && exists) {
UnixMarshal.ThrowExceptionForLastErrorIf (r); throw new IOException ("File exists and FileMode.CreateNew specified");
GC.KeepAlive (this); }
}
public void RestoreFilePosition (Native.FilePosition pos) if ((mode == FileMode.Open || mode == FileMode.Truncate) && !exists) {
{ throw new FileNotFoundException ("File doesn't exist and FileMode.Open specified", file);
AssertNotDisposed (); }
if (pos == null)
throw new ArgumentNullException ("value");
int r = Native.Stdlib.fsetpos (file, pos);
UnixMarshal.ThrowExceptionForLastErrorIf (r);
GC.KeepAlive (this);
}
public override void Flush () return exists;
{ }
AssertNotDisposed ();
int r = Native.Stdlib.fflush (file);
if (r != 0)
UnixMarshal.ThrowExceptionForLastError ();
GC.KeepAlive (this);
}
public override unsafe int Read ([In, Out] byte[] buffer, int offset, int count) private static Boolean FileExists (String file)
{ {
AssertNotDisposed (); Boolean found = false;
AssertValidBuffer (buffer, offset, count); IntPtr f = Native.Stdlib.fopen (file, "r");
if (!CanRead) found = f != IntPtr.Zero;
throw new NotSupportedException ("Stream does not support reading"); if (f != IntPtr.Zero) {
_ = Native.Stdlib.fclose(f);
}
ulong r = 0; return found;
fixed (byte* buf = &buffer[offset]) { }
r = Native.Stdlib.fread (buf, 1, (ulong) count, file);
}
if (r != (ulong) count) {
if (Native.Stdlib.ferror (file) != 0)
throw new IOException ();
}
GC.KeepAlive (this);
return (int) r;
}
private void AssertValidBuffer (byte[] buffer, int offset, int count) private void AssertNotDisposed ()
{ {
if (buffer == null) if (this.file == InvalidFileStream) {
throw new ArgumentNullException ("buffer"); throw new ObjectDisposedException ("Invalid File Stream");
if (offset < 0) }
throw new ArgumentOutOfRangeException ("offset", "< 0");
if (count < 0)
throw new ArgumentOutOfRangeException ("count", "< 0");
if (offset > buffer.Length)
throw new ArgumentException ("destination offset is beyond array size");
if (offset > (buffer.Length - count))
throw new ArgumentException ("would overrun buffer");
}
public void Rewind () GC.KeepAlive (this);
{ }
AssertNotDisposed ();
Native.Stdlib.rewind (file);
GC.KeepAlive (this);
}
public override long Seek (long offset, SeekOrigin origin) public IntPtr Handle {
{ get {
AssertNotDisposed (); this.AssertNotDisposed ();
if (!CanSeek) GC.KeepAlive (this);
throw new NotSupportedException ("The File Stream does not support seeking"); return this.file;
}
}
Native.SeekFlags sf = Native.SeekFlags.SEEK_CUR; public override Boolean CanRead => this.canRead;
switch (origin) {
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;
default: throw new ArgumentException ("origin");
}
int r = Native.Stdlib.fseek (file, offset, sf); public override Boolean CanSeek => this.canSeek;
if (r != 0)
throw new IOException ("Unable to seek",
UnixMarshal.CreateExceptionForLastError ());
long pos = Native.Stdlib.ftell (file); public override Boolean CanWrite => this.canWrite;
if (pos == -1)
throw new IOException ("Unable to get current file position",
UnixMarshal.CreateExceptionForLastError ());
GC.KeepAlive (this); public override Int64 Length {
return pos; get {
} this.AssertNotDisposed ();
if (!this.CanSeek) {
throw new NotSupportedException ("File Stream doesn't support seeking");
}
public override void SetLength (long value) Int64 curPos = Native.Stdlib.ftell (this.file);
{ if (curPos == -1) {
throw new NotSupportedException ("ANSI C doesn't provide a way to truncate a file"); throw new NotSupportedException ("Unable to obtain current file position");
} }
public override unsafe void Write (byte[] buffer, int offset, int count) Int32 r = Native.Stdlib.fseek (this.file, 0, Native.SeekFlags.SEEK_END);
{ UnixMarshal.ThrowExceptionForLastErrorIf (r);
AssertNotDisposed ();
AssertValidBuffer (buffer, offset, count);
if (!CanWrite)
throw new NotSupportedException ("File Stream does not support writing");
ulong r = 0; Int64 endPos = Native.Stdlib.ftell (this.file);
fixed (byte* buf = &buffer[offset]) { if (endPos == -1) {
r = Native.Stdlib.fwrite (buf, (ulong) 1, (ulong) count, file); UnixMarshal.ThrowExceptionForLastError ();
} }
if (r != (ulong) count)
UnixMarshal.ThrowExceptionForLastError ();
GC.KeepAlive (this);
}
~StdioFileStream () r = Native.Stdlib.fseek (this.file, curPos, Native.SeekFlags.SEEK_SET);
{ UnixMarshal.ThrowExceptionForLastErrorIf (r);
Close ();
}
public override void Close () GC.KeepAlive (this);
{ return endPos;
if (file == InvalidFileStream) }
return; }
if (owner) { public override Int64 Position {
int r = Native.Stdlib.fclose (file); get {
if (r != 0) this.AssertNotDisposed ();
UnixMarshal.ThrowExceptionForLastError (); if (!this.CanSeek) {
} else throw new NotSupportedException ("The stream does not support seeking");
Flush (); }
file = InvalidFileStream; Int64 pos = Native.Stdlib.ftell (this.file);
canRead = false; if (pos == -1) {
canSeek = false; UnixMarshal.ThrowExceptionForLastError ();
canWrite = false; }
GC.SuppressFinalize (this); GC.KeepAlive (this);
GC.KeepAlive (this); return (Int64) pos;
} }
set {
this.AssertNotDisposed ();
_ = this.Seek(value, SeekOrigin.Begin);
}
}
private bool canSeek = false; public void SaveFilePosition (Native.FilePosition pos)
private bool canRead = false; {
private bool canWrite = false; this.AssertNotDisposed ();
private bool owner = true; Int32 r = Native.Stdlib.fgetpos (this.file, pos);
private IntPtr file = InvalidFileStream; UnixMarshal.ThrowExceptionForLastErrorIf (r);
} GC.KeepAlive (this);
}
public void RestoreFilePosition (Native.FilePosition pos)
{
this.AssertNotDisposed ();
if (pos == null) {
throw new ArgumentNullException ("value");
}
Int32 r = Native.Stdlib.fsetpos (this.file, pos);
UnixMarshal.ThrowExceptionForLastErrorIf (r);
GC.KeepAlive (this);
}
public override void Flush ()
{
this.AssertNotDisposed ();
Int32 r = Native.Stdlib.fflush (this.file);
if (r != 0) {
UnixMarshal.ThrowExceptionForLastError ();
}
GC.KeepAlive (this);
}
public override unsafe Int32 Read ([In, Out] Byte[] buffer, Int32 offset, Int32 count)
{
this.AssertNotDisposed ();
this.AssertValidBuffer (buffer, offset, count);
if (!this.CanRead) {
throw new NotSupportedException ("Stream does not support reading");
}
UInt64 r = 0;
fixed (Byte* buf = &buffer[offset]) {
r = Native.Stdlib.fread (buf, 1, (UInt64) count, this.file);
}
if (r != (UInt64) count) {
if (Native.Stdlib.ferror (this.file) != 0) {
throw new IOException ();
}
}
GC.KeepAlive (this);
return (Int32) r;
}
private void AssertValidBuffer (Byte[] buffer, Int32 offset, Int32 count)
{
if (buffer == null) {
throw new ArgumentNullException ("buffer");
}
if (offset < 0) {
throw new ArgumentOutOfRangeException ("offset", "< 0");
}
if (count < 0) {
throw new ArgumentOutOfRangeException ("count", "< 0");
}
if (offset > buffer.Length) {
throw new ArgumentException ("destination offset is beyond array size");
}
if (offset > buffer.Length - count) {
throw new ArgumentException ("would overrun buffer");
}
}
public void Rewind ()
{
this.AssertNotDisposed ();
_ = Native.Stdlib.rewind(this.file);
GC.KeepAlive (this);
}
public override Int64 Seek (Int64 offset, SeekOrigin origin)
{
this.AssertNotDisposed ();
if (!this.CanSeek) {
throw new NotSupportedException ("The File Stream does not support seeking");
}
Native.SeekFlags sf = Native.SeekFlags.SEEK_CUR;
switch (origin) {
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;
default: throw new ArgumentException ("origin");
}
Int32 r = Native.Stdlib.fseek (this.file, offset, sf);
if (r != 0) {
throw new IOException ("Unable to seek",
UnixMarshal.CreateExceptionForLastError ());
}
Int64 pos = Native.Stdlib.ftell (this.file);
if (pos == -1) {
throw new IOException ("Unable to get current file position",
UnixMarshal.CreateExceptionForLastError ());
}
GC.KeepAlive (this);
return pos;
}
public override void SetLength(Int64 value) => throw new NotSupportedException("ANSI C doesn't provide a way to truncate a file");
public override unsafe void Write (Byte[] buffer, Int32 offset, Int32 count)
{
this.AssertNotDisposed ();
this.AssertValidBuffer (buffer, offset, count);
if (!this.CanWrite) {
throw new NotSupportedException ("File Stream does not support writing");
}
UInt64 r = 0;
fixed (Byte* buf = &buffer[offset]) {
r = Native.Stdlib.fwrite (buf, (UInt64) 1, (UInt64) count, this.file);
}
if (r != (UInt64) count) {
UnixMarshal.ThrowExceptionForLastError ();
}
GC.KeepAlive (this);
}
~StdioFileStream ()
{
this.Close ();
}
public override void Close ()
{
if (this.file == InvalidFileStream) {
return;
}
if (this.owner) {
Int32 r = Native.Stdlib.fclose (this.file);
if (r != 0) {
UnixMarshal.ThrowExceptionForLastError ();
}
} else {
this.Flush ();
}
this.file = InvalidFileStream;
this.canRead = false;
this.canSeek = false;
this.canWrite = false;
GC.SuppressFinalize (this);
GC.KeepAlive (this);
}
private Boolean canSeek = false;
private Boolean canRead = false;
private Boolean canWrite = false;
private Boolean owner = true;
private IntPtr file = InvalidFileStream;
}
} }
// vim: noexpandtab // vim: noexpandtab

View File

@ -35,196 +35,198 @@ using System.Runtime.InteropServices;
namespace Mono.Unix { namespace Mono.Unix {
public class UnixClient : MarshalByRefObject, IDisposable { public class UnixClient : MarshalByRefObject, IDisposable {
NetworkStream stream; NetworkStream stream;
Socket client; Socket client;
bool disposed; Boolean disposed;
public UnixClient () public UnixClient ()
{ {
if (client != null) { if (this.client != null) {
client.Close (); this.client.Close ();
client = null; this.client = null;
} }
client = new Socket (AddressFamily.Unix, SocketType.Stream, 0); this.client = new Socket (AddressFamily.Unix, SocketType.Stream, 0);
} }
public UnixClient (string path) : this () public UnixClient (String path) : this ()
{ {
if (path == null) if (path == null) {
throw new ArgumentNullException ("ep"); throw new ArgumentNullException ("ep");
}
Connect (path); this.Connect (path);
} }
public UnixClient (UnixEndPoint ep) : this () public UnixClient (UnixEndPoint ep) : this ()
{ {
if (ep == null) if (ep == null) {
throw new ArgumentNullException ("ep"); throw new ArgumentNullException ("ep");
}
Connect (ep); this.Connect (ep);
} }
// UnixListener uses this when accepting a connection. // UnixListener uses this when accepting a connection.
internal UnixClient (Socket sock) internal UnixClient(Socket sock) => this.Client = sock;
{
Client = sock;
}
public public
Socket Client { Socket Client {
get { return client; } get => this.client;
set { set {
client = value; this.client = value;
stream = null; this.stream = null;
} }
} }
public PeerCred PeerCredential { public PeerCred PeerCredential {
get { get {
CheckDisposed (); this.CheckDisposed ();
return new PeerCred (client); return new PeerCred (this.client);
} }
} }
public LingerOption LingerState { public LingerOption LingerState {
get { get {
CheckDisposed (); this.CheckDisposed ();
return (LingerOption) client.GetSocketOption (SocketOptionLevel.Socket, return (LingerOption)this.client.GetSocketOption (SocketOptionLevel.Socket,
SocketOptionName.Linger); SocketOptionName.Linger);
} }
set { set {
CheckDisposed (); this.CheckDisposed ();
client.SetSocketOption (SocketOptionLevel.Socket, this.client.SetSocketOption (SocketOptionLevel.Socket,
SocketOptionName.Linger, value); SocketOptionName.Linger, value);
} }
} }
public int ReceiveBufferSize { public Int32 ReceiveBufferSize {
get { get {
CheckDisposed (); this.CheckDisposed ();
return (int) client.GetSocketOption (SocketOptionLevel.Socket, return (Int32)this.client.GetSocketOption (SocketOptionLevel.Socket,
SocketOptionName.ReceiveBuffer); SocketOptionName.ReceiveBuffer);
} }
set { set {
CheckDisposed (); this.CheckDisposed ();
client.SetSocketOption (SocketOptionLevel.Socket, this.client.SetSocketOption (SocketOptionLevel.Socket,
SocketOptionName.ReceiveBuffer, value); SocketOptionName.ReceiveBuffer, value);
} }
} }
public int ReceiveTimeout { public Int32 ReceiveTimeout {
get { get {
CheckDisposed (); this.CheckDisposed ();
return (int) client.GetSocketOption (SocketOptionLevel.Socket, return (Int32)this.client.GetSocketOption (SocketOptionLevel.Socket,
SocketOptionName.ReceiveTimeout); SocketOptionName.ReceiveTimeout);
} }
set { set {
CheckDisposed (); this.CheckDisposed ();
client.SetSocketOption (SocketOptionLevel.Socket, this.client.SetSocketOption (SocketOptionLevel.Socket,
SocketOptionName.ReceiveTimeout, value); SocketOptionName.ReceiveTimeout, value);
} }
} }
public int SendBufferSize { public Int32 SendBufferSize {
get { get {
CheckDisposed (); this.CheckDisposed ();
return (int) client.GetSocketOption (SocketOptionLevel.Socket, return (Int32)this.client.GetSocketOption (SocketOptionLevel.Socket,
SocketOptionName.SendBuffer); SocketOptionName.SendBuffer);
} }
set { set {
CheckDisposed (); this.CheckDisposed ();
client.SetSocketOption (SocketOptionLevel.Socket, this.client.SetSocketOption (SocketOptionLevel.Socket,
SocketOptionName.SendBuffer, value); SocketOptionName.SendBuffer, value);
} }
} }
public int SendTimeout { public Int32 SendTimeout {
get { get {
CheckDisposed (); this.CheckDisposed ();
return (int) client.GetSocketOption (SocketOptionLevel.Socket, return (Int32)this.client.GetSocketOption (SocketOptionLevel.Socket,
SocketOptionName.SendTimeout); SocketOptionName.SendTimeout);
} }
set { set {
CheckDisposed (); this.CheckDisposed ();
client.SetSocketOption (SocketOptionLevel.Socket, this.client.SetSocketOption (SocketOptionLevel.Socket,
SocketOptionName.SendTimeout, value); SocketOptionName.SendTimeout, value);
} }
} }
public void Close () public void Close ()
{ {
CheckDisposed (); this.CheckDisposed ();
Dispose (); this.Dispose ();
} }
public void Connect (UnixEndPoint remoteEndPoint) public void Connect (UnixEndPoint remoteEndPoint)
{ {
CheckDisposed (); this.CheckDisposed ();
client.Connect (remoteEndPoint); this.client.Connect (remoteEndPoint);
stream = new NetworkStream (client, true); this.stream = new NetworkStream (this.client, true);
} }
public void Connect (string path) public void Connect (String path)
{ {
CheckDisposed (); this.CheckDisposed ();
Connect (new UnixEndPoint (path)); this.Connect (new UnixEndPoint (path));
} }
public void Dispose () public void Dispose ()
{ {
Dispose (true); this.Dispose (true);
GC.SuppressFinalize (this); GC.SuppressFinalize (this);
} }
protected virtual void Dispose (bool disposing) protected virtual void Dispose (Boolean disposing)
{ {
if (disposed) if (this.disposed) {
return; return;
}
if (disposing) { if (disposing) {
// release managed resources // release managed resources
NetworkStream s = stream; NetworkStream s = this.stream;
stream = null; this.stream = null;
if (s != null) { if (s != null) {
// This closes the socket as well, as the NetworkStream // This closes the socket as well, as the NetworkStream
// owns the socket. // owns the socket.
s.Close(); s.Close();
s = null; s = null;
} else if (client != null){ } else if (this.client != null){
client.Close (); this.client.Close ();
} }
client = null; this.client = null;
} }
disposed = true; this.disposed = true;
} }
public NetworkStream GetStream () public NetworkStream GetStream ()
{ {
CheckDisposed (); this.CheckDisposed ();
if (stream == null) if (this.stream == null) {
stream = new NetworkStream (client, true); this.stream = new NetworkStream (this.client, true);
}
return stream; return this.stream;
} }
void CheckDisposed () void CheckDisposed ()
{ {
if (disposed) if (this.disposed) {
throw new ObjectDisposedException (GetType().FullName); throw new ObjectDisposedException (this.GetType().FullName);
} }
}
~UnixClient () ~UnixClient ()
{ {
Dispose (false); this.Dispose (false);
} }
} }
} }

View File

@ -35,216 +35,223 @@ using Mono.Unix;
namespace Mono.Unix { namespace Mono.Unix {
public sealed class UnixDirectoryInfo : UnixFileSystemInfo public sealed class UnixDirectoryInfo : UnixFileSystemInfo
{ {
public UnixDirectoryInfo (string path) public UnixDirectoryInfo (String path)
: base (path) : base (path)
{ {
} }
internal UnixDirectoryInfo (string path, Native.Stat stat) internal UnixDirectoryInfo (String path, Native.Stat stat)
: base (path, stat) : base (path, stat)
{ {
} }
public override string Name { public override String Name {
get { get {
string r = UnixPath.GetFileName (FullPath); String r = UnixPath.GetFileName (this.FullPath);
if (r == null || r.Length == 0) return r == null || r.Length == 0 ? this.FullPath : r;
return FullPath; }
return r; }
}
}
public UnixDirectoryInfo Parent { public UnixDirectoryInfo Parent {
get { get {
if (FullPath == "/") if (this.FullPath == "/") {
return this; return this;
string dirname = UnixPath.GetDirectoryName (FullPath); }
if (dirname == "")
throw new InvalidOperationException ("Do not know parent directory for path `" + FullPath + "'");
return new UnixDirectoryInfo (dirname);
}
}
public UnixDirectoryInfo Root { String dirname = UnixPath.GetDirectoryName (this.FullPath);
get { if (dirname == "") {
string root = UnixPath.GetPathRoot (FullPath); throw new InvalidOperationException ("Do not know parent directory for path `" + this.FullPath + "'");
if (root == null) }
return null;
return new UnixDirectoryInfo (root);
}
}
[CLSCompliant (false)] return new UnixDirectoryInfo (dirname);
public void Create (Mono.Unix.Native.FilePermissions mode) }
{ }
int r = Mono.Unix.Native.Syscall.mkdir (FullPath, mode);
UnixMarshal.ThrowExceptionForLastErrorIf (r);
base.Refresh ();
}
public void Create (FileAccessPermissions mode) public UnixDirectoryInfo Root {
{ get {
Create ((Native.FilePermissions) mode); String root = UnixPath.GetPathRoot (this.FullPath);
} return root == null ? null : new UnixDirectoryInfo (root);
}
}
public void Create () //[CLSCompliant (false)]
{ public void Create (Mono.Unix.Native.FilePermissions mode)
Mono.Unix.Native.FilePermissions mode = {
Mono.Unix.Native.FilePermissions.ACCESSPERMS; Int32 r = Mono.Unix.Native.Syscall.mkdir (this.FullPath, mode);
Create (mode); UnixMarshal.ThrowExceptionForLastErrorIf (r);
} base.Refresh ();
}
public override void Delete () public void Create(FileAccessPermissions mode) => this.Create((Native.FilePermissions)mode);
{
Delete (false);
}
public void Delete (bool recursive) public void Create ()
{ {
if (recursive) { Mono.Unix.Native.FilePermissions mode =
foreach (UnixFileSystemInfo e in GetFileSystemEntries ()) { Mono.Unix.Native.FilePermissions.ACCESSPERMS;
UnixDirectoryInfo d = e as UnixDirectoryInfo; this.Create (mode);
if (d != null) }
d.Delete (true);
else
e.Delete ();
}
}
int r = Native.Syscall.rmdir (FullPath);
UnixMarshal.ThrowExceptionForLastErrorIf (r);
base.Refresh ();
}
public Native.Dirent[] GetEntries () public override void Delete() => this.Delete(false);
{
IntPtr dirp = Native.Syscall.opendir (FullPath);
if (dirp == IntPtr.Zero)
UnixMarshal.ThrowExceptionForLastError ();
bool complete = false; public void Delete (Boolean recursive)
try { {
Native.Dirent[] entries = GetEntries (dirp); if (recursive) {
complete = true; foreach (UnixFileSystemInfo e in this.GetFileSystemEntries ()) {
return entries; UnixDirectoryInfo d = e as UnixDirectoryInfo;
} if (d != null) {
finally { d.Delete (true);
int r = Native.Syscall.closedir (dirp); } else {
// don't throw an exception if an exception is in progress e.Delete ();
if (complete) }
UnixMarshal.ThrowExceptionForLastErrorIf (r); }
} }
} Int32 r = Native.Syscall.rmdir (this.FullPath);
UnixMarshal.ThrowExceptionForLastErrorIf (r);
base.Refresh ();
}
private static Native.Dirent[] GetEntries (IntPtr dirp) public Native.Dirent[] GetEntries ()
{ {
ArrayList entries = new ArrayList (); IntPtr dirp = Native.Syscall.opendir (this.FullPath);
if (dirp == IntPtr.Zero) {
UnixMarshal.ThrowExceptionForLastError ();
}
int r; Boolean complete = false;
IntPtr result; try {
do { Native.Dirent[] entries = GetEntries (dirp);
Native.Dirent d = new Native.Dirent (); complete = true;
r = Native.Syscall.readdir_r (dirp, d, out result); return entries;
if (r == 0 && result != IntPtr.Zero) }
// don't include current & parent dirs finally {
if (d.d_name != "." && d.d_name != "..") Int32 r = Native.Syscall.closedir (dirp);
entries.Add (d); // don't throw an exception if an exception is in progress
} while (r == 0 && result != IntPtr.Zero); if (complete) {
if (r != 0) UnixMarshal.ThrowExceptionForLastErrorIf (r);
UnixMarshal.ThrowExceptionForLastErrorIf (r); }
}
}
return (Native.Dirent[]) entries.ToArray (typeof(Native.Dirent)); private static Native.Dirent[] GetEntries (IntPtr dirp)
} {
ArrayList entries = new ArrayList ();
public Native.Dirent[] GetEntries (Regex regex) Int32 r;
{ IntPtr result;
IntPtr dirp = Native.Syscall.opendir (FullPath); do {
if (dirp == IntPtr.Zero) Native.Dirent d = new Native.Dirent ();
UnixMarshal.ThrowExceptionForLastError (); r = Native.Syscall.readdir_r (dirp, d, out result);
if (r == 0 && result != IntPtr.Zero) {
// don't include current & parent dirs
if (d.d_name != "." && d.d_name != "..") {
_ = entries.Add(d);
}
}
} while (r == 0 && result != IntPtr.Zero);
if (r != 0) {
UnixMarshal.ThrowExceptionForLastErrorIf (r);
}
try { return (Native.Dirent[]) entries.ToArray (typeof(Native.Dirent));
return GetEntries (dirp, regex); }
}
finally {
int r = Native.Syscall.closedir (dirp);
UnixMarshal.ThrowExceptionForLastErrorIf (r);
}
}
private static Native.Dirent[] GetEntries (IntPtr dirp, Regex regex) public Native.Dirent[] GetEntries (Regex regex)
{ {
ArrayList entries = new ArrayList (); IntPtr dirp = Native.Syscall.opendir (this.FullPath);
if (dirp == IntPtr.Zero) {
UnixMarshal.ThrowExceptionForLastError ();
}
int r; try {
IntPtr result; return GetEntries (dirp, regex);
do { }
Native.Dirent d = new Native.Dirent (); finally {
r = Native.Syscall.readdir_r (dirp, d, out result); Int32 r = Native.Syscall.closedir (dirp);
if (r == 0 && result != IntPtr.Zero && regex.Match (d.d_name).Success) { UnixMarshal.ThrowExceptionForLastErrorIf (r);
// don't include current & parent dirs }
if (d.d_name != "." && d.d_name != "..") }
entries.Add (d);
}
} while (r == 0 && result != IntPtr.Zero);
if (r != 0)
UnixMarshal.ThrowExceptionForLastError ();
return (Native.Dirent[]) entries.ToArray (typeof(Native.Dirent)); private static Native.Dirent[] GetEntries (IntPtr dirp, Regex regex)
} {
ArrayList entries = new ArrayList ();
public Native.Dirent[] GetEntries (string regex) Int32 r;
{ IntPtr result;
Regex re = new Regex (regex); do {
return GetEntries (re); Native.Dirent d = new Native.Dirent ();
} r = Native.Syscall.readdir_r (dirp, d, out result);
if (r == 0 && result != IntPtr.Zero && regex.Match (d.d_name).Success) {
// don't include current & parent dirs
if (d.d_name != "." && d.d_name != "..") {
_ = entries.Add(d);
}
}
} while (r == 0 && result != IntPtr.Zero);
if (r != 0) {
UnixMarshal.ThrowExceptionForLastError ();
}
public UnixFileSystemInfo[] GetFileSystemEntries () return (Native.Dirent[]) entries.ToArray (typeof(Native.Dirent));
{ }
Native.Dirent[] dentries = GetEntries ();
return GetFileSystemEntries (dentries);
}
private UnixFileSystemInfo[] GetFileSystemEntries (Native.Dirent[] dentries) public Native.Dirent[] GetEntries (String regex)
{ {
UnixFileSystemInfo[] entries = new UnixFileSystemInfo[dentries.Length]; Regex re = new Regex (regex);
for (int i = 0; i != entries.Length; ++i) return this.GetEntries (re);
entries [i] = UnixFileSystemInfo.GetFileSystemEntry ( }
UnixPath.Combine (FullPath, dentries[i].d_name));
return entries;
}
public UnixFileSystemInfo[] GetFileSystemEntries (Regex regex) public UnixFileSystemInfo[] GetFileSystemEntries ()
{ {
Native.Dirent[] dentries = GetEntries (regex); Native.Dirent[] dentries = this.GetEntries ();
return GetFileSystemEntries (dentries); return this.GetFileSystemEntries (dentries);
} }
public UnixFileSystemInfo[] GetFileSystemEntries (string regex) private UnixFileSystemInfo[] GetFileSystemEntries (Native.Dirent[] dentries)
{ {
Regex re = new Regex (regex); UnixFileSystemInfo[] entries = new UnixFileSystemInfo[dentries.Length];
return GetFileSystemEntries (re); for (Int32 i = 0; i != entries.Length; ++i) {
} entries [i] = UnixFileSystemInfo.GetFileSystemEntry (
UnixPath.Combine (this.FullPath, dentries[i].d_name));
}
public static string GetCurrentDirectory () return entries;
{ }
StringBuilder buf = new StringBuilder (16);
IntPtr r = IntPtr.Zero;
do {
buf.Capacity *= 2;
r = Native.Syscall.getcwd (buf, (ulong) buf.Capacity);
} while (r == IntPtr.Zero && Native.Syscall.GetLastError() == Native.Errno.ERANGE);
if (r == IntPtr.Zero)
UnixMarshal.ThrowExceptionForLastError ();
return buf.ToString ();
}
public static void SetCurrentDirectory (string path) public UnixFileSystemInfo[] GetFileSystemEntries (Regex regex)
{ {
int r = Native.Syscall.chdir (path); Native.Dirent[] dentries = this.GetEntries (regex);
UnixMarshal.ThrowExceptionForLastErrorIf (r); return this.GetFileSystemEntries (dentries);
} }
}
public UnixFileSystemInfo[] GetFileSystemEntries (String regex)
{
Regex re = new Regex (regex);
return this.GetFileSystemEntries (re);
}
public static String GetCurrentDirectory ()
{
StringBuilder buf = new StringBuilder (16);
IntPtr r = IntPtr.Zero;
do {
buf.Capacity *= 2;
r = Native.Syscall.getcwd (buf, (UInt64) buf.Capacity);
} while (r == IntPtr.Zero && Native.Syscall.GetLastError() == Native.Errno.ERANGE);
if (r == IntPtr.Zero) {
UnixMarshal.ThrowExceptionForLastError ();
}
return buf.ToString ();
}
public static void SetCurrentDirectory (String path)
{
Int32 r = Native.Syscall.chdir (path);
UnixMarshal.ThrowExceptionForLastErrorIf (r);
}
}
} }
// vim: noexpandtab // vim: noexpandtab

View File

@ -33,163 +33,157 @@ using Mono.Unix;
namespace Mono.Unix { namespace Mono.Unix {
public enum UnixDriveType { public enum UnixDriveType {
Unknown, Unknown,
NoRootDirectory, NoRootDirectory,
Removable, Removable,
Fixed, Fixed,
Network, Network,
CDRom, CDRom,
Ram Ram
} }
// All methods & properties can throw IOException // All methods & properties can throw IOException
public sealed class UnixDriveInfo public sealed class UnixDriveInfo
{ {
private Native.Statvfs stat; private Native.Statvfs stat;
private string fstype, mount_point, block_device; private String fstype, mount_point, block_device;
public UnixDriveInfo (string mountPoint) public UnixDriveInfo (String mountPoint)
{ {
if (mountPoint == null) if (mountPoint == null) {
throw new ArgumentNullException ("mountPoint"); throw new ArgumentNullException ("mountPoint");
Native.Fstab fstab = Native.Syscall.getfsfile (mountPoint); }
if (fstab != null) {
FromFstab (fstab);
}
else {
this.mount_point = mountPoint;
this.block_device = "";
this.fstype = "Unknown";
}
}
private void FromFstab (Native.Fstab fstab) Native.Fstab fstab = Native.Syscall.getfsfile (mountPoint);
{ if (fstab != null) {
this.fstype = fstab.fs_vfstype; this.FromFstab (fstab);
this.mount_point = fstab.fs_file; }
this.block_device = fstab.fs_spec; else {
} this.mount_point = mountPoint;
this.block_device = "";
this.fstype = "Unknown";
}
}
public static UnixDriveInfo GetForSpecialFile (string specialFile) private void FromFstab (Native.Fstab fstab)
{ {
if (specialFile == null) this.fstype = fstab.fs_vfstype;
throw new ArgumentNullException ("specialFile"); this.mount_point = fstab.fs_file;
Native.Fstab f = Native.Syscall.getfsspec (specialFile); this.block_device = fstab.fs_spec;
if (f == null) }
throw new ArgumentException ("specialFile isn't valid: " + specialFile);
return new UnixDriveInfo (f);
}
private UnixDriveInfo (Native.Fstab fstab) public static UnixDriveInfo GetForSpecialFile (String specialFile)
{ {
FromFstab (fstab); if (specialFile == null) {
} throw new ArgumentNullException ("specialFile");
}
public long AvailableFreeSpace { Native.Fstab f = Native.Syscall.getfsspec (specialFile);
get {Refresh (); return Convert.ToInt64 (stat.f_bavail * stat.f_frsize);} if (f == null) {
} throw new ArgumentException ("specialFile isn't valid: " + specialFile);
}
public string DriveFormat { return new UnixDriveInfo (f);
get {return fstype;} }
}
public UnixDriveType DriveType { private UnixDriveInfo(Native.Fstab fstab) => this.FromFstab(fstab);
get {return UnixDriveType.Unknown;}
}
// this throws no exceptions public Int64 AvailableFreeSpace {
public bool IsReady { get {
get { this.Refresh (); return Convert.ToInt64 (this.stat.f_bavail * this.stat.f_frsize);}
bool ready = Refresh (false); }
if (mount_point == "/" || !ready)
return ready;
Native.Statvfs parent;
int r = Native.Syscall.statvfs (RootDirectory.Parent.FullName,
out parent);
if (r != 0)
return false;
return parent.f_fsid != stat.f_fsid;
}
}
public string Name { public String DriveFormat => this.fstype;
get {return mount_point;}
}
public UnixDirectoryInfo RootDirectory { public UnixDriveType DriveType => UnixDriveType.Unknown;
get {return new UnixDirectoryInfo (mount_point);}
}
public long TotalFreeSpace { // this throws no exceptions
get {Refresh (); return (long) (stat.f_bfree * stat.f_frsize);} public Boolean IsReady {
} get {
Boolean ready = this.Refresh (false);
if (this.mount_point == "/" || !ready) {
return ready;
}
public long TotalSize { Int32 r = Native.Syscall.statvfs(this.RootDirectory.Parent.FullName,
get {Refresh (); return (long) (stat.f_frsize * stat.f_blocks);} out Native.Statvfs parent);
} return r != 0 ? false : parent.f_fsid != this.stat.f_fsid;
}
}
// also throws SecurityException if caller lacks perms public String Name => this.mount_point;
public string VolumeLabel {
get {return block_device;}
// set {}
}
public long MaximumFilenameLength { public UnixDirectoryInfo RootDirectory => new UnixDirectoryInfo(this.mount_point);
get {Refresh (); return Convert.ToInt64 (stat.f_namemax);}
}
public static UnixDriveInfo[] GetDrives () public Int64 TotalFreeSpace {
{ get {
// TODO: Return any drives mentioned by getmntent(3) once getmntent(3) this.Refresh (); return (Int64) (this.stat.f_bfree * this.stat.f_frsize);}
// is exported by Syscall. }
// throws IOException, UnauthorizedAccessException (no permission) public Int64 TotalSize {
ArrayList entries = new ArrayList (); get {
this.Refresh (); return (Int64) (this.stat.f_frsize * this.stat.f_blocks);}
}
lock (Native.Syscall.fstab_lock) { // also throws SecurityException if caller lacks perms
int r = Native.Syscall.setfsent (); public String VolumeLabel => this.block_device;
if (r != 1)
throw new IOException ("Error calling setfsent(3)", new UnixIOException ());
try {
Native.Fstab fs;
while ((fs = Native.Syscall.getfsent()) != null) {
// avoid virtual entries, such as "swap"
if (fs.fs_file != null && fs.fs_file.StartsWith ("/"))
entries.Add (new UnixDriveInfo (fs));
}
}
finally {
Native.Syscall.endfsent ();
}
}
return (UnixDriveInfo[]) entries.ToArray (typeof(UnixDriveInfo));
}
public override string ToString () public Int64 MaximumFilenameLength {
{ get {
return VolumeLabel; this.Refresh (); return Convert.ToInt64 (this.stat.f_namemax);}
} }
private void Refresh () public static UnixDriveInfo[] GetDrives ()
{ {
Refresh (true); // TODO: Return any drives mentioned by getmntent(3) once getmntent(3)
} // is exported by Syscall.
private bool Refresh (bool throwException) // throws IOException, UnauthorizedAccessException (no permission)
{ ArrayList entries = new ArrayList ();
int r = Native.Syscall.statvfs (mount_point, out stat);
if (r == -1 && throwException) { lock (Native.Syscall.fstab_lock) {
Native.Errno e = Native.Syscall.GetLastError (); Int32 r = Native.Syscall.setfsent ();
throw new InvalidOperationException ( if (r != 1) {
UnixMarshal.GetErrorDescription (e), throw new IOException ("Error calling setfsent(3)", new UnixIOException ());
new UnixIOException (e)); }
}
else if (r == -1) try {
return false; Native.Fstab fs;
return true; while ((fs = Native.Syscall.getfsent()) != null) {
} // avoid virtual entries, such as "swap"
} if (fs.fs_file != null && fs.fs_file.StartsWith ("/")) {
_ = entries.Add(new UnixDriveInfo(fs));
}
}
}
finally {
_ = Native.Syscall.endfsent();
}
}
return (UnixDriveInfo[]) entries.ToArray (typeof(UnixDriveInfo));
}
public override String ToString() => this.VolumeLabel;
private void Refresh() => this.Refresh(true);
private Boolean Refresh (Boolean throwException)
{
Int32 r = Native.Syscall.statvfs (this.mount_point, out this.stat);
if (r == -1 && throwException) {
Native.Errno e = Native.Syscall.GetLastError ();
throw new InvalidOperationException (
UnixMarshal.GetErrorDescription (e),
new UnixIOException (e));
}
else if (r == -1) {
return false;
}
return true;
}
}
} }
// vim: noexpandtab // vim: noexpandtab

File diff suppressed because it is too large Load Diff

View File

@ -34,100 +34,95 @@ using System.Text;
namespace Mono.Unix namespace Mono.Unix
{ {
[Serializable] [Serializable]
public class UnixEndPoint : EndPoint public class UnixEndPoint : EndPoint
{ {
string filename; String filename;
public UnixEndPoint (string filename) public UnixEndPoint (String filename)
{ {
if (filename == null) if (filename == null) {
throw new ArgumentNullException ("filename"); throw new ArgumentNullException ("filename");
}
if (filename == "") if (filename == "") {
throw new ArgumentException ("Cannot be empty.", "filename"); throw new ArgumentException ("Cannot be empty.", "filename");
this.filename = filename; }
}
public string Filename { this.filename = filename;
get { }
return(filename);
}
set {
filename=value;
}
}
public override AddressFamily AddressFamily { public String Filename {
get { return AddressFamily.Unix; } get => this.filename;
} set => this.filename = value;
}
public override EndPoint Create (SocketAddress socketAddress) public override AddressFamily AddressFamily => AddressFamily.Unix;
{
/*
* Should also check this
*
int addr = (int) AddressFamily.Unix;
if (socketAddress [0] != (addr & 0xFF))
throw new ArgumentException ("socketAddress is not a unix socket address.");
if (socketAddress [1] != ((addr & 0xFF00) >> 8)) public override EndPoint Create (SocketAddress socketAddress)
throw new ArgumentException ("socketAddress is not a unix socket address."); {
*/ /*
* Should also check this
*
int addr = (int) AddressFamily.Unix;
if (socketAddress [0] != (addr & 0xFF))
throw new ArgumentException ("socketAddress is not a unix socket address.");
if (socketAddress.Size == 2) { if (socketAddress [1] != ((addr & 0xFF00) >> 8))
// Empty filename. throw new ArgumentException ("socketAddress is not a unix socket address.");
// Probably from RemoteEndPoint which on linux does not return the file name. */
UnixEndPoint uep = new UnixEndPoint ("a");
uep.filename = "";
return uep;
}
int size = socketAddress.Size - 2;
byte [] bytes = new byte [size];
for (int i = 0; i < bytes.Length; i++) {
bytes [i] = socketAddress [i + 2];
// There may be junk after the null terminator, so ignore it all.
if (bytes [i] == 0) {
size = i;
break;
}
}
string name = Encoding.Default.GetString (bytes, 0, size); if (socketAddress.Size == 2) {
return new UnixEndPoint (name); // Empty filename.
} // Probably from RemoteEndPoint which on linux does not return the file name.
UnixEndPoint uep = new UnixEndPoint("a") {
filename = ""
};
return uep;
}
Int32 size = socketAddress.Size - 2;
Byte[] bytes = new Byte[size];
for (Int32 i = 0; i < bytes.Length; i++) {
bytes [i] = socketAddress [i + 2];
// There may be junk after the null terminator, so ignore it all.
if (bytes [i] == 0) {
size = i;
break;
}
}
public override SocketAddress Serialize () String name = Encoding.Default.GetString (bytes, 0, size);
{ return new UnixEndPoint (name);
byte [] bytes = Encoding.Default.GetBytes (filename); }
SocketAddress sa = new SocketAddress (AddressFamily, 2 + bytes.Length + 1);
// sa [0] -> family low byte, sa [1] -> family high byte
for (int i = 0; i < bytes.Length; i++)
sa [2 + i] = bytes [i];
//NULL suffix for non-abstract path public override SocketAddress Serialize ()
sa[2 + bytes.Length] = 0; {
Byte[] bytes = Encoding.Default.GetBytes (this.filename);
SocketAddress sa = new SocketAddress (this.AddressFamily, 2 + bytes.Length + 1);
// sa [0] -> family low byte, sa [1] -> family high byte
for (Int32 i = 0; i < bytes.Length; i++) {
sa [2 + i] = bytes [i];
}
return sa; //NULL suffix for non-abstract path
} sa[2 + bytes.Length] = 0;
public override string ToString() { return sa;
return(filename); }
}
public override int GetHashCode () public override String ToString() => this.filename;
{
return filename.GetHashCode ();
}
public override bool Equals (object o) public override Int32 GetHashCode() => this.filename.GetHashCode();
{
UnixEndPoint other = o as UnixEndPoint;
if (other == null)
return false;
return (other.filename == filename); public override Boolean Equals (Object o)
} {
} UnixEndPoint other = o as UnixEndPoint;
if (other == null) {
return false;
}
return other.filename == this.filename;
}
}
} }

View File

@ -28,211 +28,204 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Diagnostics.CodeAnalysis;
using System.Text; using System.Text;
using Mono.Unix; using Mono.Unix;
namespace Mono.Unix { namespace Mono.Unix {
public sealed /* static */ class UnixEnvironment public sealed /* static */ class UnixEnvironment
{ {
private UnixEnvironment () {} private UnixEnvironment () {}
public static string CurrentDirectory { public static String CurrentDirectory {
get { get => UnixDirectoryInfo.GetCurrentDirectory();
return UnixDirectoryInfo.GetCurrentDirectory (); set => UnixDirectoryInfo.SetCurrentDirectory(value);
} }
set {
UnixDirectoryInfo.SetCurrentDirectory (value);
}
}
public static string MachineName { public static String MachineName {
get { get {
Native.Utsname buf; if(Native.Syscall.uname(out Native.Utsname buf) != 0) {
if (Native.Syscall.uname (out buf) != 0) throw UnixMarshal.CreateExceptionForLastError();
throw UnixMarshal.CreateExceptionForLastError (); }
return buf.nodename;
}
set {
int r = Native.Syscall.sethostname (value);
UnixMarshal.ThrowExceptionForLastErrorIf (r);
}
}
public static string UserName { return buf.nodename;
get {return UnixUserInfo.GetRealUser ().UserName;} }
} set {
Int32 r = Native.Syscall.sethostname (value);
UnixMarshal.ThrowExceptionForLastErrorIf (r);
}
}
public static UnixGroupInfo RealGroup { public static String UserName => UnixUserInfo.GetRealUser().UserName;
get {return new UnixGroupInfo (RealGroupId);}
// set can't be done as setgid(2) modifies effective gid as well
}
public static long RealGroupId { public static UnixGroupInfo RealGroup => new UnixGroupInfo(RealGroupId);
get {return Native.Syscall.getgid ();}
// set can't be done as setgid(2) modifies effective gid as well
}
public static UnixUserInfo RealUser { public static Int64 RealGroupId => Native.Syscall.getgid();
get {return new UnixUserInfo (RealUserId);}
// set can't be done as setuid(2) modifies effective uid as well
}
public static long RealUserId { public static UnixUserInfo RealUser => new UnixUserInfo(RealUserId);
get {return Native.Syscall.getuid ();}
// set can't be done as setuid(2) modifies effective uid as well
}
public static UnixGroupInfo EffectiveGroup { public static Int64 RealUserId => Native.Syscall.getuid();
get {return new UnixGroupInfo (EffectiveGroupId);}
set {EffectiveGroupId = value.GroupId;}
}
public static long EffectiveGroupId { public static UnixGroupInfo EffectiveGroup {
get {return Native.Syscall.getegid ();} get => new UnixGroupInfo(EffectiveGroupId);
set {Native.Syscall.setegid (Convert.ToUInt32 (value));} set => EffectiveGroupId = value.GroupId;
} }
public static UnixUserInfo EffectiveUser { public static Int64 EffectiveGroupId {
get {return new UnixUserInfo (EffectiveUserId);} get => Native.Syscall.getegid();
set {EffectiveUserId = value.UserId;} set => _ = Native.Syscall.setegid(Convert.ToUInt32(value));
} }
public static long EffectiveUserId { public static UnixUserInfo EffectiveUser {
get {return Native.Syscall.geteuid ();} get => new UnixUserInfo(EffectiveUserId);
set {Native.Syscall.seteuid (Convert.ToUInt32 (value));} set => EffectiveUserId = value.UserId;
} }
public static string Login { public static Int64 EffectiveUserId {
get {return UnixUserInfo.GetRealUser ().UserName;} get => Native.Syscall.geteuid();
} set => _ = Native.Syscall.seteuid(Convert.ToUInt32(value));
}
[CLSCompliant (false)] public static String Login => UnixUserInfo.GetRealUser().UserName;
public static long GetConfigurationValue (Native.SysconfName name)
{
long r = Native.Syscall.sysconf (name);
if (r == -1 && Native.Stdlib.GetLastError() != (Native.Errno) 0)
UnixMarshal.ThrowExceptionForLastError ();
return r;
}
[CLSCompliant (false)] //[CLSCompliant (false)]
public static string GetConfigurationString (Native.ConfstrName name) public static Int64 GetConfigurationValue (Native.SysconfName name)
{ {
ulong len = Native.Syscall.confstr (name, null, 0); Int64 r = Native.Syscall.sysconf (name);
if (len == unchecked ((ulong) (-1))) if (r == -1 && Native.Stdlib.GetLastError() != (Native.Errno) 0) {
UnixMarshal.ThrowExceptionForLastError (); UnixMarshal.ThrowExceptionForLastError ();
if (len == 0) }
return "";
StringBuilder buf = new StringBuilder ((int) len+1);
len = Native.Syscall.confstr (name, buf, len);
if (len == unchecked ((ulong) (-1)))
UnixMarshal.ThrowExceptionForLastError ();
return buf.ToString ();
}
public static void SetNiceValue (int inc) return r;
{ }
int r = Native.Syscall.nice (inc);
UnixMarshal.ThrowExceptionForLastErrorIf (r);
}
public static int CreateSession () //[CLSCompliant (false)]
{ public static String GetConfigurationString (Native.ConfstrName name)
int s = Native.Syscall.setsid (); {
UnixMarshal.ThrowExceptionForLastErrorIf (s); UInt64 len = Native.Syscall.confstr (name, null, 0);
return s; if (len == unchecked ((UInt64) (-1))) {
} UnixMarshal.ThrowExceptionForLastError ();
}
public static void SetProcessGroup () if (len == 0) {
{ return "";
int r = Native.Syscall.setpgrp (); }
UnixMarshal.ThrowExceptionForLastErrorIf (r);
}
public static int GetProcessGroup () StringBuilder buf = new StringBuilder ((Int32) len+1);
{ len = Native.Syscall.confstr (name, buf, len);
return Native.Syscall.getpgrp (); if (len == unchecked ((UInt64) (-1))) {
} UnixMarshal.ThrowExceptionForLastError ();
}
public static UnixGroupInfo[] GetSupplementaryGroups () return buf.ToString ();
{ }
uint[] ids = _GetSupplementaryGroupIds ();
UnixGroupInfo[] groups = new UnixGroupInfo [ids.Length];
for (int i = 0; i < groups.Length; ++i)
groups [i] = new UnixGroupInfo (ids [i]);
return groups;
}
private static uint[] _GetSupplementaryGroupIds () public static void SetNiceValue (Int32 inc)
{ {
int ngroups = Native.Syscall.getgroups (0, new uint[]{}); Int32 r = Native.Syscall.nice (inc);
if (ngroups == -1) UnixMarshal.ThrowExceptionForLastErrorIf (r);
UnixMarshal.ThrowExceptionForLastError (); }
uint[] groups = new uint[ngroups];
int r = Native.Syscall.getgroups (groups);
UnixMarshal.ThrowExceptionForLastErrorIf (r);
return groups;
}
public static void SetSupplementaryGroups (UnixGroupInfo[] groups) public static Int32 CreateSession ()
{ {
uint[] list = new uint [groups.Length]; Int32 s = Native.Syscall.setsid ();
for (int i = 0; i < list.Length; ++i) { UnixMarshal.ThrowExceptionForLastErrorIf (s);
list [i] = Convert.ToUInt32 (groups [i].GroupId); return s;
} }
int r = Native.Syscall.setgroups (list);
UnixMarshal.ThrowExceptionForLastErrorIf (r);
}
public static long[] GetSupplementaryGroupIds () public static void SetProcessGroup ()
{ {
uint[] _groups = _GetSupplementaryGroupIds (); Int32 r = Native.Syscall.setpgrp ();
long[] groups = new long [_groups.Length]; UnixMarshal.ThrowExceptionForLastErrorIf (r);
for (int i = 0; i < groups.Length; ++i) }
groups [i] = _groups [i];
return groups;
}
public static void SetSupplementaryGroupIds (long[] list) public static Int32 GetProcessGroup() => Native.Syscall.getpgrp();
{
uint[] _list = new uint [list.Length];
for (int i = 0; i < _list.Length; ++i)
_list [i] = Convert.ToUInt32 (list [i]);
int r = Native.Syscall.setgroups (_list);
UnixMarshal.ThrowExceptionForLastErrorIf (r);
}
public static int GetParentProcessId () public static UnixGroupInfo[] GetSupplementaryGroups ()
{ {
return Native.Syscall.getppid (); UInt32[] ids = _GetSupplementaryGroupIds ();
} UnixGroupInfo[] groups = new UnixGroupInfo [ids.Length];
for (Int32 i = 0; i < groups.Length; ++i) {
groups [i] = new UnixGroupInfo (ids [i]);
}
public static UnixProcess GetParentProcess () return groups;
{ }
return new UnixProcess (GetParentProcessId ());
}
public static string[] GetUserShells () [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
{ private static UInt32[] _GetSupplementaryGroupIds ()
ArrayList shells = new ArrayList (); {
Int32 ngroups = Native.Syscall.getgroups (0, new UInt32[]{});
if (ngroups == -1) {
UnixMarshal.ThrowExceptionForLastError ();
}
lock (Native.Syscall.usershell_lock) { UInt32[] groups = new UInt32[ngroups];
try { Int32 r = Native.Syscall.getgroups (groups);
if (Native.Syscall.setusershell () != 0) UnixMarshal.ThrowExceptionForLastErrorIf (r);
UnixMarshal.ThrowExceptionForLastError (); return groups;
string shell; }
while ((shell = Native.Syscall.getusershell ()) != null)
shells.Add (shell);
}
finally {
Native.Syscall.endusershell ();
}
}
return (string[]) shells.ToArray (typeof(string)); public static void SetSupplementaryGroups (UnixGroupInfo[] groups)
} {
} UInt32[] list = new UInt32[groups.Length];
for (Int32 i = 0; i < list.Length; ++i) {
list [i] = Convert.ToUInt32 (groups [i].GroupId);
}
Int32 r = Native.Syscall.setgroups (list);
UnixMarshal.ThrowExceptionForLastErrorIf (r);
}
public static Int64[] GetSupplementaryGroupIds ()
{
UInt32[] _groups = _GetSupplementaryGroupIds ();
Int64[] groups = new Int64[_groups.Length];
for (Int32 i = 0; i < groups.Length; ++i) {
groups [i] = _groups [i];
}
return groups;
}
public static void SetSupplementaryGroupIds (Int64[] list)
{
UInt32[] _list = new UInt32[list.Length];
for (Int32 i = 0; i < _list.Length; ++i) {
_list [i] = Convert.ToUInt32 (list [i]);
}
Int32 r = Native.Syscall.setgroups (_list);
UnixMarshal.ThrowExceptionForLastErrorIf (r);
}
public static Int32 GetParentProcessId() => Native.Syscall.getppid();
public static UnixProcess GetParentProcess() => new UnixProcess(GetParentProcessId());
public static String[] GetUserShells ()
{
ArrayList shells = new ArrayList ();
lock (Native.Syscall.usershell_lock) {
try {
if (Native.Syscall.setusershell () != 0) {
UnixMarshal.ThrowExceptionForLastError ();
}
String shell;
while ((shell = Native.Syscall.getusershell ()) != null) {
_ = shells.Add(shell);
}
}
finally {
_ = Native.Syscall.endusershell();
}
}
return (String[]) shells.ToArray (typeof(String));
}
}
} }
// vim: noexpandtab // vim: noexpandtab

View File

@ -33,115 +33,110 @@ using Mono.Unix;
namespace Mono.Unix { namespace Mono.Unix {
public sealed class UnixFileInfo : UnixFileSystemInfo public sealed class UnixFileInfo : UnixFileSystemInfo
{ {
public UnixFileInfo (string path) public UnixFileInfo (String path)
: base (path) : base (path)
{ {
} }
internal UnixFileInfo (string path, Native.Stat stat) internal UnixFileInfo (String path, Native.Stat stat)
: base (path, stat) : base (path, stat)
{ {
} }
public override string Name { public override String Name => UnixPath.GetFileName(this.FullPath);
get {return UnixPath.GetFileName (FullPath);}
}
public string DirectoryName { public String DirectoryName => UnixPath.GetDirectoryName(this.FullPath);
get {return UnixPath.GetDirectoryName (FullPath);}
}
public UnixDirectoryInfo Directory { public UnixDirectoryInfo Directory => new UnixDirectoryInfo(this.DirectoryName);
get {return new UnixDirectoryInfo (DirectoryName);}
}
public override void Delete () public override void Delete ()
{ {
int r = Native.Syscall.unlink (FullPath); Int32 r = Native.Syscall.unlink (this.FullPath);
UnixMarshal.ThrowExceptionForLastErrorIf (r); UnixMarshal.ThrowExceptionForLastErrorIf (r);
base.Refresh (); base.Refresh ();
} }
public UnixStream Create () public UnixStream Create ()
{ {
Native.FilePermissions mode = // 0644 Native.FilePermissions mode = // 0644
Native.FilePermissions.S_IRUSR | Native.FilePermissions.S_IWUSR | Native.FilePermissions.S_IRUSR | Native.FilePermissions.S_IWUSR |
Native.FilePermissions.S_IRGRP | Native.FilePermissions.S_IROTH; Native.FilePermissions.S_IRGRP | Native.FilePermissions.S_IROTH;
return Create (mode); return this.Create (mode);
} }
[CLSCompliant (false)] //[CLSCompliant (false)]
public UnixStream Create (Native.FilePermissions mode) public UnixStream Create (Native.FilePermissions mode)
{ {
int fd = Native.Syscall.creat (FullPath, mode); Int32 fd = Native.Syscall.creat (this.FullPath, mode);
if (fd < 0) if (fd < 0) {
UnixMarshal.ThrowExceptionForLastError (); UnixMarshal.ThrowExceptionForLastError ();
base.Refresh (); }
return new UnixStream (fd);
}
public UnixStream Create (FileAccessPermissions mode) base.Refresh ();
{ return new UnixStream (fd);
return Create ((Native.FilePermissions) mode); }
}
[CLSCompliant (false)] public UnixStream Create(FileAccessPermissions mode) => this.Create((Native.FilePermissions)mode);
public UnixStream Open (Native.OpenFlags flags)
{
if ((flags & Native.OpenFlags.O_CREAT) != 0)
throw new ArgumentException (
"Cannot specify OpenFlags.O_CREAT without providing " +
"FilePermissions. Use the Open(OpenFlags, FilePermissions) " +
"method instead");
int fd = Native.Syscall.open (FullPath, flags);
if (fd < 0)
UnixMarshal.ThrowExceptionForLastError ();
return new UnixStream (fd);
}
[CLSCompliant (false)] //[CLSCompliant (false)]
public UnixStream Open (Native.OpenFlags flags, Native.FilePermissions mode) public UnixStream Open (Native.OpenFlags flags)
{ {
int fd = Native.Syscall.open (FullPath, flags, mode); if ((flags & Native.OpenFlags.O_CREAT) != 0) {
if (fd < 0) throw new ArgumentException (
UnixMarshal.ThrowExceptionForLastError (); "Cannot specify OpenFlags.O_CREAT without providing " +
return new UnixStream (fd); "FilePermissions. Use the Open(OpenFlags, FilePermissions) " +
} "method instead");
}
public UnixStream Open (FileMode mode) Int32 fd = Native.Syscall.open (this.FullPath, flags);
{ if (fd < 0) {
Native.OpenFlags flags = Native.NativeConvert.ToOpenFlags (mode, FileAccess.ReadWrite); UnixMarshal.ThrowExceptionForLastError ();
return Open (flags); }
}
public UnixStream Open (FileMode mode, FileAccess access) return new UnixStream (fd);
{ }
Native.OpenFlags flags = Native.NativeConvert.ToOpenFlags (mode, access);
return Open (flags);
}
[CLSCompliant (false)] //[CLSCompliant (false)]
public UnixStream Open (FileMode mode, FileAccess access, Native.FilePermissions perms) public UnixStream Open (Native.OpenFlags flags, Native.FilePermissions mode)
{ {
Native.OpenFlags flags = Native.NativeConvert.ToOpenFlags (mode, access); Int32 fd = Native.Syscall.open (this.FullPath, flags, mode);
int fd = Native.Syscall.open (FullPath, flags, perms); if (fd < 0) {
if (fd < 0) UnixMarshal.ThrowExceptionForLastError ();
UnixMarshal.ThrowExceptionForLastError (); }
return new UnixStream (fd);
}
public UnixStream OpenRead () return new UnixStream (fd);
{ }
return Open (FileMode.Open, FileAccess.Read);
}
public UnixStream OpenWrite () public UnixStream Open (FileMode mode)
{ {
return Open (FileMode.OpenOrCreate, FileAccess.Write); Native.OpenFlags flags = Native.NativeConvert.ToOpenFlags (mode, FileAccess.ReadWrite);
} return this.Open (flags);
} }
public UnixStream Open (FileMode mode, FileAccess access)
{
Native.OpenFlags flags = Native.NativeConvert.ToOpenFlags (mode, access);
return this.Open (flags);
}
//[CLSCompliant (false)]
public UnixStream Open (FileMode mode, FileAccess access, Native.FilePermissions perms)
{
Native.OpenFlags flags = Native.NativeConvert.ToOpenFlags (mode, access);
Int32 fd = Native.Syscall.open (this.FullPath, flags, perms);
if (fd < 0) {
UnixMarshal.ThrowExceptionForLastError ();
}
return new UnixStream (fd);
}
public UnixStream OpenRead() => this.Open(FileMode.Open, FileAccess.Read);
public UnixStream OpenWrite() => this.Open(FileMode.OpenOrCreate, FileAccess.Write);
}
} }
// vim: noexpandtab // vim: noexpandtab

View File

@ -33,396 +33,409 @@ using Mono.Unix;
namespace Mono.Unix { namespace Mono.Unix {
public abstract class UnixFileSystemInfo public abstract class UnixFileSystemInfo
{ {
private Native.Stat stat; private Native.Stat stat;
private string fullPath; private String fullPath;
private string originalPath; private String originalPath;
private bool valid = false; private Boolean valid = false;
internal const FileSpecialAttributes AllSpecialAttributes = internal const FileSpecialAttributes AllSpecialAttributes =
FileSpecialAttributes.SetUserId | FileSpecialAttributes.SetGroupId | FileSpecialAttributes.SetUserId | FileSpecialAttributes.SetGroupId |
FileSpecialAttributes.Sticky; FileSpecialAttributes.Sticky;
internal const FileTypes AllFileTypes = internal const FileTypes AllFileTypes =
FileTypes.Directory | FileTypes.CharacterDevice | FileTypes.BlockDevice | FileTypes.Directory | FileTypes.CharacterDevice | FileTypes.BlockDevice |
FileTypes.RegularFile | FileTypes.Fifo | FileTypes.SymbolicLink | FileTypes.RegularFile | FileTypes.Fifo | FileTypes.SymbolicLink |
FileTypes.Socket; FileTypes.Socket;
protected UnixFileSystemInfo (string path) protected UnixFileSystemInfo (String path)
{ {
UnixPath.CheckPath (path); UnixPath.CheckPath (path);
this.originalPath = path; this.originalPath = path;
this.fullPath = UnixPath.GetFullPath (path); this.fullPath = UnixPath.GetFullPath (path);
Refresh (true); this.Refresh (true);
} }
internal UnixFileSystemInfo (String path, Native.Stat stat) internal UnixFileSystemInfo (String path, Native.Stat stat)
{ {
this.originalPath = path; this.originalPath = path;
this.fullPath = UnixPath.GetFullPath (path); this.fullPath = UnixPath.GetFullPath (path);
this.stat = stat; this.stat = stat;
this.valid = true; this.valid = true;
} }
protected string FullPath { protected String FullPath {
get {return fullPath;} get => this.fullPath;
set { set {
if (fullPath != value) { if(this.fullPath != value) {
UnixPath.CheckPath (value); UnixPath.CheckPath(value);
valid = false; this.valid = false;
fullPath = value; this.fullPath = value;
} }
} }
} }
protected string OriginalPath { protected String OriginalPath {
get {return originalPath;} get => this.originalPath;
set {originalPath = value;} set => this.originalPath = value;
} }
private void AssertValid () private void AssertValid ()
{ {
Refresh (false); this.Refresh (false);
if (!valid) if (!this.valid) {
throw new InvalidOperationException ("Path doesn't exist!"); throw new InvalidOperationException ("Path doesn't exist!");
} }
}
public virtual string FullName {
get {return FullPath;} public virtual String FullName => this.FullPath;
}
public abstract String Name {get;}
public abstract string Name {get;}
public Boolean Exists {
public bool Exists { get {
get { this.Refresh (true);
Refresh (true); return this.valid;
return valid; }
} }
}
public Int64 Device {
public long Device { get {
get {AssertValid (); return Convert.ToInt64 (stat.st_dev);} this.AssertValid (); return Convert.ToInt64 (this.stat.st_dev);}
} }
public long Inode { public Int64 Inode {
get {AssertValid (); return Convert.ToInt64 (stat.st_ino);} get {
} this.AssertValid (); return Convert.ToInt64 (this.stat.st_ino);}
}
[CLSCompliant (false)]
public Native.FilePermissions Protection { //[CLSCompliant (false)]
get {AssertValid (); return (Native.FilePermissions) stat.st_mode;} public Native.FilePermissions Protection {
set { get {
int r = Native.Syscall.chmod (FullPath, value); this.AssertValid (); return (Native.FilePermissions)this.stat.st_mode;}
UnixMarshal.ThrowExceptionForLastErrorIf (r); set {
} Int32 r = Native.Syscall.chmod (this.FullPath, value);
} UnixMarshal.ThrowExceptionForLastErrorIf (r);
}
public FileTypes FileType { }
get {
AssertValid (); public FileTypes FileType {
return (FileTypes) (stat.st_mode & Native.FilePermissions.S_IFMT); get {
} this.AssertValid ();
// no set as chmod(2) won't accept changing the file type. return (FileTypes) (this.stat.st_mode & Native.FilePermissions.S_IFMT);
} }
// no set as chmod(2) won't accept changing the file type.
public FileAccessPermissions FileAccessPermissions { }
get {
AssertValid (); public FileAccessPermissions FileAccessPermissions {
int perms = (int) stat.st_mode; get {
return (FileAccessPermissions) (perms & (int) FileAccessPermissions.AllPermissions); this.AssertValid ();
} Int32 perms = (Int32)this.stat.st_mode;
set { return (FileAccessPermissions) (perms & (Int32) FileAccessPermissions.AllPermissions);
AssertValid (); }
int perms = (int) stat.st_mode; set {
perms &= (int) ~FileAccessPermissions.AllPermissions; this.AssertValid ();
perms |= (int) value; Int32 perms = (Int32)this.stat.st_mode;
Protection = (Native.FilePermissions) perms; perms &= (Int32) ~FileAccessPermissions.AllPermissions;
} perms |= (Int32) value;
} this.Protection = (Native.FilePermissions) perms;
}
public FileSpecialAttributes FileSpecialAttributes { }
get {
AssertValid (); public FileSpecialAttributes FileSpecialAttributes {
int attrs = (int) stat.st_mode; get {
return (FileSpecialAttributes) (attrs & (int) AllSpecialAttributes); this.AssertValid ();
} Int32 attrs = (Int32)this.stat.st_mode;
set { return (FileSpecialAttributes) (attrs & (Int32) AllSpecialAttributes);
AssertValid (); }
int perms = (int) stat.st_mode; set {
perms &= (int) ~AllSpecialAttributes; this.AssertValid ();
perms |= (int) value; Int32 perms = (Int32)this.stat.st_mode;
Protection = (Native.FilePermissions) perms; perms &= (Int32) ~AllSpecialAttributes;
} perms |= (Int32) value;
} this.Protection = (Native.FilePermissions) perms;
}
public long LinkCount { }
get {AssertValid (); return Convert.ToInt64 (stat.st_nlink);}
} public Int64 LinkCount {
get {
public UnixUserInfo OwnerUser { this.AssertValid (); return Convert.ToInt64 (this.stat.st_nlink);}
get {AssertValid (); return new UnixUserInfo (stat.st_uid);} }
}
public UnixUserInfo OwnerUser {
public long OwnerUserId { get {
get {AssertValid (); return stat.st_uid;} this.AssertValid (); return new UnixUserInfo (this.stat.st_uid);}
} }
public UnixGroupInfo OwnerGroup { public Int64 OwnerUserId {
get {AssertValid (); return new UnixGroupInfo (stat.st_gid);} get {
} this.AssertValid (); return this.stat.st_uid;}
}
public long OwnerGroupId {
get {AssertValid (); return stat.st_gid;} public UnixGroupInfo OwnerGroup {
} get {
this.AssertValid (); return new UnixGroupInfo (this.stat.st_gid);}
public long DeviceType { }
get {AssertValid (); return Convert.ToInt64 (stat.st_rdev);}
} public Int64 OwnerGroupId {
get {
public long Length { this.AssertValid (); return this.stat.st_gid;}
get {AssertValid (); return (long) stat.st_size;} }
}
public Int64 DeviceType {
public long BlockSize { get {
get {AssertValid (); return (long) stat.st_blksize;} this.AssertValid (); return Convert.ToInt64 (this.stat.st_rdev);}
} }
public long BlocksAllocated { public Int64 Length {
get {AssertValid (); return (long) stat.st_blocks;} get {
} this.AssertValid (); return (Int64)this.stat.st_size;}
}
public DateTime LastAccessTime {
get {AssertValid (); return Native.NativeConvert.ToDateTime (stat.st_atime, stat.st_atime_nsec);} public Int64 BlockSize {
} get {
this.AssertValid (); return (Int64)this.stat.st_blksize;}
public DateTime LastAccessTimeUtc { }
get {return LastAccessTime.ToUniversalTime ();}
} public Int64 BlocksAllocated {
get {
public DateTime LastWriteTime { this.AssertValid (); return (Int64)this.stat.st_blocks;}
get {AssertValid (); return Native.NativeConvert.ToDateTime (stat.st_mtime, stat.st_mtime_nsec);} }
}
public DateTime LastAccessTime {
public DateTime LastWriteTimeUtc { get {
get {return LastWriteTime.ToUniversalTime ();} this.AssertValid (); return Native.NativeConvert.ToDateTime (this.stat.st_atime, this.stat.st_atime_nsec);}
} }
public DateTime LastStatusChangeTime { public DateTime LastAccessTimeUtc => this.LastAccessTime.ToUniversalTime();
get {AssertValid (); return Native.NativeConvert.ToDateTime (stat.st_ctime, stat.st_ctime_nsec);}
} public DateTime LastWriteTime {
get {
public DateTime LastStatusChangeTimeUtc { this.AssertValid (); return Native.NativeConvert.ToDateTime (this.stat.st_mtime, this.stat.st_mtime_nsec);}
get {return LastStatusChangeTime.ToUniversalTime ();} }
}
public DateTime LastWriteTimeUtc => this.LastWriteTime.ToUniversalTime();
public bool IsDirectory {
get {AssertValid (); return IsFileType (stat.st_mode, Native.FilePermissions.S_IFDIR);} public DateTime LastStatusChangeTime {
} get {
this.AssertValid (); return Native.NativeConvert.ToDateTime (this.stat.st_ctime, this.stat.st_ctime_nsec);}
public bool IsCharacterDevice { }
get {AssertValid (); return IsFileType (stat.st_mode, Native.FilePermissions.S_IFCHR);}
} public DateTime LastStatusChangeTimeUtc => this.LastStatusChangeTime.ToUniversalTime();
public bool IsBlockDevice { public Boolean IsDirectory {
get {AssertValid (); return IsFileType (stat.st_mode, Native.FilePermissions.S_IFBLK);} get {
} this.AssertValid (); return IsFileType (this.stat.st_mode, Native.FilePermissions.S_IFDIR);}
}
public bool IsRegularFile {
get {AssertValid (); return IsFileType (stat.st_mode, Native.FilePermissions.S_IFREG);} public Boolean IsCharacterDevice {
} get {
this.AssertValid (); return IsFileType (this.stat.st_mode, Native.FilePermissions.S_IFCHR);}
public bool IsFifo { }
get {AssertValid (); return IsFileType (stat.st_mode, Native.FilePermissions.S_IFIFO);}
} public Boolean IsBlockDevice {
get {
public bool IsSymbolicLink { this.AssertValid (); return IsFileType (this.stat.st_mode, Native.FilePermissions.S_IFBLK);}
get {AssertValid (); return IsFileType (stat.st_mode, Native.FilePermissions.S_IFLNK);} }
}
public Boolean IsRegularFile {
public bool IsSocket { get {
get {AssertValid (); return IsFileType (stat.st_mode, Native.FilePermissions.S_IFSOCK);} this.AssertValid (); return IsFileType (this.stat.st_mode, Native.FilePermissions.S_IFREG);}
} }
public bool IsSetUser { public Boolean IsFifo {
get {AssertValid (); return IsSet (stat.st_mode, Native.FilePermissions.S_ISUID);} get {
} this.AssertValid (); return IsFileType (this.stat.st_mode, Native.FilePermissions.S_IFIFO);}
}
public bool IsSetGroup {
get {AssertValid (); return IsSet (stat.st_mode, Native.FilePermissions.S_ISGID);} public Boolean IsSymbolicLink {
} get {
this.AssertValid (); return IsFileType (this.stat.st_mode, Native.FilePermissions.S_IFLNK);}
public bool IsSticky { }
get {AssertValid (); return IsSet (stat.st_mode, Native.FilePermissions.S_ISVTX);}
} public Boolean IsSocket {
get {
internal static bool IsFileType (Native.FilePermissions mode, Native.FilePermissions type) this.AssertValid (); return IsFileType (this.stat.st_mode, Native.FilePermissions.S_IFSOCK);}
{ }
return (mode & Native.FilePermissions.S_IFMT) == type;
} public Boolean IsSetUser {
get {
internal static bool IsSet (Native.FilePermissions mode, Native.FilePermissions type) this.AssertValid (); return IsSet (this.stat.st_mode, Native.FilePermissions.S_ISUID);}
{ }
return (mode & type) == type;
} public Boolean IsSetGroup {
get {
[CLSCompliant (false)] this.AssertValid (); return IsSet (this.stat.st_mode, Native.FilePermissions.S_ISGID);}
public bool CanAccess (Native.AccessModes mode) }
{
int r = Native.Syscall.access (FullPath, mode); public Boolean IsSticky {
return r == 0; get {
} this.AssertValid (); return IsSet (this.stat.st_mode, Native.FilePermissions.S_ISVTX);}
}
public UnixFileSystemInfo CreateLink (string path)
{ internal static Boolean IsFileType(Native.FilePermissions mode, Native.FilePermissions type) => (mode & Native.FilePermissions.S_IFMT) == type;
int r = Native.Syscall.link (FullName, path);
UnixMarshal.ThrowExceptionForLastErrorIf (r); internal static Boolean IsSet(Native.FilePermissions mode, Native.FilePermissions type) => (mode & type) == type;
return GetFileSystemEntry (path);
} //[CLSCompliant (false)]
public Boolean CanAccess (Native.AccessModes mode)
public UnixSymbolicLinkInfo CreateSymbolicLink (string path) {
{ Int32 r = Native.Syscall.access (this.FullPath, mode);
int r = Native.Syscall.symlink (FullName, path); return r == 0;
UnixMarshal.ThrowExceptionForLastErrorIf (r); }
return new UnixSymbolicLinkInfo (path);
} public UnixFileSystemInfo CreateLink (String path)
{
public abstract void Delete (); Int32 r = Native.Syscall.link (this.FullName, path);
UnixMarshal.ThrowExceptionForLastErrorIf (r);
[CLSCompliant (false)] return GetFileSystemEntry (path);
public long GetConfigurationValue (Native.PathconfName name) }
{
long r = Native.Syscall.pathconf (FullPath, name); public UnixSymbolicLinkInfo CreateSymbolicLink (String path)
if (r == -1 && Native.Stdlib.GetLastError() != (Native.Errno) 0) {
UnixMarshal.ThrowExceptionForLastError (); Int32 r = Native.Syscall.symlink (this.FullName, path);
return r; UnixMarshal.ThrowExceptionForLastErrorIf (r);
} return new UnixSymbolicLinkInfo (path);
}
public void Refresh ()
{ public abstract void Delete ();
Refresh (true);
} //[CLSCompliant (false)]
public Int64 GetConfigurationValue (Native.PathconfName name)
internal void Refresh (bool force) {
{ Int64 r = Native.Syscall.pathconf (this.FullPath, name);
if (valid && !force) if (r == -1 && Native.Stdlib.GetLastError() != (Native.Errno) 0) {
return; UnixMarshal.ThrowExceptionForLastError ();
valid = GetFileStatus (FullPath, out this.stat); }
}
return r;
protected virtual bool GetFileStatus (string path, out Native.Stat stat) }
{
return Native.Syscall.stat (path, out stat) == 0; public void Refresh() => this.Refresh(true);
}
internal void Refresh (Boolean force)
public void SetLength (long length) {
{ if (this.valid && !force) {
int r; return;
do { }
r = Native.Syscall.truncate (FullPath, length);
} while (UnixMarshal.ShouldRetrySyscall (r)); this.valid = this.GetFileStatus (this.FullPath, out this.stat);
UnixMarshal.ThrowExceptionForLastErrorIf (r); }
}
protected virtual Boolean GetFileStatus(String path, out Native.Stat stat) => Native.Syscall.stat(path, out stat) == 0;
public virtual void SetOwner (long owner, long group)
{ public void SetLength (Int64 length)
uint _owner = Convert.ToUInt32 (owner); {
uint _group = Convert.ToUInt32 (group); Int32 r;
int r = Native.Syscall.chown (FullPath, _owner, _group); do {
UnixMarshal.ThrowExceptionForLastErrorIf (r); r = Native.Syscall.truncate (this.FullPath, length);
} } while (UnixMarshal.ShouldRetrySyscall (r));
UnixMarshal.ThrowExceptionForLastErrorIf (r);
public void SetOwner (string owner) }
{
Native.Passwd pw = Native.Syscall.getpwnam (owner); public virtual void SetOwner (Int64 owner, Int64 group)
if (pw == null) {
throw new ArgumentException (Locale.GetText ("invalid username"), "owner"); UInt32 _owner = Convert.ToUInt32 (owner);
uint uid = pw.pw_uid; UInt32 _group = Convert.ToUInt32 (group);
uint gid = pw.pw_gid; Int32 r = Native.Syscall.chown (this.FullPath, _owner, _group);
SetOwner ((long) uid, (long) gid); UnixMarshal.ThrowExceptionForLastErrorIf (r);
} }
public void SetOwner (string owner, string group) public void SetOwner (String owner)
{ {
long uid = -1; Native.Passwd pw = Native.Syscall.getpwnam (owner);
if (owner != null) if (pw == null) {
uid = new UnixUserInfo (owner).UserId; throw new ArgumentException (Locale.GetText ("invalid username"), "owner");
long gid = -1; }
if (group != null)
gid = new UnixGroupInfo (group).GroupId; UInt32 uid = pw.pw_uid;
UInt32 gid = pw.pw_gid;
SetOwner (uid, gid); this.SetOwner ((Int64) uid, (Int64) gid);
} }
public void SetOwner (UnixUserInfo owner) public void SetOwner (String owner, String group)
{ {
long uid, gid; Int64 uid = -1;
uid = gid = -1; if (owner != null) {
if (owner != null) { uid = new UnixUserInfo (owner).UserId;
uid = owner.UserId; }
gid = owner.GroupId;
} Int64 gid = -1;
SetOwner (uid, gid); if (group != null) {
} gid = new UnixGroupInfo (group).GroupId;
}
public void SetOwner (UnixUserInfo owner, UnixGroupInfo group)
{ this.SetOwner (uid, gid);
long uid, gid; }
uid = gid = -1;
if (owner != null) public void SetOwner (UnixUserInfo owner)
uid = owner.UserId; {
if (group != null) Int64 uid, gid;
gid = owner.GroupId; uid = gid = -1;
SetOwner (uid, gid); if (owner != null) {
} uid = owner.UserId;
gid = owner.GroupId;
public override string ToString () }
{ this.SetOwner (uid, gid);
return FullPath; }
}
public void SetOwner (UnixUserInfo owner, UnixGroupInfo group)
public Native.Stat ToStat () {
{ Int64 uid, gid;
AssertValid (); uid = gid = -1;
return stat; if (owner != null) {
} uid = owner.UserId;
}
public static UnixFileSystemInfo GetFileSystemEntry (string path)
{ if (group != null) {
UnixFileSystemInfo info; gid = owner.GroupId;
if (TryGetFileSystemEntry (path, out info)) }
return info;
this.SetOwner (uid, gid);
UnixMarshal.ThrowExceptionForLastError (); }
// Throw DirectoryNotFoundException because lstat(2) probably failed public override String ToString() => this.FullPath;
// because of ENOTDIR (e.g. "/path/to/file/wtf"), so
// DirectoryNotFoundException is what would have been thrown anyway. public Native.Stat ToStat ()
throw new DirectoryNotFoundException ("UnixMarshal.ThrowExceptionForLastError didn't throw?!"); {
} this.AssertValid ();
return this.stat;
public static bool TryGetFileSystemEntry (string path, out UnixFileSystemInfo entry) }
{
Native.Stat stat; public static UnixFileSystemInfo GetFileSystemEntry (String path)
int r = Native.Syscall.lstat (path, out stat); {
if (r == -1) { if(TryGetFileSystemEntry(path, out UnixFileSystemInfo info)) {
if (Native.Stdlib.GetLastError() == Native.Errno.ENOENT) { return info;
entry = new UnixFileInfo (path); }
return true;
} UnixMarshal.ThrowExceptionForLastError ();
entry = null;
return false; // Throw DirectoryNotFoundException because lstat(2) probably failed
} // because of ENOTDIR (e.g. "/path/to/file/wtf"), so
// DirectoryNotFoundException is what would have been thrown anyway.
if (IsFileType (stat.st_mode, Native.FilePermissions.S_IFDIR)) throw new DirectoryNotFoundException ("UnixMarshal.ThrowExceptionForLastError didn't throw?!");
entry = new UnixDirectoryInfo (path, stat); }
else if (IsFileType (stat.st_mode, Native.FilePermissions.S_IFLNK))
entry = new UnixSymbolicLinkInfo (path, stat); public static Boolean TryGetFileSystemEntry (String path, out UnixFileSystemInfo entry)
else {
entry = new UnixFileInfo (path, stat); Int32 r = Native.Syscall.lstat(path, out Native.Stat stat);
if (r == -1) {
return true; if (Native.Stdlib.GetLastError() == Native.Errno.ENOENT) {
} entry = new UnixFileInfo (path);
} return true;
}
entry = null;
return false;
}
entry = IsFileType (stat.st_mode, Native.FilePermissions.S_IFDIR)
? new UnixDirectoryInfo (path, stat)
: IsFileType(stat.st_mode, Native.FilePermissions.S_IFLNK)
? new UnixSymbolicLinkInfo(path, stat)
: (UnixFileSystemInfo)new UnixFileInfo(path, stat);
return true;
}
}
} }
// vim: noexpandtab // vim: noexpandtab

View File

@ -33,117 +33,91 @@ using Mono.Unix;
namespace Mono.Unix { namespace Mono.Unix {
public sealed class UnixGroupInfo public sealed class UnixGroupInfo
{ {
private Native.Group group; private readonly Native.Group group;
public UnixGroupInfo (string group) public UnixGroupInfo (String group)
{ {
this.group = new Native.Group (); this.group = new Native.Group ();
Native.Group gr; Int32 r = Native.Syscall.getgrnam_r(group, this.group, out Native.Group gr);
int r = Native.Syscall.getgrnam_r (group, this.group, out gr); if (r != 0 || gr == null) {
if (r != 0 || gr == null) throw new ArgumentException (Locale.GetText ("invalid group name"), "group");
throw new ArgumentException (Locale.GetText ("invalid group name"), "group"); }
} }
public UnixGroupInfo (long group) public UnixGroupInfo (Int64 group)
{ {
this.group = new Native.Group (); this.group = new Native.Group ();
Native.Group gr; Int32 r = Native.Syscall.getgrgid_r(Convert.ToUInt32(group), this.group, out Native.Group gr);
int r = Native.Syscall.getgrgid_r (Convert.ToUInt32 (group), this.group, out gr); if (r != 0 || gr == null) {
if (r != 0 || gr == null) throw new ArgumentException (Locale.GetText ("invalid group id"), "group");
throw new ArgumentException (Locale.GetText ("invalid group id"), "group"); }
} }
public UnixGroupInfo (Native.Group group) public UnixGroupInfo(Native.Group group) => this.group = CopyGroup(group);
{
this.group = CopyGroup (group);
}
private static Native.Group CopyGroup (Native.Group group) private static Native.Group CopyGroup(Native.Group group) => new Native.Group {
{ gr_gid = group.gr_gid,
Native.Group g = new Native.Group (); gr_mem = group.gr_mem,
gr_name = group.gr_name,
gr_passwd = group.gr_passwd
};
g.gr_gid = group.gr_gid; public String GroupName => this.group.gr_name;
g.gr_mem = group.gr_mem;
g.gr_name = group.gr_name;
g.gr_passwd = group.gr_passwd;
return g; public String Password => this.group.gr_passwd;
}
public string GroupName { public Int64 GroupId => this.group.gr_gid;
get {return group.gr_name;}
}
public string Password { public UnixUserInfo[] GetMembers ()
get {return group.gr_passwd;} {
} ArrayList members = new ArrayList (this.group.gr_mem.Length);
for (Int32 i = 0; i < this.group.gr_mem.Length; ++i) {
try {
_ = members.Add(new UnixUserInfo(this.group.gr_mem[i]));
} catch (ArgumentException) {
// ignore invalid users
}
}
return (UnixUserInfo[]) members.ToArray (typeof (UnixUserInfo));
}
public long GroupId { public String[] GetMemberNames() => (String[])this.group.gr_mem.Clone();
get {return group.gr_gid;}
}
public UnixUserInfo[] GetMembers () public override Int32 GetHashCode() => this.group.GetHashCode();
{
ArrayList members = new ArrayList (group.gr_mem.Length);
for (int i = 0; i < group.gr_mem.Length; ++i) {
try {
members.Add (new UnixUserInfo (group.gr_mem [i]));
} catch (ArgumentException) {
// ignore invalid users
}
}
return (UnixUserInfo[]) members.ToArray (typeof (UnixUserInfo));
}
public string[] GetMemberNames () public override Boolean Equals(Object obj) => obj == null || this.GetType() != obj.GetType() ? false : this.group.Equals(((UnixGroupInfo)obj).group);
{
return (string[]) group.gr_mem.Clone ();
}
public override int GetHashCode () public override String ToString() => this.group.ToString();
{
return group.GetHashCode ();
}
public override bool Equals (object obj) public Native.Group ToGroup() => CopyGroup(this.group);
{
if (obj == null || GetType () != obj.GetType())
return false;
return group.Equals (((UnixGroupInfo) obj).group);
}
public override string ToString () public static UnixGroupInfo[] GetLocalGroups ()
{ {
return group.ToString(); ArrayList entries = new ArrayList ();
} lock (Native.Syscall.grp_lock) {
if (Native.Syscall.setgrent () != 0) {
UnixMarshal.ThrowExceptionForLastError ();
}
public Native.Group ToGroup () try {
{ Native.Group g;
return CopyGroup (group); while ((g = Native.Syscall.getgrent()) != null) {
} _ = entries.Add(new UnixGroupInfo(g));
}
public static UnixGroupInfo[] GetLocalGroups () if (Native.Syscall.GetLastError() != (Native.Errno) 0) {
{ UnixMarshal.ThrowExceptionForLastError ();
ArrayList entries = new ArrayList (); }
lock (Native.Syscall.grp_lock) { }
if (Native.Syscall.setgrent () != 0) finally {
UnixMarshal.ThrowExceptionForLastError (); _ = Native.Syscall.endgrent();
try { }
Native.Group g; }
while ((g = Native.Syscall.getgrent()) != null) return (UnixGroupInfo[]) entries.ToArray (typeof(UnixGroupInfo));
entries.Add (new UnixGroupInfo (g)); }
if (Native.Syscall.GetLastError() != (Native.Errno) 0) }
UnixMarshal.ThrowExceptionForLastError ();
}
finally {
Native.Syscall.endgrent ();
}
}
return (UnixGroupInfo[]) entries.ToArray (typeof(UnixGroupInfo));
}
}
} }
// vim: noexpandtab // vim: noexpandtab

View File

@ -30,75 +30,49 @@ using System;
using System.IO; using System.IO;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using Mono.Unix;
namespace Mono.Unix { namespace Mono.Unix {
[Serializable] [Serializable]
public class UnixIOException : IOException public class UnixIOException : IOException
{ {
private int errno; private Int32 errno;
public UnixIOException () public UnixIOException ()
: this (Marshal.GetLastWin32Error()) : this (Marshal.GetLastWin32Error())
{} {}
public UnixIOException (int errno) public UnixIOException(Int32 errno)
: base (GetMessage (Native.NativeConvert.ToErrno (errno))) : base(GetMessage(Native.NativeConvert.ToErrno(errno))) => this.errno = errno;
{
this.errno = errno;
}
public UnixIOException (int errno, Exception inner) public UnixIOException(Int32 errno, Exception inner)
: base (GetMessage (Native.NativeConvert.ToErrno (errno)), inner) : base(GetMessage(Native.NativeConvert.ToErrno(errno)), inner) => this.errno = errno;
{
this.errno = errno;
}
public UnixIOException (Native.Errno errno) public UnixIOException(Native.Errno errno)
: base (GetMessage (errno)) : base(GetMessage(errno)) => this.errno = Native.NativeConvert.FromErrno(errno);
{
this.errno = Native.NativeConvert.FromErrno (errno);
}
public UnixIOException (Native.Errno errno, Exception inner) public UnixIOException(Native.Errno errno, Exception inner)
: base (GetMessage (errno), inner) : base(GetMessage(errno), inner) => this.errno = Native.NativeConvert.FromErrno(errno);
{
this.errno = Native.NativeConvert.FromErrno (errno);
}
public UnixIOException (string message) public UnixIOException(String message)
: base (message) : base(message) => this.errno = 0;
{
this.errno = 0;
}
public UnixIOException (string message, Exception inner) public UnixIOException(String message, Exception inner)
: base (message, inner) : base(message, inner) => this.errno = 0;
{
this.errno = 0;
}
protected UnixIOException (SerializationInfo info, StreamingContext context) protected UnixIOException (SerializationInfo info, StreamingContext context)
: base (info, context) : base (info, context)
{ {
} }
public int NativeErrorCode { public Int32 NativeErrorCode => this.errno;
get {return errno;}
}
public Native.Errno ErrorCode { public Native.Errno ErrorCode => Native.NativeConvert.ToErrno(this.errno);
get {return Native.NativeConvert.ToErrno (errno);}
}
private static string GetMessage (Native.Errno errno) private static String GetMessage(Native.Errno errno) => String.Format("{0} [{1}].",
{ UnixMarshal.GetErrorDescription(errno),
return string.Format ("{0} [{1}].", errno);
UnixMarshal.GetErrorDescription (errno), }
errno);
}
}
} }
// vim: noexpandtab // vim: noexpandtab

View File

@ -35,139 +35,141 @@ using System.IO;
namespace Mono.Unix { namespace Mono.Unix {
public class UnixListener : MarshalByRefObject, IDisposable { public class UnixListener : MarshalByRefObject, IDisposable {
bool disposed; Boolean disposed;
bool listening; Boolean listening;
Socket server; Socket server;
EndPoint savedEP; EndPoint savedEP;
void Init (UnixEndPoint ep) void Init (UnixEndPoint ep)
{ {
listening = false; this.listening = false;
string filename = ep.Filename; String filename = ep.Filename;
if (File.Exists (filename)) { if (File.Exists (filename)) {
Socket conn = new Socket (AddressFamily.Unix, SocketType.Stream, 0); Socket conn = new Socket (AddressFamily.Unix, SocketType.Stream, 0);
try { try {
conn.Connect (ep); conn.Connect (ep);
conn.Close (); conn.Close ();
throw new InvalidOperationException ("There's already a server listening on " + filename); throw new InvalidOperationException ("There's already a server listening on " + filename);
} catch (SocketException) { } catch (SocketException) {
} }
File.Delete (filename); File.Delete (filename);
} }
server = new Socket (AddressFamily.Unix, SocketType.Stream, 0); this.server = new Socket (AddressFamily.Unix, SocketType.Stream, 0);
server.Bind (ep); this.server.Bind (ep);
savedEP = server.LocalEndPoint; this.savedEP = this.server.LocalEndPoint;
} }
public UnixListener (string path) public UnixListener (String path)
{ {
if (!Directory.Exists (Path.GetDirectoryName (path))) if (!Directory.Exists (Path.GetDirectoryName (path))) {
Directory.CreateDirectory (Path.GetDirectoryName (path)); _ = Directory.CreateDirectory(Path.GetDirectoryName(path));
}
Init (new UnixEndPoint (path)); this.Init (new UnixEndPoint (path));
} }
public UnixListener (UnixEndPoint localEndPoint) public UnixListener (UnixEndPoint localEndPoint)
{ {
if (localEndPoint == null) if (localEndPoint == null) {
throw new ArgumentNullException ("localendPoint"); throw new ArgumentNullException ("localendPoint");
}
Init (localEndPoint); this.Init (localEndPoint);
} }
public EndPoint LocalEndpoint { public EndPoint LocalEndpoint => this.savedEP;
get { return savedEP; }
}
protected Socket Server { protected Socket Server => this.server;
get { return server; }
}
public Socket AcceptSocket () public Socket AcceptSocket ()
{ {
CheckDisposed (); this.CheckDisposed ();
if (!listening) if (!this.listening) {
throw new InvalidOperationException ("Socket is not listening"); throw new InvalidOperationException ("Socket is not listening");
}
return server.Accept (); return this.server.Accept ();
} }
public UnixClient AcceptUnixClient () public UnixClient AcceptUnixClient ()
{ {
CheckDisposed (); this.CheckDisposed ();
if (!listening) if (!this.listening) {
throw new InvalidOperationException ("Socket is not listening"); throw new InvalidOperationException ("Socket is not listening");
}
return new UnixClient (AcceptSocket ()); return new UnixClient (this.AcceptSocket ());
} }
~UnixListener () ~UnixListener ()
{ {
Dispose (false); this.Dispose (false);
} }
public bool Pending () public Boolean Pending ()
{ {
CheckDisposed (); this.CheckDisposed ();
if (!listening) if (!this.listening) {
throw new InvalidOperationException ("Socket is not listening"); throw new InvalidOperationException ("Socket is not listening");
}
return server.Poll (1000, SelectMode.SelectRead); return this.server.Poll (1000, SelectMode.SelectRead);
} }
public void Start () public void Start() => this.Start(5);
{
Start (5);
}
public void Start (int backlog) public void Start (Int32 backlog)
{ {
CheckDisposed (); this.CheckDisposed ();
if (listening) if (this.listening) {
return; return;
}
server.Listen (backlog); this.server.Listen (backlog);
listening = true; this.listening = true;
} }
public void Stop () public void Stop ()
{ {
CheckDisposed (); this.CheckDisposed ();
Dispose (true); this.Dispose (true);
} }
public void Dispose () public void Dispose ()
{ {
Dispose (true); this.Dispose (true);
GC.SuppressFinalize (this); GC.SuppressFinalize (this);
} }
protected void Dispose (bool disposing) protected void Dispose (Boolean disposing)
{ {
if (disposed) if (this.disposed) {
return; return;
}
if (disposing) { if (disposing) {
try { try {
File.Delete (((UnixEndPoint) savedEP).Filename); File.Delete (((UnixEndPoint)this.savedEP).Filename);
} catch { } catch {
} }
if (server != null) if (this.server != null) {
server.Close (); this.server.Close ();
}
server = null; this.server = null;
} }
disposed = true; this.disposed = true;
} }
void CheckDisposed () void CheckDisposed ()
{ {
if (disposed) if (this.disposed) {
throw new ObjectDisposedException (GetType().FullName); throw new ObjectDisposedException (this.GetType().FullName);
} }
} }
}
} }

View File

@ -27,6 +27,7 @@
// //
using System; using System;
using System.Diagnostics.CodeAnalysis;
using System.IO; using System.IO;
using System.Net.Sockets; using System.Net.Sockets;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -36,461 +37,434 @@ using Mono.Unix;
namespace Mono.Unix { namespace Mono.Unix {
// Scenario: We want to be able to translate an Error to a string. // Scenario: We want to be able to translate an Error to a string.
// Problem: Thread-safety. Strerror(3) isn't thread safe (unless // Problem: Thread-safety. Strerror(3) isn't thread safe (unless
// thread-local-variables are used, which is probably only // thread-local-variables are used, which is probably only
// true on Windows). // true on Windows).
// Solution: Use strerror_r(). // Solution: Use strerror_r().
// Problem: strerror_r() isn't portable. // Problem: strerror_r() isn't portable.
// (Apparently Solaris doesn't provide it.) // (Apparently Solaris doesn't provide it.)
// Solution: Cry. Then introduce an intermediary, ErrorMarshal. // Solution: Cry. Then introduce an intermediary, ErrorMarshal.
// ErrorMarshal exposes a single public delegate, Translator, // ErrorMarshal exposes a single public delegate, Translator,
// which will convert an Error to a string. It's static // which will convert an Error to a string. It's static
// constructor first tries using strerror_r(). If it works, // constructor first tries using strerror_r(). If it works,
// great; use it in the future. If it doesn't work, fallback to // great; use it in the future. If it doesn't work, fallback to
// using strerror(3). // using strerror(3).
// This should be thread safe, since the check is done within the // This should be thread safe, since the check is done within the
// class constructor lock. // class constructor lock.
// Strerror(3) will be thread-safe from managed code, but won't // Strerror(3) will be thread-safe from managed code, but won't
// be thread-safe between managed & unmanaged code. // be thread-safe between managed & unmanaged code.
internal class ErrorMarshal internal class ErrorMarshal
{ {
internal delegate string ErrorTranslator (Native.Errno errno); internal delegate String ErrorTranslator (Native.Errno errno);
internal static readonly ErrorTranslator Translate; internal static readonly ErrorTranslator Translate;
static ErrorMarshal () static ErrorMarshal ()
{ {
try { try {
Translate = new ErrorTranslator (strerror_r); Translate = new ErrorTranslator (strerror_r);
Translate (Native.Errno.ERANGE); _ = Translate(Native.Errno.ERANGE);
} }
catch (EntryPointNotFoundException) { catch (EntryPointNotFoundException) {
Translate = new ErrorTranslator (strerror); Translate = new ErrorTranslator (strerror);
} }
} }
private static string strerror (Native.Errno errno) [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
{ private static String strerror(Native.Errno errno) => Native.Stdlib.strerror(errno);
return Native.Stdlib.strerror (errno);
} [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
private static String strerror_r (Native.Errno errno)
private static string strerror_r (Native.Errno errno) {
{ StringBuilder buf = new StringBuilder (16);
StringBuilder buf = new StringBuilder (16); Int32 r;
int r = 0; do {
do { buf.Capacity *= 2;
buf.Capacity *= 2; r = Native.Syscall.strerror_r (errno, buf);
r = Native.Syscall.strerror_r (errno, buf); } while (r == -1 && Native.Stdlib.GetLastError() == Native.Errno.ERANGE);
} while (r == -1 && Native.Stdlib.GetLastError() == Native.Errno.ERANGE);
return r == -1 ? "** Unknown error code: " + (Int32) errno + "**" : buf.ToString();
if (r == -1) }
return "** Unknown error code: " + ((int) errno) + "**"; }
return buf.ToString();
} public sealed /* static */ class UnixMarshal
} {
private UnixMarshal () {}
public sealed /* static */ class UnixMarshal
{ //[CLSCompliant(false)]
private UnixMarshal () {} public static String GetErrorDescription(Native.Errno errno) => ErrorMarshal.Translate(errno);
[CLSCompliant (false)] public static IntPtr AllocHeap (Int64 size)
public static string GetErrorDescription (Native.Errno errno) {
{ if (size < 0) {
return ErrorMarshal.Translate (errno); throw new ArgumentOutOfRangeException ("size", "< 0");
} }
public static IntPtr AllocHeap (long size) return Native.Stdlib.malloc ((UInt64) size);
{ }
if (size < 0)
throw new ArgumentOutOfRangeException ("size", "< 0"); public static IntPtr ReAllocHeap (IntPtr ptr, Int64 size)
return Native.Stdlib.malloc ((ulong) size); {
} if (size < 0) {
throw new ArgumentOutOfRangeException ("size", "< 0");
public static IntPtr ReAllocHeap (IntPtr ptr, long size) }
{
if (size < 0) return Native.Stdlib.realloc (ptr, (UInt64) size);
throw new ArgumentOutOfRangeException ("size", "< 0"); }
return Native.Stdlib.realloc (ptr, (ulong) size);
} public static void FreeHeap(IntPtr ptr) => Native.Stdlib.free(ptr);
public static void FreeHeap (IntPtr ptr) public static unsafe String PtrToStringUnix (IntPtr p)
{ {
Native.Stdlib.free (ptr); if (p == IntPtr.Zero) {
} return null;
}
public static unsafe string PtrToStringUnix (IntPtr p)
{ Int32 len = checked ((Int32) Native.Stdlib.strlen (p));
if (p == IntPtr.Zero) return new String((SByte*) p, 0, len, UnixEncoding.Instance);
return null; }
int len = checked ((int) Native.Stdlib.strlen (p)); public static String PtrToString(IntPtr p) => p == IntPtr.Zero ? null : PtrToString(p, UnixEncoding.Instance);
return new string ((sbyte*) p, 0, len, UnixEncoding.Instance);
} public static unsafe String PtrToString (IntPtr p, Encoding encoding)
{
public static string PtrToString (IntPtr p) if (p == IntPtr.Zero) {
{ return null;
if (p == IntPtr.Zero) }
return null;
return PtrToString (p, UnixEncoding.Instance); if (encoding == null) {
} throw new ArgumentNullException ("encoding");
}
public static unsafe string PtrToString (IntPtr p, Encoding encoding)
{ Int32 len = GetStringByteLength (p, encoding);
if (p == IntPtr.Zero)
return null; // Due to variable-length encoding schemes, GetStringByteLength() may
// have returned multiple "null" characters. (For example, when
if (encoding == null) // encoding a string into UTF-8 there will be 4 terminating nulls.)
throw new ArgumentNullException ("encoding"); // We don't want these null's to be in the returned string, so strip
// them off.
int len = GetStringByteLength (p, encoding); String s = new String((SByte*) p, 0, len, encoding);
len = s.Length;
// Due to variable-length encoding schemes, GetStringByteLength() may while (len > 0 && s [len-1] == 0) {
// have returned multiple "null" characters. (For example, when --len;
// encoding a string into UTF-8 there will be 4 terminating nulls.) }
// We don't want these null's to be in the returned string, so strip
// them off. return len == s.Length ? s : s.Substring (0, len);
string s = new string ((sbyte*) p, 0, len, encoding); }
len = s.Length;
while (len > 0 && s [len-1] == 0) private static Int32 GetStringByteLength (IntPtr p, Encoding encoding)
--len; {
if (len == s.Length) Type encodingType = encoding.GetType ();
return s;
return s.Substring (0, len); Int32 len = typeof(UTF8Encoding).IsAssignableFrom (encodingType) ||
} typeof(UTF7Encoding).IsAssignableFrom (encodingType) ||
typeof(UnixEncoding).IsAssignableFrom (encodingType) ||
private static int GetStringByteLength (IntPtr p, Encoding encoding) typeof(ASCIIEncoding).IsAssignableFrom (encodingType)
{ ? (Int32) Native.Stdlib.strlen (p)
Type encodingType = encoding.GetType (); : typeof(UnicodeEncoding).IsAssignableFrom(encodingType)
? GetInt16BufferLength(p)
int len = -1; : typeof(UTF32Encoding).IsAssignableFrom(encodingType)
? GetInt32BufferLength(p)
// Encodings that will always end with a single null byte : GetRandomBufferLength(p, encoding.GetMaxByteCount(1));
if (typeof(UTF8Encoding).IsAssignableFrom (encodingType) ||
typeof(UTF7Encoding).IsAssignableFrom (encodingType) || // Encodings that will always end with a single null byte
typeof(UnixEncoding).IsAssignableFrom (encodingType) ||
typeof(ASCIIEncoding).IsAssignableFrom (encodingType)) { if(len == -1) {
len = checked ((int) Native.Stdlib.strlen (p)); throw new NotSupportedException ("Unable to determine native string buffer length");
} }
// Encodings that will always end with a 0x0000 16-bit word
else if (typeof(UnicodeEncoding).IsAssignableFrom (encodingType)) { return len;
len = GetInt16BufferLength (p); }
}
// Encodings that will always end with a 0x00000000 32-bit word private static Int32 GetInt16BufferLength (IntPtr p)
else if (typeof(UTF32Encoding).IsAssignableFrom (encodingType)) { {
len = GetInt32BufferLength (p); Int32 len = 0;
} while (Marshal.ReadInt16 (p, len*2) != 0) {
// Some non-public encoding, such as Latin1 or a DBCS charset. checked {++len;}
// Look for a sequence of encoding.GetMaxByteCount() bytes that are all }
// 0, which should be the terminating null.
// This is "iffy", since it may fail for variable-width encodings; for return checked(len*2);
// example, UTF8Encoding.GetMaxByteCount(1) = 4, so this would read 3 }
// bytes past the end of the string, possibly into garbage memory
// (which is why we special case UTF above). private static Int32 GetInt32BufferLength (IntPtr p)
else { {
len = GetRandomBufferLength (p, encoding.GetMaxByteCount(1)); Int32 len = 0;
} while (Marshal.ReadInt32 (p, len*4) != 0) {
checked {++len;}
if (len == -1) }
throw new NotSupportedException ("Unable to determine native string buffer length");
return len; return checked(len*4);
} }
private static int GetInt16BufferLength (IntPtr p) private static Int32 GetRandomBufferLength (IntPtr p, Int32 nullLength)
{ {
int len = 0; switch (nullLength) {
while (Marshal.ReadInt16 (p, len*2) != 0) case 1: return checked ((Int32) Native.Stdlib.strlen (p));
checked {++len;} case 2: return GetInt16BufferLength (p);
return checked(len*2); case 4: return GetInt32BufferLength (p);
} }
private static int GetInt32BufferLength (IntPtr p) Int32 len = 0;
{ Int32 num_null_seen = 0;
int len = 0;
while (Marshal.ReadInt32 (p, len*4) != 0) do {
checked {++len;} Byte b = Marshal.ReadByte (p, len++);
return checked(len*4); if (b == 0) {
} ++num_null_seen;
} else {
private static int GetRandomBufferLength (IntPtr p, int nullLength) num_null_seen = 0;
{ }
switch (nullLength) { } while (num_null_seen != nullLength);
case 1: return checked ((int) Native.Stdlib.strlen (p));
case 2: return GetInt16BufferLength (p); return len;
case 4: return GetInt32BufferLength (p); }
}
/*
int len = 0; * Marshal a C `char **'. ANSI C `main' requirements are assumed:
int num_null_seen = 0; *
* stringArray is an array of pointers to C strings
do { * stringArray has a terminating NULL string.
byte b = Marshal.ReadByte (p, len++); *
if (b == 0) * For example:
++num_null_seen; * stringArray[0] = "string 1";
else * stringArray[1] = "string 2";
num_null_seen = 0; * stringArray[2] = NULL
} while (num_null_seen != nullLength); *
* The terminating NULL is required so that we know when to stop looking
return len; * for strings.
} */
public static String[] PtrToStringArray(IntPtr stringArray) => PtrToStringArray(stringArray, UnixEncoding.Instance);
/*
* Marshal a C `char **'. ANSI C `main' requirements are assumed: public static String[] PtrToStringArray (IntPtr stringArray, Encoding encoding)
* {
* stringArray is an array of pointers to C strings if (stringArray == IntPtr.Zero) {
* stringArray has a terminating NULL string. return new String[]{};
* }
* For example:
* stringArray[0] = "string 1"; Int32 argc = CountStrings (stringArray);
* stringArray[1] = "string 2"; return PtrToStringArray (argc, stringArray, encoding);
* stringArray[2] = NULL }
*
* The terminating NULL is required so that we know when to stop looking private static Int32 CountStrings (IntPtr stringArray)
* for strings. {
*/ Int32 count = 0;
public static string[] PtrToStringArray (IntPtr stringArray) while (Marshal.ReadIntPtr (stringArray, count*IntPtr.Size) != IntPtr.Zero) {
{ ++count;
return PtrToStringArray (stringArray, UnixEncoding.Instance); }
}
return count;
public static string[] PtrToStringArray (IntPtr stringArray, Encoding encoding) }
{
if (stringArray == IntPtr.Zero) /*
return new string[]{}; * Like PtrToStringArray(IntPtr), but it allows the user to specify how
* many strings to look for in the array. As such, the requirement for a
int argc = CountStrings (stringArray); * terminating NULL element is not required.
return PtrToStringArray (argc, stringArray, encoding); *
} * Usage is similar to ANSI C `main': count is argc, stringArray is argv.
* stringArray[count] is NOT accessed (though ANSI C requires that
private static int CountStrings (IntPtr stringArray) * argv[argc] = NULL, which PtrToStringArray(IntPtr) requires).
{ */
int count = 0; public static String[] PtrToStringArray(Int32 count, IntPtr stringArray) => PtrToStringArray(count, stringArray, UnixEncoding.Instance);
while (Marshal.ReadIntPtr (stringArray, count*IntPtr.Size) != IntPtr.Zero)
++count; public static String[] PtrToStringArray (Int32 count, IntPtr stringArray, Encoding encoding)
return count; {
} if (count < 0) {
throw new ArgumentOutOfRangeException ("count", "< 0");
/* }
* Like PtrToStringArray(IntPtr), but it allows the user to specify how
* many strings to look for in the array. As such, the requirement for a if (encoding == null) {
* terminating NULL element is not required. throw new ArgumentNullException ("encoding");
* }
* Usage is similar to ANSI C `main': count is argc, stringArray is argv.
* stringArray[count] is NOT accessed (though ANSI C requires that if (stringArray == IntPtr.Zero) {
* argv[argc] = NULL, which PtrToStringArray(IntPtr) requires). return new String[count];
*/ }
public static string[] PtrToStringArray (int count, IntPtr stringArray)
{ String[] members = new String[count];
return PtrToStringArray (count, stringArray, UnixEncoding.Instance); for (Int32 i = 0; i < count; ++i) {
} IntPtr s = Marshal.ReadIntPtr (stringArray, i * IntPtr.Size);
members[i] = PtrToString (s, encoding);
public static string[] PtrToStringArray (int count, IntPtr stringArray, Encoding encoding) }
{
if (count < 0) return members;
throw new ArgumentOutOfRangeException ("count", "< 0"); }
if (encoding == null)
throw new ArgumentNullException ("encoding"); public static IntPtr StringToHeap(String s) => StringToHeap(s, UnixEncoding.Instance);
if (stringArray == IntPtr.Zero)
return new string[count]; public static IntPtr StringToHeap(String s, Encoding encoding) => s == null ? IntPtr.Zero : StringToHeap(s, 0, s.Length, encoding);
string[] members = new string[count]; public static IntPtr StringToHeap(String s, Int32 index, Int32 count) => StringToHeap(s, index, count, UnixEncoding.Instance);
for (int i = 0; i < count; ++i) {
IntPtr s = Marshal.ReadIntPtr (stringArray, i * IntPtr.Size); public static IntPtr StringToHeap (String s, Int32 index, Int32 count, Encoding encoding)
members[i] = PtrToString (s, encoding); {
} if (s == null) {
return IntPtr.Zero;
return members; }
}
if (encoding == null) {
public static IntPtr StringToHeap (string s) throw new ArgumentNullException ("encoding");
{ }
return StringToHeap (s, UnixEncoding.Instance);
} if (index < 0 || count < 0) {
throw new ArgumentOutOfRangeException (index < 0 ? "index" : "count",
public static IntPtr StringToHeap (string s, Encoding encoding) "Non - negative number required.");
{ }
if (s == null)
return IntPtr.Zero; if (s.Length - index < count) {
throw new ArgumentOutOfRangeException ("s", "Index and count must refer to a location within the string.");
return StringToHeap (s, 0, s.Length, encoding); }
}
Int32 null_terminator_count = encoding.GetMaxByteCount (1);
public static IntPtr StringToHeap (string s, int index, int count) Int32 length_without_null = encoding.GetByteCount (s);
{ Int32 marshalLength = checked (length_without_null + null_terminator_count);
return StringToHeap (s, index, count, UnixEncoding.Instance);
} IntPtr mem = AllocHeap (marshalLength);
if (mem == IntPtr.Zero) {
public static IntPtr StringToHeap (string s, int index, int count, Encoding encoding) throw new UnixIOException (Native.Errno.ENOMEM);
{ }
if (s == null)
return IntPtr.Zero; unsafe {
fixed (Char* p = s) {
if (encoding == null) Byte* marshal = (Byte*)mem;
throw new ArgumentNullException ("encoding"); Int32 bytes_copied;
if (index < 0 || count < 0) try {
throw new ArgumentOutOfRangeException ((index < 0 ? "index" : "count"), bytes_copied = encoding.GetBytes (p + index, count, marshal, marshalLength);
"Non - negative number required."); } catch {
FreeHeap (mem);
if (s.Length - index < count) throw;
throw new ArgumentOutOfRangeException ("s", "Index and count must refer to a location within the string."); }
int null_terminator_count = encoding.GetMaxByteCount (1); if (bytes_copied != length_without_null) {
int length_without_null = encoding.GetByteCount (s); FreeHeap (mem);
int marshalLength = checked (length_without_null + null_terminator_count); throw new NotSupportedException ("encoding.GetBytes() doesn't equal encoding.GetByteCount()!");
}
IntPtr mem = AllocHeap (marshalLength);
if (mem == IntPtr.Zero) marshal += length_without_null;
throw new UnixIOException (Native.Errno.ENOMEM); for (Int32 i = 0; i < null_terminator_count; ++i) {
marshal[i] = 0;
unsafe { }
fixed (char* p = s) { }
byte* marshal = (byte*)mem; }
int bytes_copied;
return mem;
try { }
bytes_copied = encoding.GetBytes (p + index, count, marshal, marshalLength);
} catch { public static Boolean ShouldRetrySyscall(Int32 r) => r == -1 && Native.Stdlib.GetLastError() == Native.Errno.EINTR;
FreeHeap (mem);
throw; //[CLSCompliant (false)]
} public static Boolean ShouldRetrySyscall (Int32 r, out Native.Errno errno)
{
if (bytes_copied != length_without_null) { errno = (Native.Errno) 0;
FreeHeap (mem); return r == -1 && (errno = Native.Stdlib.GetLastError ()) == Native.Errno.EINTR;
throw new NotSupportedException ("encoding.GetBytes() doesn't equal encoding.GetByteCount()!"); }
}
// we can't permit any printf(3)-style formatting information, since that
marshal += length_without_null; // would kill the stack. However, replacing %% is silly, and some %* are
for (int i = 0; i < null_terminator_count; ++i) // permitted (such as %m in syslog to print strerror(errno)).
marshal[i] = 0; internal static String EscapeFormatString (String message,
} Char[] permitted)
} {
if (message == null) {
return mem; return "";
} }
public static bool ShouldRetrySyscall (int r) StringBuilder sb = new StringBuilder (message.Length);
{ for (Int32 i = 0; i < message.Length; ++i) {
if (r == -1 && Native.Stdlib.GetLastError () == Native.Errno.EINTR) Char c = message [i];
return true; _ = sb.Append(c);
return false; if (c == '%' && i+1 < message.Length) {
} Char n = message [i+1];
_ = n == '%' || IsCharPresent (permitted, n) ? sb.Append(n) : sb.Append('%').Append(n);
[CLSCompliant (false)]
public static bool ShouldRetrySyscall (int r, out Native.Errno errno) ++i;
{ }
errno = (Native.Errno) 0; // invalid format string: % at EOS.
if (r == -1 && (errno = Native.Stdlib.GetLastError ()) == Native.Errno.EINTR) else if (c == '%') {
return true; _ = sb.Append('%');
return false; }
} }
return sb.ToString ();
// we can't permit any printf(3)-style formatting information, since that }
// would kill the stack. However, replacing %% is silly, and some %* are
// permitted (such as %m in syslog to print strerror(errno)). private static Boolean IsCharPresent (Char[] array, Char c)
internal static string EscapeFormatString (string message, {
char [] permitted) if (array == null) {
{ return false;
if (message == null) }
return "";
StringBuilder sb = new StringBuilder (message.Length); for (Int32 i = 0; i < array.Length; ++i) {
for (int i = 0; i < message.Length; ++i) { if (array [i] == c) {
char c = message [i]; return true;
sb.Append (c); }
if (c == '%' && (i+1) < message.Length) { }
char n = message [i+1];
if (n == '%' || IsCharPresent (permitted, n)) return false;
sb.Append (n); }
else
sb.Append ('%').Append (n); internal static Exception CreateExceptionForError (Native.Errno errno)
++i; {
} String message = GetErrorDescription (errno);
// invalid format string: % at EOS. UnixIOException p = new UnixIOException (errno);
else if (c == '%')
sb.Append ('%'); // Ordering: Order alphabetically by exception first (right column),
} // then order alphabetically by Errno value (left column) for the given
return sb.ToString (); // exception.
} switch (errno) {
case Native.Errno.EBADF:
private static bool IsCharPresent (char[] array, char c) case Native.Errno.EINVAL: return new ArgumentException (message, p);
{
if (array == null) case Native.Errno.ERANGE: return new ArgumentOutOfRangeException (message);
return false; case Native.Errno.ENOTDIR: return new DirectoryNotFoundException (message, p);
for (int i = 0; i < array.Length; ++i) case Native.Errno.ENOENT: return new FileNotFoundException (message, p);
if (array [i] == c)
return true; case Native.Errno.EOPNOTSUPP:
return false; case Native.Errno.EPERM: return new InvalidOperationException (message, p);
}
case Native.Errno.ENOEXEC: return new InvalidProgramException (message, p);
internal static Exception CreateExceptionForError (Native.Errno errno)
{ case Native.Errno.EIO:
string message = GetErrorDescription (errno); case Native.Errno.ENOSPC:
UnixIOException p = new UnixIOException (errno); case Native.Errno.ENOTEMPTY:
case Native.Errno.ENXIO:
// Ordering: Order alphabetically by exception first (right column), case Native.Errno.EROFS:
// then order alphabetically by Errno value (left column) for the given case Native.Errno.ESPIPE: return new IOException (message, p);
// exception.
switch (errno) { case Native.Errno.EFAULT: return new NullReferenceException (message, p);
case Native.Errno.EBADF: case Native.Errno.EOVERFLOW: return new OverflowException (message, p);
case Native.Errno.EINVAL: return new ArgumentException (message, p); case Native.Errno.ENAMETOOLONG: return new PathTooLongException (message, p);
case Native.Errno.ERANGE: return new ArgumentOutOfRangeException (message); case Native.Errno.EACCES:
case Native.Errno.ENOTDIR: return new DirectoryNotFoundException (message, p); case Native.Errno.EISDIR: return new UnauthorizedAccessException (message, p);
case Native.Errno.ENOENT: return new FileNotFoundException (message, p);
default: /* ignore */ break;
case Native.Errno.EOPNOTSUPP: }
case Native.Errno.EPERM: return new InvalidOperationException (message, p); return p;
}
case Native.Errno.ENOEXEC: return new InvalidProgramException (message, p);
internal static Exception CreateExceptionForLastError() => CreateExceptionForError(Native.Stdlib.GetLastError());
case Native.Errno.EIO:
case Native.Errno.ENOSPC: //[CLSCompliant(false)]
case Native.Errno.ENOTEMPTY: public static void ThrowExceptionForError(Native.Errno errno) => throw CreateExceptionForError(errno);
case Native.Errno.ENXIO:
case Native.Errno.EROFS: public static void ThrowExceptionForLastError() => throw CreateExceptionForLastError();
case Native.Errno.ESPIPE: return new IOException (message, p);
//[CLSCompliant (false)]
case Native.Errno.EFAULT: return new NullReferenceException (message, p); public static void ThrowExceptionForErrorIf (Int32 retval, Native.Errno errno)
case Native.Errno.EOVERFLOW: return new OverflowException (message, p); {
case Native.Errno.ENAMETOOLONG: return new PathTooLongException (message, p); if (retval == -1) {
ThrowExceptionForError (errno);
case Native.Errno.EACCES: }
case Native.Errno.EISDIR: return new UnauthorizedAccessException (message, p); }
default: /* ignore */ break; public static void ThrowExceptionForLastErrorIf (Int32 retval)
} {
return p; if (retval == -1) {
} ThrowExceptionForLastError ();
}
internal static Exception CreateExceptionForLastError () }
{ }
return CreateExceptionForError (Native.Stdlib.GetLastError());
}
[CLSCompliant (false)]
public static void ThrowExceptionForError (Native.Errno errno)
{
throw CreateExceptionForError (errno);
}
public static void ThrowExceptionForLastError ()
{
throw CreateExceptionForLastError ();
}
[CLSCompliant (false)]
public static void ThrowExceptionForErrorIf (int retval, Native.Errno errno)
{
if (retval == -1)
ThrowExceptionForError (errno);
}
public static void ThrowExceptionForLastErrorIf (int retval)
{
if (retval == -1)
ThrowExceptionForLastError ();
}
}
} }
// vim: noexpandtab // vim: noexpandtab

View File

@ -28,259 +28,272 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Diagnostics.CodeAnalysis;
using System.Text; using System.Text;
using Mono.Unix; using Mono.Unix;
namespace Mono.Unix { namespace Mono.Unix {
public sealed class UnixPath public sealed class UnixPath
{ {
private UnixPath () {} private UnixPath () {}
public static readonly char DirectorySeparatorChar = '/'; public static readonly Char DirectorySeparatorChar = '/';
public static readonly char AltDirectorySeparatorChar = '/'; public static readonly Char AltDirectorySeparatorChar = '/';
public static readonly char PathSeparator = ':'; public static readonly Char PathSeparator = ':';
public static readonly char VolumeSeparatorChar = '/'; public static readonly Char VolumeSeparatorChar = '/';
private static readonly char[] _InvalidPathChars = new char[]{}; private static readonly Char[] _InvalidPathChars = new Char[]{};
public static char[] GetInvalidPathChars () public static Char[] GetInvalidPathChars() => (Char[])_InvalidPathChars.Clone();
{
return (char[]) _InvalidPathChars.Clone ();
}
public static string Combine (string path1, params string[] paths) public static String Combine (String path1, params String[] paths)
{ {
if (path1 == null) if (path1 == null) {
throw new ArgumentNullException ("path1"); 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; if (paths == null) {
int start = -1; throw new ArgumentNullException ("paths");
for (int i = 0; i < paths.Length; ++i) { }
if (paths [i] == null)
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); if (path1.IndexOfAny (_InvalidPathChars) != -1) {
if (start == -1) { throw new ArgumentException ("Illegal characters in path", "path1");
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) Int32 len = path1.Length;
{ Int32 start = -1;
if (path.Length > 0 && part.Length > 0) { for (Int32 i = 0; i < paths.Length; ++i) {
char end = path [path.Length-1]; if (paths [i] == null) {
if (end != DirectorySeparatorChar && throw new ArgumentNullException ("paths[" + i + "]");
end != AltDirectorySeparatorChar && }
end != VolumeSeparatorChar)
path.Append (DirectorySeparatorChar);
}
path.Append (part);
}
public static string GetDirectoryName (string path) if (paths [i].IndexOfAny (_InvalidPathChars) != -1) {
{ throw new ArgumentException ("Illegal characters in path", "paths[" + i + "]");
CheckPath (path); }
int lastDir = path.LastIndexOf (DirectorySeparatorChar); if (IsPathRooted (paths [i])) {
if (lastDir > 0) len = 0;
return path.Substring (0, lastDir); start = i;
if (lastDir == 0) }
return "/"; len += paths [i].Length + 1;
return ""; }
}
public static string GetFileName (string path) StringBuilder sb = new StringBuilder (len);
{ if (start == -1) {
if (path == null || path.Length == 0) _ = sb.Append(path1);
return path; start = 0;
}
for (Int32 i = start; i < paths.Length; ++i) {
Combine (sb, paths [i]);
}
int lastDir = path.LastIndexOf (DirectorySeparatorChar); return sb.ToString ();
if (lastDir >= 0) }
return path.Substring (lastDir+1);
return path; private static void Combine (StringBuilder path, String part)
} {
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);
}
public static string GetFullPath (string path) public static String GetDirectoryName (String path)
{ {
path = _GetFullPath (path); CheckPath (path);
return GetCanonicalPath (path);
}
private static string _GetFullPath (string path) Int32 lastDir = path.LastIndexOf (DirectorySeparatorChar);
{ return lastDir > 0 ? path.Substring (0, lastDir) : lastDir == 0 ? "/" : "";
if (path == null) }
throw new ArgumentNullException ("path");
if (!IsPathRooted (path))
path = UnixDirectoryInfo.GetCurrentDirectory() + DirectorySeparatorChar + path;
return path; public static String GetFileName (String path)
} {
if (path == null || path.Length == 0) {
return path;
}
public static string GetCanonicalPath (string path) Int32 lastDir = path.LastIndexOf (DirectorySeparatorChar);
{ return lastDir >= 0 ? path.Substring (lastDir+1) : path;
string [] dirs; }
int lastIndex;
GetPathComponents (path, out dirs, out lastIndex);
string end = string.Join ("/", dirs, 0, lastIndex);
return IsPathRooted (path) ? "/" + end : end;
}
private static void GetPathComponents (string path, public static String GetFullPath (String path)
out string[] components, out int lastIndex) {
{ path = _GetFullPath (path);
string [] dirs = path.Split (DirectorySeparatorChar); return GetCanonicalPath (path);
int target = 0; }
for (int i = 0; i < dirs.Length; ++i) {
if (dirs [i] == "." || dirs [i] == string.Empty) continue;
else if (dirs [i] == "..") {
if (target != 0) --target;
else ++target;
}
else
dirs [target++] = dirs [i];
}
components = dirs;
lastIndex = target;
}
public static string GetPathRoot (string path) [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
{ private static String _GetFullPath (String path)
if (path == null) {
return null; if (path == null) {
if (!IsPathRooted (path)) throw new ArgumentNullException ("path");
return ""; }
return "/";
}
public static string GetCompleteRealPath (string path) if (!IsPathRooted (path)) {
{ path = UnixDirectoryInfo.GetCurrentDirectory() + DirectorySeparatorChar + path;
if (path == null) }
throw new ArgumentNullException ("path");
string [] dirs;
int lastIndex;
GetPathComponents (path, out dirs, out lastIndex);
StringBuilder realPath = new StringBuilder ();
if (dirs.Length > 0) {
string dir = IsPathRooted (path) ? "/" : "";
dir += dirs [0];
realPath.Append (GetRealPath (dir));
}
for (int i = 1; i < lastIndex; ++i) {
realPath.Append ("/").Append (dirs [i]);
string p = GetRealPath (realPath.ToString());
realPath.Remove (0, realPath.Length);
realPath.Append (p);
}
return realPath.ToString ();
}
public static string GetRealPath (string path) return path;
{ }
do {
string name = ReadSymbolicLink (path);
if (name == null)
return path;
if (IsPathRooted (name))
path = name;
else {
path = GetDirectoryName (path) + DirectorySeparatorChar + name;
path = GetCanonicalPath (path);
}
} while (true);
}
// Read the specified symbolic link. If the file isn't a symbolic link, public static String GetCanonicalPath (String path)
// return null; otherwise, return the contents of the symbolic link. {
internal static string ReadSymbolicLink (string path) GetPathComponents(path, out String[] dirs, out Int32 lastIndex);
{ String end = String.Join ("/", dirs, 0, lastIndex);
string target = TryReadLink (path); return IsPathRooted (path) ? "/" + end : end;
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) private static void GetPathComponents (String path,
{ out String[] components, out Int32 lastIndex)
byte[] buf = new byte[256]; {
do { String[] dirs = path.Split (DirectorySeparatorChar);
long r = Native.Syscall.readlink (path, buf); Int32 target = 0;
if (r < 0) for (Int32 i = 0; i < dirs.Length; ++i) {
return null; if (dirs [i] == "." || dirs [i] == String.Empty) {
else if (r == buf.Length) continue;
buf = new byte[checked (buf.LongLength * 2)]; } else if (dirs [i] == "..") {
else if (target != 0) {
return UnixEncoding.Instance.GetString (buf, 0, checked ((int) r)); --target;
} while (true); } else {
} ++target;
}
}
else {
dirs [target++] = dirs [i];
}
}
components = dirs;
lastIndex = target;
}
public static string TryReadLinkAt (int dirfd, string path) public static String GetPathRoot(String path) => path == null ? null : !IsPathRooted(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 UnixEncoding.Instance.GetString (buf, 0, checked ((int) r));
} while (true);
}
public static string ReadLink (string path) public static String GetCompleteRealPath (String path)
{ {
string target = TryReadLink (path); if (path == null) {
if (target == null) throw new ArgumentNullException ("path");
UnixMarshal.ThrowExceptionForLastError (); }
return target;
}
public static string ReadLinkAt (int dirfd, string path) GetPathComponents(path, out String[] dirs, out Int32 lastIndex);
{ StringBuilder realPath = new StringBuilder ();
string target = TryReadLinkAt (dirfd, path); if (dirs.Length > 0) {
if (target == null) String dir = IsPathRooted (path) ? "/" : "";
UnixMarshal.ThrowExceptionForLastError (); dir += dirs [0];
return target; _ = realPath.Append(GetRealPath(dir));
} }
for (Int32 i = 1; i < lastIndex; ++i) {
_ = realPath.Append("/").Append(dirs[i]);
String p = GetRealPath (realPath.ToString());
_ = realPath.Remove(0, realPath.Length);
_ = realPath.Append(p);
}
return realPath.ToString ();
}
public static bool IsPathRooted (string path) public static String GetRealPath (String path)
{ {
if (path == null || path.Length == 0) do {
return false; String name = ReadSymbolicLink (path);
return path [0] == DirectorySeparatorChar; if (name == null) {
} return path;
}
internal static void CheckPath (string path) if (IsPathRooted (name)) {
{ path = name;
if (path == null) } else {
throw new ArgumentNullException (); path = GetDirectoryName (path) + DirectorySeparatorChar + name;
if (path.Length == 0) path = GetCanonicalPath (path);
throw new ArgumentException ("Path cannot contain a zero-length string", "path"); }
if (path.IndexOfAny (_InvalidPathChars) != -1) } while (true);
throw new ArgumentException ("Invalid characters in path.", "path"); }
}
} // Read the specified symbolic link. If the file isn't a symbolic link,
// return null; otherwise, return the contents of the symbolic link.
internal static String ReadSymbolicLink (String path)
{
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 {
Int64 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 ((Int32) r));
}
} while (true);
}
public static String TryReadLinkAt (Int32 dirfd, String path)
{
Byte[] buf = new Byte[256];
do {
Int64 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 UnixEncoding.Instance.GetString (buf, 0, checked ((Int32) r));
}
} while (true);
}
public static String ReadLink (String path)
{
String target = TryReadLink (path);
if (target == null) {
UnixMarshal.ThrowExceptionForLastError ();
}
return target;
}
public static String ReadLinkAt (Int32 dirfd, String path)
{
String target = TryReadLinkAt (dirfd, path);
if (target == null) {
UnixMarshal.ThrowExceptionForLastError ();
}
return target;
}
public static Boolean IsPathRooted(String path) => path == null || path.Length == 0 ? false : path[0] == DirectorySeparatorChar;
internal static void CheckPath (String path)
{
if (path == null) {
throw new ArgumentNullException ();
}
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");
}
}
}
} }
// vim: noexpandtab // vim: noexpandtab

View File

@ -33,56 +33,45 @@ using Mono.Unix;
namespace Mono.Unix { namespace Mono.Unix {
public struct UnixPipes public struct UnixPipes
: IEquatable <UnixPipes> : IEquatable <UnixPipes>
{ {
public UnixPipes (UnixStream reading, UnixStream writing) public UnixPipes (UnixStream reading, UnixStream writing)
{ {
Reading = reading; this.Reading = reading;
Writing = writing; this.Writing = writing;
} }
public UnixStream Reading; public UnixStream Reading;
public UnixStream Writing; public UnixStream Writing;
public static UnixPipes CreatePipes () public static UnixPipes CreatePipes ()
{ {
int reading, writing; Int32 r = Native.Syscall.pipe(out Int32 reading, out Int32 writing);
int r = Native.Syscall.pipe (out reading, out writing); UnixMarshal.ThrowExceptionForLastErrorIf (r);
UnixMarshal.ThrowExceptionForLastErrorIf (r); return new UnixPipes (new UnixStream (reading), new UnixStream (writing));
return new UnixPipes (new UnixStream (reading), new UnixStream (writing)); }
}
public override bool Equals (object value) public override Boolean Equals (Object value)
{ {
if ((value == null) || (value.GetType () != GetType ())) if (value == null || value.GetType () != this.GetType ()) {
return false; return false;
UnixPipes other = (UnixPipes) value; }
return Reading.Handle == other.Reading.Handle &&
Writing.Handle == other.Writing.Handle;
}
public bool Equals (UnixPipes value) UnixPipes other = (UnixPipes) value;
{ return this.Reading.Handle == other.Reading.Handle &&
return Reading.Handle == value.Reading.Handle && this.Writing.Handle == other.Writing.Handle;
Writing.Handle == value.Writing.Handle; }
}
public override int GetHashCode () public Boolean Equals(UnixPipes value) => this.Reading.Handle == value.Reading.Handle &&
{ this.Writing.Handle == value.Writing.Handle;
return Reading.Handle.GetHashCode () ^ Writing.Handle.GetHashCode ();
}
public static bool operator== (UnixPipes lhs, UnixPipes rhs) public override Int32 GetHashCode() => this.Reading.Handle.GetHashCode() ^ this.Writing.Handle.GetHashCode();
{
return lhs.Equals (rhs);
}
public static bool operator!= (UnixPipes lhs, UnixPipes rhs) public static Boolean operator ==(UnixPipes lhs, UnixPipes rhs) => lhs.Equals(rhs);
{
return !lhs.Equals (rhs); public static Boolean operator !=(UnixPipes lhs, UnixPipes rhs) => !lhs.Equals(rhs);
} }
}
} }
// vim: noexpandtab // vim: noexpandtab

View File

@ -31,127 +31,117 @@ using Mono.Unix;
namespace Mono.Unix { namespace Mono.Unix {
public sealed class UnixProcess public sealed class UnixProcess
{ {
private int pid; private Int32 pid;
internal UnixProcess (int pid) internal UnixProcess(Int32 pid) => this.pid = pid;
{
this.pid = pid;
}
public int Id { public Int32 Id => this.pid;
get {return pid;}
}
public bool HasExited { public Boolean HasExited {
get { get {
int status = GetProcessStatus (); Int32 status = this.GetProcessStatus ();
return Native.Syscall.WIFEXITED (status); return Native.Syscall.WIFEXITED (status);
} }
} }
private int GetProcessStatus () private Int32 GetProcessStatus ()
{ {
int status; Int32 r = Native.Syscall.waitpid(this.pid, out Int32 status,
int r = Native.Syscall.waitpid (pid, out status, Native.WaitOptions.WNOHANG | Native.WaitOptions.WUNTRACED);
Native.WaitOptions.WNOHANG | Native.WaitOptions.WUNTRACED); UnixMarshal.ThrowExceptionForLastErrorIf (r);
UnixMarshal.ThrowExceptionForLastErrorIf (r); return r;
return r; }
}
public int ExitCode { public Int32 ExitCode {
get { get {
if (!HasExited) if (!this.HasExited) {
throw new InvalidOperationException ( throw new InvalidOperationException (
Locale.GetText ("Process hasn't exited")); Locale.GetText ("Process hasn't exited"));
int status = GetProcessStatus (); }
return Native.Syscall.WEXITSTATUS (status);
}
}
public bool HasSignaled { Int32 status = this.GetProcessStatus ();
get { return Native.Syscall.WEXITSTATUS (status);
int status = GetProcessStatus (); }
return Native.Syscall.WIFSIGNALED (status); }
}
}
public Native.Signum TerminationSignal { public Boolean HasSignaled {
get { get {
if (!HasSignaled) Int32 status = this.GetProcessStatus ();
throw new InvalidOperationException ( return Native.Syscall.WIFSIGNALED (status);
Locale.GetText ("Process wasn't terminated by a signal")); }
int status = GetProcessStatus (); }
return Native.Syscall.WTERMSIG (status);
}
}
public bool HasStopped { public Native.Signum TerminationSignal {
get { get {
int status = GetProcessStatus (); if (!this.HasSignaled) {
return Native.Syscall.WIFSTOPPED (status); throw new InvalidOperationException (
} Locale.GetText ("Process wasn't terminated by a signal"));
} }
public Native.Signum StopSignal { Int32 status = this.GetProcessStatus ();
get { return Native.Syscall.WTERMSIG (status);
if (!HasStopped) }
throw new InvalidOperationException ( }
Locale.GetText ("Process isn't stopped"));
int status = GetProcessStatus ();
return Native.Syscall.WSTOPSIG (status);
}
}
public int ProcessGroupId { public Boolean HasStopped {
get {return Native.Syscall.getpgid (pid);} get {
set { Int32 status = this.GetProcessStatus ();
int r = Native.Syscall.setpgid (pid, value); return Native.Syscall.WIFSTOPPED (status);
UnixMarshal.ThrowExceptionForLastErrorIf (r); }
} }
}
public int SessionId { public Native.Signum StopSignal {
get { get {
int r = Native.Syscall.getsid (pid); if (!this.HasStopped) {
UnixMarshal.ThrowExceptionForLastErrorIf (r); throw new InvalidOperationException (
return r; Locale.GetText ("Process isn't stopped"));
} }
}
public static UnixProcess GetCurrentProcess () Int32 status = this.GetProcessStatus ();
{ return Native.Syscall.WSTOPSIG (status);
return new UnixProcess (GetCurrentProcessId ()); }
} }
public static int GetCurrentProcessId () public Int32 ProcessGroupId {
{ get => Native.Syscall.getpgid(this.pid);
return Native.Syscall.getpid (); set {
} Int32 r = Native.Syscall.setpgid(this.pid, value);
UnixMarshal.ThrowExceptionForLastErrorIf(r);
}
}
public void Kill () public Int32 SessionId {
{ get {
Signal (Native.Signum.SIGKILL); Int32 r = Native.Syscall.getsid (this.pid);
} UnixMarshal.ThrowExceptionForLastErrorIf (r);
return r;
}
}
[CLSCompliant (false)] public static UnixProcess GetCurrentProcess() => new UnixProcess(GetCurrentProcessId());
public void Signal (Native.Signum signal)
{
int r = Native.Syscall.kill (pid, signal);
UnixMarshal.ThrowExceptionForLastErrorIf (r);
}
public void WaitForExit () public static Int32 GetCurrentProcessId() => Native.Syscall.getpid();
{
int status; public void Kill() => this.Signal(Native.Signum.SIGKILL);
int r;
do { //[CLSCompliant (false)]
r = Native.Syscall.waitpid (pid, out status, (Native.WaitOptions) 0); public void Signal (Native.Signum signal)
} while (UnixMarshal.ShouldRetrySyscall (r)); {
UnixMarshal.ThrowExceptionForLastErrorIf (r); Int32 r = Native.Syscall.kill (this.pid, signal);
} UnixMarshal.ThrowExceptionForLastErrorIf (r);
} }
public void WaitForExit ()
{
Int32 r;
do {
r = Native.Syscall.waitpid (this.pid, out Int32 status, (Native.WaitOptions) 0);
} while (UnixMarshal.ShouldRetrySyscall (r));
UnixMarshal.ThrowExceptionForLastErrorIf (r);
}
}
} }
// vim: noexpandtab // vim: noexpandtab

View File

@ -28,6 +28,7 @@
// //
using System; using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading; using System.Threading;
@ -35,193 +36,195 @@ using Mono.Unix.Native;
namespace Mono.Unix { namespace Mono.Unix {
public class UnixSignal : WaitHandle { public class UnixSignal : WaitHandle {
private int signum; private readonly Int32 signum;
private IntPtr signal_info; private IntPtr signal_info;
static UnixSignal () static UnixSignal() => Stdlib.VersionCheck();
{
Stdlib.VersionCheck ();
}
public UnixSignal (Signum signum) public UnixSignal (Signum signum)
{ {
this.signum = NativeConvert.FromSignum (signum); this.signum = NativeConvert.FromSignum (signum);
this.signal_info = install (this.signum); this.signal_info = install (this.signum);
if (this.signal_info == IntPtr.Zero) { if (this.signal_info == IntPtr.Zero) {
throw new ArgumentException ("Unable to handle signal", "signum"); throw new ArgumentException ("Unable to handle signal", "signum");
} }
} }
public UnixSignal (Mono.Unix.Native.RealTimeSignum rtsig) public UnixSignal (RealTimeSignum rtsig)
{ {
signum = NativeConvert.FromRealTimeSignum (rtsig); this.signum = NativeConvert.FromRealTimeSignum (rtsig);
this.signal_info = install (this.signum); this.signal_info = install (this.signum);
Native.Errno err = Native.Stdlib.GetLastError (); Native.Errno err = Native.Stdlib.GetLastError ();
if (this.signal_info == IntPtr.Zero) { if (this.signal_info == IntPtr.Zero) {
if (err == Native.Errno.EADDRINUSE) if (err == Native.Errno.EADDRINUSE) {
throw new ArgumentException ("Signal registered outside of Mono.Posix", "signum"); throw new ArgumentException ("Signal registered outside of Mono.Posix", "signum");
throw new ArgumentException ("Unable to handle signal", "signum"); }
}
}
public Signum Signum { throw new ArgumentException ("Unable to handle signal", "signum");
get { }
if (IsRealTimeSignal) }
throw new InvalidOperationException ("This signal is a RealTimeSignum");
return NativeConvert.ToSignum (signum);
}
}
public RealTimeSignum RealTimeSignum { public Signum Signum {
get { get {
if (!IsRealTimeSignal) if (this.IsRealTimeSignal) {
throw new InvalidOperationException ("This signal is not a RealTimeSignum"); throw new InvalidOperationException ("This signal is a RealTimeSignum");
return NativeConvert.ToRealTimeSignum (signum-GetSIGRTMIN ()); }
}
}
public bool IsRealTimeSignal { return NativeConvert.ToSignum (this.signum);
get { }
AssertValid (); }
int sigrtmin = GetSIGRTMIN ();
if (sigrtmin == -1)
return false;
return signum >= sigrtmin;
}
}
[DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl, public RealTimeSignum RealTimeSignum {
EntryPoint="Mono_Unix_UnixSignal_install", SetLastError=true)] get {
private static extern IntPtr install (int signum); if (!this.IsRealTimeSignal) {
throw new InvalidOperationException ("This signal is not a RealTimeSignum");
}
[DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl, return NativeConvert.ToRealTimeSignum (this.signum -GetSIGRTMIN ());
EntryPoint="Mono_Unix_UnixSignal_uninstall")] }
private static extern int uninstall (IntPtr info); }
[UnmanagedFunctionPointer (CallingConvention.Cdecl)] public Boolean IsRealTimeSignal {
delegate int Mono_Posix_RuntimeIsShuttingDown (); get {
static Mono_Posix_RuntimeIsShuttingDown ShuttingDown = RuntimeShuttingDownCallback; this.AssertValid ();
Int32 sigrtmin = GetSIGRTMIN ();
return sigrtmin == -1 ? false : this.signum >= sigrtmin;
}
}
static int RuntimeShuttingDownCallback () [DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl,
{ EntryPoint="Mono_Unix_UnixSignal_install", SetLastError=true)]
return Environment.HasShutdownStarted ? 1 : 0; [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
} private static extern IntPtr install (Int32 signum);
[DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl, [DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl,
EntryPoint="Mono_Unix_UnixSignal_WaitAny")] EntryPoint="Mono_Unix_UnixSignal_uninstall")]
private static extern int WaitAny (IntPtr[] infos, int count, int timeout, Mono_Posix_RuntimeIsShuttingDown shutting_down); [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
private static extern Int32 uninstall (IntPtr info);
[DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl, [UnmanagedFunctionPointer (CallingConvention.Cdecl)]
delegate Int32 Mono_Posix_RuntimeIsShuttingDown ();
static Mono_Posix_RuntimeIsShuttingDown ShuttingDown = RuntimeShuttingDownCallback;
static Int32 RuntimeShuttingDownCallback() => Environment.HasShutdownStarted ? 1 : 0;
[DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl,
EntryPoint="Mono_Unix_UnixSignal_WaitAny")]
private static extern Int32 WaitAny (IntPtr[] infos, Int32 count, Int32 timeout, Mono_Posix_RuntimeIsShuttingDown shutting_down);
[DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl,
EntryPoint="Mono_Posix_SIGRTMIN")] EntryPoint="Mono_Posix_SIGRTMIN")]
internal static extern int GetSIGRTMIN (); internal static extern Int32 GetSIGRTMIN ();
[DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl, [DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl,
EntryPoint="Mono_Posix_SIGRTMAX")] EntryPoint="Mono_Posix_SIGRTMAX")]
internal static extern int GetSIGRTMAX (); internal static extern Int32 GetSIGRTMAX ();
private void AssertValid () private void AssertValid ()
{ {
if (signal_info == IntPtr.Zero) if (this.signal_info == IntPtr.Zero) {
throw new ObjectDisposedException (GetType().FullName); throw new ObjectDisposedException (this.GetType().FullName);
} }
}
private unsafe SignalInfo* Info { private unsafe SignalInfo* Info {
get { get {
AssertValid (); this.AssertValid ();
return (SignalInfo*) signal_info; return (SignalInfo*)this.signal_info;
} }
} }
public bool IsSet { public Boolean IsSet => this.Count > 0;
get {
return Count > 0;
}
}
public unsafe bool Reset () public unsafe Boolean Reset ()
{ {
int n = Interlocked.Exchange (ref Info->count, 0); Int32 n = Interlocked.Exchange (ref this.Info->count, 0);
return n != 0; return n != 0;
} }
public unsafe int Count { public unsafe Int32 Count {
get {return Info->count;} get => this.Info->count;
set {Interlocked.Exchange (ref Info->count, value);} set => Interlocked.Exchange(ref this.Info->count, value);
} }
// signum, count, write_fd, pipecnt, and pipelock are read from a signal handler thread // signum, count, write_fd, pipecnt, and pipelock are read from a signal handler thread
// count and pipelock are both read and written from the signal handler thread // count and pipelock are both read and written from the signal handler thread
#pragma warning disable 649 #pragma warning disable 649
[Map] [Map]
struct SignalInfo { struct SignalInfo {
public int signum, count, read_fd, write_fd, pipecnt, pipelock, have_handler; public Int32 signum, count, read_fd, write_fd, pipecnt, pipelock, have_handler;
public IntPtr handler; // Backed-up handler to restore when signal unregistered public IntPtr handler; // Backed-up handler to restore when signal unregistered
} }
#pragma warning restore 649 #pragma warning restore 649
#region WaitHandle overrides #region WaitHandle overrides
protected unsafe override void Dispose (bool disposing) protected unsafe override void Dispose (Boolean disposing)
{ {
base.Dispose (disposing); base.Dispose (disposing);
if (signal_info == IntPtr.Zero) if (this.signal_info == IntPtr.Zero) {
return; return;
uninstall (signal_info); }
signal_info = IntPtr.Zero;
}
public override bool WaitOne () _ = uninstall(this.signal_info);
{ this.signal_info = IntPtr.Zero;
return WaitOne (-1, false); }
}
public override bool WaitOne (TimeSpan timeout, bool exitContext) public override Boolean WaitOne() => this.WaitOne(-1, false);
{
long ms = (long) timeout.TotalMilliseconds;
if (ms < -1 || ms > Int32.MaxValue)
throw new ArgumentOutOfRangeException ("timeout");
return WaitOne ((int) ms, exitContext);
}
public override bool WaitOne (int millisecondsTimeout, bool exitContext) public override Boolean WaitOne (TimeSpan timeout, Boolean exitContext)
{ {
AssertValid (); Int64 ms = (Int64) timeout.TotalMilliseconds;
if (exitContext) if (ms < -1 || ms > Int32.MaxValue) {
throw new InvalidOperationException ("exitContext is not supported"); throw new ArgumentOutOfRangeException ("timeout");
if (millisecondsTimeout == 0) }
return IsSet;
return WaitAny (new UnixSignal[]{this}, millisecondsTimeout) == 0;
}
#endregion
public static int WaitAny (UnixSignal[] signals) return this.WaitOne ((Int32) ms, exitContext);
{ }
return WaitAny (signals, -1);
}
public static int WaitAny (UnixSignal[] signals, TimeSpan timeout) public override Boolean WaitOne (Int32 millisecondsTimeout, Boolean exitContext)
{ {
long ms = (long) timeout.TotalMilliseconds; this.AssertValid ();
if (ms < -1 || ms > Int32.MaxValue) if (exitContext) {
throw new ArgumentOutOfRangeException ("timeout"); throw new InvalidOperationException ("exitContext is not supported");
return WaitAny (signals, (int) ms); }
}
return millisecondsTimeout == 0 ? this.IsSet : WaitAny (new UnixSignal[]{this}, millisecondsTimeout) == 0;
}
#endregion
public static Int32 WaitAny(UnixSignal[] signals) => WaitAny(signals, -1);
public static Int32 WaitAny (UnixSignal[] signals, TimeSpan timeout)
{
Int64 ms = (Int64) timeout.TotalMilliseconds;
if (ms < -1 || ms > Int32.MaxValue) {
throw new ArgumentOutOfRangeException ("timeout");
}
return WaitAny (signals, (Int32) ms);
}
public static unsafe int WaitAny (UnixSignal[] signals, int millisecondsTimeout) public static unsafe Int32 WaitAny (UnixSignal[] signals, Int32 millisecondsTimeout)
{ {
if (signals == null) if (signals == null) {
throw new ArgumentNullException ("signals"); throw new ArgumentNullException ("signals");
if (millisecondsTimeout < -1) }
throw new ArgumentOutOfRangeException ("millisecondsTimeout");
IntPtr[] infos = new IntPtr [signals.Length]; if (millisecondsTimeout < -1) {
for (int i = 0; i < signals.Length; ++i) { throw new ArgumentOutOfRangeException ("millisecondsTimeout");
infos [i] = signals [i].signal_info; }
if (infos [i] == IntPtr.Zero)
throw new InvalidOperationException ("Disposed UnixSignal"); IntPtr[] infos = new IntPtr [signals.Length];
} for (Int32 i = 0; i < signals.Length; ++i) {
return WaitAny (infos, infos.Length, millisecondsTimeout, ShuttingDown); infos [i] = signals [i].signal_info;
} if (infos [i] == IntPtr.Zero) {
} throw new InvalidOperationException ("Disposed UnixSignal");
}
}
return WaitAny (infos, infos.Length, millisecondsTimeout, ShuttingDown);
}
}
} }

View File

@ -36,400 +36,427 @@ using Mono.Unix;
namespace Mono.Unix { namespace Mono.Unix {
public sealed class UnixStream : Stream, IDisposable public sealed class UnixStream : Stream, IDisposable {
{ public const Int32 InvalidFileDescriptor = -1;
public const int InvalidFileDescriptor = -1; public const Int32 StandardInputFileDescriptor = 0;
public const int StandardInputFileDescriptor = 0; public const Int32 StandardOutputFileDescriptor = 1;
public const int StandardOutputFileDescriptor = 1; public const Int32 StandardErrorFileDescriptor = 2;
public const int StandardErrorFileDescriptor = 2;
public UnixStream (int fileDescriptor) public UnixStream(Int32 fileDescriptor)
: this (fileDescriptor, true) {} : this(fileDescriptor, true) { }
public UnixStream (int fileDescriptor, bool ownsHandle) public UnixStream(Int32 fileDescriptor, Boolean ownsHandle) {
{ if(InvalidFileDescriptor == fileDescriptor) {
if (InvalidFileDescriptor == fileDescriptor) throw new ArgumentException(Locale.GetText("Invalid file descriptor"), "fileDescriptor");
throw new ArgumentException (Locale.GetText ("Invalid file descriptor"), "fileDescriptor"); }
this.fileDescriptor = fileDescriptor; this.fileDescriptor = fileDescriptor;
this.owner = ownsHandle; this.owner = ownsHandle;
long offset = Native.Syscall.lseek (fileDescriptor, 0, Native.SeekFlags.SEEK_CUR); Int64 offset = Native.Syscall.lseek(fileDescriptor, 0, Native.SeekFlags.SEEK_CUR);
if (offset != -1) if(offset != -1) {
canSeek = true; this.canSeek = 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 () Int64 read = Native.Syscall.read(fileDescriptor, IntPtr.Zero, 0);
{ if(read != -1) {
if (fileDescriptor == InvalidFileDescriptor) this.canRead = true;
throw new ObjectDisposedException ("Invalid File Descriptor"); }
}
public int Handle { Int64 write = Native.Syscall.write(fileDescriptor, IntPtr.Zero, 0);
get {return fileDescriptor;} if(write != -1) {
} this.canWrite = true;
}
}
public override bool CanRead { private void AssertNotDisposed() {
get {return canRead;} if(this.fileDescriptor == InvalidFileDescriptor) {
} throw new ObjectDisposedException("Invalid File Descriptor");
}
}
public override bool CanSeek { public Int32 Handle => this.fileDescriptor;
get {return canSeek;}
}
public override bool CanWrite { public override Boolean CanRead => this.canRead;
get {return canWrite;}
}
public override long Length { public override Boolean CanSeek => this.canSeek;
get {
AssertNotDisposed ();
if (!CanSeek)
throw new NotSupportedException ("File descriptor doesn't support seeking");
RefreshStat ();
return stat.st_size;
}
}
public override long Position { public override Boolean CanWrite => this.canWrite;
get {
AssertNotDisposed ();
if (!CanSeek)
throw new NotSupportedException ("The stream does not support seeking");
long pos = Native.Syscall.lseek (fileDescriptor, 0, Native.SeekFlags.SEEK_CUR);
if (pos == -1)
UnixMarshal.ThrowExceptionForLastError ();
return (long) pos;
}
set {
Seek (value, SeekOrigin.Begin);
}
}
[CLSCompliant (false)] public override Int64 Length {
public Native.FilePermissions Protection { get {
get { this.AssertNotDisposed();
RefreshStat (); if(!this.CanSeek) {
return stat.st_mode; throw new NotSupportedException("File descriptor doesn't support seeking");
} }
set {
// 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 FileTypes FileType { this.RefreshStat();
get { return this.stat.st_size;
int type = (int) Protection; }
return (FileTypes) (type & (int) UnixFileSystemInfo.AllFileTypes); }
}
// no set as fchmod(2) won't accept changing the file type.
}
public FileAccessPermissions FileAccessPermissions { public override Int64 Position {
get { get {
int perms = (int) Protection; this.AssertNotDisposed();
return (FileAccessPermissions) (perms & (int) FileAccessPermissions.AllPermissions); if(!this.CanSeek) {
} throw new NotSupportedException("The stream does not support seeking");
set { }
int perms = (int) Protection;
perms &= (int) ~FileAccessPermissions.AllPermissions;
perms |= (int) value;
Protection = (Native.FilePermissions) perms;
}
}
public FileSpecialAttributes FileSpecialAttributes { Int64 pos = Native.Syscall.lseek(this.fileDescriptor, 0, Native.SeekFlags.SEEK_CUR);
get { if(pos == -1) {
int attrs = (int) Protection; UnixMarshal.ThrowExceptionForLastError();
return (FileSpecialAttributes) (attrs & (int) UnixFileSystemInfo.AllSpecialAttributes); }
}
set {
int perms = (int) Protection;
perms &= (int) ~UnixFileSystemInfo.AllSpecialAttributes;
perms |= (int) value;
Protection = (Native.FilePermissions) perms;
}
}
public UnixUserInfo OwnerUser { return (Int64)pos;
get {RefreshStat (); return new UnixUserInfo (stat.st_uid);} }
} set => _ = this.Seek(value, SeekOrigin.Begin);
}
public long OwnerUserId { //[CLSCompliant(false)]
get {RefreshStat (); return stat.st_uid;} public Native.FilePermissions Protection {
} get {
this.RefreshStat();
return this.stat.st_mode;
}
set {
// we can't change file type with fchmod, so clear out that portion
value &= ~Native.FilePermissions.S_IFMT;
Int32 r = Native.Syscall.fchmod(this.fileDescriptor, value);
UnixMarshal.ThrowExceptionForLastErrorIf(r);
}
}
public UnixGroupInfo OwnerGroup { public FileTypes FileType {
get {RefreshStat (); return new UnixGroupInfo (stat.st_gid);} get {
} Int32 type = (Int32)this.Protection;
return (FileTypes)(type & (Int32)UnixFileSystemInfo.AllFileTypes);
}
// no set as fchmod(2) won't accept changing the file type.
}
public long OwnerGroupId { public FileAccessPermissions FileAccessPermissions {
get {RefreshStat (); return stat.st_gid;} get {
} Int32 perms = (Int32)this.Protection;
return (FileAccessPermissions)(perms & (Int32)FileAccessPermissions.AllPermissions);
}
set {
Int32 perms = (Int32)this.Protection;
perms &= (Int32)~FileAccessPermissions.AllPermissions;
perms |= (Int32)value;
this.Protection = (Native.FilePermissions)perms;
}
}
private void RefreshStat () public FileSpecialAttributes FileSpecialAttributes {
{ get {
AssertNotDisposed (); Int32 attrs = (Int32)this.Protection;
int r = Native.Syscall.fstat (fileDescriptor, out stat); return (FileSpecialAttributes)(attrs & (Int32)UnixFileSystemInfo.AllSpecialAttributes);
UnixMarshal.ThrowExceptionForLastErrorIf (r); }
} set {
Int32 perms = (Int32)this.Protection;
perms &= (Int32)~UnixFileSystemInfo.AllSpecialAttributes;
perms |= (Int32)value;
this.Protection = (Native.FilePermissions)perms;
}
}
public void AdviseFileAccessPattern (FileAccessPattern pattern, long offset, long len) public UnixUserInfo OwnerUser {
{ get {
FileHandleOperations.AdviseFileAccessPattern (fileDescriptor, pattern, offset, len); this.RefreshStat();
} return new UnixUserInfo(this.stat.st_uid);
}
}
public void AdviseFileAccessPattern (FileAccessPattern pattern) public Int64 OwnerUserId {
{ get {
AdviseFileAccessPattern (pattern, 0, 0); this.RefreshStat();
} return this.stat.st_uid;
}
}
public override void Flush () public UnixGroupInfo OwnerGroup {
{ get {
} this.RefreshStat();
return new UnixGroupInfo(this.stat.st_gid);
}
}
public override unsafe int Read ([In, Out] byte[] buffer, int offset, int count) public Int64 OwnerGroupId {
{ get {
AssertNotDisposed (); this.RefreshStat();
AssertValidBuffer (buffer, offset, count); return this.stat.st_gid;
if (!CanRead) }
throw new NotSupportedException ("Stream does not support reading"); }
if (buffer.Length == 0) private void RefreshStat() {
return 0; this.AssertNotDisposed();
Int32 r = Native.Syscall.fstat(this.fileDescriptor, out this.stat);
UnixMarshal.ThrowExceptionForLastErrorIf(r);
}
long r = 0; public void AdviseFileAccessPattern(FileAccessPattern pattern, Int64 offset, Int64 len) => FileHandleOperations.AdviseFileAccessPattern(this.fileDescriptor, pattern, offset, len);
fixed (byte* buf = &buffer[offset]) {
do {
r = Native.Syscall.read (fileDescriptor, buf, (ulong) count);
} while (UnixMarshal.ShouldRetrySyscall ((int) r));
}
if (r == -1)
UnixMarshal.ThrowExceptionForLastError ();
return (int) r;
}
private void AssertValidBuffer (byte[] buffer, int offset, int count) public void AdviseFileAccessPattern(FileAccessPattern pattern) => this.AdviseFileAccessPattern(pattern, 0, 0);
{
if (buffer == null)
throw new ArgumentNullException ("buffer");
if (offset < 0)
throw new ArgumentOutOfRangeException ("offset", "< 0");
if (count < 0)
throw new ArgumentOutOfRangeException ("count", "< 0");
if (offset > buffer.Length)
throw new ArgumentException ("destination offset is beyond array size");
if (offset > (buffer.Length - count))
throw new ArgumentException ("would overrun buffer");
}
public unsafe int ReadAtOffset ([In, Out] byte[] buffer, public override void Flush() {
int offset, int count, long fileOffset) }
{
AssertNotDisposed ();
AssertValidBuffer (buffer, offset, count);
if (!CanRead)
throw new NotSupportedException ("Stream does not support reading");
if (buffer.Length == 0) public override unsafe Int32 Read([In, Out] Byte[] buffer, Int32 offset, Int32 count) {
return 0; this.AssertNotDisposed();
this.AssertValidBuffer(buffer, offset, count);
if(!this.CanRead) {
throw new NotSupportedException("Stream does not support reading");
}
long r = 0; if(buffer.Length == 0) {
fixed (byte* buf = &buffer[offset]) { return 0;
do { }
r = Native.Syscall.pread (fileDescriptor, buf, (ulong) count, fileOffset);
} while (UnixMarshal.ShouldRetrySyscall ((int) r));
}
if (r == -1)
UnixMarshal.ThrowExceptionForLastError ();
return (int) r;
}
public override long Seek (long offset, SeekOrigin origin) Int64 r = 0;
{ fixed(Byte* buf = &buffer[offset]) {
AssertNotDisposed (); do {
if (!CanSeek) r = Native.Syscall.read(this.fileDescriptor, buf, (UInt64)count);
throw new NotSupportedException ("The File Descriptor does not support seeking"); } while(UnixMarshal.ShouldRetrySyscall((Int32)r));
}
if(r == -1) {
UnixMarshal.ThrowExceptionForLastError();
}
Native.SeekFlags sf = Native.SeekFlags.SEEK_CUR; return (Int32)r;
switch (origin) { }
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 = Native.Syscall.lseek (fileDescriptor, offset, sf); private void AssertValidBuffer(Byte[] buffer, Int32 offset, Int32 count) {
if (pos == -1) if(buffer == null) {
UnixMarshal.ThrowExceptionForLastError (); throw new ArgumentNullException("buffer");
return (long) pos; }
}
public override void SetLength (long value) if(offset < 0) {
{ throw new ArgumentOutOfRangeException("offset", "< 0");
AssertNotDisposed (); }
if (value < 0)
throw new ArgumentOutOfRangeException ("value", "< 0");
if (!CanSeek && !CanWrite)
throw new NotSupportedException ("You can't truncating the current file descriptor");
int r; if(count < 0) {
do { throw new ArgumentOutOfRangeException("count", "< 0");
r = Native.Syscall.ftruncate (fileDescriptor, value); }
} while (UnixMarshal.ShouldRetrySyscall (r));
UnixMarshal.ThrowExceptionForLastErrorIf (r);
}
public override unsafe void Write (byte[] buffer, int offset, int count) if(offset > buffer.Length) {
{ throw new ArgumentException("destination offset is beyond array size");
AssertNotDisposed (); }
AssertValidBuffer (buffer, offset, count);
if (!CanWrite)
throw new NotSupportedException ("File Descriptor does not support writing");
if (buffer.Length == 0) if(offset > buffer.Length - count) {
return; throw new ArgumentException("would overrun buffer");
}
}
long r = 0; public unsafe Int32 ReadAtOffset([In, Out] Byte[] buffer,
fixed (byte* buf = &buffer[offset]) { Int32 offset, Int32 count, Int64 fileOffset) {
do { this.AssertNotDisposed();
r = Native.Syscall.write (fileDescriptor, buf, (ulong) count); this.AssertValidBuffer(buffer, offset, count);
} while (UnixMarshal.ShouldRetrySyscall ((int) r)); if(!this.CanRead) {
} throw new NotSupportedException("Stream does not support reading");
if (r == -1) }
UnixMarshal.ThrowExceptionForLastError ();
}
public unsafe void WriteAtOffset (byte[] buffer, if(buffer.Length == 0) {
int offset, int count, long fileOffset) return 0;
{ }
AssertNotDisposed ();
AssertValidBuffer (buffer, offset, count);
if (!CanWrite)
throw new NotSupportedException ("File Descriptor does not support writing");
if (buffer.Length == 0) Int64 r = 0;
return; fixed(Byte* buf = &buffer[offset]) {
do {
r = Native.Syscall.pread(this.fileDescriptor, buf, (UInt64)count, fileOffset);
} while(UnixMarshal.ShouldRetrySyscall((Int32)r));
}
if(r == -1) {
UnixMarshal.ThrowExceptionForLastError();
}
long r = 0; return (Int32)r;
fixed (byte* buf = &buffer[offset]) { }
do {
r = Native.Syscall.pwrite (fileDescriptor, buf, (ulong) count, fileOffset);
} while (UnixMarshal.ShouldRetrySyscall ((int) r));
}
if (r == -1)
UnixMarshal.ThrowExceptionForLastError ();
}
public void SendTo (UnixStream output) public override Int64 Seek(Int64 offset, SeekOrigin origin) {
{ this.AssertNotDisposed();
SendTo (output, (ulong) output.Length); if(!this.CanSeek) {
} throw new NotSupportedException("The File Descriptor does not support seeking");
}
[CLSCompliant (false)] Native.SeekFlags sf = Native.SeekFlags.SEEK_CUR;
public void SendTo (UnixStream output, ulong count) switch(origin) {
{ case SeekOrigin.Begin:
SendTo (output.Handle, count); sf = Native.SeekFlags.SEEK_SET;
} break;
case SeekOrigin.Current:
sf = Native.SeekFlags.SEEK_CUR;
break;
case SeekOrigin.End:
sf = Native.SeekFlags.SEEK_END;
break;
}
[CLSCompliant (false)] Int64 pos = Native.Syscall.lseek(this.fileDescriptor, offset, sf);
public void SendTo (int out_fd, ulong count) if(pos == -1) {
{ UnixMarshal.ThrowExceptionForLastError();
if (!CanWrite) }
throw new NotSupportedException ("Unable to write to the current file descriptor");
long offset = Position;
long r = Native.Syscall.sendfile (out_fd, fileDescriptor, ref offset, count);
if (r == -1)
UnixMarshal.ThrowExceptionForLastError ();
}
public void SetOwner (long user, long group) return (Int64)pos;
{ }
AssertNotDisposed ();
int r = Native.Syscall.fchown (fileDescriptor, public override void SetLength(Int64 value) {
Convert.ToUInt32 (user), Convert.ToUInt32 (group)); this.AssertNotDisposed();
UnixMarshal.ThrowExceptionForLastErrorIf (r); if(value < 0) {
} throw new ArgumentOutOfRangeException("value", "< 0");
}
public void SetOwner (string user, string group) if(!this.CanSeek && !this.CanWrite) {
{ throw new NotSupportedException("You can't truncating the current file descriptor");
AssertNotDisposed (); }
long uid = new UnixUserInfo (user).UserId; Int32 r;
long gid = new UnixGroupInfo (group).GroupId; do {
SetOwner (uid, gid); r = Native.Syscall.ftruncate(this.fileDescriptor, value);
} } while(UnixMarshal.ShouldRetrySyscall(r));
UnixMarshal.ThrowExceptionForLastErrorIf(r);
}
public void SetOwner (string user) public override unsafe void Write(Byte[] buffer, Int32 offset, Int32 count) {
{ this.AssertNotDisposed();
AssertNotDisposed (); this.AssertValidBuffer(buffer, offset, count);
if(!this.CanWrite) {
throw new NotSupportedException("File Descriptor does not support writing");
}
Native.Passwd pw = Native.Syscall.getpwnam (user); if(buffer.Length == 0) {
if (pw == null) return;
throw new ArgumentException (Locale.GetText ("invalid username"), "user"); }
long uid = pw.pw_uid;
long gid = pw.pw_gid;
SetOwner (uid, gid);
}
[CLSCompliant (false)] Int64 r = 0;
public long GetConfigurationValue (Native.PathconfName name) fixed(Byte* buf = &buffer[offset]) {
{ do {
AssertNotDisposed (); r = Native.Syscall.write(this.fileDescriptor, buf, (UInt64)count);
long r = Native.Syscall.fpathconf (fileDescriptor, name); } while(UnixMarshal.ShouldRetrySyscall((Int32)r));
if (r == -1 && Native.Syscall.GetLastError() != (Native.Errno) 0) }
UnixMarshal.ThrowExceptionForLastError (); if(r == -1) {
return r; UnixMarshal.ThrowExceptionForLastError();
} }
}
~UnixStream () public unsafe void WriteAtOffset(Byte[] buffer,
{ Int32 offset, Int32 count, Int64 fileOffset) {
Close (); this.AssertNotDisposed();
} this.AssertValidBuffer(buffer, offset, count);
if(!this.CanWrite) {
throw new NotSupportedException("File Descriptor does not support writing");
}
public override void Close () if(buffer.Length == 0) {
{ return;
if (fileDescriptor == InvalidFileDescriptor) }
return;
Flush (); Int64 r = 0;
fixed(Byte* buf = &buffer[offset]) {
do {
r = Native.Syscall.pwrite(this.fileDescriptor, buf, (UInt64)count, fileOffset);
} while(UnixMarshal.ShouldRetrySyscall((Int32)r));
}
if(r == -1) {
UnixMarshal.ThrowExceptionForLastError();
}
}
if (!owner) public void SendTo(UnixStream output) => this.SendTo(output, (UInt64)output.Length);
return;
int r; //[CLSCompliant(false)]
do { public void SendTo(UnixStream output, UInt64 count) => this.SendTo(output.Handle, count);
r = Native.Syscall.close (fileDescriptor);
} while (UnixMarshal.ShouldRetrySyscall (r));
UnixMarshal.ThrowExceptionForLastErrorIf (r);
fileDescriptor = InvalidFileDescriptor;
GC.SuppressFinalize (this);
}
void IDisposable.Dispose () //[CLSCompliant(false)]
{ public void SendTo(Int32 out_fd, UInt64 count) {
if (fileDescriptor != InvalidFileDescriptor && owner) { if(!this.CanWrite) {
Close (); throw new NotSupportedException("Unable to write to the current file descriptor");
} }
GC.SuppressFinalize (this);
}
private bool canSeek = false; Int64 offset = this.Position;
private bool canRead = false; Int64 r = Native.Syscall.sendfile(out_fd, this.fileDescriptor, ref offset, count);
private bool canWrite = false; if(r == -1) {
private bool owner = true; UnixMarshal.ThrowExceptionForLastError();
private int fileDescriptor = InvalidFileDescriptor; }
private Native.Stat stat; }
}
public void SetOwner(Int64 user, Int64 group) {
this.AssertNotDisposed();
Int32 r = Native.Syscall.fchown(this.fileDescriptor,
Convert.ToUInt32(user), Convert.ToUInt32(group));
UnixMarshal.ThrowExceptionForLastErrorIf(r);
}
public void SetOwner(String user, String group) {
this.AssertNotDisposed();
Int64 uid = new UnixUserInfo(user).UserId;
Int64 gid = new UnixGroupInfo(group).GroupId;
this.SetOwner(uid, gid);
}
public void SetOwner(String user) {
this.AssertNotDisposed();
Native.Passwd pw = Native.Syscall.getpwnam(user);
if(pw == null) {
throw new ArgumentException(Locale.GetText("invalid username"), "user");
}
Int64 uid = pw.pw_uid;
Int64 gid = pw.pw_gid;
this.SetOwner(uid, gid);
}
//[CLSCompliant(false)]
public Int64 GetConfigurationValue(Native.PathconfName name) {
this.AssertNotDisposed();
Int64 r = Native.Syscall.fpathconf(this.fileDescriptor, name);
if(r == -1 && Native.Syscall.GetLastError() != (Native.Errno)0) {
UnixMarshal.ThrowExceptionForLastError();
}
return r;
}
~UnixStream() {
this.Close();
}
public override void Close() {
if(this.fileDescriptor == InvalidFileDescriptor) {
return;
}
this.Flush();
if(!this.owner) {
return;
}
Int32 r;
do {
r = Native.Syscall.close(this.fileDescriptor);
} while(UnixMarshal.ShouldRetrySyscall(r));
UnixMarshal.ThrowExceptionForLastErrorIf(r);
this.fileDescriptor = InvalidFileDescriptor;
GC.SuppressFinalize(this);
}
void IDisposable.Dispose() {
if(this.fileDescriptor != InvalidFileDescriptor && this.owner) {
this.Close();
}
GC.SuppressFinalize(this);
}
private Boolean canSeek = false;
private Boolean canRead = false;
private Boolean canWrite = false;
private Boolean owner = true;
private Int32 fileDescriptor = InvalidFileDescriptor;
private Native.Stat stat;
}
} }
// vim: noexpandtab // vim: noexpandtab

View File

@ -27,82 +27,61 @@
// //
using System; using System;
using System.IO;
using System.Text;
using Mono.Unix;
namespace Mono.Unix { namespace Mono.Unix {
public sealed class UnixSymbolicLinkInfo : UnixFileSystemInfo public sealed class UnixSymbolicLinkInfo : UnixFileSystemInfo
{ {
public UnixSymbolicLinkInfo (string path) public UnixSymbolicLinkInfo (String path)
: base (path) : base (path)
{ {
} }
internal UnixSymbolicLinkInfo (string path, Native.Stat stat) internal UnixSymbolicLinkInfo (String path, Native.Stat stat)
: base (path, stat) : base (path, stat)
{ {
} }
public override string Name { public override String Name => UnixPath.GetFileName(this.FullPath);
get {return UnixPath.GetFileName (FullPath);}
}
[Obsolete ("Use GetContents()")] [Obsolete("Use GetContents()")]
public UnixFileSystemInfo Contents { public UnixFileSystemInfo Contents => this.GetContents();
get {return GetContents ();}
}
public string ContentsPath { public String ContentsPath => UnixPath.ReadLink(this.FullPath);
get {
return UnixPath.ReadLink (FullPath);
}
}
public bool HasContents { public Boolean HasContents => UnixPath.TryReadLink(this.FullPath) != null;
get {
return UnixPath.TryReadLink (FullPath) != null;
}
}
public UnixFileSystemInfo GetContents () public UnixFileSystemInfo GetContents() => UnixFileSystemInfo.GetFileSystemEntry(
{ UnixPath.Combine(UnixPath.GetDirectoryName(this.FullPath),
return UnixFileSystemInfo.GetFileSystemEntry ( this.ContentsPath));
UnixPath.Combine (UnixPath.GetDirectoryName (FullPath),
ContentsPath));
}
public void CreateSymbolicLinkTo (string path) public void CreateSymbolicLinkTo (String path)
{ {
int r = Native.Syscall.symlink (path, FullName); Int32 r = Native.Syscall.symlink (path, this.FullName);
UnixMarshal.ThrowExceptionForLastErrorIf (r); UnixMarshal.ThrowExceptionForLastErrorIf (r);
} }
public void CreateSymbolicLinkTo (UnixFileSystemInfo path) public void CreateSymbolicLinkTo (UnixFileSystemInfo path)
{ {
int r = Native.Syscall.symlink (path.FullName, FullName); Int32 r = Native.Syscall.symlink (path.FullName, this.FullName);
UnixMarshal.ThrowExceptionForLastErrorIf (r); UnixMarshal.ThrowExceptionForLastErrorIf (r);
} }
public override void Delete () public override void Delete ()
{ {
int r = Native.Syscall.unlink (FullPath); Int32 r = Native.Syscall.unlink (this.FullPath);
UnixMarshal.ThrowExceptionForLastErrorIf (r); UnixMarshal.ThrowExceptionForLastErrorIf (r);
base.Refresh (); this.Refresh();
} }
public override void SetOwner (long owner, long group) public override void SetOwner (Int64 owner, Int64 group)
{ {
int r = Native.Syscall.lchown (FullPath, Convert.ToUInt32 (owner), Convert.ToUInt32 (group)); Int32 r = Native.Syscall.lchown (this.FullPath, Convert.ToUInt32 (owner), Convert.ToUInt32 (group));
UnixMarshal.ThrowExceptionForLastErrorIf (r); UnixMarshal.ThrowExceptionForLastErrorIf (r);
} }
protected override bool GetFileStatus (string path, out Native.Stat stat) protected override Boolean GetFileStatus(String path, out Native.Stat stat) => Native.Syscall.lstat(path, out stat) == 0;
{ }
return Native.Syscall.lstat (path, out stat) == 0;
}
}
} }
// vim: noexpandtab // vim: noexpandtab

View File

@ -29,165 +29,121 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Text; using System.Text;
using Mono.Unix;
namespace Mono.Unix { namespace Mono.Unix {
public sealed class UnixUserInfo public sealed class UnixUserInfo
{ {
private Native.Passwd passwd; private readonly Native.Passwd passwd;
public UnixUserInfo (string user) public UnixUserInfo (String user)
{ {
passwd = new Native.Passwd (); this.passwd = new Native.Passwd ();
Native.Passwd pw; Int32 r = Native.Syscall.getpwnam_r(user, this.passwd, out Native.Passwd pw);
int r = Native.Syscall.getpwnam_r (user, passwd, out pw); if (r != 0 || pw == null) {
if (r != 0 || pw == null) throw new ArgumentException (Locale.GetText ("invalid username"), "user");
throw new ArgumentException (Locale.GetText ("invalid username"), "user"); }
} }
[CLSCompliant (false)] //[CLSCompliant (false)]
public UnixUserInfo (uint user) public UnixUserInfo (UInt32 user)
{ {
passwd = new Native.Passwd (); this.passwd = new Native.Passwd ();
Native.Passwd pw; Int32 r = Native.Syscall.getpwuid_r(user, this.passwd, out Native.Passwd pw);
int r = Native.Syscall.getpwuid_r (user, passwd, out pw); if (r != 0 || pw == null) {
if (r != 0 || pw == null) throw new ArgumentException (Locale.GetText ("invalid user id"), "user");
throw new ArgumentException (Locale.GetText ("invalid user id"), "user"); }
} }
public UnixUserInfo (long user) public UnixUserInfo (Int64 user)
{ {
passwd = new Native.Passwd (); this.passwd = new Native.Passwd ();
Native.Passwd pw; Int32 r = Native.Syscall.getpwuid_r(Convert.ToUInt32(user), this.passwd, out Native.Passwd pw);
int r = Native.Syscall.getpwuid_r (Convert.ToUInt32 (user), passwd, out pw); if (r != 0 || pw == null) {
if (r != 0 || pw == null) throw new ArgumentException (Locale.GetText ("invalid user id"), "user");
throw new ArgumentException (Locale.GetText ("invalid user id"), "user"); }
} }
public UnixUserInfo (Native.Passwd passwd) public UnixUserInfo(Native.Passwd passwd) => this.passwd = CopyPasswd(passwd);
{
this.passwd = CopyPasswd (passwd);
}
private static Native.Passwd CopyPasswd (Native.Passwd pw) private static Native.Passwd CopyPasswd(Native.Passwd pw) => new Native.Passwd {
{ pw_name = pw.pw_name,
Native.Passwd p = new Native.Passwd (); pw_passwd = pw.pw_passwd,
pw_uid = pw.pw_uid,
pw_gid = pw.pw_gid,
pw_gecos = pw.pw_gecos,
pw_dir = pw.pw_dir,
pw_shell = pw.pw_shell
};
p.pw_name = pw.pw_name; public String UserName => this.passwd.pw_name;
p.pw_passwd = pw.pw_passwd;
p.pw_uid = pw.pw_uid;
p.pw_gid = pw.pw_gid;
p.pw_gecos = pw.pw_gecos;
p.pw_dir = pw.pw_dir;
p.pw_shell = pw.pw_shell;
return p; public String Password => this.passwd.pw_passwd;
}
public string UserName { public Int64 UserId => this.passwd.pw_uid;
get {return passwd.pw_name;}
}
public string Password { public UnixGroupInfo Group => new UnixGroupInfo(this.passwd.pw_gid);
get {return passwd.pw_passwd;}
}
public long UserId { public Int64 GroupId => this.passwd.pw_gid;
get {return passwd.pw_uid;}
}
public UnixGroupInfo Group { public String GroupName => this.Group.GroupName;
get {return new UnixGroupInfo (passwd.pw_gid);}
}
public long GroupId { public String RealName => this.passwd.pw_gecos;
get {return passwd.pw_gid;}
}
public string GroupName { public String HomeDirectory => this.passwd.pw_dir;
get {return Group.GroupName;}
}
public string RealName { public String ShellProgram => this.passwd.pw_shell;
get {return passwd.pw_gecos;}
}
public string HomeDirectory { public override Int32 GetHashCode() => this.passwd.GetHashCode();
get {return passwd.pw_dir;}
}
public string ShellProgram { public override Boolean Equals(Object obj) => obj == null || this.GetType() != obj.GetType() ? false : this.passwd.Equals(((UnixUserInfo)obj).passwd);
get {return passwd.pw_shell;}
}
public override int GetHashCode () public override String ToString() => this.passwd.ToString();
{
return passwd.GetHashCode ();
}
public override bool Equals (object obj) public static UnixUserInfo GetRealUser() => new UnixUserInfo(GetRealUserId());
{
if (obj == null || GetType () != obj.GetType())
return false;
return passwd.Equals (((UnixUserInfo) obj).passwd);
}
public override string ToString () public static Int64 GetRealUserId() => Native.Syscall.getuid();
{
return passwd.ToString ();
}
public static UnixUserInfo GetRealUser () // I would hope that this is the same as GetCurrentUserName, but it is a
{ // different syscall, so who knows.
return new UnixUserInfo (GetRealUserId ()); public static String GetLoginName ()
} {
StringBuilder buf = new StringBuilder (4);
Int32 r;
do {
buf.Capacity *= 2;
r = Native.Syscall.getlogin_r (buf, (UInt64) buf.Capacity);
} while (r == -1 && Native.Stdlib.GetLastError() == Native.Errno.ERANGE);
UnixMarshal.ThrowExceptionForLastErrorIf (r);
return buf.ToString ();
}
public static long GetRealUserId () public Native.Passwd ToPasswd() => CopyPasswd(this.passwd);
{
return Native.Syscall.getuid ();
}
// I would hope that this is the same as GetCurrentUserName, but it is a public static UnixUserInfo[] GetLocalUsers ()
// different syscall, so who knows. {
public static string GetLoginName () ArrayList entries = new ArrayList ();
{ lock (Native.Syscall.pwd_lock) {
StringBuilder buf = new StringBuilder (4); if (Native.Syscall.setpwent () != 0) {
int r; UnixMarshal.ThrowExceptionForLastError ();
do { }
buf.Capacity *= 2; try {
r = Native.Syscall.getlogin_r (buf, (ulong) buf.Capacity); Native.Passwd p;
} while (r == (-1) && Native.Stdlib.GetLastError() == Native.Errno.ERANGE); while ((p = Native.Syscall.getpwent()) != null) {
UnixMarshal.ThrowExceptionForLastErrorIf (r); _ = entries.Add(new UnixUserInfo(p));
return buf.ToString (); }
}
public Native.Passwd ToPasswd () if (Native.Syscall.GetLastError () != (Native.Errno) 0) {
{ UnixMarshal.ThrowExceptionForLastError ();
return CopyPasswd (passwd); }
} }
finally {
public static UnixUserInfo[] GetLocalUsers () _ = Native.Syscall.endpwent();
{ }
ArrayList entries = new ArrayList (); }
lock (Native.Syscall.pwd_lock) { return (UnixUserInfo[]) entries.ToArray (typeof(UnixUserInfo));
if (Native.Syscall.setpwent () != 0) { }
UnixMarshal.ThrowExceptionForLastError (); }
}
try {
Native.Passwd p;
while ((p = Native.Syscall.getpwent()) != null)
entries.Add (new UnixUserInfo (p));
if (Native.Syscall.GetLastError () != (Native.Errno) 0)
UnixMarshal.ThrowExceptionForLastError ();
}
finally {
Native.Syscall.endpwent ();
}
}
return (UnixUserInfo[]) entries.ToArray (typeof(UnixUserInfo));
}
}
} }
// vim: noexpandtab // vim: noexpandtab