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
//
@ -30,107 +32,107 @@
static partial class Consts
{
public const string MonoCorlibVersion = "@MONO_CORLIB_VERSION@";
public const String MonoCorlibVersion = "@MONO_CORLIB_VERSION@";
}
#if !NETCORE
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 MonoCompany = "Mono development team";
public const string MonoProduct = "Mono Common Language Infrastructure";
public const string MonoCopyright = "(c) Various Mono authors";
public const String MonoVersion = "@MONO_VERSION@";
public const String MonoCompany = "Mono development team";
public const String MonoProduct = "Mono Common Language Infrastructure";
public const String MonoCopyright = "(c) Various Mono authors";
#if MOBILE
// Versions of .NET Framework for Silverlight 4.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 FxFileVersion = "4.0.50524.0";
public const string EnvironmentVersion = FxFileVersion;
// Versions of .NET Framework for Silverlight 4.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 FxFileVersion = "4.0.50524.0";
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
public const string FxVersion = "4.0.0.0";
public const string FxFileVersion = "4.6.57.0";
public const string EnvironmentVersion = "4.0.30319.42000";
public const String FxVersion = "4.0.0.0";
public const String FxFileVersion = "4.6.57.0";
public const String EnvironmentVersion = "4.0.30319.42000";
public const string VsVersion = "0.0.0.0"; // Useless ?
public const string VsFileVersion = "11.0.0.0"; // TODO:
public const String VsVersion = "0.0.0.0"; // Useless ?
public const String VsFileVersion = "11.0.0.0"; // TODO:
#elif NET_4_5
public const string FxVersion = "4.0.0.0";
public const string FxFileVersion = "4.0.30319.17020";
public const string EnvironmentVersion = FxFileVersion;
public const string FxVersion = "4.0.0.0";
public const string FxFileVersion = "4.0.30319.17020";
public const string EnvironmentVersion = FxFileVersion;
public const string VsVersion = "0.0.0.0"; // Useless ?
public const string VsFileVersion = "11.0.0.0"; // TODO:
public const string VsVersion = "0.0.0.0"; // Useless ?
public const string VsFileVersion = "11.0.0.0"; // TODO:
#elif NETCORE
public const string FxVersion = "";
public const string FxFileVersion = "";
public const string EnvironmentVersion = FxFileVersion;
public const string FxVersion = "";
public const string FxFileVersion = "";
public const string EnvironmentVersion = FxFileVersion;
public const string VsVersion = "";
public const string VsFileVersion = "";
public const string VsVersion = "";
public const string VsFileVersion = "";
#elif NET_4_0
#error Profile NET_4_0 is not supported.
#error Profile NET_4_0 is not supported.
#elif NET_3_5
#error Profile NET_3_5 is not supported.
#error Profile NET_3_5 is not supported.
#elif NET_3_0
#error Profile NET_3_0 is not supported.
#error Profile NET_3_0 is not supported.
#elif NET_2_0
#error Profile NET_2_0 is not supported.
#error Profile NET_2_0 is not supported.
#elif NET_1_1
#error Profile NET_1_1 is not supported.
#error Profile NET_1_1 is not supported.
#elif NET_1_0
#error Profile NET_1_0 is not supported.
#error Profile NET_1_0 is not supported.
#else
#error No profile symbols defined.
#endif
#if MOBILE
const string PublicKeyToken = "7cec85d7bea7798e";
const string PublicKeyToken = "7cec85d7bea7798e";
#else
const string PublicKeyToken = "b77a5c561934e089";
const String PublicKeyToken = "b77a5c561934e089";
#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 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_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 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_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 AssemblyCorlib = "mscorlib, 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_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_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_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_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_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 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 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 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 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 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_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_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_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_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 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_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_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_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_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_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 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 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 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 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";
}
#endif

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -34,85 +34,79 @@ using System.Text;
namespace Mono.Posix
{
[Serializable]
[Obsolete ("Use Mono.Unix.UnixEndPoint")]
public class UnixEndPoint : EndPoint
{
string filename;
[Serializable]
[Obsolete ("Use Mono.Unix.UnixEndPoint")]
public class UnixEndPoint : EndPoint
{
String filename;
public UnixEndPoint (string filename)
{
if (filename == null)
throw new ArgumentNullException ("filename");
public UnixEndPoint (String filename)
{
if (filename == null) {
throw new ArgumentNullException ("filename");
}
if (filename == "")
throw new ArgumentException ("Cannot be empty.", "filename");
this.filename = filename;
}
if (filename == "") {
throw new ArgumentException ("Cannot be empty.", "filename");
}
public string Filename {
get {
return(filename);
}
set {
filename=value;
}
}
this.filename = filename;
}
public override AddressFamily AddressFamily {
get { return AddressFamily.Unix; }
}
public String Filename {
get => this.filename;
set => this.filename = value;
}
public override EndPoint Create (SocketAddress socketAddress)
{
/*
* Should also check this
*
int addr = (int) AddressFamily.Unix;
if (socketAddress [0] != (addr & 0xFF))
throw new ArgumentException ("socketAddress is not a unix socket address.");
public override AddressFamily AddressFamily => AddressFamily.Unix;
if (socketAddress [1] != ((addr & 0xFF00) >> 8))
throw new ArgumentException ("socketAddress is not a unix socket address.");
*/
public override EndPoint Create (SocketAddress socketAddress)
{
/*
* 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];
for (int i = 0; i < bytes.Length; i++) {
bytes [i] = socketAddress [i + 2];
}
if (socketAddress [1] != ((addr & 0xFF00) >> 8))
throw new ArgumentException ("socketAddress is not a unix socket address.");
*/
string name = Encoding.Default.GetString (bytes);
return new UnixEndPoint (name);
}
Byte[] bytes = new Byte[socketAddress.Size - 2];
for (Int32 i = 0; i < bytes.Length; i++) {
bytes [i] = socketAddress [i + 2];
}
public override SocketAddress Serialize ()
{
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];
String name = Encoding.Default.GetString (bytes);
return new UnixEndPoint (name);
}
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(filename);
}
return sa;
}
public override int GetHashCode ()
{
return filename.GetHashCode ();
}
public override String ToString() => this.filename;
public override bool Equals (object o)
{
UnixEndPoint other = o as UnixEndPoint;
if (other == null)
return false;
public override Int32 GetHashCode() => this.filename.GetHashCode();
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
{
internal class UnixBinaryClientFormatterSink : IClientFormatterSink, IMessageSink, IClientChannelSink, IChannelSinkBase
{
UnixBinaryCore _binaryCore = UnixBinaryCore.DefaultInstance;
IClientChannelSink _nextInChain;
internal class UnixBinaryClientFormatterSink : IClientFormatterSink, IMessageSink, IClientChannelSink, IChannelSinkBase
{
UnixBinaryCore _binaryCore = UnixBinaryCore.DefaultInstance;
IClientChannelSink _nextInChain;
public UnixBinaryClientFormatterSink (IClientChannelSink nextSink)
{
_nextInChain = nextSink;
}
public UnixBinaryClientFormatterSink(IClientChannelSink nextSink) => this._nextInChain = nextSink;
internal UnixBinaryCore BinaryCore
{
get { return _binaryCore; }
set { _binaryCore = value; }
}
internal UnixBinaryCore BinaryCore {
get => this._binaryCore;
set => this._binaryCore = value;
}
public IClientChannelSink NextChannelSink
{
get {
return _nextInChain;
}
}
public IClientChannelSink NextChannelSink => this._nextInChain;
public IMessageSink NextSink
{
get {
// This is the last sink in the IMessageSink sink chain
return null;
}
}
public IMessageSink NextSink =>
// This is the last sink in the IMessageSink sink chain
null;
public IDictionary Properties
{
get {
return null;
}
}
public IDictionary Properties => null;
public void AsyncProcessRequest (IClientChannelSinkStack sinkStack,
IMessage msg,
ITransportHeaders headers,
Stream stream)
{
// never called because the formatter sink is
// always the first in the chain
throw new NotSupportedException("UnixBinaryClientFormatterSink must be the first sink in the IClientChannelSink chain");
}
public void AsyncProcessRequest(IClientChannelSinkStack sinkStack,
IMessage msg,
ITransportHeaders headers,
Stream stream) =>
// never called because the formatter sink is
// always the first in the chain
throw new NotSupportedException("UnixBinaryClientFormatterSink must be the first sink in the IClientChannelSink chain");
public void AsyncProcessResponse (IClientResponseChannelSinkStack sinkStack,
object state,
ITransportHeaders headers,
Stream stream)
{
IMessage replyMessage = (IMessage)_binaryCore.Deserializer.DeserializeMethodResponse (stream, null, (IMethodCallMessage)state);
sinkStack.DispatchReplyMessage (replyMessage);
}
public void AsyncProcessResponse (IClientResponseChannelSinkStack sinkStack,
Object state,
ITransportHeaders headers,
Stream stream)
{
IMessage replyMessage = (IMessage)this._binaryCore.Deserializer.DeserializeMethodResponse (stream, null, (IMethodCallMessage)state);
sinkStack.DispatchReplyMessage (replyMessage);
}
public Stream GetRequestStream (IMessage msg,
ITransportHeaders headers)
{
// never called
throw new NotSupportedException ();
}
public Stream GetRequestStream(IMessage msg,
ITransportHeaders headers) =>
// never called
throw new NotSupportedException();
public void ProcessMessage (IMessage msg,
ITransportHeaders requestHeaders,
Stream requestStream,
out ITransportHeaders responseHeaders,
out Stream responseStream)
{
// never called because the formatter sink is
// always the first in the chain
throw new NotSupportedException ();
}
public void ProcessMessage(IMessage msg,
ITransportHeaders requestHeaders,
Stream requestStream,
out ITransportHeaders responseHeaders,
out Stream responseStream) =>
// never called because the formatter sink is
// always the first in the chain
throw new NotSupportedException();
public IMessageCtrl AsyncProcessMessage (IMessage msg,
IMessageSink replySink)
{
ITransportHeaders transportHeaders = new TransportHeaders();
Stream stream = _nextInChain.GetRequestStream(msg, transportHeaders);
if (stream == null) stream = new MemoryStream ();
public IMessageCtrl AsyncProcessMessage (IMessage msg,
IMessageSink replySink)
{
ITransportHeaders transportHeaders = new TransportHeaders();
Stream stream = this._nextInChain.GetRequestStream(msg, transportHeaders);
if (stream == null) {
stream = new MemoryStream ();
}
_binaryCore.Serializer.Serialize (stream, msg, null);
if (stream is MemoryStream) stream.Position = 0;
this._binaryCore.Serializer.Serialize (stream, msg, null);
if (stream is MemoryStream) {
stream.Position = 0;
}
ClientChannelSinkStack stack = new ClientChannelSinkStack(replySink);
stack.Push (this, msg);
ClientChannelSinkStack stack = new ClientChannelSinkStack(replySink);
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
return null;
}
// FIXME: No idea about how to implement IMessageCtrl
return null;
}
public IMessage SyncProcessMessage (IMessage msg)
{
try {
public IMessage SyncProcessMessage (IMessage msg)
{
try {
ITransportHeaders call_headers = new TransportHeaders();
call_headers["__RequestUri"] = ((IMethodCallMessage)msg).Uri;
call_headers["Content-Type"] = "application/octet-stream";
ITransportHeaders call_headers = new TransportHeaders();
call_headers["__RequestUri"] = ((IMethodCallMessage)msg).Uri;
call_headers["Content-Type"] = "application/octet-stream";
Stream call_stream = _nextInChain.GetRequestStream(msg, call_headers);
if (call_stream == null) call_stream = new MemoryStream ();
Stream call_stream = this._nextInChain.GetRequestStream(msg, call_headers);
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);
if (call_stream is MemoryStream) call_stream.Position = 0;
this._binaryCore.Serializer.Serialize (call_stream, msg, null);
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,
out response_stream);
this._nextInChain.ProcessMessage(msg, call_headers, call_stream, out ITransportHeaders response_headers,
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) {
return new ReturnMessage (e, (IMethodCallMessage)msg);
}
}
}
} catch (Exception e) {
return new ReturnMessage (e, (IMethodCallMessage)msg);
}
}
}
}

View File

@ -33,48 +33,38 @@ using System.Runtime.Remoting.Channels;
namespace Mono.Remoting.Channels.Unix
{
internal class UnixBinaryClientFormatterSinkProvider: IClientFormatterSinkProvider, IClientChannelSinkProvider
{
IClientChannelSinkProvider next = null;
UnixBinaryCore _binaryCore;
static string[] allowedProperties = new string [] { "includeVersions", "strictBinding" };
internal class UnixBinaryClientFormatterSinkProvider: IClientFormatterSinkProvider, IClientChannelSinkProvider
{
IClientChannelSinkProvider next = null;
UnixBinaryCore _binaryCore;
static System.String[] allowedProperties = new System.String[] { "includeVersions", "strictBinding" };
public UnixBinaryClientFormatterSinkProvider ()
{
_binaryCore = UnixBinaryCore.DefaultInstance;
}
public UnixBinaryClientFormatterSinkProvider() => this._binaryCore = UnixBinaryCore.DefaultInstance;
public UnixBinaryClientFormatterSinkProvider (IDictionary properties,
ICollection providerData)
{
_binaryCore = new UnixBinaryCore (this, properties, allowedProperties);
}
public UnixBinaryClientFormatterSinkProvider(IDictionary properties,
ICollection providerData) => this._binaryCore = new UnixBinaryCore(this, properties, allowedProperties);
public IClientChannelSinkProvider Next
{
get {
return next;
}
public IClientChannelSinkProvider Next {
get => this.next;
set {
next = value;
}
}
set => this.next = value;
}
public IClientChannelSink CreateSink (IChannelSender channel,
string url,
object remoteChannelData)
{
IClientChannelSink next_sink = null;
UnixBinaryClientFormatterSink result;
public IClientChannelSink CreateSink (IChannelSender channel,
System.String url,
System.Object remoteChannelData)
{
IClientChannelSink next_sink = null;
UnixBinaryClientFormatterSink result;
if (next != null)
next_sink = next.CreateSink (channel, url, remoteChannelData);
if (this.next != null) {
next_sink = this.next.CreateSink (channel, url, remoteChannelData);
}
result = new UnixBinaryClientFormatterSink (next_sink);
result.BinaryCore = _binaryCore;
result = new UnixBinaryClientFormatterSink (next_sink);
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.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
using System.Diagnostics.CodeAnalysis;
namespace Mono.Remoting.Channels.Unix
{
internal class UnixBinaryCore
{
BinaryFormatter _serializationFormatter;
BinaryFormatter _deserializationFormatter;
bool _includeVersions = true;
bool _strictBinding = false;
IDictionary _properties;
internal class UnixBinaryCore
{
BinaryFormatter _serializationFormatter;
BinaryFormatter _deserializationFormatter;
Boolean _includeVersions = true;
Boolean _strictBinding = false;
IDictionary _properties;
public static UnixBinaryCore DefaultInstance = new UnixBinaryCore ();
public static UnixBinaryCore DefaultInstance = new UnixBinaryCore ();
public UnixBinaryCore (object owner, IDictionary properties, string[] allowedProperties)
{
_properties = properties;
public UnixBinaryCore (Object owner, IDictionary properties, String[] allowedProperties)
{
this._properties = properties;
foreach(DictionaryEntry property in properties)
{
string key = (string) property.Key;
if (Array.IndexOf (allowedProperties, key) == -1)
throw new RemotingException (owner.GetType().Name + " does not recognize '" + key + "' configuration property");
foreach(DictionaryEntry property in properties)
{
String key = (String) property.Key;
if (Array.IndexOf (allowedProperties, key) == -1) {
throw new RemotingException (owner.GetType().Name + " does not recognize '" + key + "' configuration property");
}
switch (key)
{
case "includeVersions":
_includeVersions = Convert.ToBoolean (property.Value);
break;
switch (key)
{
case "includeVersions":
this._includeVersions = Convert.ToBoolean (property.Value);
break;
case "strictBinding":
_strictBinding = Convert.ToBoolean (property.Value);
break;
}
}
case "strictBinding":
this._strictBinding = Convert.ToBoolean (property.Value);
break;
}
}
Init ();
}
this.Init ();
}
public UnixBinaryCore ()
{
_properties = new Hashtable ();
Init ();
}
public UnixBinaryCore ()
{
this._properties = new Hashtable ();
this.Init ();
}
public void Init ()
{
RemotingSurrogateSelector surrogateSelector = new RemotingSurrogateSelector ();
StreamingContext context = new StreamingContext (StreamingContextStates.Remoting, null);
public void Init ()
{
RemotingSurrogateSelector surrogateSelector = new RemotingSurrogateSelector ();
StreamingContext context = new StreamingContext (StreamingContextStates.Remoting, null);
_serializationFormatter = new BinaryFormatter (surrogateSelector, context);
_deserializationFormatter = new BinaryFormatter (null, context);
this._serializationFormatter = new BinaryFormatter (surrogateSelector, context);
this._deserializationFormatter = new BinaryFormatter (null, context);
if (!_includeVersions)
{
_serializationFormatter.AssemblyFormat = FormatterAssemblyStyle.Simple;
_deserializationFormatter.AssemblyFormat = FormatterAssemblyStyle.Simple;
}
if (!this._includeVersions)
{
this._serializationFormatter.AssemblyFormat = FormatterAssemblyStyle.Simple;
this._deserializationFormatter.AssemblyFormat = FormatterAssemblyStyle.Simple;
}
if (!_strictBinding)
{
_serializationFormatter.Binder = SimpleBinder.Instance;
_deserializationFormatter.Binder = SimpleBinder.Instance;
}
}
if (!this._strictBinding)
{
this._serializationFormatter.Binder = SimpleBinder.Instance;
this._deserializationFormatter.Binder = SimpleBinder.Instance;
}
}
public BinaryFormatter Serializer
{
get { return _serializationFormatter; }
}
public BinaryFormatter Serializer => this._serializationFormatter;
public BinaryFormatter Deserializer
{
get { return _deserializationFormatter; }
}
public BinaryFormatter Deserializer => this._deserializationFormatter;
public IDictionary Properties
{
get { return _properties; }
}
}
public IDictionary Properties => this._properties;
}
internal class SimpleBinder: SerializationBinder
{
public static SimpleBinder Instance = new SimpleBinder ();
internal class SimpleBinder: SerializationBinder
{
public static SimpleBinder Instance = new SimpleBinder ();
public override Type BindToType (String assemblyName, string typeName)
{
Assembly asm;
[SuppressMessage("Microsoft.Design", "CS0618", Justification = "Someone do shit")]
public override Type BindToType (String assemblyName, String typeName)
{
Assembly asm;
if (assemblyName.IndexOf (',') != -1)
{
// Try using the full name
try
{
asm = Assembly.Load (assemblyName);
if (asm == null) return null;
Type t = asm.GetType (typeName);
if (t != null) return t;
}
catch {}
}
if (assemblyName.IndexOf (',') != -1)
{
// Try using the full name
try
{
asm = Assembly.Load (assemblyName);
if (asm == null) {
return null;
}
// Try using the simple name
asm = Assembly.LoadWithPartialName (assemblyName);
if (asm == null) return null;
return asm.GetType (typeName, true);
}
}
Type t = asm.GetType (typeName);
if (t != null) {
return t;
}
}
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 {
internal class UnixBinaryServerFormatterSink : IServerChannelSink, IChannelSinkBase
{
UnixBinaryCore _binaryCore = UnixBinaryCore.DefaultInstance;
internal class UnixBinaryServerFormatterSink : IServerChannelSink, IChannelSinkBase
{
UnixBinaryCore _binaryCore = UnixBinaryCore.DefaultInstance;
IServerChannelSink next_sink;
IChannelReceiver receiver;
IServerChannelSink next_sink;
IChannelReceiver receiver;
public UnixBinaryServerFormatterSink (IServerChannelSink nextSink, IChannelReceiver receiver)
{
this.next_sink = nextSink;
this.receiver = receiver;
}
public UnixBinaryServerFormatterSink (IServerChannelSink nextSink, IChannelReceiver receiver)
{
this.next_sink = nextSink;
this.receiver = receiver;
}
internal UnixBinaryCore BinaryCore
{
get { return _binaryCore; }
set { _binaryCore = value; }
}
internal UnixBinaryCore BinaryCore {
get => this._binaryCore;
set => this._binaryCore = value;
}
public IServerChannelSink NextChannelSink {
get {
return next_sink;
}
}
public IServerChannelSink NextChannelSink => this.next_sink;
public IDictionary Properties {
get {
return null;
}
}
public IDictionary Properties => null;
public void AsyncProcessResponse (IServerResponseChannelSinkStack sinkStack, object state,
IMessage message, ITransportHeaders headers, Stream stream)
{
ITransportHeaders responseHeaders = new TransportHeaders();
public void AsyncProcessResponse (IServerResponseChannelSinkStack sinkStack, Object state,
IMessage message, ITransportHeaders headers, Stream stream)
{
ITransportHeaders responseHeaders = new TransportHeaders();
if (sinkStack != null) stream = sinkStack.GetResponseStream (message, responseHeaders);
if (stream == null) stream = new MemoryStream();
if (sinkStack != null) {
stream = sinkStack.GetResponseStream (message, responseHeaders);
}
_binaryCore.Serializer.Serialize (stream, message, null);
if (stream is MemoryStream) stream.Position = 0;
if (stream == null) {
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,
IMessage msg, ITransportHeaders headers)
{
return null;
}
sinkStack.AsyncProcessResponse (message, responseHeaders, stream);
}
public ServerProcessing ProcessMessage (IServerChannelSinkStack sinkStack,
IMessage requestMsg, ITransportHeaders requestHeaders, Stream requestStream,
out IMessage responseMsg, out ITransportHeaders responseHeaders, out Stream responseStream)
{
sinkStack.Push (this, null);
ServerProcessing res;
public Stream GetResponseStream(IServerResponseChannelSinkStack sinkStack, Object state,
IMessage msg, ITransportHeaders headers) => null;
try
{
string url = (string)requestHeaders["__RequestUri"];
string uri;
receiver.Parse (url, out uri);
if (uri == null) uri = url;
public ServerProcessing ProcessMessage (IServerChannelSinkStack sinkStack,
IMessage requestMsg, ITransportHeaders requestHeaders, Stream requestStream,
out IMessage responseMsg, out ITransportHeaders responseHeaders, out Stream responseStream)
{
sinkStack.Push (this, null);
ServerProcessing res;
MethodCallHeaderHandler mhh = new MethodCallHeaderHandler(uri);
requestMsg = (IMessage) _binaryCore.Deserializer.Deserialize (requestStream, new HeaderHandler(mhh.HandleHeaders));
try
{
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);
}
catch (Exception ex)
{
responseMsg = new ReturnMessage (ex, (IMethodCallMessage)requestMsg);
res = ServerProcessing.Complete;
responseHeaders = null;
responseStream = null;
}
MethodCallHeaderHandler mhh = new MethodCallHeaderHandler(uri);
requestMsg = (IMessage)this._binaryCore.Deserializer.Deserialize (requestStream, new HeaderHandler(mhh.HandleHeaders));
if (res == ServerProcessing.Complete)
{
for (int n=0; n<3; n++) {
responseStream = null;
responseHeaders = new TransportHeaders();
res = this.next_sink.ProcessMessage (sinkStack, requestMsg, requestHeaders, null, out responseMsg, out responseHeaders, out responseStream);
}
catch (Exception ex)
{
responseMsg = new ReturnMessage (ex, (IMethodCallMessage)requestMsg);
res = ServerProcessing.Complete;
responseHeaders = null;
responseStream = null;
}
if (sinkStack != null) responseStream = sinkStack.GetResponseStream (responseMsg, responseHeaders);
if (responseStream == null) responseStream = new MemoryStream();
if (res == ServerProcessing.Complete)
{
for (Int32 n =0; n<3; n++) {
responseStream = null;
responseHeaders = new TransportHeaders();
try {
_binaryCore.Serializer.Serialize (responseStream, responseMsg);
break;
} catch (Exception ex) {
if (n == 2) throw ex;
else responseMsg = new ReturnMessage (ex, (IMethodCallMessage)requestMsg);
}
}
if (sinkStack != null) {
responseStream = sinkStack.GetResponseStream (responseMsg, responseHeaders);
}
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);
}
return res;
}
if (responseStream is MemoryStream) {
responseStream.Position = 0;
}
}
_ = sinkStack.Pop(this);
}
return res;
}
internal class MethodCallHeaderHandler
{
string _uri;
}
public MethodCallHeaderHandler (string uri)
{
_uri = uri;
}
internal class MethodCallHeaderHandler
{
String _uri;
public object HandleHeaders (Header[] headers)
{
return _uri;
}
}
public MethodCallHeaderHandler(String uri) => this._uri = uri;
public Object HandleHeaders(Header[] headers) => this._uri;
}
}

View File

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

View File

@ -40,104 +40,109 @@ namespace Mono.Remoting.Channels.Unix
{
private UnixClientChannel _clientChannel;
private UnixServerChannel _serverChannel = null;
private string _name = "unix";
private int _priority = 1;
private String _name = "unix";
private Int32 _priority = 1;
public UnixChannel (): this (null)
{
}
public UnixChannel (string path)
public UnixChannel (String path)
{
Hashtable ht = new Hashtable();
ht["path"] = path;
Init(ht, null, null);
this.Init(ht, null, null);
}
void Init (IDictionary properties, IClientChannelSinkProvider clientSink, IServerChannelSinkProvider serverSink)
{
_clientChannel = new UnixClientChannel (properties,clientSink);
this._clientChannel = new UnixClientChannel (properties,clientSink);
if(properties["path"] != null)
_serverChannel = new UnixServerChannel(properties, serverSink);
if(properties["path"] != null) {
this._serverChannel = new UnixServerChannel(properties, serverSink);
}
object val = properties ["name"];
if (val != null) _name = val as string;
Object val = properties ["name"];
if (val != null) {
this._name = val as String;
}
val = properties ["priority"];
if (val != null) _priority = Convert.ToInt32 (val);
}
val = properties ["priority"];
if (val != null) {
this._priority = Convert.ToInt32 (val);
}
}
public UnixChannel (IDictionary properties,
IClientChannelSinkProvider clientSinkProvider,
IServerChannelSinkProvider serverSinkProvider)
public UnixChannel(IDictionary properties,
IClientChannelSinkProvider clientSinkProvider,
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
{
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
public Object ChannelData
{
get
{
if (_serverChannel != null) return _serverChannel.ChannelData;
else return null;
}
if (this._serverChannel != null) {
return this._serverChannel.ChannelData;
} else {
return null;
}
}
}
public string Parse (string url, out string objectURI)
{
return UnixChannel.ParseUnixURL (url, out objectURI);
}
public String Parse(String url, out String objectURI) => 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"
objectURI = null;
if (!url.StartsWith ("unix://")) return null;
if (!url.StartsWith ("unix://")) {
return null;
}
int i = url.IndexOf ('?');
if (i == -1) return url.Substring (7);
Int32 i = url.IndexOf ('?');
if (i == -1) {
return url.Substring (7);
}
objectURI = url.Substring (i+1);
objectURI = url.Substring (i+1);
if (objectURI.Length == 0)
objectURI = null;
if (objectURI.Length == 0) {
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
{
int priority = 1;
string name = "unix";
Int32 priority = 1;
String name = "unix";
IClientChannelSinkProvider _sinkProvider;
public UnixClientChannel ()
{
_sinkProvider = new UnixBinaryClientFormatterSinkProvider ();
_sinkProvider.Next = new UnixClientTransportSinkProvider ();
this._sinkProvider = new UnixBinaryClientFormatterSinkProvider ();
this._sinkProvider.Next = new UnixClientTransportSinkProvider ();
}
public UnixClientChannel (IDictionary properties, IClientChannelSinkProvider sinkProvider)
{
object val = properties ["name"];
if (val != null) name = val as string;
Object val = properties ["name"];
if (val != null) {
this.name = val as String;
}
val = properties ["priority"];
if (val != null) priority = Convert.ToInt32 (val);
val = properties ["priority"];
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
IClientChannelSinkProvider prov = sinkProvider;
while (prov.Next != null) prov = prov.Next;
prov.Next = new UnixClientTransportSinkProvider ();
while (prov.Next != null) {
prov = prov.Next;
}
prov.Next = new UnixClientTransportSinkProvider ();
// Note: a default formatter is added only when
// no sink providers are specified in the config file.
}
else
{
_sinkProvider = new UnixBinaryClientFormatterSinkProvider ();
_sinkProvider.Next = new UnixClientTransportSinkProvider ();
this._sinkProvider = new UnixBinaryClientFormatterSinkProvider ();
this._sinkProvider.Next = new UnixClientTransportSinkProvider ();
}
}
public UnixClientChannel (string name, IClientChannelSinkProvider sinkProvider)
public UnixClientChannel (String name, IClientChannelSinkProvider sinkProvider)
{
this.name = name;
_sinkProvider = sinkProvider;
this._sinkProvider = sinkProvider;
// add the unix provider at the end of the chain
IClientChannelSinkProvider prov = sinkProvider;
while (prov.Next != null) prov = prov.Next;
prov.Next = new UnixClientTransportSinkProvider ();
while (prov.Next != null) {
prov = prov.Next;
}
prov.Next = new UnixClientTransportSinkProvider ();
}
public string ChannelName
{
get {
return name;
}
}
public String ChannelName => this.name;
public int ChannelPriority
{
get {
return priority;
}
}
public Int32 ChannelPriority => this.priority;
public IMessageSink CreateMessageSink (string url,
object remoteChannelData,
out string objectURI)
public IMessageSink CreateMessageSink (String url,
Object remoteChannelData,
out String objectURI)
{
if (url != null && Parse (url, out objectURI) != null)
return (IMessageSink) _sinkProvider.CreateSink (this, url, remoteChannelData);
if (url != null && this.Parse (url, out objectURI) != null) {
return (IMessageSink)this._sinkProvider.CreateSink (this, url, remoteChannelData);
}
if (remoteChannelData != null) {
if (remoteChannelData != null) {
IChannelDataStore ds = remoteChannelData as IChannelDataStore;
if (ds != null && ds.ChannelUris.Length > 0)
url = ds.ChannelUris [0];
else {
if (ds != null && ds.ChannelUris.Length > 0) {
url = ds.ChannelUris [0];
} else {
objectURI = null;
return null;
}
}
if (Parse (url, out objectURI) == null)
return null;
if (this.Parse (url, out objectURI) == 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)
{
return UnixChannel.ParseUnixURL (url, out objectURI);
}
}
public String Parse(String url, out String objectURI) => UnixChannel.ParseUnixURL(url, out objectURI);
}
}

View File

@ -38,156 +38,156 @@ using System.Runtime.Remoting;
namespace Mono.Remoting.Channels.Unix
{
internal class UnixClientTransportSink : IClientChannelSink
{
string _path;
internal class UnixClientTransportSink : IClientChannelSink
{
String _path;
public UnixClientTransportSink (string url)
{
string objectUri;
_path = UnixChannel.ParseUnixURL (url, out objectUri);
}
public UnixClientTransportSink (String url)
{
this._path = UnixChannel.ParseUnixURL(url, out String objectUri);
}
public IDictionary Properties
{
get
{
return null;
}
}
public IDictionary Properties => null;
public IClientChannelSink NextChannelSink
{
get
{
// we are the last one
return null;
}
}
public IClientChannelSink NextChannelSink =>
// we are the last one
null;
public void AsyncProcessRequest (IClientChannelSinkStack sinkStack, IMessage msg,
ITransportHeaders headers, Stream requestStream)
{
UnixConnection connection = null;
bool isOneWay = RemotingServices.IsOneWay (((IMethodMessage)msg).MethodBase);
public void AsyncProcessRequest (IClientChannelSinkStack sinkStack, IMessage msg,
ITransportHeaders headers, Stream requestStream)
{
UnixConnection connection = null;
Boolean isOneWay = RemotingServices.IsOneWay (((IMethodMessage)msg).MethodBase);
try
{
if (headers == null) headers = new TransportHeaders();
headers ["__RequestUri"] = ((IMethodMessage)msg).Uri;
try
{
if (headers == null) {
headers = new TransportHeaders();
}
// Sends the stream using a connection from the pool
// and creates a WorkItem that will wait for the
// response of the server
headers ["__RequestUri"] = ((IMethodMessage)msg).Uri;
connection = UnixConnectionPool.GetConnection (_path);
UnixMessageIO.SendMessageStream (connection.Stream, requestStream, headers, connection.Buffer);
connection.Stream.Flush ();
// Sends the stream using a connection from the pool
// and creates a WorkItem that will wait for the
// response of the server
if (!isOneWay)
{
sinkStack.Push (this, connection);
ThreadPool.QueueUserWorkItem (new WaitCallback(data => {
try {
ReadAsyncUnixMessage (data);
} catch {}
}), sinkStack);
}
else
connection.Release();
}
catch
{
if (connection != null) connection.Release();
if (!isOneWay) throw;
}
}
connection = UnixConnectionPool.GetConnection (this._path);
UnixMessageIO.SendMessageStream (connection.Stream, requestStream, headers, connection.Buffer);
connection.Stream.Flush ();
private void ReadAsyncUnixMessage(object data)
{
// This method is called by a new thread to asynchronously
// read the response to a request
if (!isOneWay)
{
sinkStack.Push (this, connection);
_ = 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
IClientChannelSinkStack stack = (IClientChannelSinkStack)data;
if (!isOneWay) {
throw;
}
}
}
// The first sink in the stack is this sink. Pop it and
// get the status data, which is the UnixConnection used to send
// the request
UnixConnection connection = (UnixConnection)stack.Pop(this);
private void ReadAsyncUnixMessage(Object data)
{
// This method is called by a new thread to asynchronously
// read the response to a request
try
{
ITransportHeaders responseHeaders;
// The stack was provided as state data in QueueUserWorkItem
IClientChannelSinkStack stack = (IClientChannelSinkStack)data;
// Read the response, blocking if necessary
MessageStatus status = UnixMessageIO.ReceiveMessageStatus (connection.Stream, connection.Buffer);
// The first sink in the stack is this sink. Pop it and
// get the status data, which is the UnixConnection used to send
// the request
UnixConnection connection = (UnixConnection)stack.Pop(this);
if (status != MessageStatus.MethodMessage)
throw new RemotingException ("Unknown response message from server");
try
{
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
connection.Release();
connection = null;
if (status != MessageStatus.MethodMessage) {
throw new RemotingException ("Unknown response message from server");
}
// Ok, proceed with the other sinks
stack.AsyncProcessResponse (responseHeaders, responseStream);
}
catch
{
if (connection != null) connection.Release();
throw;
}
}
Stream responseStream = UnixMessageIO.ReceiveMessageStream (connection.Stream, out ITransportHeaders responseHeaders, connection.Buffer);
public void AsyncProcessResponse (IClientResponseChannelSinkStack sinkStack,
object state, ITransportHeaders headers,
Stream stream)
{
// Should never be called
throw new NotSupportedException();
}
// Free the connection, so it can be reused
connection.Release();
connection = null;
public Stream GetRequestStream (IMessage msg, ITransportHeaders headers)
{
return null;
}
// Ok, proceed with the other sinks
stack.AsyncProcessResponse (responseHeaders, responseStream);
}
catch
{
if (connection != null) {
connection.Release();
}
public void ProcessMessage (IMessage msg,
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;
throw;
}
}
// Sends the message
connection = UnixConnectionPool.GetConnection (_path);
UnixMessageIO.SendMessageStream (connection.Stream, requestStream, requestHeaders, connection.Buffer);
connection.Stream.Flush ();
public void AsyncProcessResponse(IClientResponseChannelSinkStack sinkStack,
Object state, ITransportHeaders headers,
Stream stream) =>
// Should never be called
throw new NotSupportedException();
// Reads the response
MessageStatus status = UnixMessageIO.ReceiveMessageStatus (connection.Stream, connection.Buffer);
public Stream GetRequestStream(IMessage msg, ITransportHeaders headers) => null;
if (status != MessageStatus.MethodMessage)
throw new RemotingException ("Unknown response message from server");
public void ProcessMessage (IMessage msg,
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);
}
finally
{
if (connection != null)
connection.Release();
}
}
requestHeaders ["__RequestUri"] = ((IMethodMessage)msg).Uri;
}
// 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 ?
}
public IClientChannelSinkProvider Next
{
get
{
return null;
}
public IClientChannelSinkProvider Next {
get => null;
set
{
// ignore, we are always the last in the chain
}
}
public IClientChannelSink CreateSink (IChannelSender channel, string url,
object remoteChannelData)
{
return new UnixClientTransportSink (url);
}
set {
// ignore, we are always the last in the chain
}
}
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
{
// This is a pool of Unix connections. Connections requested
// by the TCP channel are pooled after their use, and can
// be reused later. Connections are automaticaly closed
// if not used after some time, specified in KeepAliveSeconds.
// The number of allowed open connections can also be specified
// in MaxOpenConnections. The limit is per host.
// If a thread requests a connection and the limit has been
// reached, the thread is suspended until one is released.
// This is a pool of Unix connections. Connections requested
// by the TCP channel are pooled after their use, and can
// be reused later. Connections are automaticaly closed
// if not used after some time, specified in KeepAliveSeconds.
// The number of allowed open connections can also be specified
// in MaxOpenConnections. The limit is per host.
// If a thread requests a connection and the limit has been
// reached, the thread is suspended until one is released.
internal class UnixConnectionPool
{
// Table of pools. There is a HostConnectionPool
// instance for each host
static Hashtable _pools = new Hashtable();
internal class UnixConnectionPool
{
// Table of pools. There is a HostConnectionPool
// instance for each host
static Hashtable _pools = new Hashtable();
static int _maxOpenConnections = int.MaxValue;
static int _keepAliveSeconds = 15;
static Int32 _maxOpenConnections = Int32.MaxValue;
static Int32 _keepAliveSeconds = 15;
static Thread _poolThread;
static Thread _poolThread;
static UnixConnectionPool()
{
// This thread will close unused connections
_poolThread = new Thread (new ThreadStart (ConnectionCollector));
_poolThread.Start();
_poolThread.IsBackground = true;
}
static UnixConnectionPool()
{
// This thread will close unused connections
_poolThread = new Thread (new ThreadStart (ConnectionCollector));
_poolThread.Start();
_poolThread.IsBackground = true;
}
public static void Shutdown ()
{
if (_poolThread != null)
_poolThread.Abort();
}
public static void Shutdown ()
{
if (_poolThread != null) {
_poolThread.Abort();
}
}
public static int MaxOpenConnections
{
get { return _maxOpenConnections; }
set
{
if (value < 1) throw new RemotingException ("MaxOpenConnections must be greater than zero");
_maxOpenConnections = value;
}
}
public static Int32 MaxOpenConnections {
get => _maxOpenConnections;
set {
if(value < 1) {
throw new RemotingException("MaxOpenConnections must be greater than zero");
}
public static int KeepAliveSeconds
{
get { return _keepAliveSeconds; }
set { _keepAliveSeconds = value; }
}
_maxOpenConnections = value;
}
}
public static UnixConnection GetConnection (string path)
{
HostConnectionPool hostPool;
public static Int32 KeepAliveSeconds {
get => _keepAliveSeconds;
set => _keepAliveSeconds = value;
}
lock (_pools)
{
hostPool = (HostConnectionPool) _pools[path];
if (hostPool == null)
{
hostPool = new HostConnectionPool(path);
_pools[path] = hostPool;
}
}
public static UnixConnection GetConnection (String path)
{
HostConnectionPool hostPool;
return hostPool.GetConnection();
}
lock (_pools)
{
hostPool = (HostConnectionPool) _pools[path];
if (hostPool == null)
{
hostPool = new HostConnectionPool(path);
_pools[path] = hostPool;
}
}
private static void ConnectionCollector ()
{
while (true)
{
Thread.Sleep(3000);
lock (_pools)
{
ICollection values = _pools.Values;
foreach (HostConnectionPool pool in values)
pool.PurgeConnections();
}
}
}
}
return hostPool.GetConnection();
}
internal class ReusableUnixClient : UnixClient
{
public ReusableUnixClient (string path): base (path)
{
}
private static void ConnectionCollector ()
{
while (true)
{
Thread.Sleep(3000);
lock (_pools)
{
ICollection values = _pools.Values;
foreach (HostConnectionPool pool in values) {
pool.PurgeConnections();
}
}
}
}
}
public bool IsAlive
{
get
{
// 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 ReusableUnixClient : UnixClient
{
public ReusableUnixClient (String path): base (path)
{
}
internal class UnixConnection
{
DateTime _controlTime;
Stream _stream;
ReusableUnixClient _client;
HostConnectionPool _pool;
byte[] _buffer;
public Boolean IsAlive =>
// 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.
!this.Client.Poll(0, SelectMode.SelectRead);
}
public UnixConnection (HostConnectionPool pool, ReusableUnixClient client)
{
_pool = pool;
_client = client;
_stream = new BufferedStream (client.GetStream());
_controlTime = DateTime.UtcNow;
_buffer = new byte[UnixMessageIO.DefaultStreamBufferSize];
}
internal class UnixConnection
{
DateTime _controlTime;
Stream _stream;
ReusableUnixClient _client;
HostConnectionPool _pool;
Byte[] _buffer;
public Stream Stream
{
get { return _stream; }
}
public UnixConnection (HostConnectionPool pool, ReusableUnixClient client)
{
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
{
get { return _controlTime; }
set { _controlTime = value; }
}
public Stream Stream => this._stream;
public bool IsAlive
{
get { return _client.IsAlive; }
}
public DateTime ControlTime {
get => this._controlTime;
set => this._controlTime = value;
}
// This is a "thread safe" buffer that can be used by
// 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; }
}
public Boolean IsAlive => this._client.IsAlive;
// Returns the connection to the pool
public void Release()
{
_pool.ReleaseConnection (this);
}
// This is a "thread safe" buffer that can be used by
// 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 => this._buffer;
public void Close()
{
_client.Close();
}
}
// Returns the connection to the pool
public void Release() => this._pool.ReleaseConnection(this);
internal class HostConnectionPool
{
ArrayList _pool = new ArrayList();
int _activeConnections = 0;
public void Close() => this._client.Close();
}
string _path;
internal class HostConnectionPool
{
ArrayList _pool = new ArrayList();
Int32 _activeConnections = 0;
public HostConnectionPool (string path)
{
_path = path;
}
String _path;
public UnixConnection GetConnection ()
{
UnixConnection connection = null;
lock (_pool)
{
do
{
if (_pool.Count > 0)
{
// There are available connections
public HostConnectionPool(String path) => this._path = path;
connection = (UnixConnection)_pool[_pool.Count - 1];
_pool.RemoveAt(_pool.Count - 1);
if (!connection.IsAlive) {
CancelConnection (connection);
connection = null;
continue;
}
}
public UnixConnection GetConnection ()
{
UnixConnection connection = null;
lock (this._pool)
{
do
{
if (this._pool.Count > 0)
{
// There are available connections
if (connection == null && _activeConnections < UnixConnectionPool.MaxOpenConnections)
{
// 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;
}
connection = (UnixConnection)this._pool[this._pool.Count - 1];
this._pool.RemoveAt(this._pool.Count - 1);
if (!connection.IsAlive) {
this.CancelConnection (connection);
connection = null;
continue;
}
}
// No available connections in the pool
// Wait for somewone to release one.
if (connection == null && this._activeConnections < UnixConnectionPool.MaxOpenConnections)
{
// 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)
{
Monitor.Wait(_pool);
}
}
while (connection == null);
}
// No available connections in the pool
// Wait for somewone to release one.
if (connection == null)
return CreateConnection ();
else
return connection;
}
if (connection == null)
{
_ = Monitor.Wait(this._pool);
}
}
while (connection == null);
}
private UnixConnection CreateConnection()
{
try
{
ReusableUnixClient client = new ReusableUnixClient (_path);
UnixConnection entry = new UnixConnection(this, client);
_activeConnections++;
return entry;
}
catch (Exception ex)
{
throw new RemotingException (ex.Message);
}
}
if (connection == null) {
return this.CreateConnection ();
} else {
return connection;
}
}
public void ReleaseConnection (UnixConnection entry)
{
lock (_pool)
{
entry.ControlTime = DateTime.UtcNow; // Initialize timeout
_pool.Add (entry);
Monitor.Pulse (_pool);
}
}
private UnixConnection CreateConnection()
{
try
{
ReusableUnixClient client = new ReusableUnixClient (this._path);
UnixConnection entry = new UnixConnection(this, client);
this._activeConnections++;
return entry;
}
catch (Exception ex)
{
throw new RemotingException (ex.Message);
}
}
private void CancelConnection(UnixConnection entry)
{
try
{
entry.Stream.Close();
_activeConnections--;
}
catch
{
}
}
public void ReleaseConnection (UnixConnection entry)
{
lock (this._pool)
{
entry.ControlTime = DateTime.UtcNow; // Initialize timeout
_ = this._pool.Add(entry);
Monitor.Pulse (this._pool);
}
}
public void PurgeConnections()
{
lock (_pool)
{
for (int n=0; n < _pool.Count; n++)
{
UnixConnection entry = (UnixConnection)_pool[n];
if ( (DateTime.UtcNow - entry.ControlTime).TotalSeconds > UnixConnectionPool.KeepAliveSeconds)
{
CancelConnection (entry);
_pool.RemoveAt(n);
n--;
}
}
}
}
private void CancelConnection(UnixConnection entry)
{
try
{
entry.Stream.Close();
this._activeConnections--;
}
catch
{
}
}
}
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
{
enum MessageStatus { MethodMessage = 0, CancelSignal = 1, Unknown = 10}
enum MessageStatus { MethodMessage = 0, CancelSignal = 1, Unknown = 10}
internal class UnixMessageIO
{
static byte[][] _msgHeaders =
{
new byte[] { (byte)'.', (byte)'N', (byte)'E', (byte)'T', 1, 0 },
new byte[] { 255, 255, 255, 255, 255, 255 }
};
internal class UnixMessageIO
{
static Byte[][] _msgHeaders =
{
new Byte[] { (Byte)'.', (Byte)'N', (Byte)'E', (Byte)'T', 1, 0 },
new Byte[] { 255, 255, 255, 255, 255, 255 }
};
public static int DefaultStreamBufferSize = 1000;
public static Int32 DefaultStreamBufferSize = 1000;
// Identifies an incoming message
public static MessageStatus ReceiveMessageStatus (Stream networkStream, byte[] buffer)
{
try {
StreamRead (networkStream, buffer, 6);
} catch (Exception ex) {
throw new RemotingException ("Unix transport error.", ex);
}
// Identifies an incoming message
public static MessageStatus ReceiveMessageStatus (Stream networkStream, Byte[] buffer)
{
try {
_ = StreamRead(networkStream, buffer, 6);
} catch (Exception ex) {
throw new RemotingException ("Unix transport error.", ex);
}
try
{
bool[] isOnTrack = new bool[_msgHeaders.Length];
bool atLeastOneOnTrack = true;
int i = 0;
try
{
Boolean[] isOnTrack = new Boolean[_msgHeaders.Length];
Boolean atLeastOneOnTrack = true;
Int32 i = 0;
while (atLeastOneOnTrack)
{
atLeastOneOnTrack = false;
byte c = buffer [i];
for (int n = 0; n<_msgHeaders.Length; n++)
{
if (i > 0 && !isOnTrack[n]) continue;
while (atLeastOneOnTrack)
{
atLeastOneOnTrack = false;
Byte c = buffer [i];
for (Int32 n = 0; n<_msgHeaders.Length; n++)
{
if (i > 0 && !isOnTrack[n]) {
continue;
}
isOnTrack[n] = (c == _msgHeaders[n][i]);
if (isOnTrack[n] && (i == _msgHeaders[n].Length-1)) return (MessageStatus) n;
atLeastOneOnTrack = atLeastOneOnTrack || isOnTrack[n];
}
i++;
}
return MessageStatus.Unknown;
}
catch (Exception ex) {
throw new RemotingException ("Unix transport error.", ex);
}
}
isOnTrack[n] = c == _msgHeaders[n][i];
if (isOnTrack[n] && i == _msgHeaders[n].Length-1) {
return (MessageStatus) n;
}
static bool StreamRead (Stream networkStream, byte[] buffer, int count)
{
int nr = 0;
do {
int pr = networkStream.Read (buffer, nr, count - nr);
if (pr == 0)
throw new RemotingException ("Connection closed");
nr += pr;
} while (nr < count);
return true;
}
atLeastOneOnTrack = atLeastOneOnTrack || isOnTrack[n];
}
i++;
}
return MessageStatus.Unknown;
}
catch (Exception ex) {
throw new RemotingException ("Unix transport error.", ex);
}
}
public static void SendMessageStream (Stream networkStream, Stream data, ITransportHeaders requestHeaders, byte[] buffer)
{
if (buffer == null) buffer = new byte[DefaultStreamBufferSize];
static Boolean StreamRead (Stream networkStream, Byte[] buffer, Int32 count)
{
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
byte[] dotnetHeader = _msgHeaders[(int) MessageStatus.MethodMessage];
networkStream.Write(dotnetHeader, 0, dotnetHeader.Length);
nr += pr;
} while (nr < count);
return true;
}
// Writes header tag (0x0000 if request stream, 0x0002 if response stream)
if(requestHeaders["__RequestUri"]!=null) buffer [0] = (byte) 0;
else buffer[0] = (byte) 2;
buffer [1] = (byte) 0 ;
public static void SendMessageStream (Stream networkStream, Stream data, ITransportHeaders requestHeaders, Byte[] buffer)
{
if (buffer == null) {
buffer = new Byte[DefaultStreamBufferSize];
}
// Writes ID
buffer [2] = (byte) 0;
// Writes the message start header
Byte[] dotnetHeader = _msgHeaders[(Int32) MessageStatus.MethodMessage];
networkStream.Write(dotnetHeader, 0, dotnetHeader.Length);
// Writes assemblyID????
buffer [3] = (byte) 0;
// Writes header tag (0x0000 if request stream, 0x0002 if response stream)
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)
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);
buffer [1] = (Byte) 0 ;
// Writes the message headers
SendHeaders (networkStream, requestHeaders, buffer);
// Writes ID
buffer [2] = (Byte) 0;
// Writes the stream
if (data is MemoryStream)
{
// 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);
}
}
}
// Writes assemblyID????
buffer [3] = (Byte) 0;
static byte[] msgUriTransportKey = new byte[] { 4, 0, 1, 1 };
static byte[] msgContentTypeTransportKey = new byte[] { 6, 0, 1, 1 };
static byte[] msgDefaultTransportKey = new byte[] { 1, 0, 1 };
static byte[] msgHeaderTerminator = new byte[] { 0, 0 };
// Writes the length of the stream being sent (not including the headers)
Int32 num = (Int32)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);
private static void SendHeaders(Stream networkStream, ITransportHeaders requestHeaders, byte[] 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
}
// Writes the message headers
SendHeaders (networkStream, requestHeaders, buffer);
public static ITransportHeaders ReceiveHeaders (Stream networkStream, byte[] buffer)
{
StreamRead (networkStream, buffer, 2);
// Writes the stream
if (data is MemoryStream)
{
// 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];
TransportHeaders headers = new TransportHeaders ();
static Byte[] msgUriTransportKey = new Byte[] { 4, 0, 1, 1 };
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)
{
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);
private static void SendHeaders(Stream networkStream, ITransportHeaders requestHeaders, Byte[] 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
}
StreamRead (networkStream, buffer, 2);
headerType = buffer [0];
}
public static ITransportHeaders ReceiveHeaders (Stream networkStream, Byte[] buffer)
{
_ = 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)
{
headers = null;
while (headerType != 0)
{
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
// +
// Gets the length of the data stream
StreamRead (networkStream, buffer, 8);
return headers;
}
int byteCount = (buffer [4] | (buffer [5] << 8) |
(buffer [6] << 16) | (buffer [7] << 24));
public static Stream ReceiveMessageStream (Stream networkStream, out ITransportHeaders headers, Byte[] buffer)
{
headers = null;
// Reads the headers
headers = ReceiveHeaders (networkStream, buffer);
if (buffer == null) {
buffer = new Byte[DefaultStreamBufferSize];
}
byte[] resultBuffer = new byte[byteCount];
StreamRead (networkStream, resultBuffer, byteCount);
// Reads header tag: 0 -> Stream with headers or 2 -> Response Stream
// +
// 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)
{
// Allocates a buffer. Use the internal buffer if it is
// big enough. If not, create a new one.
// Reads the headers
headers = ReceiveHeaders (networkStream, buffer);
int maxBytes = Encoding.UTF8.GetMaxByteCount(str.Length)+4; //+4 bytes for storing the string length
if (maxBytes > buffer.Length)
buffer = new byte[maxBytes];
Byte[] resultBuffer = new Byte[byteCount];
_ = StreamRead(networkStream, resultBuffer, byteCount);
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;
buffer [1] = (byte) (num >> 8);
buffer [2] = (byte) (num >> 16);
buffer [3] = (byte) (num >> 24);
Int32 maxBytes = Encoding.UTF8.GetMaxByteCount(str.Length)+4; //+4 bytes for storing the string length
if (maxBytes > buffer.Length) {
buffer = new Byte[maxBytes];
}
// Write the string bytes
networkStream.Write (buffer, 0, num + 4);
}
Int32 num = Encoding.UTF8.GetBytes (str, 0, str.Length, buffer, 4);
private static string ReceiveString (Stream networkStream, byte[] buffer)
{
StreamRead (networkStream, buffer, 4);
// store number of bytes (not number of chars!)
// 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) |
(buffer [2] << 16) | (buffer [3] << 24));
// Write the string bytes
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
// internal buffer if it is big enough
// Reads the number of bytes (not chars!)
if (byteCount > buffer.Length)
buffer = new byte[byteCount];
Int32 byteCount = buffer [0] | (buffer [1] << 8) |
(buffer [2] << 16) | (buffer [3] << 24);
// Reads the string
if (byteCount == 0) {
return String.Empty;
}
StreamRead (networkStream, buffer, byteCount);
char[] chars = Encoding.UTF8.GetChars (buffer, 0, byteCount);
// Allocates a buffer of the correct size. Use the
// 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
{
string path = null;
string name = "unix";
String path = null;
String name = "unix";
int priority = 1;
bool supressChannelData = false;
Int32 priority = 1;
Boolean supressChannelData = false;
Thread server_thread = null;
UnixListener listener;
UnixServerTransportSink sink;
ChannelDataStore channel_data;
int _maxConcurrentConnections = 100;
Int32 _maxConcurrentConnections = 100;
ArrayList _activeConnections = new ArrayList();
@ -64,28 +64,28 @@ namespace Mono.Remoting.Channels.Unix
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;
while (provider != null)
{
provider.GetChannelData(channel_data);
provider.GetChannelData(this.channel_data);
provider = provider.Next;
}
// Creates the sink chain that will process all incoming messages
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;
Init (null);
this.Init (null);
}
public UnixServerChannel (IDictionary properties,
@ -93,90 +93,80 @@ namespace Mono.Remoting.Channels.Unix
{
foreach(DictionaryEntry property in properties)
{
switch((string)property.Key)
switch((String)property.Key)
{
case "path":
path = property.Value as string;
this.path = property.Value as String;
break;
case "priority":
priority = Convert.ToInt32(property.Value);
this.priority = Convert.ToInt32(property.Value);
break;
case "supressChannelData":
supressChannelData = Convert.ToBoolean (property.Value);
this.supressChannelData = Convert.ToBoolean (property.Value);
break;
}
}
Init (serverSinkProvider);
this.Init (serverSinkProvider);
}
public UnixServerChannel (string name, string path,
public UnixServerChannel (String name, String path,
IServerChannelSinkProvider serverSinkProvider)
{
this.name = name;
this.path = path;
Init (serverSinkProvider);
this.Init (serverSinkProvider);
}
public UnixServerChannel (string name, string path)
public UnixServerChannel (String name, String path)
{
this.name = name;
this.path = path;
Init (null);
this.Init (null);
}
public object ChannelData
public Object ChannelData
{
get {
if (supressChannelData) return null;
else return channel_data;
}
if (this.supressChannelData) {
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 {
return name;
}
if (!uri.StartsWith ("/")) {
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
{
get {
return priority;
}
}
public String Parse(String url, out String objectURI) => UnixChannel.ParseUnixURL(url, out objectURI);
public string GetChannelUri ()
{
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 ()
void WaitForConnections ()
{
try
{
while (true)
{
Socket client = listener.AcceptSocket ();
CreateListenerConnection (client);
Socket client = this.listener.AcceptSocket ();
this.CreateListenerConnection (client);
}
}
catch
@ -185,71 +175,77 @@ namespace Mono.Remoting.Channels.Unix
internal void CreateListenerConnection (Socket client)
{
lock (_activeConnections)
lock (this._activeConnections)
{
if (_activeConnections.Count >= _maxConcurrentConnections)
Monitor.Wait (_activeConnections);
if (this._activeConnections.Count >= this._maxConcurrentConnections) {
_ = 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.Start();
thread.IsBackground = true;
_activeConnections.Add (thread);
_ = this._activeConnections.Add(thread);
}
}
internal void ReleaseConnection (Thread thread)
{
lock (_activeConnections)
lock (this._activeConnections)
{
_activeConnections.Remove (thread);
Monitor.Pulse (_activeConnections);
this._activeConnections.Remove (thread);
Monitor.Pulse (this._activeConnections);
}
}
public void StartListening (object data)
public void StartListening (Object data)
{
listener = new UnixListener (path);
Mono.Unix.Native.Syscall.chmod (path,
Mono.Unix.Native.FilePermissions.S_IRUSR |
Mono.Unix.Native.FilePermissions.S_IWUSR |
Mono.Unix.Native.FilePermissions.S_IRGRP |
Mono.Unix.Native.FilePermissions.S_IWGRP |
Mono.Unix.Native.FilePermissions.S_IROTH |
Mono.Unix.Native.FilePermissions.S_IWOTH);
this.listener = new UnixListener (this.path);
_ = Mono.Unix.Native.Syscall.chmod(this.path,
Mono.Unix.Native.FilePermissions.S_IRUSR |
Mono.Unix.Native.FilePermissions.S_IWUSR |
Mono.Unix.Native.FilePermissions.S_IRGRP |
Mono.Unix.Native.FilePermissions.S_IWGRP |
Mono.Unix.Native.FilePermissions.S_IROTH |
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 [0] = GetChannelUri ();
channel_data.ChannelUris = uris;
uris [0] = this.GetChannelUri ();
this.channel_data.ChannelUris = uris;
server_thread = new Thread (new ThreadStart (WaitForConnections));
server_thread.IsBackground = true;
server_thread.Start ();
this.server_thread = new Thread (new ThreadStart (this.WaitForConnections));
this.server_thread.IsBackground = true;
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 ();
server_thread = null;
listener.Stop ();
this.server_thread.Abort ();
this.server_thread = null;
this.listener.Stop ();
foreach (Thread thread in _activeConnections)
thread.Abort();
foreach (Thread thread in this._activeConnections) {
thread.Abort();
}
_activeConnections.Clear();
Monitor.PulseAll (_activeConnections);
this._activeConnections.Clear();
Monitor.PulseAll (this._activeConnections);
}
}
}
@ -261,46 +257,41 @@ namespace Mono.Remoting.Channels.Unix
Stream _stream;
UnixServerChannel _serverChannel;
byte[] _buffer = new byte[UnixMessageIO.DefaultStreamBufferSize];
Byte[] _buffer = new Byte[UnixMessageIO.DefaultStreamBufferSize];
public ClientConnection (UnixServerChannel serverChannel, Socket client, UnixServerTransportSink sink)
{
_serverChannel = serverChannel;
_client = client;
_sink = sink;
this._serverChannel = serverChannel;
this._client = client;
this._sink = sink;
}
public Socket Client {
get { return _client; }
}
public Socket Client => this._client;
public byte[] Buffer
public Byte[] Buffer => this._buffer;
public void ProcessMessages()
{
get { return _buffer; }
}
public void ProcessMessages()
{
byte[] buffer = new byte[256];
_stream = new BufferedStream (new NetworkStream (_client));
Byte[] buffer = new Byte[256];
this._stream = new BufferedStream (new NetworkStream (this._client));
try
{
bool end = false;
Boolean end = false;
while (!end)
{
MessageStatus type = UnixMessageIO.ReceiveMessageStatus (_stream, buffer);
MessageStatus type = UnixMessageIO.ReceiveMessageStatus (this._stream, buffer);
switch (type)
{
case MessageStatus.MethodMessage:
_sink.InternalProcessMessage (this, _stream);
break;
case MessageStatus.MethodMessage:
this._sink.InternalProcessMessage (this, this._stream);
break;
case MessageStatus.Unknown:
case MessageStatus.CancelSignal:
end = true;
break;
case MessageStatus.Unknown:
case MessageStatus.CancelSignal:
end = true;
break;
}
}
}
@ -310,21 +301,15 @@ namespace Mono.Remoting.Channels.Unix
}
finally
{
try {
_serverChannel.ReleaseConnection (Thread.CurrentThread);
_stream.Close();
_client.Close ();
} catch {
}
try {
this._serverChannel.ReleaseConnection (Thread.CurrentThread);
this._stream.Close();
this._client.Close ();
} catch {
}
}
}
public bool IsLocal
{
get
{
return true;
}
}
}
public Boolean IsLocal => true;
}
}

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -25,57 +25,39 @@
//
using System;
using System.Runtime.InteropServices;
using System.Threading;
namespace Mono.Unix.Native {
public struct RealTimeSignum
: IEquatable <RealTimeSignum>
{
private int rt_offset;
private static readonly int MaxOffset = UnixSignal.GetSIGRTMAX () - UnixSignal.GetSIGRTMIN () - 1;
public static readonly RealTimeSignum MinValue = new RealTimeSignum (0);
public static readonly RealTimeSignum MaxValue = new RealTimeSignum (MaxOffset);
public struct RealTimeSignum
: IEquatable <RealTimeSignum>
{
private static readonly Int32 MaxOffset = UnixSignal.GetSIGRTMAX () - UnixSignal.GetSIGRTMIN () - 1;
public static readonly RealTimeSignum MinValue = new RealTimeSignum (0);
public static readonly RealTimeSignum MaxValue = new RealTimeSignum (MaxOffset);
public RealTimeSignum (int offset)
{
if (offset < 0)
throw new ArgumentOutOfRangeException ("Offset cannot be negative");
if (offset > MaxOffset)
throw new ArgumentOutOfRangeException ("Offset greater than maximum supported SIGRT");
rt_offset = offset;
}
public RealTimeSignum (Int32 offset)
{
if (offset < 0) {
throw new ArgumentOutOfRangeException ("Offset cannot be negative");
}
public int Offset {
get { return rt_offset; }
}
if (offset > MaxOffset) {
throw new ArgumentOutOfRangeException ("Offset greater than maximum supported SIGRT");
}
public override int GetHashCode ()
{
return rt_offset.GetHashCode ();
}
this.Offset = offset;
}
public override bool Equals (object obj)
{
if ((obj == null) || (obj.GetType () != GetType ()))
return false;
return Equals ((RealTimeSignum)obj);
}
public Int32 Offset { get; }
public bool Equals (RealTimeSignum value)
{
return Offset == value.Offset;
}
public override Int32 GetHashCode() => this.Offset.GetHashCode();
public static bool operator== (RealTimeSignum lhs, RealTimeSignum rhs)
{
return lhs.Equals (rhs);
}
public override Boolean Equals(Object obj) => obj == null || obj.GetType() != this.GetType() ? false : this.Equals((RealTimeSignum)obj);
public static bool operator!= (RealTimeSignum lhs, RealTimeSignum rhs)
{
return !lhs.Equals (rhs);
}
}
public Boolean Equals(RealTimeSignum value) => this.Offset == value.Offset;
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.
//
using System;
using System.Diagnostics.CodeAnalysis;
namespace Mono.Unix.Native {
[AttributeUsage (AttributeTargets.Field)]
internal class blkcnt_tAttribute : MapAttribute {
[AttributeUsage (AttributeTargets.Field)]
[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)]
internal class blksize_tAttribute : MapAttribute {
[AttributeUsage (AttributeTargets.Field)]
[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)]
internal class dev_tAttribute : MapAttribute {
[AttributeUsage (AttributeTargets.Field)]
[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)]
internal class gid_tAttribute : MapAttribute {
[AttributeUsage (AttributeTargets.Field)]
[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)]
internal class fsblkcnt_tAttribute : MapAttribute {
[AttributeUsage (AttributeTargets.Field)]
[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)]
internal class fsfilcnt_tAttribute : MapAttribute {
[AttributeUsage (AttributeTargets.Field)]
[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)]
internal class ino_tAttribute : MapAttribute {
[AttributeUsage (AttributeTargets.Field)]
[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)]
internal class nlink_tAttribute : MapAttribute {
[AttributeUsage (AttributeTargets.Field)]
[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)]
internal class off_tAttribute : MapAttribute {
[AttributeUsage (AttributeTargets.Field)]
[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)]
internal class pid_tAttribute : MapAttribute {
[AttributeUsage (AttributeTargets.Field)]
[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)]
internal class suseconds_tAttribute : MapAttribute {
[AttributeUsage (AttributeTargets.Field)]
[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)]
internal class uid_tAttribute : MapAttribute {
[AttributeUsage (AttributeTargets.Field)]
[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)]
internal class time_tAttribute : MapAttribute {
[AttributeUsage (AttributeTargets.Field)]
[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
{
[Serializable]
public class AbstractUnixEndPoint : EndPoint
{
string path;
[Serializable]
public class AbstractUnixEndPoint : EndPoint
{
String path;
public AbstractUnixEndPoint (string path)
{
if (path == null)
throw new ArgumentNullException ("path");
public AbstractUnixEndPoint (String path)
{
if (path == null) {
throw new ArgumentNullException ("path");
}
if (path == "")
throw new ArgumentException ("Cannot be empty.", "path");
this.path = path;
}
if (path == "") {
throw new ArgumentException ("Cannot be empty.", "path");
}
public string Path {
get {
return(path);
}
set {
path=value;
}
}
this.path = path;
}
public override AddressFamily AddressFamily {
get { return AddressFamily.Unix; }
}
public String Path {
get => this.path;
set => this.path = value;
}
public override EndPoint Create (SocketAddress socketAddress)
{
/*
* Should also check this
*
int addr = (int) AddressFamily.Unix;
if (socketAddress [0] != (addr & 0xFF))
throw new ArgumentException ("socketAddress is not a unix socket address.");
public override AddressFamily AddressFamily => AddressFamily.Unix;
if (socketAddress [1] != ((addr & 0xFF00) >> 8))
throw new ArgumentException ("socketAddress is not a unix socket address.");
*/
public override EndPoint Create (SocketAddress socketAddress)
{
/*
* 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];
for (int i = 0; i < bytes.Length; i++) {
bytes [i] = socketAddress [2 + 1 + i];
}
if (socketAddress [1] != ((addr & 0xFF00) >> 8))
throw new ArgumentException ("socketAddress is not a unix socket address.");
*/
string name = Encoding.Default.GetString (bytes);
return new AbstractUnixEndPoint (name);
}
Byte[] bytes = new Byte[socketAddress.Size - 2 - 1];
for (Int32 i = 0; i < bytes.Length; i++) {
bytes [i] = socketAddress [2 + 1 + i];
}
public override SocketAddress Serialize ()
{
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;
String name = Encoding.Default.GetString (bytes);
return new AbstractUnixEndPoint (name);
}
// sa [0] -> family low byte, sa [1] -> family high byte
for (int i = 0; i < bytes.Length; i++)
sa [i + 2 + 1] = bytes [i];
public override SocketAddress Serialize ()
{
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(path);
}
return sa;
}
public override int GetHashCode ()
{
return path.GetHashCode ();
}
public override String ToString() => this.path;
public override bool Equals (object o)
{
AbstractUnixEndPoint other = o as AbstractUnixEndPoint;
if (other == null)
return false;
public override Int32 GetHashCode() => this.path.GetHashCode();
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.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
namespace Mono.Unix {
public class Catalog {
private Catalog () {}
public class Catalog {
private Catalog () {}
[DllImport("intl", CallingConvention=CallingConvention.Cdecl)]
static extern IntPtr bindtextdomain (IntPtr domainname, IntPtr dirname);
[DllImport("intl", CallingConvention=CallingConvention.Cdecl)]
static extern IntPtr bind_textdomain_codeset (IntPtr domainname,
IntPtr codeset);
[DllImport("intl", CallingConvention=CallingConvention.Cdecl)]
static extern IntPtr textdomain (IntPtr domainname);
[DllImport("intl", CallingConvention=CallingConvention.Cdecl)]
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
static extern IntPtr bindtextdomain (IntPtr domainname, IntPtr dirname);
[DllImport("intl", CallingConvention=CallingConvention.Cdecl)]
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
static extern IntPtr bind_textdomain_codeset (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)
{
IntPtr ipackage, ilocaledir, iutf8;
MarshalStrings (package, out ipackage, localedir, out ilocaledir,
"UTF-8", out iutf8);
try {
if (bindtextdomain (ipackage, ilocaledir) == IntPtr.Zero)
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);
}
}
public static void Init (String package, String localedir)
{
MarshalStrings(package, out IntPtr ipackage, localedir, out IntPtr ilocaledir,
"UTF-8", out IntPtr iutf8);
try {
if (bindtextdomain (ipackage, ilocaledir) == IntPtr.Zero) {
throw new UnixIOException (Native.Errno.ENOMEM);
}
private static void MarshalStrings (string s1, out IntPtr p1,
string s2, out IntPtr p2, string s3, out IntPtr p3)
{
p1 = p2 = p3 = IntPtr.Zero;
if (bind_textdomain_codeset (ipackage, iutf8) == IntPtr.Zero) {
throw new UnixIOException (Native.Errno.ENOMEM);
}
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 {
p1 = UnixMarshal.StringToHeap (s1);
p2 = UnixMarshal.StringToHeap (s2);
if (s3 != null)
p3 = UnixMarshal.StringToHeap (s3);
cleanup = false;
}
finally {
if (cleanup) {
UnixMarshal.FreeHeap (p1);
UnixMarshal.FreeHeap (p2);
UnixMarshal.FreeHeap (p3);
}
}
}
private static void MarshalStrings (String s1, out IntPtr p1,
String s2, out IntPtr p2, String s3, out IntPtr p3)
{
p1 = p2 = p3 = IntPtr.Zero;
[DllImport("intl", CallingConvention=CallingConvention.Cdecl)]
static extern IntPtr gettext (IntPtr instring);
Boolean cleanup = true;
public static String GetString (String s)
{
IntPtr ints = UnixMarshal.StringToHeap (s);
try {
// gettext(3) returns the input pointer if no translation is found
IntPtr r = gettext (ints);
if (r != ints)
return UnixMarshal.PtrToStringUnix (r);
return s;
}
finally {
UnixMarshal.FreeHeap (ints);
}
}
try {
p1 = UnixMarshal.StringToHeap (s1);
p2 = UnixMarshal.StringToHeap (s2);
if (s3 != null) {
p3 = UnixMarshal.StringToHeap (s3);
}
[DllImport("intl", CallingConvention=CallingConvention.Cdecl)]
static extern IntPtr ngettext (IntPtr singular, IntPtr plural, Int32 n);
cleanup = false;
}
finally {
if (cleanup) {
UnixMarshal.FreeHeap (p1);
UnixMarshal.FreeHeap (p2);
UnixMarshal.FreeHeap (p3);
}
}
}
public static String GetPluralString (String s, String p, Int32 n)
{
IntPtr ints, intp, _ignore;
MarshalStrings (s, out ints, p, out intp, null, out _ignore);
[DllImport("intl", CallingConvention=CallingConvention.Cdecl)]
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
static extern IntPtr gettext (IntPtr instring);
try {
// ngettext(3) returns an input pointer if no translation is found
IntPtr r = ngettext (ints, intp, n);
if (r == ints)
return s;
if (r == intp)
return p;
return UnixMarshal.PtrToStringUnix (r);
}
finally {
UnixMarshal.FreeHeap (ints);
UnixMarshal.FreeHeap (intp);
}
}
}
public static String GetString (String s)
{
IntPtr ints = UnixMarshal.StringToHeap (s);
try {
// gettext(3) returns the input pointer if no translation is found
IntPtr r = gettext (ints);
if (r != ints) {
return UnixMarshal.PtrToStringUnix (r);
}
return s;
}
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 {
public enum FileAccessPattern {
Normal = Native.PosixFadviseAdvice.POSIX_FADV_NORMAL,
Sequential = Native.PosixFadviseAdvice.POSIX_FADV_SEQUENTIAL,
Random = Native.PosixFadviseAdvice.POSIX_FADV_RANDOM,
NoReuse = Native.PosixFadviseAdvice.POSIX_FADV_NOREUSE,
PreLoad = Native.PosixFadviseAdvice.POSIX_FADV_WILLNEED,
FlushCache = Native.PosixFadviseAdvice.POSIX_FADV_DONTNEED,
}
public enum FileAccessPattern {
Normal = Native.PosixFadviseAdvice.POSIX_FADV_NORMAL,
Sequential = Native.PosixFadviseAdvice.POSIX_FADV_SEQUENTIAL,
Random = Native.PosixFadviseAdvice.POSIX_FADV_RANDOM,
NoReuse = Native.PosixFadviseAdvice.POSIX_FADV_NOREUSE,
PreLoad = Native.PosixFadviseAdvice.POSIX_FADV_WILLNEED,
FlushCache = Native.PosixFadviseAdvice.POSIX_FADV_DONTNEED,
}
}

View File

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

View File

@ -27,56 +27,53 @@
//
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Text;
using Mono.Unix;
namespace Mono.Unix {
public sealed /* static */ class FileHandleOperations
{
private FileHandleOperations () {}
public sealed /* static */ class FileHandleOperations
{
private FileHandleOperations () {}
public static void AdviseFileAccessPattern (int fd, FileAccessPattern pattern, long offset, long len)
{
int r = Native.Syscall.posix_fadvise (fd, offset, len,
(Native.PosixFadviseAdvice) pattern);
UnixMarshal.ThrowExceptionForLastErrorIf (r);
}
public static void AdviseFileAccessPattern (Int32 fd, FileAccessPattern pattern, Int64 offset, Int64 len)
{
Int32 r = Native.Syscall.posix_fadvise (fd, offset, len,
(Native.PosixFadviseAdvice) pattern);
UnixMarshal.ThrowExceptionForLastErrorIf (r);
}
public static void AdviseFileAccessPattern (int fd, FileAccessPattern pattern)
{
AdviseFileAccessPattern (fd, pattern, 0, 0);
}
public static void AdviseFileAccessPattern(Int32 fd, FileAccessPattern pattern) => AdviseFileAccessPattern(fd, pattern, 0, 0);
public static void AdviseFileAccessPattern (FileStream file, FileAccessPattern pattern, long offset, long len)
{
if (file == null)
throw new ArgumentNullException ("file");
int r = Native.Syscall.posix_fadvise (file.Handle.ToInt32(), offset, len,
(Native.PosixFadviseAdvice) pattern);
UnixMarshal.ThrowExceptionForLastErrorIf (r);
}
[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");
}
public static void AdviseFileAccessPattern (FileStream file, FileAccessPattern pattern)
{
AdviseFileAccessPattern (file, pattern, 0, 0);
}
Int32 r = Native.Syscall.posix_fadvise (file.Handle.ToInt32(), offset, len,
(Native.PosixFadviseAdvice) pattern);
UnixMarshal.ThrowExceptionForLastErrorIf (r);
}
public static void AdviseFileAccessPattern (UnixStream stream, FileAccessPattern pattern, long offset, long len)
{
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(FileStream file, FileAccessPattern pattern) => AdviseFileAccessPattern(file, pattern, 0, 0);
public static void AdviseFileAccessPattern (UnixStream stream, FileAccessPattern pattern)
{
AdviseFileAccessPattern (stream, pattern, 0, 0);
}
}
public static void AdviseFileAccessPattern (UnixStream stream, FileAccessPattern pattern, Int64 offset, Int64 len)
{
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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -34,100 +34,95 @@ using System.Text;
namespace Mono.Unix
{
[Serializable]
public class UnixEndPoint : EndPoint
{
string filename;
[Serializable]
public class UnixEndPoint : EndPoint
{
String filename;
public UnixEndPoint (string filename)
{
if (filename == null)
throw new ArgumentNullException ("filename");
public UnixEndPoint (String filename)
{
if (filename == null) {
throw new ArgumentNullException ("filename");
}
if (filename == "")
throw new ArgumentException ("Cannot be empty.", "filename");
this.filename = filename;
}
if (filename == "") {
throw new ArgumentException ("Cannot be empty.", "filename");
}
public string Filename {
get {
return(filename);
}
set {
filename=value;
}
}
this.filename = filename;
}
public override AddressFamily AddressFamily {
get { return AddressFamily.Unix; }
}
public String Filename {
get => this.filename;
set => this.filename = value;
}
public override EndPoint Create (SocketAddress socketAddress)
{
/*
* Should also check this
*
int addr = (int) AddressFamily.Unix;
if (socketAddress [0] != (addr & 0xFF))
throw new ArgumentException ("socketAddress is not a unix socket address.");
public override AddressFamily AddressFamily => AddressFamily.Unix;
if (socketAddress [1] != ((addr & 0xFF00) >> 8))
throw new ArgumentException ("socketAddress is not a unix socket address.");
*/
public override EndPoint Create (SocketAddress socketAddress)
{
/*
* 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) {
// Empty filename.
// 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;
}
}
if (socketAddress [1] != ((addr & 0xFF00) >> 8))
throw new ArgumentException ("socketAddress is not a unix socket address.");
*/
string name = Encoding.Default.GetString (bytes, 0, size);
return new UnixEndPoint (name);
}
if (socketAddress.Size == 2) {
// 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 ()
{
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];
String name = Encoding.Default.GetString (bytes, 0, size);
return new UnixEndPoint (name);
}
//NULL suffix for non-abstract path
sa[2 + bytes.Length] = 0;
public override SocketAddress Serialize ()
{
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(filename);
}
return sa;
}
public override int GetHashCode ()
{
return filename.GetHashCode ();
}
public override String ToString() => this.filename;
public override bool Equals (object o)
{
UnixEndPoint other = o as UnixEndPoint;
if (other == null)
return false;
public override Int32 GetHashCode() => this.filename.GetHashCode();
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.Collections;
using System.Diagnostics.CodeAnalysis;
using System.Text;
using Mono.Unix;
namespace Mono.Unix {
public sealed /* static */ class UnixEnvironment
{
private UnixEnvironment () {}
public sealed /* static */ class UnixEnvironment
{
private UnixEnvironment () {}
public static string CurrentDirectory {
get {
return UnixDirectoryInfo.GetCurrentDirectory ();
}
set {
UnixDirectoryInfo.SetCurrentDirectory (value);
}
}
public static String CurrentDirectory {
get => UnixDirectoryInfo.GetCurrentDirectory();
set => UnixDirectoryInfo.SetCurrentDirectory(value);
}
public static string MachineName {
get {
Native.Utsname buf;
if (Native.Syscall.uname (out buf) != 0)
throw UnixMarshal.CreateExceptionForLastError ();
return buf.nodename;
}
set {
int r = Native.Syscall.sethostname (value);
UnixMarshal.ThrowExceptionForLastErrorIf (r);
}
}
public static String MachineName {
get {
if(Native.Syscall.uname(out Native.Utsname buf) != 0) {
throw UnixMarshal.CreateExceptionForLastError();
}
public static string UserName {
get {return UnixUserInfo.GetRealUser ().UserName;}
}
return buf.nodename;
}
set {
Int32 r = Native.Syscall.sethostname (value);
UnixMarshal.ThrowExceptionForLastErrorIf (r);
}
}
public static UnixGroupInfo RealGroup {
get {return new UnixGroupInfo (RealGroupId);}
// set can't be done as setgid(2) modifies effective gid as well
}
public static String UserName => UnixUserInfo.GetRealUser().UserName;
public static long RealGroupId {
get {return Native.Syscall.getgid ();}
// set can't be done as setgid(2) modifies effective gid as well
}
public static UnixGroupInfo RealGroup => new UnixGroupInfo(RealGroupId);
public static UnixUserInfo RealUser {
get {return new UnixUserInfo (RealUserId);}
// set can't be done as setuid(2) modifies effective uid as well
}
public static Int64 RealGroupId => Native.Syscall.getgid();
public static long RealUserId {
get {return Native.Syscall.getuid ();}
// set can't be done as setuid(2) modifies effective uid as well
}
public static UnixUserInfo RealUser => new UnixUserInfo(RealUserId);
public static UnixGroupInfo EffectiveGroup {
get {return new UnixGroupInfo (EffectiveGroupId);}
set {EffectiveGroupId = value.GroupId;}
}
public static Int64 RealUserId => Native.Syscall.getuid();
public static long EffectiveGroupId {
get {return Native.Syscall.getegid ();}
set {Native.Syscall.setegid (Convert.ToUInt32 (value));}
}
public static UnixGroupInfo EffectiveGroup {
get => new UnixGroupInfo(EffectiveGroupId);
set => EffectiveGroupId = value.GroupId;
}
public static UnixUserInfo EffectiveUser {
get {return new UnixUserInfo (EffectiveUserId);}
set {EffectiveUserId = value.UserId;}
}
public static Int64 EffectiveGroupId {
get => Native.Syscall.getegid();
set => _ = Native.Syscall.setegid(Convert.ToUInt32(value));
}
public static long EffectiveUserId {
get {return Native.Syscall.geteuid ();}
set {Native.Syscall.seteuid (Convert.ToUInt32 (value));}
}
public static UnixUserInfo EffectiveUser {
get => new UnixUserInfo(EffectiveUserId);
set => EffectiveUserId = value.UserId;
}
public static string Login {
get {return UnixUserInfo.GetRealUser ().UserName;}
}
public static Int64 EffectiveUserId {
get => Native.Syscall.geteuid();
set => _ = Native.Syscall.seteuid(Convert.ToUInt32(value));
}
[CLSCompliant (false)]
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;
}
public static String Login => UnixUserInfo.GetRealUser().UserName;
[CLSCompliant (false)]
public static string GetConfigurationString (Native.ConfstrName name)
{
ulong len = Native.Syscall.confstr (name, null, 0);
if (len == unchecked ((ulong) (-1)))
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 ();
}
//[CLSCompliant (false)]
public static Int64 GetConfigurationValue (Native.SysconfName name)
{
Int64 r = Native.Syscall.sysconf (name);
if (r == -1 && Native.Stdlib.GetLastError() != (Native.Errno) 0) {
UnixMarshal.ThrowExceptionForLastError ();
}
public static void SetNiceValue (int inc)
{
int r = Native.Syscall.nice (inc);
UnixMarshal.ThrowExceptionForLastErrorIf (r);
}
return r;
}
public static int CreateSession ()
{
int s = Native.Syscall.setsid ();
UnixMarshal.ThrowExceptionForLastErrorIf (s);
return s;
}
//[CLSCompliant (false)]
public static String GetConfigurationString (Native.ConfstrName name)
{
UInt64 len = Native.Syscall.confstr (name, null, 0);
if (len == unchecked ((UInt64) (-1))) {
UnixMarshal.ThrowExceptionForLastError ();
}
public static void SetProcessGroup ()
{
int r = Native.Syscall.setpgrp ();
UnixMarshal.ThrowExceptionForLastErrorIf (r);
}
if (len == 0) {
return "";
}
public static int GetProcessGroup ()
{
return Native.Syscall.getpgrp ();
}
StringBuilder buf = new StringBuilder ((Int32) len+1);
len = Native.Syscall.confstr (name, buf, len);
if (len == unchecked ((UInt64) (-1))) {
UnixMarshal.ThrowExceptionForLastError ();
}
public static UnixGroupInfo[] GetSupplementaryGroups ()
{
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;
}
return buf.ToString ();
}
private static uint[] _GetSupplementaryGroupIds ()
{
int ngroups = Native.Syscall.getgroups (0, new uint[]{});
if (ngroups == -1)
UnixMarshal.ThrowExceptionForLastError ();
uint[] groups = new uint[ngroups];
int r = Native.Syscall.getgroups (groups);
UnixMarshal.ThrowExceptionForLastErrorIf (r);
return groups;
}
public static void SetNiceValue (Int32 inc)
{
Int32 r = Native.Syscall.nice (inc);
UnixMarshal.ThrowExceptionForLastErrorIf (r);
}
public static void SetSupplementaryGroups (UnixGroupInfo[] groups)
{
uint[] list = new uint [groups.Length];
for (int i = 0; i < list.Length; ++i) {
list [i] = Convert.ToUInt32 (groups [i].GroupId);
}
int r = Native.Syscall.setgroups (list);
UnixMarshal.ThrowExceptionForLastErrorIf (r);
}
public static Int32 CreateSession ()
{
Int32 s = Native.Syscall.setsid ();
UnixMarshal.ThrowExceptionForLastErrorIf (s);
return s;
}
public static long[] GetSupplementaryGroupIds ()
{
uint[] _groups = _GetSupplementaryGroupIds ();
long[] groups = new long [_groups.Length];
for (int i = 0; i < groups.Length; ++i)
groups [i] = _groups [i];
return groups;
}
public static void SetProcessGroup ()
{
Int32 r = Native.Syscall.setpgrp ();
UnixMarshal.ThrowExceptionForLastErrorIf (r);
}
public static void SetSupplementaryGroupIds (long[] list)
{
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 Int32 GetProcessGroup() => Native.Syscall.getpgrp();
public static int GetParentProcessId ()
{
return Native.Syscall.getppid ();
}
public static UnixGroupInfo[] GetSupplementaryGroups ()
{
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 new UnixProcess (GetParentProcessId ());
}
return groups;
}
public static string[] GetUserShells ()
{
ArrayList shells = new ArrayList ();
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
private static UInt32[] _GetSupplementaryGroupIds ()
{
Int32 ngroups = Native.Syscall.getgroups (0, new UInt32[]{});
if (ngroups == -1) {
UnixMarshal.ThrowExceptionForLastError ();
}
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 ();
}
}
UInt32[] groups = new UInt32[ngroups];
Int32 r = Native.Syscall.getgroups (groups);
UnixMarshal.ThrowExceptionForLastErrorIf (r);
return groups;
}
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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -28,6 +28,7 @@
//
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using System.Threading;
@ -35,193 +36,195 @@ using Mono.Unix.Native;
namespace Mono.Unix {
public class UnixSignal : WaitHandle {
private int signum;
private IntPtr signal_info;
public class UnixSignal : WaitHandle {
private readonly Int32 signum;
private IntPtr signal_info;
static UnixSignal ()
{
Stdlib.VersionCheck ();
}
static UnixSignal() => Stdlib.VersionCheck();
public UnixSignal (Signum signum)
{
this.signum = NativeConvert.FromSignum (signum);
this.signal_info = install (this.signum);
if (this.signal_info == IntPtr.Zero) {
throw new ArgumentException ("Unable to handle signal", "signum");
}
}
public UnixSignal (Signum signum)
{
this.signum = NativeConvert.FromSignum (signum);
this.signal_info = install (this.signum);
if (this.signal_info == IntPtr.Zero) {
throw new ArgumentException ("Unable to handle signal", "signum");
}
}
public UnixSignal (Mono.Unix.Native.RealTimeSignum rtsig)
{
signum = NativeConvert.FromRealTimeSignum (rtsig);
this.signal_info = install (this.signum);
Native.Errno err = Native.Stdlib.GetLastError ();
if (this.signal_info == IntPtr.Zero) {
if (err == Native.Errno.EADDRINUSE)
throw new ArgumentException ("Signal registered outside of Mono.Posix", "signum");
throw new ArgumentException ("Unable to handle signal", "signum");
}
}
public UnixSignal (RealTimeSignum rtsig)
{
this.signum = NativeConvert.FromRealTimeSignum (rtsig);
this.signal_info = install (this.signum);
Native.Errno err = Native.Stdlib.GetLastError ();
if (this.signal_info == IntPtr.Zero) {
if (err == Native.Errno.EADDRINUSE) {
throw new ArgumentException ("Signal registered outside of Mono.Posix", "signum");
}
public Signum Signum {
get {
if (IsRealTimeSignal)
throw new InvalidOperationException ("This signal is a RealTimeSignum");
return NativeConvert.ToSignum (signum);
}
}
throw new ArgumentException ("Unable to handle signal", "signum");
}
}
public RealTimeSignum RealTimeSignum {
get {
if (!IsRealTimeSignal)
throw new InvalidOperationException ("This signal is not a RealTimeSignum");
return NativeConvert.ToRealTimeSignum (signum-GetSIGRTMIN ());
}
}
public Signum Signum {
get {
if (this.IsRealTimeSignal) {
throw new InvalidOperationException ("This signal is a RealTimeSignum");
}
public bool IsRealTimeSignal {
get {
AssertValid ();
int sigrtmin = GetSIGRTMIN ();
if (sigrtmin == -1)
return false;
return signum >= sigrtmin;
}
}
return NativeConvert.ToSignum (this.signum);
}
}
[DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl,
EntryPoint="Mono_Unix_UnixSignal_install", SetLastError=true)]
private static extern IntPtr install (int signum);
public RealTimeSignum RealTimeSignum {
get {
if (!this.IsRealTimeSignal) {
throw new InvalidOperationException ("This signal is not a RealTimeSignum");
}
[DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl,
EntryPoint="Mono_Unix_UnixSignal_uninstall")]
private static extern int uninstall (IntPtr info);
return NativeConvert.ToRealTimeSignum (this.signum -GetSIGRTMIN ());
}
}
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
delegate int Mono_Posix_RuntimeIsShuttingDown ();
static Mono_Posix_RuntimeIsShuttingDown ShuttingDown = RuntimeShuttingDownCallback;
public Boolean IsRealTimeSignal {
get {
this.AssertValid ();
Int32 sigrtmin = GetSIGRTMIN ();
return sigrtmin == -1 ? false : this.signum >= sigrtmin;
}
}
static int RuntimeShuttingDownCallback ()
{
return Environment.HasShutdownStarted ? 1 : 0;
}
[DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl,
EntryPoint="Mono_Unix_UnixSignal_install", SetLastError=true)]
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
private static extern IntPtr install (Int32 signum);
[DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl,
EntryPoint="Mono_Unix_UnixSignal_WaitAny")]
private static extern int WaitAny (IntPtr[] infos, int count, int timeout, Mono_Posix_RuntimeIsShuttingDown shutting_down);
[DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl,
EntryPoint="Mono_Unix_UnixSignal_uninstall")]
[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")]
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")]
internal static extern int GetSIGRTMAX ();
internal static extern Int32 GetSIGRTMAX ();
private void AssertValid ()
{
if (signal_info == IntPtr.Zero)
throw new ObjectDisposedException (GetType().FullName);
}
private void AssertValid ()
{
if (this.signal_info == IntPtr.Zero) {
throw new ObjectDisposedException (this.GetType().FullName);
}
}
private unsafe SignalInfo* Info {
get {
AssertValid ();
return (SignalInfo*) signal_info;
}
}
private unsafe SignalInfo* Info {
get {
this.AssertValid ();
return (SignalInfo*)this.signal_info;
}
}
public bool IsSet {
get {
return Count > 0;
}
}
public Boolean IsSet => this.Count > 0;
public unsafe bool Reset ()
{
int n = Interlocked.Exchange (ref Info->count, 0);
return n != 0;
}
public unsafe Boolean Reset ()
{
Int32 n = Interlocked.Exchange (ref this.Info->count, 0);
return n != 0;
}
public unsafe int Count {
get {return Info->count;}
set {Interlocked.Exchange (ref Info->count, value);}
}
public unsafe Int32 Count {
get => this.Info->count;
set => Interlocked.Exchange(ref this.Info->count, value);
}
// 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
// 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
#pragma warning disable 649
[Map]
struct SignalInfo {
public int signum, count, read_fd, write_fd, pipecnt, pipelock, have_handler;
public IntPtr handler; // Backed-up handler to restore when signal unregistered
}
[Map]
struct SignalInfo {
public Int32 signum, count, read_fd, write_fd, pipecnt, pipelock, have_handler;
public IntPtr handler; // Backed-up handler to restore when signal unregistered
}
#pragma warning restore 649
#region WaitHandle overrides
protected unsafe override void Dispose (bool disposing)
{
base.Dispose (disposing);
if (signal_info == IntPtr.Zero)
return;
uninstall (signal_info);
signal_info = IntPtr.Zero;
}
#region WaitHandle overrides
protected unsafe override void Dispose (Boolean disposing)
{
base.Dispose (disposing);
if (this.signal_info == IntPtr.Zero) {
return;
}
public override bool WaitOne ()
{
return WaitOne (-1, false);
}
_ = uninstall(this.signal_info);
this.signal_info = IntPtr.Zero;
}
public override bool WaitOne (TimeSpan timeout, bool exitContext)
{
long ms = (long) timeout.TotalMilliseconds;
if (ms < -1 || ms > Int32.MaxValue)
throw new ArgumentOutOfRangeException ("timeout");
return WaitOne ((int) ms, exitContext);
}
public override Boolean WaitOne() => this.WaitOne(-1, false);
public override bool WaitOne (int millisecondsTimeout, bool exitContext)
{
AssertValid ();
if (exitContext)
throw new InvalidOperationException ("exitContext is not supported");
if (millisecondsTimeout == 0)
return IsSet;
return WaitAny (new UnixSignal[]{this}, millisecondsTimeout) == 0;
}
#endregion
public override Boolean WaitOne (TimeSpan timeout, Boolean exitContext)
{
Int64 ms = (Int64) timeout.TotalMilliseconds;
if (ms < -1 || ms > Int32.MaxValue) {
throw new ArgumentOutOfRangeException ("timeout");
}
public static int WaitAny (UnixSignal[] signals)
{
return WaitAny (signals, -1);
}
return this.WaitOne ((Int32) ms, exitContext);
}
public static int WaitAny (UnixSignal[] signals, TimeSpan timeout)
{
long ms = (long) timeout.TotalMilliseconds;
if (ms < -1 || ms > Int32.MaxValue)
throw new ArgumentOutOfRangeException ("timeout");
return WaitAny (signals, (int) ms);
}
public override Boolean WaitOne (Int32 millisecondsTimeout, Boolean exitContext)
{
this.AssertValid ();
if (exitContext) {
throw new InvalidOperationException ("exitContext is not supported");
}
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)
{
if (signals == null)
throw new ArgumentNullException ("signals");
if (millisecondsTimeout < -1)
throw new ArgumentOutOfRangeException ("millisecondsTimeout");
IntPtr[] infos = new IntPtr [signals.Length];
for (int i = 0; i < signals.Length; ++i) {
infos [i] = signals [i].signal_info;
if (infos [i] == IntPtr.Zero)
throw new InvalidOperationException ("Disposed UnixSignal");
}
return WaitAny (infos, infos.Length, millisecondsTimeout, ShuttingDown);
}
}
public static unsafe Int32 WaitAny (UnixSignal[] signals, Int32 millisecondsTimeout)
{
if (signals == null) {
throw new ArgumentNullException ("signals");
}
if (millisecondsTimeout < -1) {
throw new ArgumentOutOfRangeException ("millisecondsTimeout");
}
IntPtr[] infos = new IntPtr [signals.Length];
for (Int32 i = 0; i < signals.Length; ++i) {
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 {
public sealed class UnixStream : Stream, IDisposable
{
public const int InvalidFileDescriptor = -1;
public const int StandardInputFileDescriptor = 0;
public const int StandardOutputFileDescriptor = 1;
public const int StandardErrorFileDescriptor = 2;
public sealed class UnixStream : Stream, IDisposable {
public const Int32 InvalidFileDescriptor = -1;
public const Int32 StandardInputFileDescriptor = 0;
public const Int32 StandardOutputFileDescriptor = 1;
public const Int32 StandardErrorFileDescriptor = 2;
public UnixStream (int fileDescriptor)
: this (fileDescriptor, true) {}
public UnixStream(Int32 fileDescriptor)
: this(fileDescriptor, true) { }
public UnixStream (int fileDescriptor, bool ownsHandle)
{
if (InvalidFileDescriptor == fileDescriptor)
throw new ArgumentException (Locale.GetText ("Invalid file descriptor"), "fileDescriptor");
public UnixStream(Int32 fileDescriptor, Boolean ownsHandle) {
if(InvalidFileDescriptor == fileDescriptor) {
throw new ArgumentException(Locale.GetText("Invalid file descriptor"), "fileDescriptor");
}
this.fileDescriptor = fileDescriptor;
this.owner = ownsHandle;
this.fileDescriptor = fileDescriptor;
this.owner = ownsHandle;
long offset = Native.Syscall.lseek (fileDescriptor, 0, Native.SeekFlags.SEEK_CUR);
if (offset != -1)
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;
}
Int64 offset = Native.Syscall.lseek(fileDescriptor, 0, Native.SeekFlags.SEEK_CUR);
if(offset != -1) {
this.canSeek = true;
}
private void AssertNotDisposed ()
{
if (fileDescriptor == InvalidFileDescriptor)
throw new ObjectDisposedException ("Invalid File Descriptor");
}
Int64 read = Native.Syscall.read(fileDescriptor, IntPtr.Zero, 0);
if(read != -1) {
this.canRead = true;
}
public int Handle {
get {return fileDescriptor;}
}
Int64 write = Native.Syscall.write(fileDescriptor, IntPtr.Zero, 0);
if(write != -1) {
this.canWrite = true;
}
}
public override bool CanRead {
get {return canRead;}
}
private void AssertNotDisposed() {
if(this.fileDescriptor == InvalidFileDescriptor) {
throw new ObjectDisposedException("Invalid File Descriptor");
}
}
public override bool CanSeek {
get {return canSeek;}
}
public Int32 Handle => this.fileDescriptor;
public override bool CanWrite {
get {return canWrite;}
}
public override Boolean CanRead => this.canRead;
public override long Length {
get {
AssertNotDisposed ();
if (!CanSeek)
throw new NotSupportedException ("File descriptor doesn't support seeking");
RefreshStat ();
return stat.st_size;
}
}
public override Boolean CanSeek => this.canSeek;
public override long Position {
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);
}
}
public override Boolean CanWrite => this.canWrite;
[CLSCompliant (false)]
public Native.FilePermissions Protection {
get {
RefreshStat ();
return stat.st_mode;
}
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 override Int64 Length {
get {
this.AssertNotDisposed();
if(!this.CanSeek) {
throw new NotSupportedException("File descriptor doesn't support seeking");
}
public FileTypes FileType {
get {
int type = (int) Protection;
return (FileTypes) (type & (int) UnixFileSystemInfo.AllFileTypes);
}
// no set as fchmod(2) won't accept changing the file type.
}
this.RefreshStat();
return this.stat.st_size;
}
}
public FileAccessPermissions FileAccessPermissions {
get {
int perms = (int) Protection;
return (FileAccessPermissions) (perms & (int) FileAccessPermissions.AllPermissions);
}
set {
int perms = (int) Protection;
perms &= (int) ~FileAccessPermissions.AllPermissions;
perms |= (int) value;
Protection = (Native.FilePermissions) perms;
}
}
public override Int64 Position {
get {
this.AssertNotDisposed();
if(!this.CanSeek) {
throw new NotSupportedException("The stream does not support seeking");
}
public FileSpecialAttributes FileSpecialAttributes {
get {
int attrs = (int) Protection;
return (FileSpecialAttributes) (attrs & (int) UnixFileSystemInfo.AllSpecialAttributes);
}
set {
int perms = (int) Protection;
perms &= (int) ~UnixFileSystemInfo.AllSpecialAttributes;
perms |= (int) value;
Protection = (Native.FilePermissions) perms;
}
}
Int64 pos = Native.Syscall.lseek(this.fileDescriptor, 0, Native.SeekFlags.SEEK_CUR);
if(pos == -1) {
UnixMarshal.ThrowExceptionForLastError();
}
public UnixUserInfo OwnerUser {
get {RefreshStat (); return new UnixUserInfo (stat.st_uid);}
}
return (Int64)pos;
}
set => _ = this.Seek(value, SeekOrigin.Begin);
}
public long OwnerUserId {
get {RefreshStat (); return stat.st_uid;}
}
//[CLSCompliant(false)]
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 {
get {RefreshStat (); return new UnixGroupInfo (stat.st_gid);}
}
public FileTypes FileType {
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 {
get {RefreshStat (); return stat.st_gid;}
}
public FileAccessPermissions FileAccessPermissions {
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 ()
{
AssertNotDisposed ();
int r = Native.Syscall.fstat (fileDescriptor, out stat);
UnixMarshal.ThrowExceptionForLastErrorIf (r);
}
public FileSpecialAttributes FileSpecialAttributes {
get {
Int32 attrs = (Int32)this.Protection;
return (FileSpecialAttributes)(attrs & (Int32)UnixFileSystemInfo.AllSpecialAttributes);
}
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)
{
FileHandleOperations.AdviseFileAccessPattern (fileDescriptor, pattern, offset, len);
}
public UnixUserInfo OwnerUser {
get {
this.RefreshStat();
return new UnixUserInfo(this.stat.st_uid);
}
}
public void AdviseFileAccessPattern (FileAccessPattern pattern)
{
AdviseFileAccessPattern (pattern, 0, 0);
}
public Int64 OwnerUserId {
get {
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)
{
AssertNotDisposed ();
AssertValidBuffer (buffer, offset, count);
if (!CanRead)
throw new NotSupportedException ("Stream does not support reading");
public Int64 OwnerGroupId {
get {
this.RefreshStat();
return this.stat.st_gid;
}
}
if (buffer.Length == 0)
return 0;
private void RefreshStat() {
this.AssertNotDisposed();
Int32 r = Native.Syscall.fstat(this.fileDescriptor, out this.stat);
UnixMarshal.ThrowExceptionForLastErrorIf(r);
}
long r = 0;
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;
}
public void AdviseFileAccessPattern(FileAccessPattern pattern, Int64 offset, Int64 len) => FileHandleOperations.AdviseFileAccessPattern(this.fileDescriptor, pattern, offset, len);
private void AssertValidBuffer (byte[] buffer, int offset, int 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 AdviseFileAccessPattern(FileAccessPattern pattern) => this.AdviseFileAccessPattern(pattern, 0, 0);
public unsafe int ReadAtOffset ([In, Out] byte[] buffer,
int offset, int count, long fileOffset)
{
AssertNotDisposed ();
AssertValidBuffer (buffer, offset, count);
if (!CanRead)
throw new NotSupportedException ("Stream does not support reading");
public override void Flush() {
}
if (buffer.Length == 0)
return 0;
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");
}
long r = 0;
fixed (byte* buf = &buffer[offset]) {
do {
r = Native.Syscall.pread (fileDescriptor, buf, (ulong) count, fileOffset);
} while (UnixMarshal.ShouldRetrySyscall ((int) r));
}
if (r == -1)
UnixMarshal.ThrowExceptionForLastError ();
return (int) r;
}
if(buffer.Length == 0) {
return 0;
}
public override long Seek (long offset, SeekOrigin origin)
{
AssertNotDisposed ();
if (!CanSeek)
throw new NotSupportedException ("The File Descriptor does not support seeking");
Int64 r = 0;
fixed(Byte* buf = &buffer[offset]) {
do {
r = Native.Syscall.read(this.fileDescriptor, buf, (UInt64)count);
} while(UnixMarshal.ShouldRetrySyscall((Int32)r));
}
if(r == -1) {
UnixMarshal.ThrowExceptionForLastError();
}
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;
}
return (Int32)r;
}
long pos = Native.Syscall.lseek (fileDescriptor, offset, sf);
if (pos == -1)
UnixMarshal.ThrowExceptionForLastError ();
return (long) pos;
}
private void AssertValidBuffer(Byte[] buffer, Int32 offset, Int32 count) {
if(buffer == null) {
throw new ArgumentNullException("buffer");
}
public override void SetLength (long value)
{
AssertNotDisposed ();
if (value < 0)
throw new ArgumentOutOfRangeException ("value", "< 0");
if (!CanSeek && !CanWrite)
throw new NotSupportedException ("You can't truncating the current file descriptor");
if(offset < 0) {
throw new ArgumentOutOfRangeException("offset", "< 0");
}
int r;
do {
r = Native.Syscall.ftruncate (fileDescriptor, value);
} while (UnixMarshal.ShouldRetrySyscall (r));
UnixMarshal.ThrowExceptionForLastErrorIf (r);
}
if(count < 0) {
throw new ArgumentOutOfRangeException("count", "< 0");
}
public override unsafe void Write (byte[] buffer, int offset, int count)
{
AssertNotDisposed ();
AssertValidBuffer (buffer, offset, count);
if (!CanWrite)
throw new NotSupportedException ("File Descriptor does not support writing");
if(offset > buffer.Length) {
throw new ArgumentException("destination offset is beyond array size");
}
if (buffer.Length == 0)
return;
if(offset > buffer.Length - count) {
throw new ArgumentException("would overrun buffer");
}
}
long r = 0;
fixed (byte* buf = &buffer[offset]) {
do {
r = Native.Syscall.write (fileDescriptor, buf, (ulong) count);
} while (UnixMarshal.ShouldRetrySyscall ((int) r));
}
if (r == -1)
UnixMarshal.ThrowExceptionForLastError ();
}
public unsafe Int32 ReadAtOffset([In, Out] Byte[] buffer,
Int32 offset, Int32 count, Int64 fileOffset) {
this.AssertNotDisposed();
this.AssertValidBuffer(buffer, offset, count);
if(!this.CanRead) {
throw new NotSupportedException("Stream does not support reading");
}
public unsafe void WriteAtOffset (byte[] buffer,
int offset, int count, long fileOffset)
{
AssertNotDisposed ();
AssertValidBuffer (buffer, offset, count);
if (!CanWrite)
throw new NotSupportedException ("File Descriptor does not support writing");
if(buffer.Length == 0) {
return 0;
}
if (buffer.Length == 0)
return;
Int64 r = 0;
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;
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 ();
}
return (Int32)r;
}
public void SendTo (UnixStream output)
{
SendTo (output, (ulong) output.Length);
}
public override Int64 Seek(Int64 offset, SeekOrigin origin) {
this.AssertNotDisposed();
if(!this.CanSeek) {
throw new NotSupportedException("The File Descriptor does not support seeking");
}
[CLSCompliant (false)]
public void SendTo (UnixStream output, ulong count)
{
SendTo (output.Handle, count);
}
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;
}
[CLSCompliant (false)]
public void SendTo (int out_fd, ulong count)
{
if (!CanWrite)
throw new NotSupportedException ("Unable to write to the current file descriptor");
long offset = Position;
long r = Native.Syscall.sendfile (out_fd, fileDescriptor, ref offset, count);
if (r == -1)
UnixMarshal.ThrowExceptionForLastError ();
}
Int64 pos = Native.Syscall.lseek(this.fileDescriptor, offset, sf);
if(pos == -1) {
UnixMarshal.ThrowExceptionForLastError();
}
public void SetOwner (long user, long group)
{
AssertNotDisposed ();
return (Int64)pos;
}
int r = Native.Syscall.fchown (fileDescriptor,
Convert.ToUInt32 (user), Convert.ToUInt32 (group));
UnixMarshal.ThrowExceptionForLastErrorIf (r);
}
public override void SetLength(Int64 value) {
this.AssertNotDisposed();
if(value < 0) {
throw new ArgumentOutOfRangeException("value", "< 0");
}
public void SetOwner (string user, string group)
{
AssertNotDisposed ();
if(!this.CanSeek && !this.CanWrite) {
throw new NotSupportedException("You can't truncating the current file descriptor");
}
long uid = new UnixUserInfo (user).UserId;
long gid = new UnixGroupInfo (group).GroupId;
SetOwner (uid, gid);
}
Int32 r;
do {
r = Native.Syscall.ftruncate(this.fileDescriptor, value);
} while(UnixMarshal.ShouldRetrySyscall(r));
UnixMarshal.ThrowExceptionForLastErrorIf(r);
}
public void SetOwner (string user)
{
AssertNotDisposed ();
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 Descriptor does not support writing");
}
Native.Passwd pw = Native.Syscall.getpwnam (user);
if (pw == null)
throw new ArgumentException (Locale.GetText ("invalid username"), "user");
long uid = pw.pw_uid;
long gid = pw.pw_gid;
SetOwner (uid, gid);
}
if(buffer.Length == 0) {
return;
}
[CLSCompliant (false)]
public long GetConfigurationValue (Native.PathconfName name)
{
AssertNotDisposed ();
long r = Native.Syscall.fpathconf (fileDescriptor, name);
if (r == -1 && Native.Syscall.GetLastError() != (Native.Errno) 0)
UnixMarshal.ThrowExceptionForLastError ();
return r;
}
Int64 r = 0;
fixed(Byte* buf = &buffer[offset]) {
do {
r = Native.Syscall.write(this.fileDescriptor, buf, (UInt64)count);
} while(UnixMarshal.ShouldRetrySyscall((Int32)r));
}
if(r == -1) {
UnixMarshal.ThrowExceptionForLastError();
}
}
~UnixStream ()
{
Close ();
}
public unsafe void WriteAtOffset(Byte[] buffer,
Int32 offset, Int32 count, Int64 fileOffset) {
this.AssertNotDisposed();
this.AssertValidBuffer(buffer, offset, count);
if(!this.CanWrite) {
throw new NotSupportedException("File Descriptor does not support writing");
}
public override void Close ()
{
if (fileDescriptor == InvalidFileDescriptor)
return;
if(buffer.Length == 0) {
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)
return;
public void SendTo(UnixStream output) => this.SendTo(output, (UInt64)output.Length);
int r;
do {
r = Native.Syscall.close (fileDescriptor);
} while (UnixMarshal.ShouldRetrySyscall (r));
UnixMarshal.ThrowExceptionForLastErrorIf (r);
fileDescriptor = InvalidFileDescriptor;
GC.SuppressFinalize (this);
}
//[CLSCompliant(false)]
public void SendTo(UnixStream output, UInt64 count) => this.SendTo(output.Handle, count);
void IDisposable.Dispose ()
{
if (fileDescriptor != InvalidFileDescriptor && owner) {
Close ();
}
GC.SuppressFinalize (this);
}
//[CLSCompliant(false)]
public void SendTo(Int32 out_fd, UInt64 count) {
if(!this.CanWrite) {
throw new NotSupportedException("Unable to write to the current file descriptor");
}
private bool canSeek = false;
private bool canRead = false;
private bool canWrite = false;
private bool owner = true;
private int fileDescriptor = InvalidFileDescriptor;
private Native.Stat stat;
}
Int64 offset = this.Position;
Int64 r = Native.Syscall.sendfile(out_fd, this.fileDescriptor, ref offset, count);
if(r == -1) {
UnixMarshal.ThrowExceptionForLastError();
}
}
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

View File

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

View File

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