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,136 +1,138 @@
// using System;
// Consts.cs.in
// //
// Author: // Consts.cs.in
// Kornél Pál <http://www.kornelpal.hu/> //
// // Author:
// Copyright (C) 2005-2006 Kornél Pál // Kornél Pál <http://www.kornelpal.hu/>
// //
// Copyright (C) 2005-2006 Kornél Pál
// //
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the //
// "Software"), to deal in the Software without restriction, including // Permission is hereby granted, free of charge, to any person obtaining
// without limitation the rights to use, copy, modify, merge, publish, // a copy of this software and associated documentation files (the
// distribute, sublicense, and/or sell copies of the Software, and to // "Software"), to deal in the Software without restriction, including
// permit persons to whom the Software is furnished to do so, subject to // without limitation the rights to use, copy, modify, merge, publish,
// the following conditions: // distribute, sublicense, and/or sell copies of the Software, and to
// // permit persons to whom the Software is furnished to do so, subject to
// The above copyright notice and this permission notice shall be // the following conditions:
// included in all copies or substantial portions of the Software. //
// // The above copyright notice and this permission notice shall be
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // included in all copies or substantial portions of the Software.
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF //
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
static partial class Consts //
{
public const string MonoCorlibVersion = "@MONO_CORLIB_VERSION@"; static partial class Consts
} {
public const String MonoCorlibVersion = "@MONO_CORLIB_VERSION@";
#if !NETCORE }
static partial class Consts #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 MonoVersion = "@MONO_VERSION@";
public const string MonoCopyright = "(c) Various Mono authors"; public const String MonoCompany = "Mono development team";
public const String MonoProduct = "Mono Common Language Infrastructure";
#if MOBILE public const String MonoCopyright = "(c) Various Mono authors";
// Versions of .NET Framework for Silverlight 4.0
public const string FxVersion = "2.0.5.0"; #if MOBILE
public const string VsVersion = "9.0.0.0"; // unused, but needed for compilation // Versions of .NET Framework for Silverlight 4.0
public const string FxFileVersion = "4.0.50524.0"; public const string FxVersion = "2.0.5.0";
public const string EnvironmentVersion = FxFileVersion; public const string VsVersion = "9.0.0.0"; // unused, but needed for compilation
public const string FxFileVersion = "4.0.50524.0";
public const string VsFileVersion = "9.0.50727.42"; // unused, but needed for compilation public const string EnvironmentVersion = FxFileVersion;
#elif NET_4_6
public const string FxVersion = "4.0.0.0"; public const string VsFileVersion = "9.0.50727.42"; // unused, but needed for compilation
public const string FxFileVersion = "4.6.57.0"; #elif NET_4_6
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 VsVersion = "0.0.0.0"; // Useless ? public const String EnvironmentVersion = "4.0.30319.42000";
public const string VsFileVersion = "11.0.0.0"; // TODO:
#elif NET_4_5 public const String VsVersion = "0.0.0.0"; // Useless ?
public const string FxVersion = "4.0.0.0"; public const String VsFileVersion = "11.0.0.0"; // TODO:
public const string FxFileVersion = "4.0.30319.17020"; #elif NET_4_5
public const string EnvironmentVersion = FxFileVersion; public const string FxVersion = "4.0.0.0";
public const string FxFileVersion = "4.0.30319.17020";
public const string VsVersion = "0.0.0.0"; // Useless ? public const string EnvironmentVersion = FxFileVersion;
public const string VsFileVersion = "11.0.0.0"; // TODO:
#elif NETCORE public const string VsVersion = "0.0.0.0"; // Useless ?
public const string FxVersion = ""; public const string VsFileVersion = "11.0.0.0"; // TODO:
public const string FxFileVersion = ""; #elif NETCORE
public const string EnvironmentVersion = FxFileVersion; public const string FxVersion = "";
public const string FxFileVersion = "";
public const string VsVersion = ""; public const string EnvironmentVersion = FxFileVersion;
public const string VsFileVersion = "";
#elif NET_4_0 public const string VsVersion = "";
#error Profile NET_4_0 is not supported. public const string VsFileVersion = "";
#elif NET_3_5 #elif NET_4_0
#error Profile NET_3_5 is not supported. #error Profile NET_4_0 is not supported.
#elif NET_3_0 #elif NET_3_5
#error Profile NET_3_0 is not supported. #error Profile NET_3_5 is not supported.
#elif NET_2_0 #elif NET_3_0
#error Profile NET_2_0 is not supported. #error Profile NET_3_0 is not supported.
#elif NET_1_1 #elif NET_2_0
#error Profile NET_1_1 is not supported. #error Profile NET_2_0 is not supported.
#elif NET_1_0 #elif NET_1_1
#error Profile NET_1_0 is not supported. #error Profile NET_1_1 is not supported.
#else #elif NET_1_0
#error No profile symbols defined. #error Profile NET_1_0 is not supported.
#endif #else
#error No profile symbols defined.
#if MOBILE #endif
const string PublicKeyToken = "7cec85d7bea7798e";
#else #if MOBILE
const string PublicKeyToken = "b77a5c561934e089"; const string PublicKeyToken = "7cec85d7bea7798e";
#endif #else
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 AssemblyI18N = "I18N, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756";
public const string AssemblyMicrosoft_VisualStudio_Web = "Microsoft.VisualStudio.Web, Version=" + VsVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"; public const String AssemblyMicrosoft_JScript = "Microsoft.JScript, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
public const string AssemblyMicrosoft_VSDesigner = "Microsoft.VSDesigner, Version=" + VsVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"; public const String AssemblyMicrosoft_VisualStudio = "Microsoft.VisualStudio, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
public const string AssemblyMono_Http = "Mono.Http, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756"; public const String AssemblyMicrosoft_VisualStudio_Web = "Microsoft.VisualStudio.Web, Version=" + VsVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
public const string AssemblyMono_Posix = "Mono.Posix, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756"; public const String AssemblyMicrosoft_VSDesigner = "Microsoft.VSDesigner, Version=" + VsVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
public const string AssemblyMono_Security = "Mono.Security, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756"; public const String AssemblyMono_Http = "Mono.Http, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756";
public const string AssemblyMono_Messaging_RabbitMQ = "Mono.Messaging.RabbitMQ, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756"; public const String AssemblyMono_Posix = "Mono.Posix, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756";
public const string AssemblyCorlib = "mscorlib, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=" + PublicKeyToken; public const String AssemblyMono_Security = "Mono.Security, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756";
public const string AssemblySystem = "System, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=" + PublicKeyToken; public const String AssemblyMono_Messaging_RabbitMQ = "Mono.Messaging.RabbitMQ, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756";
public const string AssemblySystem_Data = "System.Data, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b77a5c561934e089"; public const String AssemblyCorlib = "mscorlib, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=" + PublicKeyToken;
public const string AssemblySystem_Design = "System.Design, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"; public const String AssemblySystem = "System, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=" + PublicKeyToken;
public const string AssemblySystem_DirectoryServices = "System.DirectoryServices, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"; public const String AssemblySystem_Data = "System.Data, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b77a5c561934e089";
public const string AssemblySystem_Drawing = "System.Drawing, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"; public const String AssemblySystem_Design = "System.Design, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
public const string AssemblySystem_Drawing_Design = "System.Drawing.Design, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"; public const String AssemblySystem_DirectoryServices = "System.DirectoryServices, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
public const string AssemblySystem_Messaging = "System.Messaging, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"; public const String AssemblySystem_Drawing = "System.Drawing, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
public const string AssemblySystem_Security = "System.Security, 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_ServiceProcess = "System.ServiceProcess, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"; public const String AssemblySystem_Messaging = "System.Messaging, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
public const string AssemblySystem_Web = "System.Web, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"; public const String AssemblySystem_Security = "System.Security, 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_ServiceProcess = "System.ServiceProcess, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
public const string AssemblySystem_2_0 = "System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"; public const String AssemblySystem_Web = "System.Web, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
public const string AssemblySystemCore_3_5 = "System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"; public const String AssemblySystem_Windows_Forms = "System.Windows.Forms, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b77a5c561934e089";
public const string AssemblySystem_Core = "System.Core, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=" + PublicKeyToken; public const String AssemblySystem_2_0 = "System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
public const string WindowsBase_3_0 = "WindowsBase, Version=3.0.0.0, PublicKeyToken=31bf3856ad364e35"; public const String AssemblySystemCore_3_5 = "System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
public const string AssemblyWindowsBase = "WindowsBase, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"; public const String AssemblySystem_Core = "System.Core, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=" + PublicKeyToken;
public const string AssemblyPresentationCore_3_5 = "PresentationCore, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"; public const String WindowsBase_3_0 = "WindowsBase, Version=3.0.0.0, PublicKeyToken=31bf3856ad364e35";
public const string AssemblyPresentationCore_4_0 = "PresentationCore, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"; public const String AssemblyWindowsBase = "WindowsBase, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35";
public const string AssemblyPresentationFramework_3_5 = "PresentationFramework, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"; public const String AssemblyPresentationCore_3_5 = "PresentationCore, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35";
public const string AssemblySystemServiceModel_3_0 = "System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"; 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 #endif

View File

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

View File

@ -31,56 +31,62 @@
// //
using System; using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Mono.Posix { namespace Mono.Posix {
[Obsolete ("Use Mono.Unix.Catalog")] [Obsolete ("Use Mono.Unix.Catalog")]
public class Catalog { public class Catalog {
[DllImport("intl")] [DllImport("intl")]
static extern IntPtr bindtextdomain (IntPtr domainname, IntPtr dirname); [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
[DllImport("intl")] static extern IntPtr bindtextdomain (IntPtr domainname, IntPtr dirname);
static extern IntPtr bind_textdomain_codeset (IntPtr domainname, [DllImport("intl")]
IntPtr codeset); [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
[DllImport("intl")] static extern IntPtr bind_textdomain_codeset (IntPtr domainname,
static extern IntPtr textdomain (IntPtr domainname); IntPtr codeset);
[DllImport("intl")]
public static void Init (String package, String localedir) [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
{ static extern IntPtr textdomain (IntPtr domainname);
IntPtr ipackage = Marshal.StringToHGlobalAuto (package);
IntPtr ilocaledir = Marshal.StringToHGlobalAuto (localedir); public static void Init (String package, String localedir)
IntPtr iutf8 = Marshal.StringToHGlobalAuto ("UTF-8"); {
bindtextdomain (ipackage, ilocaledir); IntPtr ipackage = Marshal.StringToHGlobalAuto (package);
bind_textdomain_codeset (ipackage, iutf8); IntPtr ilocaledir = Marshal.StringToHGlobalAuto (localedir);
textdomain (ipackage); IntPtr iutf8 = Marshal.StringToHGlobalAuto ("UTF-8");
Marshal.FreeHGlobal (ipackage); _ = bindtextdomain(ipackage, ilocaledir);
Marshal.FreeHGlobal (ilocaledir); _ = bind_textdomain_codeset(ipackage, iutf8);
Marshal.FreeHGlobal (iutf8); _ = textdomain(ipackage);
} Marshal.FreeHGlobal (ipackage);
Marshal.FreeHGlobal (ilocaledir);
[DllImport("intl")] Marshal.FreeHGlobal (iutf8);
static extern IntPtr gettext (IntPtr instring); }
public static String GetString (String s) [DllImport("intl")]
{ [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
IntPtr ints = Marshal.StringToHGlobalAuto (s); static extern IntPtr gettext (IntPtr instring);
String t = Marshal.PtrToStringAuto (gettext (ints));
Marshal.FreeHGlobal (ints); public static String GetString (String s)
return t; {
} IntPtr ints = Marshal.StringToHGlobalAuto (s);
String t = Marshal.PtrToStringAuto (gettext (ints));
[DllImport("intl")] Marshal.FreeHGlobal (ints);
static extern IntPtr ngettext (IntPtr singular, IntPtr plural, Int32 n); return t;
}
public static String GetPluralString (String s, String p, Int32 n)
{ [DllImport("intl")]
IntPtr ints = Marshal.StringToHGlobalAuto (s); [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
IntPtr intp = Marshal.StringToHGlobalAuto (p); static extern IntPtr ngettext (IntPtr singular, IntPtr plural, Int32 n);
String t = Marshal.PtrToStringAnsi (ngettext (ints, intp, n));
Marshal.FreeHGlobal (ints); public static String GetPluralString (String s, String p, Int32 n)
Marshal.FreeHGlobal (intp); {
return t; 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 namespace Mono.Posix
{ {
#pragma warning disable 649 #pragma warning disable 649
internal struct PeerCredData { internal struct PeerCredData {
public int pid; public Int32 pid;
public int uid; public Int32 uid;
public int gid; public Int32 gid;
} }
#pragma warning restore 649 #pragma warning restore 649
[Obsolete ("Use Mono.Unix.PeerCred")] [Obsolete ("Use Mono.Unix.PeerCred")]
public class PeerCred public class PeerCred
{ {
/* Make sure this doesn't clash with anything in /* Make sure this doesn't clash with anything in
* SocketOptionName, and keep it synchronised with the * SocketOptionName, and keep it synchronised with the
* runtime * runtime
*/ */
private const int so_peercred=10001; private const Int32 so_peercred =10001;
private PeerCredData data; private PeerCredData data;
public PeerCred (Socket sock) { public PeerCred (Socket sock) {
if (sock.AddressFamily != AddressFamily.Unix) { if (sock.AddressFamily != AddressFamily.Unix) {
throw new ArgumentException ("Only Unix sockets are supported", "sock"); throw new ArgumentException ("Only Unix sockets are supported", "sock");
} }
data = (PeerCredData)sock.GetSocketOption (SocketOptionLevel.Socket, (SocketOptionName)so_peercred); this.data = (PeerCredData)sock.GetSocketOption (SocketOptionLevel.Socket, (SocketOptionName)so_peercred);
} }
public int ProcessID { public Int32 ProcessID => this.data.pid;
get {
return(data.pid); public Int32 UserID => this.data.uid;
}
} public Int32 GroupID => this.data.gid;
}
public int UserID {
get {
return(data.uid);
}
}
public int GroupID {
get {
return(data.gid);
}
}
}
} }

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -39,129 +39,111 @@ using System.Runtime.Serialization.Formatters.Binary;
namespace Mono.Remoting.Channels.Unix namespace Mono.Remoting.Channels.Unix
{ {
internal class UnixBinaryClientFormatterSink : IClientFormatterSink, IMessageSink, IClientChannelSink, IChannelSinkBase internal class UnixBinaryClientFormatterSink : IClientFormatterSink, IMessageSink, IClientChannelSink, IChannelSinkBase
{ {
UnixBinaryCore _binaryCore = UnixBinaryCore.DefaultInstance; UnixBinaryCore _binaryCore = UnixBinaryCore.DefaultInstance;
IClientChannelSink _nextInChain; IClientChannelSink _nextInChain;
public UnixBinaryClientFormatterSink(IClientChannelSink nextSink) => this._nextInChain = nextSink;
internal UnixBinaryCore BinaryCore {
get => this._binaryCore;
set => this._binaryCore = value;
}
public IClientChannelSink NextChannelSink => this._nextInChain;
public IMessageSink NextSink =>
// This is the last sink in the IMessageSink sink chain
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 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 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 = this._nextInChain.GetRequestStream(msg, transportHeaders);
if (stream == null) {
stream = new MemoryStream ();
}
this._binaryCore.Serializer.Serialize (stream, msg, null);
if (stream is MemoryStream) {
stream.Position = 0;
}
ClientChannelSinkStack stack = new ClientChannelSinkStack(replySink);
stack.Push (this, msg);
this._nextInChain.AsyncProcessRequest (stack, msg, transportHeaders, stream);
public UnixBinaryClientFormatterSink (IClientChannelSink nextSink) // FIXME: No idea about how to implement IMessageCtrl
{ return null;
_nextInChain = nextSink; }
}
internal UnixBinaryCore BinaryCore public IMessage SyncProcessMessage (IMessage msg)
{ {
get { return _binaryCore; } try {
set { _binaryCore = value; }
}
public IClientChannelSink NextChannelSink ITransportHeaders call_headers = new TransportHeaders();
{ call_headers["__RequestUri"] = ((IMethodCallMessage)msg).Uri;
get { call_headers["Content-Type"] = "application/octet-stream";
return _nextInChain;
}
}
public IMessageSink NextSink Stream call_stream = this._nextInChain.GetRequestStream(msg, call_headers);
{ if (call_stream == null) {
get { call_stream = new MemoryStream ();
// This is the last sink in the IMessageSink sink chain }
return null;
} // Serialize msg to the stream
}
this._binaryCore.Serializer.Serialize (call_stream, msg, null);
public IDictionary Properties if (call_stream is MemoryStream) {
{ call_stream.Position = 0;
get { }
return null;
}
} this._nextInChain.ProcessMessage(msg, call_headers, call_stream, out ITransportHeaders response_headers,
out Stream response_stream);
public void AsyncProcessRequest (IClientChannelSinkStack sinkStack,
IMessage msg, // Deserialize response_stream
ITransportHeaders headers,
Stream stream) return (IMessage)this._binaryCore.Deserializer.DeserializeMethodResponse (response_stream, null, (IMethodCallMessage)msg);
{
// never called because the formatter sink is } catch (Exception e) {
// always the first in the chain return new ReturnMessage (e, (IMethodCallMessage)msg);
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 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 IMessageCtrl AsyncProcessMessage (IMessage msg,
IMessageSink replySink)
{
ITransportHeaders transportHeaders = new TransportHeaders();
Stream stream = _nextInChain.GetRequestStream(msg, transportHeaders);
if (stream == null) stream = new MemoryStream ();
_binaryCore.Serializer.Serialize (stream, msg, null);
if (stream is MemoryStream) stream.Position = 0;
ClientChannelSinkStack stack = new ClientChannelSinkStack(replySink);
stack.Push (this, msg);
_nextInChain.AsyncProcessRequest (stack, msg, transportHeaders, stream);
// FIXME: No idea about how to implement IMessageCtrl
return null;
}
public IMessage SyncProcessMessage (IMessage msg)
{
try {
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 ();
// Serialize msg to the stream
_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);
// Deserialize response_stream
return (IMessage) _binaryCore.Deserializer.DeserializeMethodResponse (response_stream, null, (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 namespace Mono.Remoting.Channels.Unix
{ {
internal class UnixBinaryClientFormatterSinkProvider: IClientFormatterSinkProvider, IClientChannelSinkProvider internal class UnixBinaryClientFormatterSinkProvider: IClientFormatterSinkProvider, IClientChannelSinkProvider
{ {
IClientChannelSinkProvider next = null; IClientChannelSinkProvider next = null;
UnixBinaryCore _binaryCore; UnixBinaryCore _binaryCore;
static string[] allowedProperties = new string [] { "includeVersions", "strictBinding" }; static System.String[] allowedProperties = new System.String[] { "includeVersions", "strictBinding" };
public UnixBinaryClientFormatterSinkProvider() => this._binaryCore = UnixBinaryCore.DefaultInstance;
public UnixBinaryClientFormatterSinkProvider(IDictionary properties,
ICollection providerData) => this._binaryCore = new UnixBinaryCore(this, properties, allowedProperties);
public IClientChannelSinkProvider Next {
get => this.next;
set => this.next = value;
}
public IClientChannelSink CreateSink (IChannelSender channel,
System.String url,
System.Object remoteChannelData)
{
IClientChannelSink next_sink = null;
UnixBinaryClientFormatterSink result;
if (this.next != null) {
next_sink = this.next.CreateSink (channel, url, remoteChannelData);
}
result = new UnixBinaryClientFormatterSink (next_sink);
result.BinaryCore = this._binaryCore;
public UnixBinaryClientFormatterSinkProvider () return result;
{ }
_binaryCore = UnixBinaryCore.DefaultInstance; }
}
public UnixBinaryClientFormatterSinkProvider (IDictionary properties,
ICollection providerData)
{
_binaryCore = new UnixBinaryCore (this, properties, allowedProperties);
}
public IClientChannelSinkProvider Next
{
get {
return next;
}
set {
next = value;
}
}
public IClientChannelSink CreateSink (IChannelSender channel,
string url,
object remoteChannelData)
{
IClientChannelSink next_sink = null;
UnixBinaryClientFormatterSink result;
if (next != null)
next_sink = next.CreateSink (channel, url, remoteChannelData);
result = new UnixBinaryClientFormatterSink (next_sink);
result.BinaryCore = _binaryCore;
return result;
}
}
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -37,275 +37,254 @@ using Mono.Unix;
namespace Mono.Remoting.Channels.Unix namespace Mono.Remoting.Channels.Unix
{ {
// This is a pool of Unix connections. Connections requested // This is a pool of Unix connections. Connections requested
// by the TCP channel are pooled after their use, and can // by the TCP channel are pooled after their use, and can
// be reused later. Connections are automaticaly closed // be reused later. Connections are automaticaly closed
// if not used after some time, specified in KeepAliveSeconds. // if not used after some time, specified in KeepAliveSeconds.
// The number of allowed open connections can also be specified // The number of allowed open connections can also be specified
// in MaxOpenConnections. The limit is per host. // in MaxOpenConnections. The limit is per host.
// If a thread requests a connection and the limit has been // If a thread requests a connection and the limit has been
// reached, the thread is suspended until one is released. // reached, the thread is suspended until one is released.
internal class UnixConnectionPool internal class UnixConnectionPool
{ {
// Table of pools. There is a HostConnectionPool // Table of pools. There is a HostConnectionPool
// instance for each host // instance for each host
static Hashtable _pools = new Hashtable(); static Hashtable _pools = new Hashtable();
static int _maxOpenConnections = int.MaxValue; static Int32 _maxOpenConnections = Int32.MaxValue;
static int _keepAliveSeconds = 15; static Int32 _keepAliveSeconds = 15;
static Thread _poolThread; static Thread _poolThread;
static UnixConnectionPool() static UnixConnectionPool()
{ {
// This thread will close unused connections // This thread will close unused connections
_poolThread = new Thread (new ThreadStart (ConnectionCollector)); _poolThread = new Thread (new ThreadStart (ConnectionCollector));
_poolThread.Start(); _poolThread.Start();
_poolThread.IsBackground = true; _poolThread.IsBackground = true;
} }
public static void Shutdown () public static void Shutdown ()
{ {
if (_poolThread != null) if (_poolThread != null) {
_poolThread.Abort(); _poolThread.Abort();
} }
}
public static int MaxOpenConnections public static Int32 MaxOpenConnections {
{ get => _maxOpenConnections;
get { return _maxOpenConnections; } set {
set if(value < 1) {
{ throw new RemotingException("MaxOpenConnections must be greater than zero");
if (value < 1) throw new RemotingException ("MaxOpenConnections must be greater than zero"); }
_maxOpenConnections = value;
}
}
public static int KeepAliveSeconds _maxOpenConnections = value;
{ }
get { return _keepAliveSeconds; } }
set { _keepAliveSeconds = value; }
}
public static UnixConnection GetConnection (string path) public static Int32 KeepAliveSeconds {
{ get => _keepAliveSeconds;
HostConnectionPool hostPool; set => _keepAliveSeconds = value;
}
lock (_pools) public static UnixConnection GetConnection (String path)
{ {
hostPool = (HostConnectionPool) _pools[path]; HostConnectionPool hostPool;
if (hostPool == null)
{
hostPool = new HostConnectionPool(path);
_pools[path] = hostPool;
}
}
return hostPool.GetConnection(); lock (_pools)
} {
hostPool = (HostConnectionPool) _pools[path];
if (hostPool == null)
{
hostPool = new HostConnectionPool(path);
_pools[path] = hostPool;
}
}
private static void ConnectionCollector () return hostPool.GetConnection();
{ }
while (true)
{
Thread.Sleep(3000);
lock (_pools)
{
ICollection values = _pools.Values;
foreach (HostConnectionPool pool in values)
pool.PurgeConnections();
}
}
}
}
internal class ReusableUnixClient : UnixClient private static void ConnectionCollector ()
{ {
public ReusableUnixClient (string path): base (path) while (true)
{ {
} Thread.Sleep(3000);
lock (_pools)
public bool IsAlive {
{ ICollection values = _pools.Values;
get foreach (HostConnectionPool pool in values) {
{ pool.PurgeConnections();
// This Poll will return true if there is data pending to }
// be read. It prob. means that a client object using this }
// connection got an exception and did not finish to read }
// the data. It can also mean that the connection has been }
// closed in the server. In both cases, the connection cannot }
// be reused.
return !Client.Poll (0, SelectMode.SelectRead);
}
}
}
internal class UnixConnection internal class ReusableUnixClient : UnixClient
{ {
DateTime _controlTime; public ReusableUnixClient (String path): base (path)
Stream _stream; {
ReusableUnixClient _client; }
HostConnectionPool _pool;
byte[] _buffer;
public UnixConnection (HostConnectionPool pool, ReusableUnixClient client) public Boolean IsAlive =>
{ // This Poll will return true if there is data pending to
_pool = pool; // be read. It prob. means that a client object using this
_client = client; // connection got an exception and did not finish to read
_stream = new BufferedStream (client.GetStream()); // the data. It can also mean that the connection has been
_controlTime = DateTime.UtcNow; // closed in the server. In both cases, the connection cannot
_buffer = new byte[UnixMessageIO.DefaultStreamBufferSize]; // be reused.
} !this.Client.Poll(0, SelectMode.SelectRead);
}
public Stream Stream internal class UnixConnection
{ {
get { return _stream; } DateTime _controlTime;
} Stream _stream;
ReusableUnixClient _client;
HostConnectionPool _pool;
Byte[] _buffer;
public DateTime ControlTime public UnixConnection (HostConnectionPool pool, ReusableUnixClient client)
{ {
get { return _controlTime; } this._pool = pool;
set { _controlTime = value; } this._client = client;
} this._stream = new BufferedStream (client.GetStream());
this._controlTime = DateTime.UtcNow;
this._buffer = new Byte[UnixMessageIO.DefaultStreamBufferSize];
}
public bool IsAlive public Stream Stream => this._stream;
{
get { return _client.IsAlive; }
}
// This is a "thread safe" buffer that can be used by public DateTime ControlTime {
// UnixClientTransportSink to read or send data to the stream. get => this._controlTime;
// The buffer is "thread safe" since only one thread can set => this._controlTime = value;
// use a connection at a given time. }
public byte[] Buffer
{
get { return _buffer; }
}
// Returns the connection to the pool public Boolean IsAlive => this._client.IsAlive;
public void Release()
{
_pool.ReleaseConnection (this);
}
public void Close() // This is a "thread safe" buffer that can be used by
{ // UnixClientTransportSink to read or send data to the stream.
_client.Close(); // The buffer is "thread safe" since only one thread can
} // use a connection at a given time.
} public Byte[] Buffer => this._buffer;
internal class HostConnectionPool // Returns the connection to the pool
{ public void Release() => this._pool.ReleaseConnection(this);
ArrayList _pool = new ArrayList();
int _activeConnections = 0;
string _path; public void Close() => this._client.Close();
}
public HostConnectionPool (string path) internal class HostConnectionPool
{ {
_path = path; ArrayList _pool = new ArrayList();
} Int32 _activeConnections = 0;
public UnixConnection GetConnection () String _path;
{
UnixConnection connection = null;
lock (_pool)
{
do
{
if (_pool.Count > 0)
{
// There are available connections
connection = (UnixConnection)_pool[_pool.Count - 1]; public HostConnectionPool(String path) => this._path = path;
_pool.RemoveAt(_pool.Count - 1);
if (!connection.IsAlive) {
CancelConnection (connection);
connection = null;
continue;
}
}
if (connection == null && _activeConnections < UnixConnectionPool.MaxOpenConnections) public UnixConnection GetConnection ()
{ {
// No connections available, but the max connections UnixConnection connection = null;
// has not been reached yet, so a new one can be created lock (this._pool)
// Create the connection outside the lock {
break; do
} {
if (this._pool.Count > 0)
{
// There are available connections
// No available connections in the pool connection = (UnixConnection)this._pool[this._pool.Count - 1];
// Wait for somewone to release one. this._pool.RemoveAt(this._pool.Count - 1);
if (!connection.IsAlive) {
this.CancelConnection (connection);
connection = null;
continue;
}
}
if (connection == null) if (connection == null && this._activeConnections < UnixConnectionPool.MaxOpenConnections)
{ {
Monitor.Wait(_pool); // 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
while (connection == null); break;
} }
if (connection == null) // No available connections in the pool
return CreateConnection (); // Wait for somewone to release one.
else
return connection;
}
private UnixConnection CreateConnection() if (connection == null)
{ {
try _ = Monitor.Wait(this._pool);
{ }
ReusableUnixClient client = new ReusableUnixClient (_path); }
UnixConnection entry = new UnixConnection(this, client); while (connection == null);
_activeConnections++; }
return entry;
}
catch (Exception ex)
{
throw new RemotingException (ex.Message);
}
}
public void ReleaseConnection (UnixConnection entry) if (connection == null) {
{ return this.CreateConnection ();
lock (_pool) } else {
{ return connection;
entry.ControlTime = DateTime.UtcNow; // Initialize timeout }
_pool.Add (entry); }
Monitor.Pulse (_pool);
}
}
private void CancelConnection(UnixConnection entry) private UnixConnection CreateConnection()
{ {
try try
{ {
entry.Stream.Close(); ReusableUnixClient client = new ReusableUnixClient (this._path);
_activeConnections--; UnixConnection entry = new UnixConnection(this, client);
} this._activeConnections++;
catch return entry;
{ }
} catch (Exception ex)
} {
throw new RemotingException (ex.Message);
}
}
public void PurgeConnections() public void ReleaseConnection (UnixConnection entry)
{ {
lock (_pool) lock (this._pool)
{ {
for (int n=0; n < _pool.Count; n++) entry.ControlTime = DateTime.UtcNow; // Initialize timeout
{ _ = this._pool.Add(entry);
UnixConnection entry = (UnixConnection)_pool[n]; Monitor.Pulse (this._pool);
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 namespace Mono.Remoting.Channels.Unix
{ {
enum MessageStatus { MethodMessage = 0, CancelSignal = 1, Unknown = 10} enum MessageStatus { MethodMessage = 0, CancelSignal = 1, Unknown = 10}
internal class UnixMessageIO internal class UnixMessageIO
{ {
static byte[][] _msgHeaders = static Byte[][] _msgHeaders =
{ {
new byte[] { (byte)'.', (byte)'N', (byte)'E', (byte)'T', 1, 0 }, new Byte[] { (Byte)'.', (Byte)'N', (Byte)'E', (Byte)'T', 1, 0 },
new byte[] { 255, 255, 255, 255, 255, 255 } new Byte[] { 255, 255, 255, 255, 255, 255 }
}; };
public static int DefaultStreamBufferSize = 1000; public static Int32 DefaultStreamBufferSize = 1000;
// Identifies an incoming message // Identifies an incoming message
public static MessageStatus ReceiveMessageStatus (Stream networkStream, byte[] buffer) public static MessageStatus ReceiveMessageStatus (Stream networkStream, Byte[] buffer)
{ {
try { try {
StreamRead (networkStream, buffer, 6); _ = StreamRead(networkStream, buffer, 6);
} catch (Exception ex) { } catch (Exception ex) {
throw new RemotingException ("Unix transport error.", ex); throw new RemotingException ("Unix transport error.", ex);
} }
try try
{ {
bool[] isOnTrack = new bool[_msgHeaders.Length]; Boolean[] isOnTrack = new Boolean[_msgHeaders.Length];
bool atLeastOneOnTrack = true; Boolean atLeastOneOnTrack = true;
int i = 0; Int32 i = 0;
while (atLeastOneOnTrack) while (atLeastOneOnTrack)
{ {
atLeastOneOnTrack = false; atLeastOneOnTrack = false;
byte c = buffer [i]; Byte c = buffer [i];
for (int n = 0; n<_msgHeaders.Length; n++) for (Int32 n = 0; n<_msgHeaders.Length; n++)
{ {
if (i > 0 && !isOnTrack[n]) continue; if (i > 0 && !isOnTrack[n]) {
continue;
}
isOnTrack[n] = c == _msgHeaders[n][i];
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);
}
}
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");
}
nr += pr;
} while (nr < count);
return true;
}
isOnTrack[n] = (c == _msgHeaders[n][i]); public static void SendMessageStream (Stream networkStream, Stream data, ITransportHeaders requestHeaders, Byte[] buffer)
if (isOnTrack[n] && (i == _msgHeaders[n].Length-1)) return (MessageStatus) n; {
atLeastOneOnTrack = atLeastOneOnTrack || isOnTrack[n]; if (buffer == null) {
} buffer = new Byte[DefaultStreamBufferSize];
i++; }
}
return MessageStatus.Unknown; // Writes the message start header
} Byte[] dotnetHeader = _msgHeaders[(Int32) MessageStatus.MethodMessage];
catch (Exception ex) { networkStream.Write(dotnetHeader, 0, dotnetHeader.Length);
throw new RemotingException ("Unix transport error.", ex);
}
}
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;
}
public static void SendMessageStream (Stream networkStream, Stream data, ITransportHeaders requestHeaders, byte[] buffer) // Writes header tag (0x0000 if request stream, 0x0002 if response stream)
{ if(requestHeaders["__RequestUri"]!=null) {
if (buffer == null) buffer = new byte[DefaultStreamBufferSize]; buffer [0] = (Byte) 0;
} else {
buffer[0] = (Byte) 2;
}
buffer [1] = (Byte) 0 ;
// Writes the message start header // Writes ID
byte[] dotnetHeader = _msgHeaders[(int) MessageStatus.MethodMessage]; buffer [2] = (Byte) 0;
networkStream.Write(dotnetHeader, 0, dotnetHeader.Length);
// Writes header tag (0x0000 if request stream, 0x0002 if response stream) // Writes assemblyID????
if(requestHeaders["__RequestUri"]!=null) buffer [0] = (byte) 0; buffer [3] = (Byte) 0;
else buffer[0] = (byte) 2;
buffer [1] = (byte) 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);
// Writes the message headers
SendHeaders (networkStream, requestHeaders, buffer);
// Writes ID // Writes the stream
buffer [2] = (byte) 0; 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);
}
}
}
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 assemblyID???? private static void SendHeaders(Stream networkStream, ITransportHeaders requestHeaders, Byte[] buffer)
buffer [3] = (byte) 0; {
// Writes the headers as a sequence of strings
if (networkStream != null)
{
IEnumerator e = requestHeaders.GetEnumerator();
while (e.MoveNext())
{
DictionaryEntry hdr = (DictionaryEntry)e.Current;
switch (hdr.Key.ToString())
{
case "__RequestUri":
networkStream.Write (msgUriTransportKey, 0, 4);
break;
case "Content-Type":
networkStream.Write (msgContentTypeTransportKey, 0, 4);
break;
default:
networkStream.Write (msgDefaultTransportKey, 0, 3);
SendString (networkStream, hdr.Key.ToString(), buffer);
networkStream.WriteByte (1);
break;
}
SendString (networkStream, hdr.Value.ToString(), buffer);
}
}
networkStream.Write (msgHeaderTerminator, 0, 2); // End of headers
}
public static ITransportHeaders ReceiveHeaders (Stream networkStream, Byte[] buffer)
{
_ = StreamRead(networkStream, buffer, 2);
Byte headerType = buffer [0];
TransportHeaders headers = new TransportHeaders ();
// Writes the length of the stream being sent (not including the headers) while (headerType != 0)
int num = (int)data.Length; {
buffer [4] = (byte) num; String key;
buffer [5] = (byte) (num >> 8); _ = StreamRead(networkStream, buffer, 1); // byte 1
buffer [6] = (byte) (num >> 16); switch (headerType)
buffer [7] = (byte) (num >> 24); {
networkStream.Write(buffer, 0, 8); case 4: key = "__RequestUri"; break;
case 6: key = "Content-Type"; break;
// Writes the message headers case 1: key = ReceiveString (networkStream, buffer); break;
SendHeaders (networkStream, requestHeaders, buffer); default: throw new NotSupportedException ("Unknown header code: " + headerType);
}
_ = StreamRead(networkStream, buffer, 1); // byte 1
headers[key] = ReceiveString (networkStream, buffer);
_ = StreamRead(networkStream, buffer, 2);
headerType = buffer [0];
}
// Writes the stream return headers;
if (data is MemoryStream) }
{
// The copy of the stream can be optimized. The internal public static Stream ReceiveMessageStream (Stream networkStream, out ITransportHeaders headers, Byte[] buffer)
// buffer of MemoryStream can be used. {
MemoryStream memStream = (MemoryStream)data; headers = null;
networkStream.Write (memStream.GetBuffer(), 0, (int)memStream.Length);
}
else
{
int nread = data.Read (buffer, 0, buffer.Length);
while (nread > 0)
{
networkStream.Write (buffer, 0, nread);
nread = data.Read (buffer, 0, buffer.Length);
}
}
}
static byte[] msgUriTransportKey = new byte[] { 4, 0, 1, 1 };
static byte[] msgContentTypeTransportKey = new byte[] { 6, 0, 1, 1 };
static byte[] msgDefaultTransportKey = new byte[] { 1, 0, 1 };
static byte[] msgHeaderTerminator = new byte[] { 0, 0 };
private static void SendHeaders(Stream networkStream, ITransportHeaders requestHeaders, byte[] buffer) if (buffer == null) {
{ buffer = new Byte[DefaultStreamBufferSize];
// Writes the headers as a sequence of strings }
if (networkStream != null)
{ // Reads header tag: 0 -> Stream with headers or 2 -> Response Stream
IEnumerator e = requestHeaders.GetEnumerator(); // +
while (e.MoveNext()) // Gets the length of the data stream
{ _ = StreamRead(networkStream, buffer, 8);
DictionaryEntry hdr = (DictionaryEntry)e.Current;
switch (hdr.Key.ToString()) Int32 byteCount = buffer [4] | (buffer [5] << 8) |
{ (buffer [6] << 16) | (buffer [7] << 24);
case "__RequestUri":
networkStream.Write (msgUriTransportKey, 0, 4);
break;
case "Content-Type":
networkStream.Write (msgContentTypeTransportKey, 0, 4);
break;
default:
networkStream.Write (msgDefaultTransportKey, 0, 3);
SendString (networkStream, hdr.Key.ToString(), buffer);
networkStream.WriteByte (1);
break;
}
SendString (networkStream, hdr.Value.ToString(), buffer);
}
}
networkStream.Write (msgHeaderTerminator, 0, 2); // End of headers
}
public static ITransportHeaders ReceiveHeaders (Stream networkStream, byte[] buffer)
{
StreamRead (networkStream, buffer, 2);
byte headerType = buffer [0];
TransportHeaders headers = new TransportHeaders ();
while (headerType != 0) // Reads the headers
{ headers = ReceiveHeaders (networkStream, buffer);
string key;
StreamRead (networkStream, buffer, 1); // byte 1 Byte[] resultBuffer = new Byte[byteCount];
switch (headerType) _ = StreamRead(networkStream, resultBuffer, byteCount);
{
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);
StreamRead (networkStream, buffer, 2); return new MemoryStream (resultBuffer);
headerType = buffer [0]; }
}
return headers; private static void SendString (Stream networkStream, String str, Byte[] buffer)
} {
// Allocates a buffer. Use the internal buffer if it is
public static Stream ReceiveMessageStream (Stream networkStream, out ITransportHeaders headers, byte[] buffer) // big enough. If not, create a new one.
{
headers = null; Int32 maxBytes = Encoding.UTF8.GetMaxByteCount(str.Length)+4; //+4 bytes for storing the string length
if (maxBytes > buffer.Length) {
buffer = new Byte[maxBytes];
}
Int32 num = Encoding.UTF8.GetBytes (str, 0, str.Length, buffer, 4);
if (buffer == null) buffer = new byte[DefaultStreamBufferSize]; // store number of bytes (not number of chars!)
// Reads header tag: 0 -> Stream with headers or 2 -> Response Stream buffer [0] = (Byte) num;
// + buffer [1] = (Byte) (num >> 8);
// Gets the length of the data stream buffer [2] = (Byte) (num >> 16);
StreamRead (networkStream, buffer, 8); buffer [3] = (Byte) (num >> 24);
int byteCount = (buffer [4] | (buffer [5] << 8) | // Write the string bytes
(buffer [6] << 16) | (buffer [7] << 24)); networkStream.Write (buffer, 0, num + 4);
}
// Reads the headers private static String ReceiveString (Stream networkStream, Byte[] buffer)
headers = ReceiveHeaders (networkStream, buffer); {
_ = StreamRead(networkStream, buffer, 4);
// Reads the number of bytes (not chars!)
Int32 byteCount = buffer [0] | (buffer [1] << 8) |
(buffer [2] << 16) | (buffer [3] << 24);
byte[] resultBuffer = new byte[byteCount]; if (byteCount == 0) {
StreamRead (networkStream, resultBuffer, byteCount); return String.Empty;
}
return new MemoryStream (resultBuffer);
} // Allocates a buffer of the correct size. Use the
// internal buffer if it is big enough
private static void SendString (Stream networkStream, string str, byte[] buffer)
{ if (byteCount > buffer.Length) {
// Allocates a buffer. Use the internal buffer if it is buffer = new Byte[byteCount];
// big enough. If not, create a new one. }
int maxBytes = Encoding.UTF8.GetMaxByteCount(str.Length)+4; //+4 bytes for storing the string length // Reads the string
if (maxBytes > buffer.Length)
buffer = new byte[maxBytes]; _ = StreamRead(networkStream, buffer, byteCount);
Char[] chars = Encoding.UTF8.GetChars (buffer, 0, byteCount);
int num = Encoding.UTF8.GetBytes (str, 0, str.Length, buffer, 4);
return new String(chars);
// store number of bytes (not number of chars!) }
buffer [0] = (byte) num; }
buffer [1] = (byte) (num >> 8);
buffer [2] = (byte) (num >> 16);
buffer [3] = (byte) (num >> 24);
// Write the string bytes
networkStream.Write (buffer, 0, num + 4);
}
private static string ReceiveString (Stream networkStream, byte[] buffer)
{
StreamRead (networkStream, buffer, 4);
// Reads the number of bytes (not chars!)
int byteCount = (buffer [0] | (buffer [1] << 8) |
(buffer [2] << 16) | (buffer [3] << 24));
if (byteCount == 0) return string.Empty;
// Allocates a buffer of the correct size. Use the
// internal buffer if it is big enough
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

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

View File

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

View File

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

View File

@ -32,48 +32,42 @@ using Mono.Unix;
namespace Mono.Unix.Native { namespace Mono.Unix.Native {
class FileNameMarshaler : ICustomMarshaler { class FileNameMarshaler : ICustomMarshaler {
private static FileNameMarshaler Instance = new FileNameMarshaler (); private static readonly FileNameMarshaler Instance = new FileNameMarshaler ();
[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 CleanUpNativeData(IntPtr pNativeData) =>
// Console.WriteLine ("# FileNameMarshaler.CleanUpManagedData ({0:x})", pNativeData);
UnixMarshal.FreeHeap(pNativeData);
public Int32 GetNativeDataSize() => IntPtr.Size;
public IntPtr MarshalManagedToNative (Object obj)
{
if(!(obj is String s)) {
return IntPtr.Zero;
}
IntPtr p = UnixMarshal.StringToHeap (s, UnixEncoding.Instance);
// Console.WriteLine ("# FileNameMarshaler.MarshalNativeToManaged for `{0}'={1:x}", s, p);
return p;
}
public static ICustomMarshaler GetInstance (string s) public Object MarshalNativeToManaged (IntPtr pNativeData)
{ {
return Instance; String s = UnixMarshal.PtrToString (pNativeData, UnixEncoding.Instance);
} // Console.WriteLine ("# FileNameMarshaler.MarshalNativeToManaged ({0:x})=`{1}'",
// pNativeData, s);
public void CleanUpManagedData (object o) return s;
{ }
} }
public void CleanUpNativeData (IntPtr pNativeData)
{
// Console.WriteLine ("# FileNameMarshaler.CleanUpManagedData ({0:x})", pNativeData);
UnixMarshal.FreeHeap (pNativeData);
}
public int GetNativeDataSize ()
{
return 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 object MarshalNativeToManaged (IntPtr pNativeData)
{
string s = UnixMarshal.PtrToString (pNativeData, UnixEncoding.Instance);
// Console.WriteLine ("# FileNameMarshaler.MarshalNativeToManaged ({0:x})=`{1}'",
// pNativeData, s);
return s;
}
}
} }
// vim: noexpandtab // vim: noexpandtab

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

@ -1,138 +1,152 @@
// //
// TypeAttributes.cs // TypeAttributes.cs
// //
// Author: // Author:
// Jonathan Pryor (jonpryor@vt.edu) // Jonathan Pryor (jonpryor@vt.edu)
// //
// (C) 2006 Jonathan Pryor // (C) 2006 Jonathan Pryor
// //
// //
// Permission is hereby granted, free of charge, to any person obtaining // Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the // a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including // "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish, // without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to // distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to // permit persons to whom the Software is furnished to do so, subject to
// the following conditions: // the following conditions:
// //
// The above copyright notice and this permission notice shall be // The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software. // included in all copies or substantial portions of the Software.
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// //
using System; using System;
using System.Diagnostics.CodeAnalysis;
namespace Mono.Unix.Native {
namespace Mono.Unix.Native {
[AttributeUsage (AttributeTargets.Field)]
internal class blkcnt_tAttribute : MapAttribute { [AttributeUsage (AttributeTargets.Field)]
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
public blkcnt_tAttribute () : base ("blkcnt_t") internal class blkcnt_tAttribute : MapAttribute {
{
} public blkcnt_tAttribute () : base ("blkcnt_t")
} {
}
[AttributeUsage (AttributeTargets.Field)] }
internal class blksize_tAttribute : MapAttribute {
[AttributeUsage (AttributeTargets.Field)]
public blksize_tAttribute () : base ("blksize_t") [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
{ internal class blksize_tAttribute : MapAttribute {
}
} public blksize_tAttribute () : base ("blksize_t")
{
[AttributeUsage (AttributeTargets.Field)] }
internal class dev_tAttribute : MapAttribute { }
public dev_tAttribute () : base ("dev_t") [AttributeUsage (AttributeTargets.Field)]
{ [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
} internal class dev_tAttribute : MapAttribute {
}
public dev_tAttribute () : base ("dev_t")
[AttributeUsage (AttributeTargets.Field)] {
internal class gid_tAttribute : MapAttribute { }
}
public gid_tAttribute () : base ("gid_t")
{ [AttributeUsage (AttributeTargets.Field)]
} [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
} internal class gid_tAttribute : MapAttribute {
[AttributeUsage (AttributeTargets.Field)] public gid_tAttribute () : base ("gid_t")
internal class fsblkcnt_tAttribute : MapAttribute { {
}
public fsblkcnt_tAttribute () : base ("fsblkcnt_t") }
{
} [AttributeUsage (AttributeTargets.Field)]
} [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
internal class fsblkcnt_tAttribute : MapAttribute {
[AttributeUsage (AttributeTargets.Field)]
internal class fsfilcnt_tAttribute : MapAttribute { public fsblkcnt_tAttribute () : base ("fsblkcnt_t")
{
public fsfilcnt_tAttribute () : base ("fsfilcnt_t") }
{ }
}
} [AttributeUsage (AttributeTargets.Field)]
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
[AttributeUsage (AttributeTargets.Field)] internal class fsfilcnt_tAttribute : MapAttribute {
internal class ino_tAttribute : MapAttribute {
public fsfilcnt_tAttribute () : base ("fsfilcnt_t")
public ino_tAttribute () : base ("ino_t") {
{ }
} }
}
[AttributeUsage (AttributeTargets.Field)]
[AttributeUsage (AttributeTargets.Field)] [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
internal class nlink_tAttribute : MapAttribute { internal class ino_tAttribute : MapAttribute {
public nlink_tAttribute () : base ("nlink_t") public ino_tAttribute () : base ("ino_t")
{ {
} }
} }
[AttributeUsage (AttributeTargets.Field)] [AttributeUsage (AttributeTargets.Field)]
internal class off_tAttribute : MapAttribute { [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
internal class nlink_tAttribute : MapAttribute {
public off_tAttribute () : base ("off_t")
{ public nlink_tAttribute () : base ("nlink_t")
} {
} }
}
[AttributeUsage (AttributeTargets.Field)]
internal class pid_tAttribute : MapAttribute { [AttributeUsage (AttributeTargets.Field)]
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
public pid_tAttribute () : base ("pid_t") internal class off_tAttribute : MapAttribute {
{
} public off_tAttribute () : base ("off_t")
} {
}
[AttributeUsage (AttributeTargets.Field)] }
internal class suseconds_tAttribute : MapAttribute {
[AttributeUsage (AttributeTargets.Field)]
public suseconds_tAttribute () : base ("suseconds_t") [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
{ internal class pid_tAttribute : MapAttribute {
}
} public pid_tAttribute () : base ("pid_t")
{
[AttributeUsage (AttributeTargets.Field)] }
internal class uid_tAttribute : MapAttribute { }
public uid_tAttribute () : base ("uid_t") [AttributeUsage (AttributeTargets.Field)]
{ [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
} internal class suseconds_tAttribute : MapAttribute {
}
public suseconds_tAttribute () : base ("suseconds_t")
[AttributeUsage (AttributeTargets.Field)] {
internal class time_tAttribute : MapAttribute { }
}
public time_tAttribute () : base ("time_t")
{ [AttributeUsage (AttributeTargets.Field)]
} [SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
} internal class uid_tAttribute : MapAttribute {
}
public uid_tAttribute () : base ("uid_t")
{
}
}
[AttributeUsage (AttributeTargets.Field)]
[SuppressMessage("Microsoft.Design","IDE1006", Justification = "Can not change name!")]
internal class time_tAttribute : MapAttribute {
public time_tAttribute () : base ("time_t")
{
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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