huge refactoring
This commit is contained in:
parent
6b5d3e07cc
commit
2f0ae844d0
@ -1,3 +1,5 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Consts.cs.in
|
// Consts.cs.in
|
||||||
//
|
//
|
||||||
@ -30,107 +32,107 @@
|
|||||||
|
|
||||||
static partial class Consts
|
static partial class Consts
|
||||||
{
|
{
|
||||||
public const string MonoCorlibVersion = "@MONO_CORLIB_VERSION@";
|
public const String MonoCorlibVersion = "@MONO_CORLIB_VERSION@";
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !NETCORE
|
#if !NETCORE
|
||||||
|
|
||||||
static partial class Consts
|
static partial class Consts
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
// Use these assembly version constants to make code more maintainable.
|
// Use these assembly version constants to make code more maintainable.
|
||||||
//
|
//
|
||||||
|
|
||||||
public const string MonoVersion = "@MONO_VERSION@";
|
public const String MonoVersion = "@MONO_VERSION@";
|
||||||
public const string MonoCompany = "Mono development team";
|
public const String MonoCompany = "Mono development team";
|
||||||
public const string MonoProduct = "Mono Common Language Infrastructure";
|
public const String MonoProduct = "Mono Common Language Infrastructure";
|
||||||
public const string MonoCopyright = "(c) Various Mono authors";
|
public const String MonoCopyright = "(c) Various Mono authors";
|
||||||
|
|
||||||
#if MOBILE
|
#if MOBILE
|
||||||
// Versions of .NET Framework for Silverlight 4.0
|
// Versions of .NET Framework for Silverlight 4.0
|
||||||
public const string FxVersion = "2.0.5.0";
|
public const string FxVersion = "2.0.5.0";
|
||||||
public const string VsVersion = "9.0.0.0"; // unused, but needed for compilation
|
public const string VsVersion = "9.0.0.0"; // unused, but needed for compilation
|
||||||
public const string FxFileVersion = "4.0.50524.0";
|
public const string FxFileVersion = "4.0.50524.0";
|
||||||
public const string EnvironmentVersion = FxFileVersion;
|
public const string EnvironmentVersion = FxFileVersion;
|
||||||
|
|
||||||
public const string VsFileVersion = "9.0.50727.42"; // unused, but needed for compilation
|
public const string VsFileVersion = "9.0.50727.42"; // unused, but needed for compilation
|
||||||
#elif NET_4_6
|
#elif NET_4_6
|
||||||
public const string FxVersion = "4.0.0.0";
|
public const String FxVersion = "4.0.0.0";
|
||||||
public const string FxFileVersion = "4.6.57.0";
|
public const String FxFileVersion = "4.6.57.0";
|
||||||
public const string EnvironmentVersion = "4.0.30319.42000";
|
public const String EnvironmentVersion = "4.0.30319.42000";
|
||||||
|
|
||||||
public const string VsVersion = "0.0.0.0"; // Useless ?
|
public const String VsVersion = "0.0.0.0"; // Useless ?
|
||||||
public const string VsFileVersion = "11.0.0.0"; // TODO:
|
public const String VsFileVersion = "11.0.0.0"; // TODO:
|
||||||
#elif NET_4_5
|
#elif NET_4_5
|
||||||
public const string FxVersion = "4.0.0.0";
|
public const string FxVersion = "4.0.0.0";
|
||||||
public const string FxFileVersion = "4.0.30319.17020";
|
public const string FxFileVersion = "4.0.30319.17020";
|
||||||
public const string EnvironmentVersion = FxFileVersion;
|
public const string EnvironmentVersion = FxFileVersion;
|
||||||
|
|
||||||
public const string VsVersion = "0.0.0.0"; // Useless ?
|
public const string VsVersion = "0.0.0.0"; // Useless ?
|
||||||
public const string VsFileVersion = "11.0.0.0"; // TODO:
|
public const string VsFileVersion = "11.0.0.0"; // TODO:
|
||||||
#elif NETCORE
|
#elif NETCORE
|
||||||
public const string FxVersion = "";
|
public const string FxVersion = "";
|
||||||
public const string FxFileVersion = "";
|
public const string FxFileVersion = "";
|
||||||
public const string EnvironmentVersion = FxFileVersion;
|
public const string EnvironmentVersion = FxFileVersion;
|
||||||
|
|
||||||
public const string VsVersion = "";
|
public const string VsVersion = "";
|
||||||
public const string VsFileVersion = "";
|
public const string VsFileVersion = "";
|
||||||
#elif NET_4_0
|
#elif NET_4_0
|
||||||
#error Profile NET_4_0 is not supported.
|
#error Profile NET_4_0 is not supported.
|
||||||
#elif NET_3_5
|
#elif NET_3_5
|
||||||
#error Profile NET_3_5 is not supported.
|
#error Profile NET_3_5 is not supported.
|
||||||
#elif NET_3_0
|
#elif NET_3_0
|
||||||
#error Profile NET_3_0 is not supported.
|
#error Profile NET_3_0 is not supported.
|
||||||
#elif NET_2_0
|
#elif NET_2_0
|
||||||
#error Profile NET_2_0 is not supported.
|
#error Profile NET_2_0 is not supported.
|
||||||
#elif NET_1_1
|
#elif NET_1_1
|
||||||
#error Profile NET_1_1 is not supported.
|
#error Profile NET_1_1 is not supported.
|
||||||
#elif NET_1_0
|
#elif NET_1_0
|
||||||
#error Profile NET_1_0 is not supported.
|
#error Profile NET_1_0 is not supported.
|
||||||
#else
|
#else
|
||||||
#error No profile symbols defined.
|
#error No profile symbols defined.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if MOBILE
|
#if MOBILE
|
||||||
const string PublicKeyToken = "7cec85d7bea7798e";
|
const string PublicKeyToken = "7cec85d7bea7798e";
|
||||||
#else
|
#else
|
||||||
const string PublicKeyToken = "b77a5c561934e089";
|
const String PublicKeyToken = "b77a5c561934e089";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//
|
//
|
||||||
// Use these assembly name constants to make code more maintainable.
|
// Use these assembly name constants to make code more maintainable.
|
||||||
//
|
//
|
||||||
|
|
||||||
public const string AssemblyI18N = "I18N, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756";
|
public const String AssemblyI18N = "I18N, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756";
|
||||||
public const string AssemblyMicrosoft_JScript = "Microsoft.JScript, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
public const String AssemblyMicrosoft_JScript = "Microsoft.JScript, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||||
public const string AssemblyMicrosoft_VisualStudio = "Microsoft.VisualStudio, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
public const String AssemblyMicrosoft_VisualStudio = "Microsoft.VisualStudio, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||||
public const string AssemblyMicrosoft_VisualStudio_Web = "Microsoft.VisualStudio.Web, Version=" + VsVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
public const String AssemblyMicrosoft_VisualStudio_Web = "Microsoft.VisualStudio.Web, Version=" + VsVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||||
public const string AssemblyMicrosoft_VSDesigner = "Microsoft.VSDesigner, Version=" + VsVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
public const String AssemblyMicrosoft_VSDesigner = "Microsoft.VSDesigner, Version=" + VsVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||||
public const string AssemblyMono_Http = "Mono.Http, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756";
|
public const String AssemblyMono_Http = "Mono.Http, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756";
|
||||||
public const string AssemblyMono_Posix = "Mono.Posix, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756";
|
public const String AssemblyMono_Posix = "Mono.Posix, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756";
|
||||||
public const string AssemblyMono_Security = "Mono.Security, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756";
|
public const String AssemblyMono_Security = "Mono.Security, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756";
|
||||||
public const string AssemblyMono_Messaging_RabbitMQ = "Mono.Messaging.RabbitMQ, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756";
|
public const String AssemblyMono_Messaging_RabbitMQ = "Mono.Messaging.RabbitMQ, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756";
|
||||||
public const string AssemblyCorlib = "mscorlib, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=" + PublicKeyToken;
|
public const String AssemblyCorlib = "mscorlib, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=" + PublicKeyToken;
|
||||||
public const string AssemblySystem = "System, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=" + PublicKeyToken;
|
public const String AssemblySystem = "System, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=" + PublicKeyToken;
|
||||||
public const string AssemblySystem_Data = "System.Data, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b77a5c561934e089";
|
public const String AssemblySystem_Data = "System.Data, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b77a5c561934e089";
|
||||||
public const string AssemblySystem_Design = "System.Design, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
public const String AssemblySystem_Design = "System.Design, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||||
public const string AssemblySystem_DirectoryServices = "System.DirectoryServices, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
public const String AssemblySystem_DirectoryServices = "System.DirectoryServices, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||||
public const string AssemblySystem_Drawing = "System.Drawing, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
public const String AssemblySystem_Drawing = "System.Drawing, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||||
public const string AssemblySystem_Drawing_Design = "System.Drawing.Design, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
public const String AssemblySystem_Drawing_Design = "System.Drawing.Design, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||||
public const string AssemblySystem_Messaging = "System.Messaging, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
public const String AssemblySystem_Messaging = "System.Messaging, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||||
public const string AssemblySystem_Security = "System.Security, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
public const String AssemblySystem_Security = "System.Security, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||||
public const string AssemblySystem_ServiceProcess = "System.ServiceProcess, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
public const String AssemblySystem_ServiceProcess = "System.ServiceProcess, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||||
public const string AssemblySystem_Web = "System.Web, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
public const String AssemblySystem_Web = "System.Web, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||||
public const string AssemblySystem_Windows_Forms = "System.Windows.Forms, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b77a5c561934e089";
|
public const String AssemblySystem_Windows_Forms = "System.Windows.Forms, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b77a5c561934e089";
|
||||||
public const string AssemblySystem_2_0 = "System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
|
public const String AssemblySystem_2_0 = "System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
|
||||||
public const string AssemblySystemCore_3_5 = "System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
|
public const String AssemblySystemCore_3_5 = "System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
|
||||||
public const string AssemblySystem_Core = "System.Core, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=" + PublicKeyToken;
|
public const String AssemblySystem_Core = "System.Core, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=" + PublicKeyToken;
|
||||||
public const string WindowsBase_3_0 = "WindowsBase, Version=3.0.0.0, PublicKeyToken=31bf3856ad364e35";
|
public const String WindowsBase_3_0 = "WindowsBase, Version=3.0.0.0, PublicKeyToken=31bf3856ad364e35";
|
||||||
public const string AssemblyWindowsBase = "WindowsBase, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35";
|
public const String AssemblyWindowsBase = "WindowsBase, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35";
|
||||||
public const string AssemblyPresentationCore_3_5 = "PresentationCore, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35";
|
public const String AssemblyPresentationCore_3_5 = "PresentationCore, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35";
|
||||||
public const string AssemblyPresentationCore_4_0 = "PresentationCore, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35";
|
public const String AssemblyPresentationCore_4_0 = "PresentationCore, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35";
|
||||||
public const string AssemblyPresentationFramework_3_5 = "PresentationFramework, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35";
|
public const String AssemblyPresentationFramework_3_5 = "PresentationFramework, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35";
|
||||||
public const string AssemblySystemServiceModel_3_0 = "System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
|
public const String AssemblySystemServiceModel_3_0 = "System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -35,17 +35,11 @@ using System;
|
|||||||
|
|
||||||
internal sealed class Locale {
|
internal sealed class Locale {
|
||||||
|
|
||||||
private Locale ()
|
private Locale ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetText (string msg)
|
public static String GetText(String msg) => msg;
|
||||||
{
|
|
||||||
return msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetText (string fmt, params object [] args)
|
public static String GetText(String fmt, params Object[] args) => String.Format(fmt, args);
|
||||||
{
|
|
||||||
return String.Format (fmt, args);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -31,56 +31,62 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Mono.Posix {
|
namespace Mono.Posix {
|
||||||
|
|
||||||
[Obsolete ("Use Mono.Unix.Catalog")]
|
[Obsolete ("Use Mono.Unix.Catalog")]
|
||||||
public class Catalog {
|
public class Catalog {
|
||||||
[DllImport("intl")]
|
[DllImport("intl")]
|
||||||
static extern IntPtr bindtextdomain (IntPtr domainname, IntPtr dirname);
|
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||||
[DllImport("intl")]
|
static extern IntPtr bindtextdomain (IntPtr domainname, IntPtr dirname);
|
||||||
static extern IntPtr bind_textdomain_codeset (IntPtr domainname,
|
[DllImport("intl")]
|
||||||
IntPtr codeset);
|
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||||
[DllImport("intl")]
|
static extern IntPtr bind_textdomain_codeset (IntPtr domainname,
|
||||||
static extern IntPtr textdomain (IntPtr domainname);
|
IntPtr codeset);
|
||||||
|
[DllImport("intl")]
|
||||||
|
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||||
|
static extern IntPtr textdomain (IntPtr domainname);
|
||||||
|
|
||||||
public static void Init (String package, String localedir)
|
public static void Init (String package, String localedir)
|
||||||
{
|
{
|
||||||
IntPtr ipackage = Marshal.StringToHGlobalAuto (package);
|
IntPtr ipackage = Marshal.StringToHGlobalAuto (package);
|
||||||
IntPtr ilocaledir = Marshal.StringToHGlobalAuto (localedir);
|
IntPtr ilocaledir = Marshal.StringToHGlobalAuto (localedir);
|
||||||
IntPtr iutf8 = Marshal.StringToHGlobalAuto ("UTF-8");
|
IntPtr iutf8 = Marshal.StringToHGlobalAuto ("UTF-8");
|
||||||
bindtextdomain (ipackage, ilocaledir);
|
_ = bindtextdomain(ipackage, ilocaledir);
|
||||||
bind_textdomain_codeset (ipackage, iutf8);
|
_ = bind_textdomain_codeset(ipackage, iutf8);
|
||||||
textdomain (ipackage);
|
_ = textdomain(ipackage);
|
||||||
Marshal.FreeHGlobal (ipackage);
|
Marshal.FreeHGlobal (ipackage);
|
||||||
Marshal.FreeHGlobal (ilocaledir);
|
Marshal.FreeHGlobal (ilocaledir);
|
||||||
Marshal.FreeHGlobal (iutf8);
|
Marshal.FreeHGlobal (iutf8);
|
||||||
}
|
}
|
||||||
|
|
||||||
[DllImport("intl")]
|
[DllImport("intl")]
|
||||||
static extern IntPtr gettext (IntPtr instring);
|
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||||
|
static extern IntPtr gettext (IntPtr instring);
|
||||||
|
|
||||||
public static String GetString (String s)
|
public static String GetString (String s)
|
||||||
{
|
{
|
||||||
IntPtr ints = Marshal.StringToHGlobalAuto (s);
|
IntPtr ints = Marshal.StringToHGlobalAuto (s);
|
||||||
String t = Marshal.PtrToStringAuto (gettext (ints));
|
String t = Marshal.PtrToStringAuto (gettext (ints));
|
||||||
Marshal.FreeHGlobal (ints);
|
Marshal.FreeHGlobal (ints);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
[DllImport("intl")]
|
[DllImport("intl")]
|
||||||
static extern IntPtr ngettext (IntPtr singular, IntPtr plural, Int32 n);
|
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||||
|
static extern IntPtr ngettext (IntPtr singular, IntPtr plural, Int32 n);
|
||||||
|
|
||||||
public static String GetPluralString (String s, String p, Int32 n)
|
public static String GetPluralString (String s, String p, Int32 n)
|
||||||
{
|
{
|
||||||
IntPtr ints = Marshal.StringToHGlobalAuto (s);
|
IntPtr ints = Marshal.StringToHGlobalAuto (s);
|
||||||
IntPtr intp = Marshal.StringToHGlobalAuto (p);
|
IntPtr intp = Marshal.StringToHGlobalAuto (p);
|
||||||
String t = Marshal.PtrToStringAnsi (ngettext (ints, intp, n));
|
String t = Marshal.PtrToStringAnsi (ngettext (ints, intp, n));
|
||||||
Marshal.FreeHGlobal (ints);
|
Marshal.FreeHGlobal (ints);
|
||||||
Marshal.FreeHGlobal (intp);
|
Marshal.FreeHGlobal (intp);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,48 +34,36 @@ using System.Net.Sockets;
|
|||||||
namespace Mono.Posix
|
namespace Mono.Posix
|
||||||
{
|
{
|
||||||
#pragma warning disable 649
|
#pragma warning disable 649
|
||||||
internal struct PeerCredData {
|
internal struct PeerCredData {
|
||||||
public int pid;
|
public Int32 pid;
|
||||||
public int uid;
|
public Int32 uid;
|
||||||
public int gid;
|
public Int32 gid;
|
||||||
}
|
}
|
||||||
#pragma warning restore 649
|
#pragma warning restore 649
|
||||||
|
|
||||||
[Obsolete ("Use Mono.Unix.PeerCred")]
|
[Obsolete ("Use Mono.Unix.PeerCred")]
|
||||||
public class PeerCred
|
public class PeerCred
|
||||||
{
|
{
|
||||||
/* Make sure this doesn't clash with anything in
|
/* Make sure this doesn't clash with anything in
|
||||||
* SocketOptionName, and keep it synchronised with the
|
* SocketOptionName, and keep it synchronised with the
|
||||||
* runtime
|
* runtime
|
||||||
*/
|
*/
|
||||||
private const int so_peercred=10001;
|
private const Int32 so_peercred =10001;
|
||||||
private PeerCredData data;
|
private PeerCredData data;
|
||||||
|
|
||||||
public PeerCred (Socket sock) {
|
public PeerCred (Socket sock) {
|
||||||
if (sock.AddressFamily != AddressFamily.Unix) {
|
if (sock.AddressFamily != AddressFamily.Unix) {
|
||||||
throw new ArgumentException ("Only Unix sockets are supported", "sock");
|
throw new ArgumentException ("Only Unix sockets are supported", "sock");
|
||||||
}
|
}
|
||||||
|
|
||||||
data = (PeerCredData)sock.GetSocketOption (SocketOptionLevel.Socket, (SocketOptionName)so_peercred);
|
this.data = (PeerCredData)sock.GetSocketOption (SocketOptionLevel.Socket, (SocketOptionName)so_peercred);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int ProcessID {
|
public Int32 ProcessID => this.data.pid;
|
||||||
get {
|
|
||||||
return(data.pid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int UserID {
|
public Int32 UserID => this.data.uid;
|
||||||
get {
|
|
||||||
return(data.uid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int GroupID {
|
public Int32 GroupID => this.data.gid;
|
||||||
get {
|
}
|
||||||
return(data.gid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -34,85 +34,79 @@ using System.Text;
|
|||||||
|
|
||||||
namespace Mono.Posix
|
namespace Mono.Posix
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
[Obsolete ("Use Mono.Unix.UnixEndPoint")]
|
[Obsolete ("Use Mono.Unix.UnixEndPoint")]
|
||||||
public class UnixEndPoint : EndPoint
|
public class UnixEndPoint : EndPoint
|
||||||
{
|
{
|
||||||
string filename;
|
String filename;
|
||||||
|
|
||||||
public UnixEndPoint (string filename)
|
public UnixEndPoint (String filename)
|
||||||
{
|
{
|
||||||
if (filename == null)
|
if (filename == null) {
|
||||||
throw new ArgumentNullException ("filename");
|
throw new ArgumentNullException ("filename");
|
||||||
|
}
|
||||||
|
|
||||||
if (filename == "")
|
if (filename == "") {
|
||||||
throw new ArgumentException ("Cannot be empty.", "filename");
|
throw new ArgumentException ("Cannot be empty.", "filename");
|
||||||
this.filename = filename;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public string Filename {
|
this.filename = filename;
|
||||||
get {
|
}
|
||||||
return(filename);
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
filename=value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override AddressFamily AddressFamily {
|
public String Filename {
|
||||||
get { return AddressFamily.Unix; }
|
get => this.filename;
|
||||||
}
|
set => this.filename = value;
|
||||||
|
}
|
||||||
|
|
||||||
public override EndPoint Create (SocketAddress socketAddress)
|
public override AddressFamily AddressFamily => AddressFamily.Unix;
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Should also check this
|
|
||||||
*
|
|
||||||
int addr = (int) AddressFamily.Unix;
|
|
||||||
if (socketAddress [0] != (addr & 0xFF))
|
|
||||||
throw new ArgumentException ("socketAddress is not a unix socket address.");
|
|
||||||
|
|
||||||
if (socketAddress [1] != ((addr & 0xFF00) >> 8))
|
public override EndPoint Create (SocketAddress socketAddress)
|
||||||
throw new ArgumentException ("socketAddress is not a unix socket address.");
|
{
|
||||||
*/
|
/*
|
||||||
|
* Should also check this
|
||||||
|
*
|
||||||
|
int addr = (int) AddressFamily.Unix;
|
||||||
|
if (socketAddress [0] != (addr & 0xFF))
|
||||||
|
throw new ArgumentException ("socketAddress is not a unix socket address.");
|
||||||
|
|
||||||
byte [] bytes = new byte [socketAddress.Size - 2];
|
if (socketAddress [1] != ((addr & 0xFF00) >> 8))
|
||||||
for (int i = 0; i < bytes.Length; i++) {
|
throw new ArgumentException ("socketAddress is not a unix socket address.");
|
||||||
bytes [i] = socketAddress [i + 2];
|
*/
|
||||||
}
|
|
||||||
|
|
||||||
string name = Encoding.Default.GetString (bytes);
|
Byte[] bytes = new Byte[socketAddress.Size - 2];
|
||||||
return new UnixEndPoint (name);
|
for (Int32 i = 0; i < bytes.Length; i++) {
|
||||||
}
|
bytes [i] = socketAddress [i + 2];
|
||||||
|
}
|
||||||
|
|
||||||
public override SocketAddress Serialize ()
|
String name = Encoding.Default.GetString (bytes);
|
||||||
{
|
return new UnixEndPoint (name);
|
||||||
byte [] bytes = Encoding.Default.GetBytes (filename);
|
}
|
||||||
SocketAddress sa = new SocketAddress (AddressFamily, bytes.Length + 2);
|
|
||||||
// sa [0] -> family low byte, sa [1] -> family high byte
|
|
||||||
for (int i = 0; i < bytes.Length; i++)
|
|
||||||
sa [i + 2] = bytes [i];
|
|
||||||
|
|
||||||
return sa;
|
public override SocketAddress Serialize ()
|
||||||
}
|
{
|
||||||
|
Byte[] bytes = Encoding.Default.GetBytes (this.filename);
|
||||||
|
SocketAddress sa = new SocketAddress (this.AddressFamily, bytes.Length + 2);
|
||||||
|
// sa [0] -> family low byte, sa [1] -> family high byte
|
||||||
|
for (Int32 i = 0; i < bytes.Length; i++) {
|
||||||
|
sa [i + 2] = bytes [i];
|
||||||
|
}
|
||||||
|
|
||||||
public override string ToString() {
|
return sa;
|
||||||
return(filename);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode ()
|
public override String ToString() => this.filename;
|
||||||
{
|
|
||||||
return filename.GetHashCode ();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals (object o)
|
public override Int32 GetHashCode() => this.filename.GetHashCode();
|
||||||
{
|
|
||||||
UnixEndPoint other = o as UnixEndPoint;
|
|
||||||
if (other == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return (other.filename == filename);
|
public override Boolean Equals (Object o)
|
||||||
}
|
{
|
||||||
}
|
UnixEndPoint other = o as UnixEndPoint;
|
||||||
|
if (other == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return other.filename == this.filename;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,129 +39,111 @@ using System.Runtime.Serialization.Formatters.Binary;
|
|||||||
|
|
||||||
namespace Mono.Remoting.Channels.Unix
|
namespace Mono.Remoting.Channels.Unix
|
||||||
{
|
{
|
||||||
internal class UnixBinaryClientFormatterSink : IClientFormatterSink, IMessageSink, IClientChannelSink, IChannelSinkBase
|
internal class UnixBinaryClientFormatterSink : IClientFormatterSink, IMessageSink, IClientChannelSink, IChannelSinkBase
|
||||||
{
|
{
|
||||||
UnixBinaryCore _binaryCore = UnixBinaryCore.DefaultInstance;
|
UnixBinaryCore _binaryCore = UnixBinaryCore.DefaultInstance;
|
||||||
IClientChannelSink _nextInChain;
|
IClientChannelSink _nextInChain;
|
||||||
|
|
||||||
public UnixBinaryClientFormatterSink (IClientChannelSink nextSink)
|
public UnixBinaryClientFormatterSink(IClientChannelSink nextSink) => this._nextInChain = nextSink;
|
||||||
{
|
|
||||||
_nextInChain = nextSink;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal UnixBinaryCore BinaryCore
|
internal UnixBinaryCore BinaryCore {
|
||||||
{
|
get => this._binaryCore;
|
||||||
get { return _binaryCore; }
|
set => this._binaryCore = value;
|
||||||
set { _binaryCore = value; }
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public IClientChannelSink NextChannelSink
|
public IClientChannelSink NextChannelSink => this._nextInChain;
|
||||||
{
|
|
||||||
get {
|
|
||||||
return _nextInChain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IMessageSink NextSink
|
public IMessageSink NextSink =>
|
||||||
{
|
// This is the last sink in the IMessageSink sink chain
|
||||||
get {
|
null;
|
||||||
// This is the last sink in the IMessageSink sink chain
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IDictionary Properties
|
public IDictionary Properties => null;
|
||||||
{
|
|
||||||
get {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AsyncProcessRequest (IClientChannelSinkStack sinkStack,
|
public void AsyncProcessRequest(IClientChannelSinkStack sinkStack,
|
||||||
IMessage msg,
|
IMessage msg,
|
||||||
ITransportHeaders headers,
|
ITransportHeaders headers,
|
||||||
Stream stream)
|
Stream stream) =>
|
||||||
{
|
// never called because the formatter sink is
|
||||||
// never called because the formatter sink is
|
// always the first in the chain
|
||||||
// always the first in the chain
|
throw new NotSupportedException("UnixBinaryClientFormatterSink must be the first sink in the IClientChannelSink chain");
|
||||||
throw new NotSupportedException("UnixBinaryClientFormatterSink must be the first sink in the IClientChannelSink chain");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AsyncProcessResponse (IClientResponseChannelSinkStack sinkStack,
|
public void AsyncProcessResponse (IClientResponseChannelSinkStack sinkStack,
|
||||||
object state,
|
Object state,
|
||||||
ITransportHeaders headers,
|
ITransportHeaders headers,
|
||||||
Stream stream)
|
Stream stream)
|
||||||
{
|
{
|
||||||
IMessage replyMessage = (IMessage)_binaryCore.Deserializer.DeserializeMethodResponse (stream, null, (IMethodCallMessage)state);
|
IMessage replyMessage = (IMessage)this._binaryCore.Deserializer.DeserializeMethodResponse (stream, null, (IMethodCallMessage)state);
|
||||||
sinkStack.DispatchReplyMessage (replyMessage);
|
sinkStack.DispatchReplyMessage (replyMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Stream GetRequestStream (IMessage msg,
|
public Stream GetRequestStream(IMessage msg,
|
||||||
ITransportHeaders headers)
|
ITransportHeaders headers) =>
|
||||||
{
|
// never called
|
||||||
// never called
|
throw new NotSupportedException();
|
||||||
throw new NotSupportedException ();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ProcessMessage (IMessage msg,
|
public void ProcessMessage(IMessage msg,
|
||||||
ITransportHeaders requestHeaders,
|
ITransportHeaders requestHeaders,
|
||||||
Stream requestStream,
|
Stream requestStream,
|
||||||
out ITransportHeaders responseHeaders,
|
out ITransportHeaders responseHeaders,
|
||||||
out Stream responseStream)
|
out Stream responseStream) =>
|
||||||
{
|
// never called because the formatter sink is
|
||||||
// never called because the formatter sink is
|
// always the first in the chain
|
||||||
// always the first in the chain
|
throw new NotSupportedException();
|
||||||
throw new NotSupportedException ();
|
|
||||||
}
|
|
||||||
|
|
||||||
public IMessageCtrl AsyncProcessMessage (IMessage msg,
|
public IMessageCtrl AsyncProcessMessage (IMessage msg,
|
||||||
IMessageSink replySink)
|
IMessageSink replySink)
|
||||||
{
|
{
|
||||||
ITransportHeaders transportHeaders = new TransportHeaders();
|
ITransportHeaders transportHeaders = new TransportHeaders();
|
||||||
Stream stream = _nextInChain.GetRequestStream(msg, transportHeaders);
|
Stream stream = this._nextInChain.GetRequestStream(msg, transportHeaders);
|
||||||
if (stream == null) stream = new MemoryStream ();
|
if (stream == null) {
|
||||||
|
stream = new MemoryStream ();
|
||||||
|
}
|
||||||
|
|
||||||
_binaryCore.Serializer.Serialize (stream, msg, null);
|
this._binaryCore.Serializer.Serialize (stream, msg, null);
|
||||||
if (stream is MemoryStream) stream.Position = 0;
|
if (stream is MemoryStream) {
|
||||||
|
stream.Position = 0;
|
||||||
|
}
|
||||||
|
|
||||||
ClientChannelSinkStack stack = new ClientChannelSinkStack(replySink);
|
ClientChannelSinkStack stack = new ClientChannelSinkStack(replySink);
|
||||||
stack.Push (this, msg);
|
stack.Push (this, msg);
|
||||||
|
|
||||||
_nextInChain.AsyncProcessRequest (stack, msg, transportHeaders, stream);
|
this._nextInChain.AsyncProcessRequest (stack, msg, transportHeaders, stream);
|
||||||
|
|
||||||
// FIXME: No idea about how to implement IMessageCtrl
|
// FIXME: No idea about how to implement IMessageCtrl
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IMessage SyncProcessMessage (IMessage msg)
|
public IMessage SyncProcessMessage (IMessage msg)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
|
||||||
ITransportHeaders call_headers = new TransportHeaders();
|
ITransportHeaders call_headers = new TransportHeaders();
|
||||||
call_headers["__RequestUri"] = ((IMethodCallMessage)msg).Uri;
|
call_headers["__RequestUri"] = ((IMethodCallMessage)msg).Uri;
|
||||||
call_headers["Content-Type"] = "application/octet-stream";
|
call_headers["Content-Type"] = "application/octet-stream";
|
||||||
|
|
||||||
Stream call_stream = _nextInChain.GetRequestStream(msg, call_headers);
|
Stream call_stream = this._nextInChain.GetRequestStream(msg, call_headers);
|
||||||
if (call_stream == null) call_stream = new MemoryStream ();
|
if (call_stream == null) {
|
||||||
|
call_stream = new MemoryStream ();
|
||||||
|
}
|
||||||
|
|
||||||
// Serialize msg to the stream
|
// Serialize msg to the stream
|
||||||
|
|
||||||
_binaryCore.Serializer.Serialize (call_stream, msg, null);
|
this._binaryCore.Serializer.Serialize (call_stream, msg, null);
|
||||||
if (call_stream is MemoryStream) call_stream.Position = 0;
|
if (call_stream is MemoryStream) {
|
||||||
|
call_stream.Position = 0;
|
||||||
|
}
|
||||||
|
|
||||||
Stream response_stream;
|
|
||||||
ITransportHeaders response_headers;
|
|
||||||
|
|
||||||
_nextInChain.ProcessMessage (msg, call_headers, call_stream, out response_headers,
|
this._nextInChain.ProcessMessage(msg, call_headers, call_stream, out ITransportHeaders response_headers,
|
||||||
out response_stream);
|
out Stream response_stream);
|
||||||
|
|
||||||
// Deserialize response_stream
|
// Deserialize response_stream
|
||||||
|
|
||||||
return (IMessage) _binaryCore.Deserializer.DeserializeMethodResponse (response_stream, null, (IMethodCallMessage)msg);
|
return (IMessage)this._binaryCore.Deserializer.DeserializeMethodResponse (response_stream, null, (IMethodCallMessage)msg);
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return new ReturnMessage (e, (IMethodCallMessage)msg);
|
return new ReturnMessage (e, (IMethodCallMessage)msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,48 +33,38 @@ using System.Runtime.Remoting.Channels;
|
|||||||
|
|
||||||
namespace Mono.Remoting.Channels.Unix
|
namespace Mono.Remoting.Channels.Unix
|
||||||
{
|
{
|
||||||
internal class UnixBinaryClientFormatterSinkProvider: IClientFormatterSinkProvider, IClientChannelSinkProvider
|
internal class UnixBinaryClientFormatterSinkProvider: IClientFormatterSinkProvider, IClientChannelSinkProvider
|
||||||
{
|
{
|
||||||
IClientChannelSinkProvider next = null;
|
IClientChannelSinkProvider next = null;
|
||||||
UnixBinaryCore _binaryCore;
|
UnixBinaryCore _binaryCore;
|
||||||
static string[] allowedProperties = new string [] { "includeVersions", "strictBinding" };
|
static System.String[] allowedProperties = new System.String[] { "includeVersions", "strictBinding" };
|
||||||
|
|
||||||
public UnixBinaryClientFormatterSinkProvider ()
|
public UnixBinaryClientFormatterSinkProvider() => this._binaryCore = UnixBinaryCore.DefaultInstance;
|
||||||
{
|
|
||||||
_binaryCore = UnixBinaryCore.DefaultInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnixBinaryClientFormatterSinkProvider (IDictionary properties,
|
public UnixBinaryClientFormatterSinkProvider(IDictionary properties,
|
||||||
ICollection providerData)
|
ICollection providerData) => this._binaryCore = new UnixBinaryCore(this, properties, allowedProperties);
|
||||||
{
|
|
||||||
_binaryCore = new UnixBinaryCore (this, properties, allowedProperties);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IClientChannelSinkProvider Next
|
public IClientChannelSinkProvider Next {
|
||||||
{
|
get => this.next;
|
||||||
get {
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
set {
|
set => this.next = value;
|
||||||
next = value;
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IClientChannelSink CreateSink (IChannelSender channel,
|
public IClientChannelSink CreateSink (IChannelSender channel,
|
||||||
string url,
|
System.String url,
|
||||||
object remoteChannelData)
|
System.Object remoteChannelData)
|
||||||
{
|
{
|
||||||
IClientChannelSink next_sink = null;
|
IClientChannelSink next_sink = null;
|
||||||
UnixBinaryClientFormatterSink result;
|
UnixBinaryClientFormatterSink result;
|
||||||
|
|
||||||
if (next != null)
|
if (this.next != null) {
|
||||||
next_sink = next.CreateSink (channel, url, remoteChannelData);
|
next_sink = this.next.CreateSink (channel, url, remoteChannelData);
|
||||||
|
}
|
||||||
|
|
||||||
result = new UnixBinaryClientFormatterSink (next_sink);
|
result = new UnixBinaryClientFormatterSink (next_sink);
|
||||||
result.BinaryCore = _binaryCore;
|
result.BinaryCore = this._binaryCore;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,114 +35,116 @@ using System.Runtime.Remoting.Messaging;
|
|||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
using System.Runtime.Serialization.Formatters;
|
using System.Runtime.Serialization.Formatters;
|
||||||
using System.Runtime.Serialization.Formatters.Binary;
|
using System.Runtime.Serialization.Formatters.Binary;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
namespace Mono.Remoting.Channels.Unix
|
namespace Mono.Remoting.Channels.Unix
|
||||||
{
|
{
|
||||||
internal class UnixBinaryCore
|
internal class UnixBinaryCore
|
||||||
{
|
{
|
||||||
BinaryFormatter _serializationFormatter;
|
BinaryFormatter _serializationFormatter;
|
||||||
BinaryFormatter _deserializationFormatter;
|
BinaryFormatter _deserializationFormatter;
|
||||||
bool _includeVersions = true;
|
Boolean _includeVersions = true;
|
||||||
bool _strictBinding = false;
|
Boolean _strictBinding = false;
|
||||||
IDictionary _properties;
|
IDictionary _properties;
|
||||||
|
|
||||||
public static UnixBinaryCore DefaultInstance = new UnixBinaryCore ();
|
public static UnixBinaryCore DefaultInstance = new UnixBinaryCore ();
|
||||||
|
|
||||||
public UnixBinaryCore (object owner, IDictionary properties, string[] allowedProperties)
|
public UnixBinaryCore (Object owner, IDictionary properties, String[] allowedProperties)
|
||||||
{
|
{
|
||||||
_properties = properties;
|
this._properties = properties;
|
||||||
|
|
||||||
foreach(DictionaryEntry property in properties)
|
foreach(DictionaryEntry property in properties)
|
||||||
{
|
{
|
||||||
string key = (string) property.Key;
|
String key = (String) property.Key;
|
||||||
if (Array.IndexOf (allowedProperties, key) == -1)
|
if (Array.IndexOf (allowedProperties, key) == -1) {
|
||||||
throw new RemotingException (owner.GetType().Name + " does not recognize '" + key + "' configuration property");
|
throw new RemotingException (owner.GetType().Name + " does not recognize '" + key + "' configuration property");
|
||||||
|
}
|
||||||
|
|
||||||
switch (key)
|
switch (key)
|
||||||
{
|
{
|
||||||
case "includeVersions":
|
case "includeVersions":
|
||||||
_includeVersions = Convert.ToBoolean (property.Value);
|
this._includeVersions = Convert.ToBoolean (property.Value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "strictBinding":
|
case "strictBinding":
|
||||||
_strictBinding = Convert.ToBoolean (property.Value);
|
this._strictBinding = Convert.ToBoolean (property.Value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Init ();
|
this.Init ();
|
||||||
}
|
}
|
||||||
|
|
||||||
public UnixBinaryCore ()
|
public UnixBinaryCore ()
|
||||||
{
|
{
|
||||||
_properties = new Hashtable ();
|
this._properties = new Hashtable ();
|
||||||
Init ();
|
this.Init ();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Init ()
|
public void Init ()
|
||||||
{
|
{
|
||||||
RemotingSurrogateSelector surrogateSelector = new RemotingSurrogateSelector ();
|
RemotingSurrogateSelector surrogateSelector = new RemotingSurrogateSelector ();
|
||||||
StreamingContext context = new StreamingContext (StreamingContextStates.Remoting, null);
|
StreamingContext context = new StreamingContext (StreamingContextStates.Remoting, null);
|
||||||
|
|
||||||
_serializationFormatter = new BinaryFormatter (surrogateSelector, context);
|
this._serializationFormatter = new BinaryFormatter (surrogateSelector, context);
|
||||||
_deserializationFormatter = new BinaryFormatter (null, context);
|
this._deserializationFormatter = new BinaryFormatter (null, context);
|
||||||
|
|
||||||
if (!_includeVersions)
|
if (!this._includeVersions)
|
||||||
{
|
{
|
||||||
_serializationFormatter.AssemblyFormat = FormatterAssemblyStyle.Simple;
|
this._serializationFormatter.AssemblyFormat = FormatterAssemblyStyle.Simple;
|
||||||
_deserializationFormatter.AssemblyFormat = FormatterAssemblyStyle.Simple;
|
this._deserializationFormatter.AssemblyFormat = FormatterAssemblyStyle.Simple;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_strictBinding)
|
if (!this._strictBinding)
|
||||||
{
|
{
|
||||||
_serializationFormatter.Binder = SimpleBinder.Instance;
|
this._serializationFormatter.Binder = SimpleBinder.Instance;
|
||||||
_deserializationFormatter.Binder = SimpleBinder.Instance;
|
this._deserializationFormatter.Binder = SimpleBinder.Instance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public BinaryFormatter Serializer
|
public BinaryFormatter Serializer => this._serializationFormatter;
|
||||||
{
|
|
||||||
get { return _serializationFormatter; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public BinaryFormatter Deserializer
|
public BinaryFormatter Deserializer => this._deserializationFormatter;
|
||||||
{
|
|
||||||
get { return _deserializationFormatter; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public IDictionary Properties
|
public IDictionary Properties => this._properties;
|
||||||
{
|
}
|
||||||
get { return _properties; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
internal class SimpleBinder: SerializationBinder
|
internal class SimpleBinder: SerializationBinder
|
||||||
{
|
{
|
||||||
public static SimpleBinder Instance = new SimpleBinder ();
|
public static SimpleBinder Instance = new SimpleBinder ();
|
||||||
|
|
||||||
public override Type BindToType (String assemblyName, string typeName)
|
[SuppressMessage("Microsoft.Design", "CS0618", Justification = "Someone do shit")]
|
||||||
{
|
public override Type BindToType (String assemblyName, String typeName)
|
||||||
Assembly asm;
|
{
|
||||||
|
Assembly asm;
|
||||||
|
|
||||||
if (assemblyName.IndexOf (',') != -1)
|
if (assemblyName.IndexOf (',') != -1)
|
||||||
{
|
{
|
||||||
// Try using the full name
|
// Try using the full name
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
asm = Assembly.Load (assemblyName);
|
asm = Assembly.Load (assemblyName);
|
||||||
if (asm == null) return null;
|
if (asm == null) {
|
||||||
Type t = asm.GetType (typeName);
|
return null;
|
||||||
if (t != null) return t;
|
}
|
||||||
}
|
|
||||||
catch {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try using the simple name
|
Type t = asm.GetType (typeName);
|
||||||
asm = Assembly.LoadWithPartialName (assemblyName);
|
if (t != null) {
|
||||||
if (asm == null) return null;
|
return t;
|
||||||
return asm.GetType (typeName, true);
|
}
|
||||||
}
|
}
|
||||||
}
|
catch {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try using the simple name
|
||||||
|
asm = Assembly.LoadWithPartialName (assemblyName);
|
||||||
|
if (asm == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return asm.GetType (typeName, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,124 +40,123 @@ using System.Runtime.InteropServices;
|
|||||||
|
|
||||||
namespace Mono.Remoting.Channels.Unix {
|
namespace Mono.Remoting.Channels.Unix {
|
||||||
|
|
||||||
internal class UnixBinaryServerFormatterSink : IServerChannelSink, IChannelSinkBase
|
internal class UnixBinaryServerFormatterSink : IServerChannelSink, IChannelSinkBase
|
||||||
{
|
{
|
||||||
UnixBinaryCore _binaryCore = UnixBinaryCore.DefaultInstance;
|
UnixBinaryCore _binaryCore = UnixBinaryCore.DefaultInstance;
|
||||||
|
|
||||||
IServerChannelSink next_sink;
|
IServerChannelSink next_sink;
|
||||||
IChannelReceiver receiver;
|
IChannelReceiver receiver;
|
||||||
|
|
||||||
public UnixBinaryServerFormatterSink (IServerChannelSink nextSink, IChannelReceiver receiver)
|
public UnixBinaryServerFormatterSink (IServerChannelSink nextSink, IChannelReceiver receiver)
|
||||||
{
|
{
|
||||||
this.next_sink = nextSink;
|
this.next_sink = nextSink;
|
||||||
this.receiver = receiver;
|
this.receiver = receiver;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal UnixBinaryCore BinaryCore
|
internal UnixBinaryCore BinaryCore {
|
||||||
{
|
get => this._binaryCore;
|
||||||
get { return _binaryCore; }
|
set => this._binaryCore = value;
|
||||||
set { _binaryCore = value; }
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public IServerChannelSink NextChannelSink {
|
public IServerChannelSink NextChannelSink => this.next_sink;
|
||||||
get {
|
|
||||||
return next_sink;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IDictionary Properties {
|
public IDictionary Properties => null;
|
||||||
get {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AsyncProcessResponse (IServerResponseChannelSinkStack sinkStack, object state,
|
public void AsyncProcessResponse (IServerResponseChannelSinkStack sinkStack, Object state,
|
||||||
IMessage message, ITransportHeaders headers, Stream stream)
|
IMessage message, ITransportHeaders headers, Stream stream)
|
||||||
{
|
{
|
||||||
ITransportHeaders responseHeaders = new TransportHeaders();
|
ITransportHeaders responseHeaders = new TransportHeaders();
|
||||||
|
|
||||||
if (sinkStack != null) stream = sinkStack.GetResponseStream (message, responseHeaders);
|
if (sinkStack != null) {
|
||||||
if (stream == null) stream = new MemoryStream();
|
stream = sinkStack.GetResponseStream (message, responseHeaders);
|
||||||
|
}
|
||||||
|
|
||||||
_binaryCore.Serializer.Serialize (stream, message, null);
|
if (stream == null) {
|
||||||
if (stream is MemoryStream) stream.Position = 0;
|
stream = new MemoryStream();
|
||||||
|
}
|
||||||
|
|
||||||
sinkStack.AsyncProcessResponse (message, responseHeaders, stream);
|
this._binaryCore.Serializer.Serialize (stream, message, null);
|
||||||
}
|
if (stream is MemoryStream) {
|
||||||
|
stream.Position = 0;
|
||||||
|
}
|
||||||
|
|
||||||
public Stream GetResponseStream (IServerResponseChannelSinkStack sinkStack, object state,
|
sinkStack.AsyncProcessResponse (message, responseHeaders, stream);
|
||||||
IMessage msg, ITransportHeaders headers)
|
}
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ServerProcessing ProcessMessage (IServerChannelSinkStack sinkStack,
|
public Stream GetResponseStream(IServerResponseChannelSinkStack sinkStack, Object state,
|
||||||
IMessage requestMsg, ITransportHeaders requestHeaders, Stream requestStream,
|
IMessage msg, ITransportHeaders headers) => null;
|
||||||
out IMessage responseMsg, out ITransportHeaders responseHeaders, out Stream responseStream)
|
|
||||||
{
|
|
||||||
sinkStack.Push (this, null);
|
|
||||||
ServerProcessing res;
|
|
||||||
|
|
||||||
try
|
public ServerProcessing ProcessMessage (IServerChannelSinkStack sinkStack,
|
||||||
{
|
IMessage requestMsg, ITransportHeaders requestHeaders, Stream requestStream,
|
||||||
string url = (string)requestHeaders["__RequestUri"];
|
out IMessage responseMsg, out ITransportHeaders responseHeaders, out Stream responseStream)
|
||||||
string uri;
|
{
|
||||||
receiver.Parse (url, out uri);
|
sinkStack.Push (this, null);
|
||||||
if (uri == null) uri = url;
|
ServerProcessing res;
|
||||||
|
|
||||||
MethodCallHeaderHandler mhh = new MethodCallHeaderHandler(uri);
|
try
|
||||||
requestMsg = (IMessage) _binaryCore.Deserializer.Deserialize (requestStream, new HeaderHandler(mhh.HandleHeaders));
|
{
|
||||||
|
String url = (String)requestHeaders["__RequestUri"];
|
||||||
|
_ = this.receiver.Parse(url, out String uri);
|
||||||
|
if (uri == null) {
|
||||||
|
uri = url;
|
||||||
|
}
|
||||||
|
|
||||||
res = next_sink.ProcessMessage (sinkStack, requestMsg, requestHeaders, null, out responseMsg, out responseHeaders, out responseStream);
|
MethodCallHeaderHandler mhh = new MethodCallHeaderHandler(uri);
|
||||||
}
|
requestMsg = (IMessage)this._binaryCore.Deserializer.Deserialize (requestStream, new HeaderHandler(mhh.HandleHeaders));
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
responseMsg = new ReturnMessage (ex, (IMethodCallMessage)requestMsg);
|
|
||||||
res = ServerProcessing.Complete;
|
|
||||||
responseHeaders = null;
|
|
||||||
responseStream = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res == ServerProcessing.Complete)
|
res = this.next_sink.ProcessMessage (sinkStack, requestMsg, requestHeaders, null, out responseMsg, out responseHeaders, out responseStream);
|
||||||
{
|
}
|
||||||
for (int n=0; n<3; n++) {
|
catch (Exception ex)
|
||||||
responseStream = null;
|
{
|
||||||
responseHeaders = new TransportHeaders();
|
responseMsg = new ReturnMessage (ex, (IMethodCallMessage)requestMsg);
|
||||||
|
res = ServerProcessing.Complete;
|
||||||
|
responseHeaders = null;
|
||||||
|
responseStream = null;
|
||||||
|
}
|
||||||
|
|
||||||
if (sinkStack != null) responseStream = sinkStack.GetResponseStream (responseMsg, responseHeaders);
|
if (res == ServerProcessing.Complete)
|
||||||
if (responseStream == null) responseStream = new MemoryStream();
|
{
|
||||||
|
for (Int32 n =0; n<3; n++) {
|
||||||
|
responseStream = null;
|
||||||
|
responseHeaders = new TransportHeaders();
|
||||||
|
|
||||||
try {
|
if (sinkStack != null) {
|
||||||
_binaryCore.Serializer.Serialize (responseStream, responseMsg);
|
responseStream = sinkStack.GetResponseStream (responseMsg, responseHeaders);
|
||||||
break;
|
}
|
||||||
} catch (Exception ex) {
|
|
||||||
if (n == 2) throw ex;
|
|
||||||
else responseMsg = new ReturnMessage (ex, (IMethodCallMessage)requestMsg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (responseStream is MemoryStream) responseStream.Position = 0;
|
if (responseStream == null) {
|
||||||
|
responseStream = new MemoryStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
this._binaryCore.Serializer.Serialize (responseStream, responseMsg);
|
||||||
|
break;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
if (n == 2) {
|
||||||
|
throw ex;
|
||||||
|
} else {
|
||||||
|
responseMsg = new ReturnMessage (ex, (IMethodCallMessage)requestMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sinkStack.Pop (this);
|
if (responseStream is MemoryStream) {
|
||||||
}
|
responseStream.Position = 0;
|
||||||
return res;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
_ = sinkStack.Pop(this);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
internal class MethodCallHeaderHandler
|
}
|
||||||
{
|
|
||||||
string _uri;
|
|
||||||
|
|
||||||
public MethodCallHeaderHandler (string uri)
|
internal class MethodCallHeaderHandler
|
||||||
{
|
{
|
||||||
_uri = uri;
|
String _uri;
|
||||||
}
|
|
||||||
|
|
||||||
public object HandleHeaders (Header[] headers)
|
public MethodCallHeaderHandler(String uri) => this._uri = uri;
|
||||||
{
|
|
||||||
return _uri;
|
public Object HandleHeaders(Header[] headers) => this._uri;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -35,51 +35,41 @@ using System.Runtime.Remoting.Channels;
|
|||||||
|
|
||||||
namespace Mono.Remoting.Channels.Unix
|
namespace Mono.Remoting.Channels.Unix
|
||||||
{
|
{
|
||||||
internal class UnixBinaryServerFormatterSinkProvider: IServerFormatterSinkProvider, IServerChannelSinkProvider
|
internal class UnixBinaryServerFormatterSinkProvider: IServerFormatterSinkProvider, IServerChannelSinkProvider
|
||||||
{
|
{
|
||||||
IServerChannelSinkProvider next = null;
|
IServerChannelSinkProvider next = null;
|
||||||
UnixBinaryCore _binaryCore;
|
UnixBinaryCore _binaryCore;
|
||||||
|
|
||||||
internal static string[] AllowedProperties = new string [] { "includeVersions", "strictBinding" };
|
internal static System.String[] AllowedProperties = new System.String[] { "includeVersions", "strictBinding" };
|
||||||
|
|
||||||
public UnixBinaryServerFormatterSinkProvider ()
|
public UnixBinaryServerFormatterSinkProvider() => this._binaryCore = UnixBinaryCore.DefaultInstance;
|
||||||
{
|
|
||||||
_binaryCore = UnixBinaryCore.DefaultInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnixBinaryServerFormatterSinkProvider (IDictionary properties, ICollection providerData)
|
public UnixBinaryServerFormatterSinkProvider(IDictionary properties, ICollection providerData) => this._binaryCore = new UnixBinaryCore(this, properties, AllowedProperties);
|
||||||
{
|
|
||||||
_binaryCore = new UnixBinaryCore (this, properties, AllowedProperties);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IServerChannelSinkProvider Next
|
public IServerChannelSinkProvider Next {
|
||||||
{
|
get => this.next;
|
||||||
get {
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
set {
|
set => this.next = value;
|
||||||
next = value;
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IServerChannelSink CreateSink (IChannelReceiver channel)
|
public IServerChannelSink CreateSink (IChannelReceiver channel)
|
||||||
{
|
{
|
||||||
IServerChannelSink next_sink = null;
|
IServerChannelSink next_sink = null;
|
||||||
UnixBinaryServerFormatterSink result;
|
UnixBinaryServerFormatterSink result;
|
||||||
|
|
||||||
if (next != null)
|
if (this.next != null) {
|
||||||
next_sink = next.CreateSink (channel);
|
next_sink = this.next.CreateSink (channel);
|
||||||
|
}
|
||||||
|
|
||||||
result = new UnixBinaryServerFormatterSink (next_sink, channel);
|
result = new UnixBinaryServerFormatterSink (next_sink, channel);
|
||||||
|
|
||||||
result.BinaryCore = _binaryCore;
|
result.BinaryCore = this._binaryCore;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GetChannelData (IChannelDataStore channelData)
|
public void GetChannelData (IChannelDataStore channelData)
|
||||||
{
|
{
|
||||||
// Nothing to add here
|
// Nothing to add here
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,104 +40,109 @@ namespace Mono.Remoting.Channels.Unix
|
|||||||
{
|
{
|
||||||
private UnixClientChannel _clientChannel;
|
private UnixClientChannel _clientChannel;
|
||||||
private UnixServerChannel _serverChannel = null;
|
private UnixServerChannel _serverChannel = null;
|
||||||
private string _name = "unix";
|
private String _name = "unix";
|
||||||
private int _priority = 1;
|
private Int32 _priority = 1;
|
||||||
|
|
||||||
public UnixChannel (): this (null)
|
public UnixChannel (): this (null)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public UnixChannel (string path)
|
public UnixChannel (String path)
|
||||||
{
|
{
|
||||||
Hashtable ht = new Hashtable();
|
Hashtable ht = new Hashtable();
|
||||||
ht["path"] = path;
|
ht["path"] = path;
|
||||||
Init(ht, null, null);
|
this.Init(ht, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Init (IDictionary properties, IClientChannelSinkProvider clientSink, IServerChannelSinkProvider serverSink)
|
void Init (IDictionary properties, IClientChannelSinkProvider clientSink, IServerChannelSinkProvider serverSink)
|
||||||
{
|
{
|
||||||
_clientChannel = new UnixClientChannel (properties,clientSink);
|
this._clientChannel = new UnixClientChannel (properties,clientSink);
|
||||||
|
|
||||||
if(properties["path"] != null)
|
if(properties["path"] != null) {
|
||||||
_serverChannel = new UnixServerChannel(properties, serverSink);
|
this._serverChannel = new UnixServerChannel(properties, serverSink);
|
||||||
|
}
|
||||||
|
|
||||||
object val = properties ["name"];
|
Object val = properties ["name"];
|
||||||
if (val != null) _name = val as string;
|
if (val != null) {
|
||||||
|
this._name = val as String;
|
||||||
|
}
|
||||||
|
|
||||||
val = properties ["priority"];
|
val = properties ["priority"];
|
||||||
if (val != null) _priority = Convert.ToInt32 (val);
|
if (val != null) {
|
||||||
}
|
this._priority = Convert.ToInt32 (val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public UnixChannel (IDictionary properties,
|
public UnixChannel(IDictionary properties,
|
||||||
IClientChannelSinkProvider clientSinkProvider,
|
IClientChannelSinkProvider clientSinkProvider,
|
||||||
IServerChannelSinkProvider serverSinkProvider)
|
IServerChannelSinkProvider serverSinkProvider) => this.Init(properties, clientSinkProvider, serverSinkProvider);
|
||||||
|
|
||||||
|
public IMessageSink CreateMessageSink(String url, Object remoteChannelData, out String objectURI) => this._clientChannel.CreateMessageSink(url, remoteChannelData, out objectURI);
|
||||||
|
|
||||||
|
public String ChannelName => this._name;
|
||||||
|
|
||||||
|
public Int32 ChannelPriority => this._priority;
|
||||||
|
|
||||||
|
public void StartListening (Object data)
|
||||||
{
|
{
|
||||||
Init (properties, clientSinkProvider, serverSinkProvider);
|
if (this._serverChannel != null) {
|
||||||
}
|
this._serverChannel.StartListening (data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public IMessageSink CreateMessageSink(string url, object remoteChannelData, out string objectURI)
|
public void StopListening (Object data)
|
||||||
{
|
{
|
||||||
return _clientChannel.CreateMessageSink(url, remoteChannelData, out objectURI);
|
if (this._serverChannel != null) {
|
||||||
}
|
this._serverChannel.StopListening(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public string ChannelName
|
public String[] GetUrlsForUri (String uri)
|
||||||
{
|
{
|
||||||
get { return _name; }
|
if (this._serverChannel != null) {
|
||||||
}
|
return this._serverChannel.GetUrlsForUri(uri);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public int ChannelPriority
|
public Object ChannelData
|
||||||
{
|
|
||||||
get { return _priority; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public void StartListening (object data)
|
|
||||||
{
|
|
||||||
if (_serverChannel != null) _serverChannel.StartListening (data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void StopListening (object data)
|
|
||||||
{
|
|
||||||
if (_serverChannel != null) _serverChannel.StopListening(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public string[] GetUrlsForUri (string uri)
|
|
||||||
{
|
|
||||||
if (_serverChannel != null) return _serverChannel.GetUrlsForUri(uri);
|
|
||||||
else return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public object ChannelData
|
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (_serverChannel != null) return _serverChannel.ChannelData;
|
if (this._serverChannel != null) {
|
||||||
else return null;
|
return this._serverChannel.ChannelData;
|
||||||
}
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Parse (string url, out string objectURI)
|
public String Parse(String url, out String objectURI) => UnixChannel.ParseUnixURL(url, out objectURI);
|
||||||
{
|
|
||||||
return UnixChannel.ParseUnixURL (url, out objectURI);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static string ParseUnixURL (string url, out string objectURI)
|
internal static String ParseUnixURL (String url, out String objectURI)
|
||||||
{
|
{
|
||||||
// format: "unix:///path/to/unix/socket?/path/to/object"
|
// format: "unix:///path/to/unix/socket?/path/to/object"
|
||||||
|
|
||||||
objectURI = null;
|
objectURI = null;
|
||||||
|
|
||||||
if (!url.StartsWith ("unix://")) return null;
|
if (!url.StartsWith ("unix://")) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
int i = url.IndexOf ('?');
|
Int32 i = url.IndexOf ('?');
|
||||||
if (i == -1) return url.Substring (7);
|
if (i == -1) {
|
||||||
|
return url.Substring (7);
|
||||||
|
}
|
||||||
|
|
||||||
objectURI = url.Substring (i+1);
|
objectURI = url.Substring (i+1);
|
||||||
|
|
||||||
if (objectURI.Length == 0)
|
if (objectURI.Length == 0) {
|
||||||
objectURI = null;
|
objectURI = null;
|
||||||
|
}
|
||||||
|
|
||||||
return url.Substring (7, i - 7);
|
return url.Substring (7, i - 7);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,95 +40,94 @@ namespace Mono.Remoting.Channels.Unix
|
|||||||
{
|
{
|
||||||
public class UnixClientChannel : IChannelSender, IChannel
|
public class UnixClientChannel : IChannelSender, IChannel
|
||||||
{
|
{
|
||||||
int priority = 1;
|
Int32 priority = 1;
|
||||||
string name = "unix";
|
String name = "unix";
|
||||||
IClientChannelSinkProvider _sinkProvider;
|
IClientChannelSinkProvider _sinkProvider;
|
||||||
|
|
||||||
public UnixClientChannel ()
|
public UnixClientChannel ()
|
||||||
{
|
{
|
||||||
_sinkProvider = new UnixBinaryClientFormatterSinkProvider ();
|
this._sinkProvider = new UnixBinaryClientFormatterSinkProvider ();
|
||||||
_sinkProvider.Next = new UnixClientTransportSinkProvider ();
|
this._sinkProvider.Next = new UnixClientTransportSinkProvider ();
|
||||||
}
|
}
|
||||||
|
|
||||||
public UnixClientChannel (IDictionary properties, IClientChannelSinkProvider sinkProvider)
|
public UnixClientChannel (IDictionary properties, IClientChannelSinkProvider sinkProvider)
|
||||||
{
|
{
|
||||||
object val = properties ["name"];
|
Object val = properties ["name"];
|
||||||
if (val != null) name = val as string;
|
if (val != null) {
|
||||||
|
this.name = val as String;
|
||||||
|
}
|
||||||
|
|
||||||
val = properties ["priority"];
|
val = properties ["priority"];
|
||||||
if (val != null) priority = Convert.ToInt32 (val);
|
if (val != null) {
|
||||||
|
this.priority = Convert.ToInt32 (val);
|
||||||
|
}
|
||||||
|
|
||||||
if (sinkProvider != null)
|
if (sinkProvider != null)
|
||||||
{
|
{
|
||||||
_sinkProvider = sinkProvider;
|
this._sinkProvider = sinkProvider;
|
||||||
|
|
||||||
// add the unix provider at the end of the chain
|
// add the unix provider at the end of the chain
|
||||||
IClientChannelSinkProvider prov = sinkProvider;
|
IClientChannelSinkProvider prov = sinkProvider;
|
||||||
while (prov.Next != null) prov = prov.Next;
|
while (prov.Next != null) {
|
||||||
prov.Next = new UnixClientTransportSinkProvider ();
|
prov = prov.Next;
|
||||||
|
}
|
||||||
|
|
||||||
|
prov.Next = new UnixClientTransportSinkProvider ();
|
||||||
|
|
||||||
// Note: a default formatter is added only when
|
// Note: a default formatter is added only when
|
||||||
// no sink providers are specified in the config file.
|
// no sink providers are specified in the config file.
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_sinkProvider = new UnixBinaryClientFormatterSinkProvider ();
|
this._sinkProvider = new UnixBinaryClientFormatterSinkProvider ();
|
||||||
_sinkProvider.Next = new UnixClientTransportSinkProvider ();
|
this._sinkProvider.Next = new UnixClientTransportSinkProvider ();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public UnixClientChannel (string name, IClientChannelSinkProvider sinkProvider)
|
public UnixClientChannel (String name, IClientChannelSinkProvider sinkProvider)
|
||||||
{
|
{
|
||||||
this.name = name;
|
this.name = name;
|
||||||
_sinkProvider = sinkProvider;
|
this._sinkProvider = sinkProvider;
|
||||||
|
|
||||||
// add the unix provider at the end of the chain
|
// add the unix provider at the end of the chain
|
||||||
IClientChannelSinkProvider prov = sinkProvider;
|
IClientChannelSinkProvider prov = sinkProvider;
|
||||||
while (prov.Next != null) prov = prov.Next;
|
while (prov.Next != null) {
|
||||||
prov.Next = new UnixClientTransportSinkProvider ();
|
prov = prov.Next;
|
||||||
|
}
|
||||||
|
|
||||||
|
prov.Next = new UnixClientTransportSinkProvider ();
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ChannelName
|
public String ChannelName => this.name;
|
||||||
{
|
|
||||||
get {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int ChannelPriority
|
public Int32 ChannelPriority => this.priority;
|
||||||
{
|
|
||||||
get {
|
|
||||||
return priority;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IMessageSink CreateMessageSink (string url,
|
public IMessageSink CreateMessageSink (String url,
|
||||||
object remoteChannelData,
|
Object remoteChannelData,
|
||||||
out string objectURI)
|
out String objectURI)
|
||||||
{
|
{
|
||||||
if (url != null && Parse (url, out objectURI) != null)
|
if (url != null && this.Parse (url, out objectURI) != null) {
|
||||||
return (IMessageSink) _sinkProvider.CreateSink (this, url, remoteChannelData);
|
return (IMessageSink)this._sinkProvider.CreateSink (this, url, remoteChannelData);
|
||||||
|
}
|
||||||
|
|
||||||
if (remoteChannelData != null) {
|
if (remoteChannelData != null) {
|
||||||
IChannelDataStore ds = remoteChannelData as IChannelDataStore;
|
IChannelDataStore ds = remoteChannelData as IChannelDataStore;
|
||||||
if (ds != null && ds.ChannelUris.Length > 0)
|
if (ds != null && ds.ChannelUris.Length > 0) {
|
||||||
url = ds.ChannelUris [0];
|
url = ds.ChannelUris [0];
|
||||||
else {
|
} else {
|
||||||
objectURI = null;
|
objectURI = null;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Parse (url, out objectURI) == null)
|
if (this.Parse (url, out objectURI) == null) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return (IMessageSink) _sinkProvider.CreateSink (this, url, remoteChannelData);
|
return (IMessageSink)this._sinkProvider.CreateSink (this, url, remoteChannelData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Parse (string url, out string objectURI)
|
public String Parse(String url, out String objectURI) => UnixChannel.ParseUnixURL(url, out objectURI);
|
||||||
{
|
}
|
||||||
return UnixChannel.ParseUnixURL (url, out objectURI);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -38,156 +38,156 @@ using System.Runtime.Remoting;
|
|||||||
|
|
||||||
namespace Mono.Remoting.Channels.Unix
|
namespace Mono.Remoting.Channels.Unix
|
||||||
{
|
{
|
||||||
internal class UnixClientTransportSink : IClientChannelSink
|
internal class UnixClientTransportSink : IClientChannelSink
|
||||||
{
|
{
|
||||||
string _path;
|
String _path;
|
||||||
|
|
||||||
public UnixClientTransportSink (string url)
|
public UnixClientTransportSink (String url)
|
||||||
{
|
{
|
||||||
string objectUri;
|
this._path = UnixChannel.ParseUnixURL(url, out String objectUri);
|
||||||
_path = UnixChannel.ParseUnixURL (url, out objectUri);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public IDictionary Properties
|
public IDictionary Properties => null;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IClientChannelSink NextChannelSink
|
public IClientChannelSink NextChannelSink =>
|
||||||
{
|
// we are the last one
|
||||||
get
|
null;
|
||||||
{
|
|
||||||
// we are the last one
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AsyncProcessRequest (IClientChannelSinkStack sinkStack, IMessage msg,
|
public void AsyncProcessRequest (IClientChannelSinkStack sinkStack, IMessage msg,
|
||||||
ITransportHeaders headers, Stream requestStream)
|
ITransportHeaders headers, Stream requestStream)
|
||||||
{
|
{
|
||||||
UnixConnection connection = null;
|
UnixConnection connection = null;
|
||||||
bool isOneWay = RemotingServices.IsOneWay (((IMethodMessage)msg).MethodBase);
|
Boolean isOneWay = RemotingServices.IsOneWay (((IMethodMessage)msg).MethodBase);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (headers == null) headers = new TransportHeaders();
|
if (headers == null) {
|
||||||
headers ["__RequestUri"] = ((IMethodMessage)msg).Uri;
|
headers = new TransportHeaders();
|
||||||
|
}
|
||||||
|
|
||||||
// Sends the stream using a connection from the pool
|
headers ["__RequestUri"] = ((IMethodMessage)msg).Uri;
|
||||||
// and creates a WorkItem that will wait for the
|
|
||||||
// response of the server
|
|
||||||
|
|
||||||
connection = UnixConnectionPool.GetConnection (_path);
|
// Sends the stream using a connection from the pool
|
||||||
UnixMessageIO.SendMessageStream (connection.Stream, requestStream, headers, connection.Buffer);
|
// and creates a WorkItem that will wait for the
|
||||||
connection.Stream.Flush ();
|
// response of the server
|
||||||
|
|
||||||
if (!isOneWay)
|
connection = UnixConnectionPool.GetConnection (this._path);
|
||||||
{
|
UnixMessageIO.SendMessageStream (connection.Stream, requestStream, headers, connection.Buffer);
|
||||||
sinkStack.Push (this, connection);
|
connection.Stream.Flush ();
|
||||||
ThreadPool.QueueUserWorkItem (new WaitCallback(data => {
|
|
||||||
try {
|
|
||||||
ReadAsyncUnixMessage (data);
|
|
||||||
} catch {}
|
|
||||||
}), sinkStack);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
connection.Release();
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
if (connection != null) connection.Release();
|
|
||||||
if (!isOneWay) throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ReadAsyncUnixMessage(object data)
|
if (!isOneWay)
|
||||||
{
|
{
|
||||||
// This method is called by a new thread to asynchronously
|
sinkStack.Push (this, connection);
|
||||||
// read the response to a request
|
_ = ThreadPool.QueueUserWorkItem(new WaitCallback(data => {
|
||||||
|
try {
|
||||||
|
this.ReadAsyncUnixMessage(data);
|
||||||
|
} catch { }
|
||||||
|
}), sinkStack);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
connection.Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
if (connection != null) {
|
||||||
|
connection.Release();
|
||||||
|
}
|
||||||
|
|
||||||
// The stack was provided as state data in QueueUserWorkItem
|
if (!isOneWay) {
|
||||||
IClientChannelSinkStack stack = (IClientChannelSinkStack)data;
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// The first sink in the stack is this sink. Pop it and
|
private void ReadAsyncUnixMessage(Object data)
|
||||||
// get the status data, which is the UnixConnection used to send
|
{
|
||||||
// the request
|
// This method is called by a new thread to asynchronously
|
||||||
UnixConnection connection = (UnixConnection)stack.Pop(this);
|
// read the response to a request
|
||||||
|
|
||||||
try
|
// The stack was provided as state data in QueueUserWorkItem
|
||||||
{
|
IClientChannelSinkStack stack = (IClientChannelSinkStack)data;
|
||||||
ITransportHeaders responseHeaders;
|
|
||||||
|
|
||||||
// Read the response, blocking if necessary
|
// The first sink in the stack is this sink. Pop it and
|
||||||
MessageStatus status = UnixMessageIO.ReceiveMessageStatus (connection.Stream, connection.Buffer);
|
// get the status data, which is the UnixConnection used to send
|
||||||
|
// the request
|
||||||
|
UnixConnection connection = (UnixConnection)stack.Pop(this);
|
||||||
|
|
||||||
if (status != MessageStatus.MethodMessage)
|
try
|
||||||
throw new RemotingException ("Unknown response message from server");
|
{
|
||||||
|
|
||||||
Stream responseStream = UnixMessageIO.ReceiveMessageStream (connection.Stream, out responseHeaders, connection.Buffer);
|
// Read the response, blocking if necessary
|
||||||
|
MessageStatus status = UnixMessageIO.ReceiveMessageStatus(connection.Stream, connection.Buffer);
|
||||||
|
|
||||||
// Free the connection, so it can be reused
|
if (status != MessageStatus.MethodMessage) {
|
||||||
connection.Release();
|
throw new RemotingException ("Unknown response message from server");
|
||||||
connection = null;
|
}
|
||||||
|
|
||||||
// Ok, proceed with the other sinks
|
Stream responseStream = UnixMessageIO.ReceiveMessageStream (connection.Stream, out ITransportHeaders responseHeaders, connection.Buffer);
|
||||||
stack.AsyncProcessResponse (responseHeaders, responseStream);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
if (connection != null) connection.Release();
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AsyncProcessResponse (IClientResponseChannelSinkStack sinkStack,
|
// Free the connection, so it can be reused
|
||||||
object state, ITransportHeaders headers,
|
connection.Release();
|
||||||
Stream stream)
|
connection = null;
|
||||||
{
|
|
||||||
// Should never be called
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Stream GetRequestStream (IMessage msg, ITransportHeaders headers)
|
// Ok, proceed with the other sinks
|
||||||
{
|
stack.AsyncProcessResponse (responseHeaders, responseStream);
|
||||||
return null;
|
}
|
||||||
}
|
catch
|
||||||
|
{
|
||||||
|
if (connection != null) {
|
||||||
|
connection.Release();
|
||||||
|
}
|
||||||
|
|
||||||
public void ProcessMessage (IMessage msg,
|
throw;
|
||||||
ITransportHeaders requestHeaders,
|
}
|
||||||
Stream requestStream,
|
}
|
||||||
out ITransportHeaders responseHeaders,
|
|
||||||
out Stream responseStream)
|
|
||||||
{
|
|
||||||
UnixConnection connection = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (requestHeaders == null) requestHeaders = new TransportHeaders();
|
|
||||||
requestHeaders ["__RequestUri"] = ((IMethodMessage)msg).Uri;
|
|
||||||
|
|
||||||
// Sends the message
|
public void AsyncProcessResponse(IClientResponseChannelSinkStack sinkStack,
|
||||||
connection = UnixConnectionPool.GetConnection (_path);
|
Object state, ITransportHeaders headers,
|
||||||
UnixMessageIO.SendMessageStream (connection.Stream, requestStream, requestHeaders, connection.Buffer);
|
Stream stream) =>
|
||||||
connection.Stream.Flush ();
|
// Should never be called
|
||||||
|
throw new NotSupportedException();
|
||||||
|
|
||||||
// Reads the response
|
public Stream GetRequestStream(IMessage msg, ITransportHeaders headers) => null;
|
||||||
MessageStatus status = UnixMessageIO.ReceiveMessageStatus (connection.Stream, connection.Buffer);
|
|
||||||
|
|
||||||
if (status != MessageStatus.MethodMessage)
|
public void ProcessMessage (IMessage msg,
|
||||||
throw new RemotingException ("Unknown response message from server");
|
ITransportHeaders requestHeaders,
|
||||||
|
Stream requestStream,
|
||||||
|
out ITransportHeaders responseHeaders,
|
||||||
|
out Stream responseStream)
|
||||||
|
{
|
||||||
|
UnixConnection connection = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (requestHeaders == null) {
|
||||||
|
requestHeaders = new TransportHeaders();
|
||||||
|
}
|
||||||
|
|
||||||
responseStream = UnixMessageIO.ReceiveMessageStream (connection.Stream, out responseHeaders, connection.Buffer);
|
requestHeaders ["__RequestUri"] = ((IMethodMessage)msg).Uri;
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (connection != null)
|
|
||||||
connection.Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
// Sends the message
|
||||||
|
connection = UnixConnectionPool.GetConnection (this._path);
|
||||||
|
UnixMessageIO.SendMessageStream (connection.Stream, requestStream, requestHeaders, connection.Buffer);
|
||||||
|
connection.Stream.Flush ();
|
||||||
|
|
||||||
|
// Reads the response
|
||||||
|
MessageStatus status = UnixMessageIO.ReceiveMessageStatus (connection.Stream, connection.Buffer);
|
||||||
|
|
||||||
|
if (status != MessageStatus.MethodMessage) {
|
||||||
|
throw new RemotingException ("Unknown response message from server");
|
||||||
|
}
|
||||||
|
|
||||||
|
responseStream = UnixMessageIO.ReceiveMessageStream (connection.Stream, out responseHeaders, connection.Buffer);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (connection != null) {
|
||||||
|
connection.Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -40,23 +40,15 @@ namespace Mono.Remoting.Channels.Unix
|
|||||||
// what should we do here ?
|
// what should we do here ?
|
||||||
}
|
}
|
||||||
|
|
||||||
public IClientChannelSinkProvider Next
|
public IClientChannelSinkProvider Next {
|
||||||
{
|
get => null;
|
||||||
get
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
set {
|
||||||
{
|
// ignore, we are always the last in the chain
|
||||||
// ignore, we are always the last in the chain
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IClientChannelSink CreateSink (IChannelSender channel, string url,
|
|
||||||
object remoteChannelData)
|
|
||||||
{
|
|
||||||
return new UnixClientTransportSink (url);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IClientChannelSink CreateSink(IChannelSender channel, String url,
|
||||||
|
Object remoteChannelData) => new UnixClientTransportSink(url);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,275 +37,254 @@ using Mono.Unix;
|
|||||||
|
|
||||||
namespace Mono.Remoting.Channels.Unix
|
namespace Mono.Remoting.Channels.Unix
|
||||||
{
|
{
|
||||||
// This is a pool of Unix connections. Connections requested
|
// This is a pool of Unix connections. Connections requested
|
||||||
// by the TCP channel are pooled after their use, and can
|
// by the TCP channel are pooled after their use, and can
|
||||||
// be reused later. Connections are automaticaly closed
|
// be reused later. Connections are automaticaly closed
|
||||||
// if not used after some time, specified in KeepAliveSeconds.
|
// if not used after some time, specified in KeepAliveSeconds.
|
||||||
// The number of allowed open connections can also be specified
|
// The number of allowed open connections can also be specified
|
||||||
// in MaxOpenConnections. The limit is per host.
|
// in MaxOpenConnections. The limit is per host.
|
||||||
// If a thread requests a connection and the limit has been
|
// If a thread requests a connection and the limit has been
|
||||||
// reached, the thread is suspended until one is released.
|
// reached, the thread is suspended until one is released.
|
||||||
|
|
||||||
internal class UnixConnectionPool
|
internal class UnixConnectionPool
|
||||||
{
|
{
|
||||||
// Table of pools. There is a HostConnectionPool
|
// Table of pools. There is a HostConnectionPool
|
||||||
// instance for each host
|
// instance for each host
|
||||||
static Hashtable _pools = new Hashtable();
|
static Hashtable _pools = new Hashtable();
|
||||||
|
|
||||||
static int _maxOpenConnections = int.MaxValue;
|
static Int32 _maxOpenConnections = Int32.MaxValue;
|
||||||
static int _keepAliveSeconds = 15;
|
static Int32 _keepAliveSeconds = 15;
|
||||||
|
|
||||||
static Thread _poolThread;
|
static Thread _poolThread;
|
||||||
|
|
||||||
static UnixConnectionPool()
|
static UnixConnectionPool()
|
||||||
{
|
{
|
||||||
// This thread will close unused connections
|
// This thread will close unused connections
|
||||||
_poolThread = new Thread (new ThreadStart (ConnectionCollector));
|
_poolThread = new Thread (new ThreadStart (ConnectionCollector));
|
||||||
_poolThread.Start();
|
_poolThread.Start();
|
||||||
_poolThread.IsBackground = true;
|
_poolThread.IsBackground = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Shutdown ()
|
public static void Shutdown ()
|
||||||
{
|
{
|
||||||
if (_poolThread != null)
|
if (_poolThread != null) {
|
||||||
_poolThread.Abort();
|
_poolThread.Abort();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static int MaxOpenConnections
|
public static Int32 MaxOpenConnections {
|
||||||
{
|
get => _maxOpenConnections;
|
||||||
get { return _maxOpenConnections; }
|
set {
|
||||||
set
|
if(value < 1) {
|
||||||
{
|
throw new RemotingException("MaxOpenConnections must be greater than zero");
|
||||||
if (value < 1) throw new RemotingException ("MaxOpenConnections must be greater than zero");
|
}
|
||||||
_maxOpenConnections = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int KeepAliveSeconds
|
_maxOpenConnections = value;
|
||||||
{
|
}
|
||||||
get { return _keepAliveSeconds; }
|
}
|
||||||
set { _keepAliveSeconds = value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UnixConnection GetConnection (string path)
|
public static Int32 KeepAliveSeconds {
|
||||||
{
|
get => _keepAliveSeconds;
|
||||||
HostConnectionPool hostPool;
|
set => _keepAliveSeconds = value;
|
||||||
|
}
|
||||||
|
|
||||||
lock (_pools)
|
public static UnixConnection GetConnection (String path)
|
||||||
{
|
{
|
||||||
hostPool = (HostConnectionPool) _pools[path];
|
HostConnectionPool hostPool;
|
||||||
if (hostPool == null)
|
|
||||||
{
|
|
||||||
hostPool = new HostConnectionPool(path);
|
|
||||||
_pools[path] = hostPool;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return hostPool.GetConnection();
|
lock (_pools)
|
||||||
}
|
{
|
||||||
|
hostPool = (HostConnectionPool) _pools[path];
|
||||||
|
if (hostPool == null)
|
||||||
|
{
|
||||||
|
hostPool = new HostConnectionPool(path);
|
||||||
|
_pools[path] = hostPool;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void ConnectionCollector ()
|
return hostPool.GetConnection();
|
||||||
{
|
}
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
Thread.Sleep(3000);
|
|
||||||
lock (_pools)
|
|
||||||
{
|
|
||||||
ICollection values = _pools.Values;
|
|
||||||
foreach (HostConnectionPool pool in values)
|
|
||||||
pool.PurgeConnections();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class ReusableUnixClient : UnixClient
|
private static void ConnectionCollector ()
|
||||||
{
|
{
|
||||||
public ReusableUnixClient (string path): base (path)
|
while (true)
|
||||||
{
|
{
|
||||||
}
|
Thread.Sleep(3000);
|
||||||
|
lock (_pools)
|
||||||
|
{
|
||||||
|
ICollection values = _pools.Values;
|
||||||
|
foreach (HostConnectionPool pool in values) {
|
||||||
|
pool.PurgeConnections();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool IsAlive
|
internal class ReusableUnixClient : UnixClient
|
||||||
{
|
{
|
||||||
get
|
public ReusableUnixClient (String path): base (path)
|
||||||
{
|
{
|
||||||
// This Poll will return true if there is data pending to
|
}
|
||||||
// be read. It prob. means that a client object using this
|
|
||||||
// connection got an exception and did not finish to read
|
|
||||||
// the data. It can also mean that the connection has been
|
|
||||||
// closed in the server. In both cases, the connection cannot
|
|
||||||
// be reused.
|
|
||||||
return !Client.Poll (0, SelectMode.SelectRead);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class UnixConnection
|
public Boolean IsAlive =>
|
||||||
{
|
// This Poll will return true if there is data pending to
|
||||||
DateTime _controlTime;
|
// be read. It prob. means that a client object using this
|
||||||
Stream _stream;
|
// connection got an exception and did not finish to read
|
||||||
ReusableUnixClient _client;
|
// the data. It can also mean that the connection has been
|
||||||
HostConnectionPool _pool;
|
// closed in the server. In both cases, the connection cannot
|
||||||
byte[] _buffer;
|
// be reused.
|
||||||
|
!this.Client.Poll(0, SelectMode.SelectRead);
|
||||||
|
}
|
||||||
|
|
||||||
public UnixConnection (HostConnectionPool pool, ReusableUnixClient client)
|
internal class UnixConnection
|
||||||
{
|
{
|
||||||
_pool = pool;
|
DateTime _controlTime;
|
||||||
_client = client;
|
Stream _stream;
|
||||||
_stream = new BufferedStream (client.GetStream());
|
ReusableUnixClient _client;
|
||||||
_controlTime = DateTime.UtcNow;
|
HostConnectionPool _pool;
|
||||||
_buffer = new byte[UnixMessageIO.DefaultStreamBufferSize];
|
Byte[] _buffer;
|
||||||
}
|
|
||||||
|
|
||||||
public Stream Stream
|
public UnixConnection (HostConnectionPool pool, ReusableUnixClient client)
|
||||||
{
|
{
|
||||||
get { return _stream; }
|
this._pool = pool;
|
||||||
}
|
this._client = client;
|
||||||
|
this._stream = new BufferedStream (client.GetStream());
|
||||||
|
this._controlTime = DateTime.UtcNow;
|
||||||
|
this._buffer = new Byte[UnixMessageIO.DefaultStreamBufferSize];
|
||||||
|
}
|
||||||
|
|
||||||
public DateTime ControlTime
|
public Stream Stream => this._stream;
|
||||||
{
|
|
||||||
get { return _controlTime; }
|
|
||||||
set { _controlTime = value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsAlive
|
public DateTime ControlTime {
|
||||||
{
|
get => this._controlTime;
|
||||||
get { return _client.IsAlive; }
|
set => this._controlTime = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a "thread safe" buffer that can be used by
|
public Boolean IsAlive => this._client.IsAlive;
|
||||||
// UnixClientTransportSink to read or send data to the stream.
|
|
||||||
// The buffer is "thread safe" since only one thread can
|
|
||||||
// use a connection at a given time.
|
|
||||||
public byte[] Buffer
|
|
||||||
{
|
|
||||||
get { return _buffer; }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the connection to the pool
|
// This is a "thread safe" buffer that can be used by
|
||||||
public void Release()
|
// UnixClientTransportSink to read or send data to the stream.
|
||||||
{
|
// The buffer is "thread safe" since only one thread can
|
||||||
_pool.ReleaseConnection (this);
|
// use a connection at a given time.
|
||||||
}
|
public Byte[] Buffer => this._buffer;
|
||||||
|
|
||||||
public void Close()
|
// Returns the connection to the pool
|
||||||
{
|
public void Release() => this._pool.ReleaseConnection(this);
|
||||||
_client.Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class HostConnectionPool
|
public void Close() => this._client.Close();
|
||||||
{
|
}
|
||||||
ArrayList _pool = new ArrayList();
|
|
||||||
int _activeConnections = 0;
|
|
||||||
|
|
||||||
string _path;
|
internal class HostConnectionPool
|
||||||
|
{
|
||||||
|
ArrayList _pool = new ArrayList();
|
||||||
|
Int32 _activeConnections = 0;
|
||||||
|
|
||||||
public HostConnectionPool (string path)
|
String _path;
|
||||||
{
|
|
||||||
_path = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnixConnection GetConnection ()
|
public HostConnectionPool(String path) => this._path = path;
|
||||||
{
|
|
||||||
UnixConnection connection = null;
|
|
||||||
lock (_pool)
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
if (_pool.Count > 0)
|
|
||||||
{
|
|
||||||
// There are available connections
|
|
||||||
|
|
||||||
connection = (UnixConnection)_pool[_pool.Count - 1];
|
public UnixConnection GetConnection ()
|
||||||
_pool.RemoveAt(_pool.Count - 1);
|
{
|
||||||
if (!connection.IsAlive) {
|
UnixConnection connection = null;
|
||||||
CancelConnection (connection);
|
lock (this._pool)
|
||||||
connection = null;
|
{
|
||||||
continue;
|
do
|
||||||
}
|
{
|
||||||
}
|
if (this._pool.Count > 0)
|
||||||
|
{
|
||||||
|
// There are available connections
|
||||||
|
|
||||||
if (connection == null && _activeConnections < UnixConnectionPool.MaxOpenConnections)
|
connection = (UnixConnection)this._pool[this._pool.Count - 1];
|
||||||
{
|
this._pool.RemoveAt(this._pool.Count - 1);
|
||||||
// No connections available, but the max connections
|
if (!connection.IsAlive) {
|
||||||
// has not been reached yet, so a new one can be created
|
this.CancelConnection (connection);
|
||||||
// Create the connection outside the lock
|
connection = null;
|
||||||
break;
|
continue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// No available connections in the pool
|
if (connection == null && this._activeConnections < UnixConnectionPool.MaxOpenConnections)
|
||||||
// Wait for somewone to release one.
|
{
|
||||||
|
// No connections available, but the max connections
|
||||||
|
// has not been reached yet, so a new one can be created
|
||||||
|
// Create the connection outside the lock
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (connection == null)
|
// No available connections in the pool
|
||||||
{
|
// Wait for somewone to release one.
|
||||||
Monitor.Wait(_pool);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (connection == null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (connection == null)
|
if (connection == null)
|
||||||
return CreateConnection ();
|
{
|
||||||
else
|
_ = Monitor.Wait(this._pool);
|
||||||
return connection;
|
}
|
||||||
}
|
}
|
||||||
|
while (connection == null);
|
||||||
|
}
|
||||||
|
|
||||||
private UnixConnection CreateConnection()
|
if (connection == null) {
|
||||||
{
|
return this.CreateConnection ();
|
||||||
try
|
} else {
|
||||||
{
|
return connection;
|
||||||
ReusableUnixClient client = new ReusableUnixClient (_path);
|
}
|
||||||
UnixConnection entry = new UnixConnection(this, client);
|
}
|
||||||
_activeConnections++;
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
throw new RemotingException (ex.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ReleaseConnection (UnixConnection entry)
|
private UnixConnection CreateConnection()
|
||||||
{
|
{
|
||||||
lock (_pool)
|
try
|
||||||
{
|
{
|
||||||
entry.ControlTime = DateTime.UtcNow; // Initialize timeout
|
ReusableUnixClient client = new ReusableUnixClient (this._path);
|
||||||
_pool.Add (entry);
|
UnixConnection entry = new UnixConnection(this, client);
|
||||||
Monitor.Pulse (_pool);
|
this._activeConnections++;
|
||||||
}
|
return entry;
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new RemotingException (ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void CancelConnection(UnixConnection entry)
|
public void ReleaseConnection (UnixConnection entry)
|
||||||
{
|
{
|
||||||
try
|
lock (this._pool)
|
||||||
{
|
{
|
||||||
entry.Stream.Close();
|
entry.ControlTime = DateTime.UtcNow; // Initialize timeout
|
||||||
_activeConnections--;
|
_ = this._pool.Add(entry);
|
||||||
}
|
Monitor.Pulse (this._pool);
|
||||||
catch
|
}
|
||||||
{
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PurgeConnections()
|
private void CancelConnection(UnixConnection entry)
|
||||||
{
|
{
|
||||||
lock (_pool)
|
try
|
||||||
{
|
{
|
||||||
for (int n=0; n < _pool.Count; n++)
|
entry.Stream.Close();
|
||||||
{
|
this._activeConnections--;
|
||||||
UnixConnection entry = (UnixConnection)_pool[n];
|
}
|
||||||
if ( (DateTime.UtcNow - entry.ControlTime).TotalSeconds > UnixConnectionPool.KeepAliveSeconds)
|
catch
|
||||||
{
|
{
|
||||||
CancelConnection (entry);
|
}
|
||||||
_pool.RemoveAt(n);
|
}
|
||||||
n--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
public void PurgeConnections()
|
||||||
|
{
|
||||||
|
lock (this._pool)
|
||||||
|
{
|
||||||
|
for (Int32 n =0; n < this._pool.Count; n++)
|
||||||
|
{
|
||||||
|
UnixConnection entry = (UnixConnection)this._pool[n];
|
||||||
|
if ( (DateTime.UtcNow - entry.ControlTime).TotalSeconds > UnixConnectionPool.KeepAliveSeconds)
|
||||||
|
{
|
||||||
|
this.CancelConnection (entry);
|
||||||
|
this._pool.RemoveAt(n);
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -38,246 +38,265 @@ using System.Runtime.Remoting;
|
|||||||
|
|
||||||
namespace Mono.Remoting.Channels.Unix
|
namespace Mono.Remoting.Channels.Unix
|
||||||
{
|
{
|
||||||
enum MessageStatus { MethodMessage = 0, CancelSignal = 1, Unknown = 10}
|
enum MessageStatus { MethodMessage = 0, CancelSignal = 1, Unknown = 10}
|
||||||
|
|
||||||
internal class UnixMessageIO
|
internal class UnixMessageIO
|
||||||
{
|
{
|
||||||
static byte[][] _msgHeaders =
|
static Byte[][] _msgHeaders =
|
||||||
{
|
{
|
||||||
new byte[] { (byte)'.', (byte)'N', (byte)'E', (byte)'T', 1, 0 },
|
new Byte[] { (Byte)'.', (Byte)'N', (Byte)'E', (Byte)'T', 1, 0 },
|
||||||
new byte[] { 255, 255, 255, 255, 255, 255 }
|
new Byte[] { 255, 255, 255, 255, 255, 255 }
|
||||||
};
|
};
|
||||||
|
|
||||||
public static int DefaultStreamBufferSize = 1000;
|
public static Int32 DefaultStreamBufferSize = 1000;
|
||||||
|
|
||||||
// Identifies an incoming message
|
// Identifies an incoming message
|
||||||
public static MessageStatus ReceiveMessageStatus (Stream networkStream, byte[] buffer)
|
public static MessageStatus ReceiveMessageStatus (Stream networkStream, Byte[] buffer)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
StreamRead (networkStream, buffer, 6);
|
_ = StreamRead(networkStream, buffer, 6);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
throw new RemotingException ("Unix transport error.", ex);
|
throw new RemotingException ("Unix transport error.", ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
bool[] isOnTrack = new bool[_msgHeaders.Length];
|
Boolean[] isOnTrack = new Boolean[_msgHeaders.Length];
|
||||||
bool atLeastOneOnTrack = true;
|
Boolean atLeastOneOnTrack = true;
|
||||||
int i = 0;
|
Int32 i = 0;
|
||||||
|
|
||||||
while (atLeastOneOnTrack)
|
while (atLeastOneOnTrack)
|
||||||
{
|
{
|
||||||
atLeastOneOnTrack = false;
|
atLeastOneOnTrack = false;
|
||||||
byte c = buffer [i];
|
Byte c = buffer [i];
|
||||||
for (int n = 0; n<_msgHeaders.Length; n++)
|
for (Int32 n = 0; n<_msgHeaders.Length; n++)
|
||||||
{
|
{
|
||||||
if (i > 0 && !isOnTrack[n]) continue;
|
if (i > 0 && !isOnTrack[n]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
isOnTrack[n] = (c == _msgHeaders[n][i]);
|
isOnTrack[n] = c == _msgHeaders[n][i];
|
||||||
if (isOnTrack[n] && (i == _msgHeaders[n].Length-1)) return (MessageStatus) n;
|
if (isOnTrack[n] && i == _msgHeaders[n].Length-1) {
|
||||||
atLeastOneOnTrack = atLeastOneOnTrack || isOnTrack[n];
|
return (MessageStatus) n;
|
||||||
}
|
}
|
||||||
i++;
|
|
||||||
}
|
|
||||||
return MessageStatus.Unknown;
|
|
||||||
}
|
|
||||||
catch (Exception ex) {
|
|
||||||
throw new RemotingException ("Unix transport error.", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool StreamRead (Stream networkStream, byte[] buffer, int count)
|
atLeastOneOnTrack = atLeastOneOnTrack || isOnTrack[n];
|
||||||
{
|
}
|
||||||
int nr = 0;
|
i++;
|
||||||
do {
|
}
|
||||||
int pr = networkStream.Read (buffer, nr, count - nr);
|
return MessageStatus.Unknown;
|
||||||
if (pr == 0)
|
}
|
||||||
throw new RemotingException ("Connection closed");
|
catch (Exception ex) {
|
||||||
nr += pr;
|
throw new RemotingException ("Unix transport error.", ex);
|
||||||
} while (nr < count);
|
}
|
||||||
return true;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public static void SendMessageStream (Stream networkStream, Stream data, ITransportHeaders requestHeaders, byte[] buffer)
|
static Boolean StreamRead (Stream networkStream, Byte[] buffer, Int32 count)
|
||||||
{
|
{
|
||||||
if (buffer == null) buffer = new byte[DefaultStreamBufferSize];
|
Int32 nr = 0;
|
||||||
|
do {
|
||||||
|
Int32 pr = networkStream.Read (buffer, nr, count - nr);
|
||||||
|
if (pr == 0) {
|
||||||
|
throw new RemotingException ("Connection closed");
|
||||||
|
}
|
||||||
|
|
||||||
// Writes the message start header
|
nr += pr;
|
||||||
byte[] dotnetHeader = _msgHeaders[(int) MessageStatus.MethodMessage];
|
} while (nr < count);
|
||||||
networkStream.Write(dotnetHeader, 0, dotnetHeader.Length);
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Writes header tag (0x0000 if request stream, 0x0002 if response stream)
|
public static void SendMessageStream (Stream networkStream, Stream data, ITransportHeaders requestHeaders, Byte[] buffer)
|
||||||
if(requestHeaders["__RequestUri"]!=null) buffer [0] = (byte) 0;
|
{
|
||||||
else buffer[0] = (byte) 2;
|
if (buffer == null) {
|
||||||
buffer [1] = (byte) 0 ;
|
buffer = new Byte[DefaultStreamBufferSize];
|
||||||
|
}
|
||||||
|
|
||||||
// Writes ID
|
// Writes the message start header
|
||||||
buffer [2] = (byte) 0;
|
Byte[] dotnetHeader = _msgHeaders[(Int32) MessageStatus.MethodMessage];
|
||||||
|
networkStream.Write(dotnetHeader, 0, dotnetHeader.Length);
|
||||||
|
|
||||||
// Writes assemblyID????
|
// Writes header tag (0x0000 if request stream, 0x0002 if response stream)
|
||||||
buffer [3] = (byte) 0;
|
if(requestHeaders["__RequestUri"]!=null) {
|
||||||
|
buffer [0] = (Byte) 0;
|
||||||
|
} else {
|
||||||
|
buffer[0] = (Byte) 2;
|
||||||
|
}
|
||||||
|
|
||||||
// Writes the length of the stream being sent (not including the headers)
|
buffer [1] = (Byte) 0 ;
|
||||||
int num = (int)data.Length;
|
|
||||||
buffer [4] = (byte) num;
|
|
||||||
buffer [5] = (byte) (num >> 8);
|
|
||||||
buffer [6] = (byte) (num >> 16);
|
|
||||||
buffer [7] = (byte) (num >> 24);
|
|
||||||
networkStream.Write(buffer, 0, 8);
|
|
||||||
|
|
||||||
// Writes the message headers
|
// Writes ID
|
||||||
SendHeaders (networkStream, requestHeaders, buffer);
|
buffer [2] = (Byte) 0;
|
||||||
|
|
||||||
// Writes the stream
|
// Writes assemblyID????
|
||||||
if (data is MemoryStream)
|
buffer [3] = (Byte) 0;
|
||||||
{
|
|
||||||
// The copy of the stream can be optimized. The internal
|
|
||||||
// buffer of MemoryStream can be used.
|
|
||||||
MemoryStream memStream = (MemoryStream)data;
|
|
||||||
networkStream.Write (memStream.GetBuffer(), 0, (int)memStream.Length);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int nread = data.Read (buffer, 0, buffer.Length);
|
|
||||||
while (nread > 0)
|
|
||||||
{
|
|
||||||
networkStream.Write (buffer, 0, nread);
|
|
||||||
nread = data.Read (buffer, 0, buffer.Length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static byte[] msgUriTransportKey = new byte[] { 4, 0, 1, 1 };
|
// Writes the length of the stream being sent (not including the headers)
|
||||||
static byte[] msgContentTypeTransportKey = new byte[] { 6, 0, 1, 1 };
|
Int32 num = (Int32)data.Length;
|
||||||
static byte[] msgDefaultTransportKey = new byte[] { 1, 0, 1 };
|
buffer [4] = (Byte) num;
|
||||||
static byte[] msgHeaderTerminator = new byte[] { 0, 0 };
|
buffer [5] = (Byte) (num >> 8);
|
||||||
|
buffer [6] = (Byte) (num >> 16);
|
||||||
|
buffer [7] = (Byte) (num >> 24);
|
||||||
|
networkStream.Write(buffer, 0, 8);
|
||||||
|
|
||||||
private static void SendHeaders(Stream networkStream, ITransportHeaders requestHeaders, byte[] buffer)
|
// Writes the message headers
|
||||||
{
|
SendHeaders (networkStream, requestHeaders, buffer);
|
||||||
// Writes the headers as a sequence of strings
|
|
||||||
if (networkStream != null)
|
|
||||||
{
|
|
||||||
IEnumerator e = requestHeaders.GetEnumerator();
|
|
||||||
while (e.MoveNext())
|
|
||||||
{
|
|
||||||
DictionaryEntry hdr = (DictionaryEntry)e.Current;
|
|
||||||
switch (hdr.Key.ToString())
|
|
||||||
{
|
|
||||||
case "__RequestUri":
|
|
||||||
networkStream.Write (msgUriTransportKey, 0, 4);
|
|
||||||
break;
|
|
||||||
case "Content-Type":
|
|
||||||
networkStream.Write (msgContentTypeTransportKey, 0, 4);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
networkStream.Write (msgDefaultTransportKey, 0, 3);
|
|
||||||
SendString (networkStream, hdr.Key.ToString(), buffer);
|
|
||||||
networkStream.WriteByte (1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
SendString (networkStream, hdr.Value.ToString(), buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
networkStream.Write (msgHeaderTerminator, 0, 2); // End of headers
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ITransportHeaders ReceiveHeaders (Stream networkStream, byte[] buffer)
|
// Writes the stream
|
||||||
{
|
if (data is MemoryStream)
|
||||||
StreamRead (networkStream, buffer, 2);
|
{
|
||||||
|
// The copy of the stream can be optimized. The internal
|
||||||
|
// buffer of MemoryStream can be used.
|
||||||
|
MemoryStream memStream = (MemoryStream)data;
|
||||||
|
networkStream.Write (memStream.GetBuffer(), 0, (Int32)memStream.Length);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Int32 nread = data.Read (buffer, 0, buffer.Length);
|
||||||
|
while (nread > 0)
|
||||||
|
{
|
||||||
|
networkStream.Write (buffer, 0, nread);
|
||||||
|
nread = data.Read (buffer, 0, buffer.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
byte headerType = buffer [0];
|
static Byte[] msgUriTransportKey = new Byte[] { 4, 0, 1, 1 };
|
||||||
TransportHeaders headers = new TransportHeaders ();
|
static Byte[] msgContentTypeTransportKey = new Byte[] { 6, 0, 1, 1 };
|
||||||
|
static Byte[] msgDefaultTransportKey = new Byte[] { 1, 0, 1 };
|
||||||
|
static Byte[] msgHeaderTerminator = new Byte[] { 0, 0 };
|
||||||
|
|
||||||
while (headerType != 0)
|
private static void SendHeaders(Stream networkStream, ITransportHeaders requestHeaders, Byte[] buffer)
|
||||||
{
|
{
|
||||||
string key;
|
// Writes the headers as a sequence of strings
|
||||||
StreamRead (networkStream, buffer, 1); // byte 1
|
if (networkStream != null)
|
||||||
switch (headerType)
|
{
|
||||||
{
|
IEnumerator e = requestHeaders.GetEnumerator();
|
||||||
case 4: key = "__RequestUri"; break;
|
while (e.MoveNext())
|
||||||
case 6: key = "Content-Type"; break;
|
{
|
||||||
case 1: key = ReceiveString (networkStream, buffer); break;
|
DictionaryEntry hdr = (DictionaryEntry)e.Current;
|
||||||
default: throw new NotSupportedException ("Unknown header code: " + headerType);
|
switch (hdr.Key.ToString())
|
||||||
}
|
{
|
||||||
StreamRead (networkStream, buffer, 1); // byte 1
|
case "__RequestUri":
|
||||||
headers[key] = ReceiveString (networkStream, buffer);
|
networkStream.Write (msgUriTransportKey, 0, 4);
|
||||||
|
break;
|
||||||
|
case "Content-Type":
|
||||||
|
networkStream.Write (msgContentTypeTransportKey, 0, 4);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
networkStream.Write (msgDefaultTransportKey, 0, 3);
|
||||||
|
SendString (networkStream, hdr.Key.ToString(), buffer);
|
||||||
|
networkStream.WriteByte (1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
SendString (networkStream, hdr.Value.ToString(), buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
networkStream.Write (msgHeaderTerminator, 0, 2); // End of headers
|
||||||
|
}
|
||||||
|
|
||||||
StreamRead (networkStream, buffer, 2);
|
public static ITransportHeaders ReceiveHeaders (Stream networkStream, Byte[] buffer)
|
||||||
headerType = buffer [0];
|
{
|
||||||
}
|
_ = StreamRead(networkStream, buffer, 2);
|
||||||
|
|
||||||
return headers;
|
Byte headerType = buffer [0];
|
||||||
}
|
TransportHeaders headers = new TransportHeaders ();
|
||||||
|
|
||||||
public static Stream ReceiveMessageStream (Stream networkStream, out ITransportHeaders headers, byte[] buffer)
|
while (headerType != 0)
|
||||||
{
|
{
|
||||||
headers = null;
|
String key;
|
||||||
|
_ = StreamRead(networkStream, buffer, 1); // byte 1
|
||||||
|
switch (headerType)
|
||||||
|
{
|
||||||
|
case 4: key = "__RequestUri"; break;
|
||||||
|
case 6: key = "Content-Type"; break;
|
||||||
|
case 1: key = ReceiveString (networkStream, buffer); break;
|
||||||
|
default: throw new NotSupportedException ("Unknown header code: " + headerType);
|
||||||
|
}
|
||||||
|
_ = StreamRead(networkStream, buffer, 1); // byte 1
|
||||||
|
headers[key] = ReceiveString (networkStream, buffer);
|
||||||
|
|
||||||
if (buffer == null) buffer = new byte[DefaultStreamBufferSize];
|
_ = StreamRead(networkStream, buffer, 2);
|
||||||
|
headerType = buffer [0];
|
||||||
|
}
|
||||||
|
|
||||||
// Reads header tag: 0 -> Stream with headers or 2 -> Response Stream
|
return headers;
|
||||||
// +
|
}
|
||||||
// Gets the length of the data stream
|
|
||||||
StreamRead (networkStream, buffer, 8);
|
|
||||||
|
|
||||||
int byteCount = (buffer [4] | (buffer [5] << 8) |
|
public static Stream ReceiveMessageStream (Stream networkStream, out ITransportHeaders headers, Byte[] buffer)
|
||||||
(buffer [6] << 16) | (buffer [7] << 24));
|
{
|
||||||
|
headers = null;
|
||||||
|
|
||||||
// Reads the headers
|
if (buffer == null) {
|
||||||
headers = ReceiveHeaders (networkStream, buffer);
|
buffer = new Byte[DefaultStreamBufferSize];
|
||||||
|
}
|
||||||
|
|
||||||
byte[] resultBuffer = new byte[byteCount];
|
// Reads header tag: 0 -> Stream with headers or 2 -> Response Stream
|
||||||
StreamRead (networkStream, resultBuffer, byteCount);
|
// +
|
||||||
|
// Gets the length of the data stream
|
||||||
|
_ = StreamRead(networkStream, buffer, 8);
|
||||||
|
|
||||||
return new MemoryStream (resultBuffer);
|
Int32 byteCount = buffer [4] | (buffer [5] << 8) |
|
||||||
}
|
(buffer [6] << 16) | (buffer [7] << 24);
|
||||||
|
|
||||||
private static void SendString (Stream networkStream, string str, byte[] buffer)
|
// Reads the headers
|
||||||
{
|
headers = ReceiveHeaders (networkStream, buffer);
|
||||||
// Allocates a buffer. Use the internal buffer if it is
|
|
||||||
// big enough. If not, create a new one.
|
|
||||||
|
|
||||||
int maxBytes = Encoding.UTF8.GetMaxByteCount(str.Length)+4; //+4 bytes for storing the string length
|
Byte[] resultBuffer = new Byte[byteCount];
|
||||||
if (maxBytes > buffer.Length)
|
_ = StreamRead(networkStream, resultBuffer, byteCount);
|
||||||
buffer = new byte[maxBytes];
|
|
||||||
|
|
||||||
int num = Encoding.UTF8.GetBytes (str, 0, str.Length, buffer, 4);
|
return new MemoryStream (resultBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
// store number of bytes (not number of chars!)
|
private static void SendString (Stream networkStream, String str, Byte[] buffer)
|
||||||
|
{
|
||||||
|
// Allocates a buffer. Use the internal buffer if it is
|
||||||
|
// big enough. If not, create a new one.
|
||||||
|
|
||||||
buffer [0] = (byte) num;
|
Int32 maxBytes = Encoding.UTF8.GetMaxByteCount(str.Length)+4; //+4 bytes for storing the string length
|
||||||
buffer [1] = (byte) (num >> 8);
|
if (maxBytes > buffer.Length) {
|
||||||
buffer [2] = (byte) (num >> 16);
|
buffer = new Byte[maxBytes];
|
||||||
buffer [3] = (byte) (num >> 24);
|
}
|
||||||
|
|
||||||
// Write the string bytes
|
Int32 num = Encoding.UTF8.GetBytes (str, 0, str.Length, buffer, 4);
|
||||||
networkStream.Write (buffer, 0, num + 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string ReceiveString (Stream networkStream, byte[] buffer)
|
// store number of bytes (not number of chars!)
|
||||||
{
|
|
||||||
StreamRead (networkStream, buffer, 4);
|
|
||||||
|
|
||||||
// Reads the number of bytes (not chars!)
|
buffer [0] = (Byte) num;
|
||||||
|
buffer [1] = (Byte) (num >> 8);
|
||||||
|
buffer [2] = (Byte) (num >> 16);
|
||||||
|
buffer [3] = (Byte) (num >> 24);
|
||||||
|
|
||||||
int byteCount = (buffer [0] | (buffer [1] << 8) |
|
// Write the string bytes
|
||||||
(buffer [2] << 16) | (buffer [3] << 24));
|
networkStream.Write (buffer, 0, num + 4);
|
||||||
|
}
|
||||||
|
|
||||||
if (byteCount == 0) return string.Empty;
|
private static String ReceiveString (Stream networkStream, Byte[] buffer)
|
||||||
|
{
|
||||||
|
_ = StreamRead(networkStream, buffer, 4);
|
||||||
|
|
||||||
// Allocates a buffer of the correct size. Use the
|
// Reads the number of bytes (not chars!)
|
||||||
// internal buffer if it is big enough
|
|
||||||
|
|
||||||
if (byteCount > buffer.Length)
|
Int32 byteCount = buffer [0] | (buffer [1] << 8) |
|
||||||
buffer = new byte[byteCount];
|
(buffer [2] << 16) | (buffer [3] << 24);
|
||||||
|
|
||||||
// Reads the string
|
if (byteCount == 0) {
|
||||||
|
return String.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
StreamRead (networkStream, buffer, byteCount);
|
// Allocates a buffer of the correct size. Use the
|
||||||
char[] chars = Encoding.UTF8.GetChars (buffer, 0, byteCount);
|
// internal buffer if it is big enough
|
||||||
|
|
||||||
return new string (chars);
|
if (byteCount > buffer.Length) {
|
||||||
}
|
buffer = new Byte[byteCount];
|
||||||
|
}
|
||||||
|
|
||||||
}
|
// Reads the string
|
||||||
|
|
||||||
|
_ = StreamRead(networkStream, buffer, byteCount);
|
||||||
|
Char[] chars = Encoding.UTF8.GetChars (buffer, 0, byteCount);
|
||||||
|
|
||||||
|
return new String(chars);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,17 +43,17 @@ namespace Mono.Remoting.Channels.Unix
|
|||||||
{
|
{
|
||||||
public class UnixServerChannel : IChannelReceiver, IChannel
|
public class UnixServerChannel : IChannelReceiver, IChannel
|
||||||
{
|
{
|
||||||
string path = null;
|
String path = null;
|
||||||
string name = "unix";
|
String name = "unix";
|
||||||
|
|
||||||
int priority = 1;
|
Int32 priority = 1;
|
||||||
bool supressChannelData = false;
|
Boolean supressChannelData = false;
|
||||||
|
|
||||||
Thread server_thread = null;
|
Thread server_thread = null;
|
||||||
UnixListener listener;
|
UnixListener listener;
|
||||||
UnixServerTransportSink sink;
|
UnixServerTransportSink sink;
|
||||||
ChannelDataStore channel_data;
|
ChannelDataStore channel_data;
|
||||||
int _maxConcurrentConnections = 100;
|
Int32 _maxConcurrentConnections = 100;
|
||||||
ArrayList _activeConnections = new ArrayList();
|
ArrayList _activeConnections = new ArrayList();
|
||||||
|
|
||||||
|
|
||||||
@ -64,28 +64,28 @@ namespace Mono.Remoting.Channels.Unix
|
|||||||
serverSinkProvider = new UnixBinaryServerFormatterSinkProvider ();
|
serverSinkProvider = new UnixBinaryServerFormatterSinkProvider ();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets channel data from the chain of channel providers
|
// Gets channel data from the chain of channel providers
|
||||||
|
|
||||||
channel_data = new ChannelDataStore (null);
|
this.channel_data = new ChannelDataStore (null);
|
||||||
IServerChannelSinkProvider provider = serverSinkProvider;
|
IServerChannelSinkProvider provider = serverSinkProvider;
|
||||||
while (provider != null)
|
while (provider != null)
|
||||||
{
|
{
|
||||||
provider.GetChannelData(channel_data);
|
provider.GetChannelData(this.channel_data);
|
||||||
provider = provider.Next;
|
provider = provider.Next;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates the sink chain that will process all incoming messages
|
// Creates the sink chain that will process all incoming messages
|
||||||
|
|
||||||
IServerChannelSink next_sink = ChannelServices.CreateServerChannelSinkChain (serverSinkProvider, this);
|
IServerChannelSink next_sink = ChannelServices.CreateServerChannelSinkChain (serverSinkProvider, this);
|
||||||
sink = new UnixServerTransportSink (next_sink);
|
this.sink = new UnixServerTransportSink (next_sink);
|
||||||
|
|
||||||
StartListening (null);
|
this.StartListening (null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public UnixServerChannel (string path)
|
public UnixServerChannel (String path)
|
||||||
{
|
{
|
||||||
this.path = path;
|
this.path = path;
|
||||||
Init (null);
|
this.Init (null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public UnixServerChannel (IDictionary properties,
|
public UnixServerChannel (IDictionary properties,
|
||||||
@ -93,90 +93,80 @@ namespace Mono.Remoting.Channels.Unix
|
|||||||
{
|
{
|
||||||
foreach(DictionaryEntry property in properties)
|
foreach(DictionaryEntry property in properties)
|
||||||
{
|
{
|
||||||
switch((string)property.Key)
|
switch((String)property.Key)
|
||||||
{
|
{
|
||||||
case "path":
|
case "path":
|
||||||
path = property.Value as string;
|
this.path = property.Value as String;
|
||||||
break;
|
break;
|
||||||
case "priority":
|
case "priority":
|
||||||
priority = Convert.ToInt32(property.Value);
|
this.priority = Convert.ToInt32(property.Value);
|
||||||
break;
|
break;
|
||||||
case "supressChannelData":
|
case "supressChannelData":
|
||||||
supressChannelData = Convert.ToBoolean (property.Value);
|
this.supressChannelData = Convert.ToBoolean (property.Value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Init (serverSinkProvider);
|
this.Init (serverSinkProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
public UnixServerChannel (string name, string path,
|
public UnixServerChannel (String name, String path,
|
||||||
IServerChannelSinkProvider serverSinkProvider)
|
IServerChannelSinkProvider serverSinkProvider)
|
||||||
{
|
{
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.path = path;
|
this.path = path;
|
||||||
Init (serverSinkProvider);
|
this.Init (serverSinkProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
public UnixServerChannel (string name, string path)
|
public UnixServerChannel (String name, String path)
|
||||||
{
|
{
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.path = path;
|
this.path = path;
|
||||||
Init (null);
|
this.Init (null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public object ChannelData
|
public Object ChannelData
|
||||||
{
|
{
|
||||||
get {
|
get {
|
||||||
if (supressChannelData) return null;
|
if (this.supressChannelData) {
|
||||||
else return channel_data;
|
return null;
|
||||||
}
|
} else {
|
||||||
|
return this.channel_data;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ChannelName
|
public String ChannelName => this.name;
|
||||||
|
|
||||||
|
public Int32 ChannelPriority => this.priority;
|
||||||
|
|
||||||
|
public String GetChannelUri() => "unix://" + this.path;
|
||||||
|
|
||||||
|
public String[] GetUrlsForUri (String uri)
|
||||||
{
|
{
|
||||||
get {
|
if (!uri.StartsWith ("/")) {
|
||||||
return name;
|
uri = "/" + uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String[] chnl_uris = this.channel_data.ChannelUris;
|
||||||
|
String[] result = new String [chnl_uris.Length];
|
||||||
|
|
||||||
|
for (Int32 i = 0; i < chnl_uris.Length; i++) {
|
||||||
|
result [i] = chnl_uris [i] + "?" + uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int ChannelPriority
|
public String Parse(String url, out String objectURI) => UnixChannel.ParseUnixURL(url, out objectURI);
|
||||||
{
|
|
||||||
get {
|
|
||||||
return priority;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GetChannelUri ()
|
void WaitForConnections ()
|
||||||
{
|
|
||||||
return "unix://" + path;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string[] GetUrlsForUri (string uri)
|
|
||||||
{
|
|
||||||
if (!uri.StartsWith ("/")) uri = "/" + uri;
|
|
||||||
|
|
||||||
string [] chnl_uris = channel_data.ChannelUris;
|
|
||||||
string [] result = new String [chnl_uris.Length];
|
|
||||||
|
|
||||||
for (int i = 0; i < chnl_uris.Length; i++)
|
|
||||||
result [i] = chnl_uris [i] + "?" + uri;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Parse (string url, out string objectURI)
|
|
||||||
{
|
|
||||||
return UnixChannel.ParseUnixURL (url, out objectURI);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WaitForConnections ()
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
Socket client = listener.AcceptSocket ();
|
Socket client = this.listener.AcceptSocket ();
|
||||||
CreateListenerConnection (client);
|
this.CreateListenerConnection (client);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@ -185,71 +175,77 @@ namespace Mono.Remoting.Channels.Unix
|
|||||||
|
|
||||||
internal void CreateListenerConnection (Socket client)
|
internal void CreateListenerConnection (Socket client)
|
||||||
{
|
{
|
||||||
lock (_activeConnections)
|
lock (this._activeConnections)
|
||||||
{
|
{
|
||||||
if (_activeConnections.Count >= _maxConcurrentConnections)
|
if (this._activeConnections.Count >= this._maxConcurrentConnections) {
|
||||||
Monitor.Wait (_activeConnections);
|
_ = Monitor.Wait(this._activeConnections);
|
||||||
|
}
|
||||||
|
|
||||||
if (server_thread == null) return; // Server was stopped while waiting
|
if (this.server_thread == null) {
|
||||||
|
return; // Server was stopped while waiting
|
||||||
|
}
|
||||||
|
|
||||||
ClientConnection reader = new ClientConnection (this, client, sink);
|
ClientConnection reader = new ClientConnection (this, client, this.sink);
|
||||||
Thread thread = new Thread (new ThreadStart (reader.ProcessMessages));
|
Thread thread = new Thread (new ThreadStart (reader.ProcessMessages));
|
||||||
thread.Start();
|
thread.Start();
|
||||||
thread.IsBackground = true;
|
thread.IsBackground = true;
|
||||||
_activeConnections.Add (thread);
|
_ = this._activeConnections.Add(thread);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void ReleaseConnection (Thread thread)
|
internal void ReleaseConnection (Thread thread)
|
||||||
{
|
{
|
||||||
lock (_activeConnections)
|
lock (this._activeConnections)
|
||||||
{
|
{
|
||||||
_activeConnections.Remove (thread);
|
this._activeConnections.Remove (thread);
|
||||||
Monitor.Pulse (_activeConnections);
|
Monitor.Pulse (this._activeConnections);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StartListening (object data)
|
public void StartListening (Object data)
|
||||||
{
|
{
|
||||||
listener = new UnixListener (path);
|
this.listener = new UnixListener (this.path);
|
||||||
Mono.Unix.Native.Syscall.chmod (path,
|
_ = Mono.Unix.Native.Syscall.chmod(this.path,
|
||||||
Mono.Unix.Native.FilePermissions.S_IRUSR |
|
Mono.Unix.Native.FilePermissions.S_IRUSR |
|
||||||
Mono.Unix.Native.FilePermissions.S_IWUSR |
|
Mono.Unix.Native.FilePermissions.S_IWUSR |
|
||||||
Mono.Unix.Native.FilePermissions.S_IRGRP |
|
Mono.Unix.Native.FilePermissions.S_IRGRP |
|
||||||
Mono.Unix.Native.FilePermissions.S_IWGRP |
|
Mono.Unix.Native.FilePermissions.S_IWGRP |
|
||||||
Mono.Unix.Native.FilePermissions.S_IROTH |
|
Mono.Unix.Native.FilePermissions.S_IROTH |
|
||||||
Mono.Unix.Native.FilePermissions.S_IWOTH);
|
Mono.Unix.Native.FilePermissions.S_IWOTH);
|
||||||
|
|
||||||
if (server_thread == null)
|
if (this.server_thread == null)
|
||||||
{
|
{
|
||||||
listener.Start ();
|
this.listener.Start ();
|
||||||
|
|
||||||
string[] uris = new String [1];
|
String[] uris = new String [1];
|
||||||
uris = new String [1];
|
uris = new String [1];
|
||||||
uris [0] = GetChannelUri ();
|
uris [0] = this.GetChannelUri ();
|
||||||
channel_data.ChannelUris = uris;
|
this.channel_data.ChannelUris = uris;
|
||||||
|
|
||||||
server_thread = new Thread (new ThreadStart (WaitForConnections));
|
this.server_thread = new Thread (new ThreadStart (this.WaitForConnections));
|
||||||
server_thread.IsBackground = true;
|
this.server_thread.IsBackground = true;
|
||||||
server_thread.Start ();
|
this.server_thread.Start ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StopListening (object data)
|
public void StopListening (Object data)
|
||||||
{
|
{
|
||||||
if (server_thread == null) return;
|
if (this.server_thread == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
lock (_activeConnections)
|
lock (this._activeConnections)
|
||||||
{
|
{
|
||||||
server_thread.Abort ();
|
this.server_thread.Abort ();
|
||||||
server_thread = null;
|
this.server_thread = null;
|
||||||
listener.Stop ();
|
this.listener.Stop ();
|
||||||
|
|
||||||
foreach (Thread thread in _activeConnections)
|
foreach (Thread thread in this._activeConnections) {
|
||||||
thread.Abort();
|
thread.Abort();
|
||||||
|
}
|
||||||
|
|
||||||
_activeConnections.Clear();
|
this._activeConnections.Clear();
|
||||||
Monitor.PulseAll (_activeConnections);
|
Monitor.PulseAll (this._activeConnections);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -261,46 +257,41 @@ namespace Mono.Remoting.Channels.Unix
|
|||||||
Stream _stream;
|
Stream _stream;
|
||||||
UnixServerChannel _serverChannel;
|
UnixServerChannel _serverChannel;
|
||||||
|
|
||||||
byte[] _buffer = new byte[UnixMessageIO.DefaultStreamBufferSize];
|
Byte[] _buffer = new Byte[UnixMessageIO.DefaultStreamBufferSize];
|
||||||
|
|
||||||
public ClientConnection (UnixServerChannel serverChannel, Socket client, UnixServerTransportSink sink)
|
public ClientConnection (UnixServerChannel serverChannel, Socket client, UnixServerTransportSink sink)
|
||||||
{
|
{
|
||||||
_serverChannel = serverChannel;
|
this._serverChannel = serverChannel;
|
||||||
_client = client;
|
this._client = client;
|
||||||
_sink = sink;
|
this._sink = sink;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Socket Client {
|
public Socket Client => this._client;
|
||||||
get { return _client; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] Buffer
|
public Byte[] Buffer => this._buffer;
|
||||||
|
|
||||||
|
public void ProcessMessages()
|
||||||
{
|
{
|
||||||
get { return _buffer; }
|
Byte[] buffer = new Byte[256];
|
||||||
}
|
this._stream = new BufferedStream (new NetworkStream (this._client));
|
||||||
|
|
||||||
public void ProcessMessages()
|
|
||||||
{
|
|
||||||
byte[] buffer = new byte[256];
|
|
||||||
_stream = new BufferedStream (new NetworkStream (_client));
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
bool end = false;
|
Boolean end = false;
|
||||||
while (!end)
|
while (!end)
|
||||||
{
|
{
|
||||||
MessageStatus type = UnixMessageIO.ReceiveMessageStatus (_stream, buffer);
|
MessageStatus type = UnixMessageIO.ReceiveMessageStatus (this._stream, buffer);
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case MessageStatus.MethodMessage:
|
case MessageStatus.MethodMessage:
|
||||||
_sink.InternalProcessMessage (this, _stream);
|
this._sink.InternalProcessMessage (this, this._stream);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MessageStatus.Unknown:
|
case MessageStatus.Unknown:
|
||||||
case MessageStatus.CancelSignal:
|
case MessageStatus.CancelSignal:
|
||||||
end = true;
|
end = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -310,21 +301,15 @@ namespace Mono.Remoting.Channels.Unix
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
_serverChannel.ReleaseConnection (Thread.CurrentThread);
|
this._serverChannel.ReleaseConnection (Thread.CurrentThread);
|
||||||
_stream.Close();
|
this._stream.Close();
|
||||||
_client.Close ();
|
this._client.Close ();
|
||||||
} catch {
|
} catch {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsLocal
|
public Boolean IsLocal => true;
|
||||||
{
|
}
|
||||||
get
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -35,102 +35,80 @@ using System.Runtime.Remoting.Messaging;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.Remoting.Channels;
|
using System.Runtime.Remoting.Channels;
|
||||||
|
|
||||||
namespace Mono.Remoting.Channels.Unix
|
namespace Mono.Remoting.Channels.Unix {
|
||||||
{
|
internal class UnixServerTransportSink : IServerChannelSink, IChannelSinkBase {
|
||||||
internal class UnixServerTransportSink : IServerChannelSink, IChannelSinkBase
|
IServerChannelSink next_sink;
|
||||||
{
|
|
||||||
IServerChannelSink next_sink;
|
|
||||||
|
|
||||||
public UnixServerTransportSink (IServerChannelSink next)
|
public UnixServerTransportSink(IServerChannelSink next) => this.next_sink = next;
|
||||||
{
|
|
||||||
next_sink = next;
|
public IServerChannelSink NextChannelSink => this.next_sink;
|
||||||
}
|
|
||||||
|
public IDictionary Properties {
|
||||||
public IServerChannelSink NextChannelSink
|
get {
|
||||||
{
|
if(this.next_sink != null) {
|
||||||
get
|
return this.next_sink.Properties;
|
||||||
{
|
} else {
|
||||||
return next_sink;
|
return null;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public IDictionary Properties
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (next_sink != null) return next_sink.Properties;
|
|
||||||
else return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AsyncProcessResponse (IServerResponseChannelSinkStack sinkStack, object state,
|
|
||||||
IMessage msg, ITransportHeaders headers, Stream responseStream)
|
|
||||||
{
|
|
||||||
ClientConnection connection = (ClientConnection)state;
|
|
||||||
NetworkStream stream = new NetworkStream (connection.Client);
|
|
||||||
UnixMessageIO.SendMessageStream (stream, responseStream, headers, connection.Buffer);
|
|
||||||
stream.Flush ();
|
|
||||||
stream.Close ();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Stream GetResponseStream (IServerResponseChannelSinkStack sinkStack, object state,
|
|
||||||
IMessage msg, ITransportHeaders headers)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ServerProcessing ProcessMessage (IServerChannelSinkStack sinkStack,
|
|
||||||
IMessage requestMsg,
|
|
||||||
ITransportHeaders requestHeaders,
|
|
||||||
Stream requestStream,
|
|
||||||
out IMessage responseMsg,
|
|
||||||
out ITransportHeaders responseHeaders,
|
|
||||||
out Stream responseStream)
|
|
||||||
{
|
|
||||||
// this is the first sink, and UnixServerChannel does not call it.
|
|
||||||
throw new NotSupportedException ();
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void InternalProcessMessage (ClientConnection connection, Stream stream)
|
|
||||||
{
|
|
||||||
// Reads the headers and the request stream
|
|
||||||
|
|
||||||
Stream requestStream;
|
|
||||||
ITransportHeaders requestHeaders;
|
|
||||||
|
|
||||||
requestStream = UnixMessageIO.ReceiveMessageStream (stream, out requestHeaders, connection.Buffer);
|
|
||||||
|
|
||||||
/* try {
|
|
||||||
PeerCred cred = connection.Client.PeerCredential;
|
|
||||||
requestHeaders["__uid"] = cred.UserID;
|
|
||||||
} catch (Exception e) {
|
|
||||||
Console.WriteLine ("Couldn't get the peer cred: " + e);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
// Pushes the connection object together with the sink. This information
|
|
||||||
// will be used for sending the response in an async call.
|
|
||||||
|
|
||||||
ServerChannelSinkStack sinkStack = new ServerChannelSinkStack();
|
|
||||||
sinkStack.Push(this, connection);
|
|
||||||
|
|
||||||
ITransportHeaders responseHeaders;
|
|
||||||
Stream responseStream;
|
|
||||||
IMessage responseMsg;
|
|
||||||
|
|
||||||
ServerProcessing proc = next_sink.ProcessMessage(sinkStack, null, requestHeaders, requestStream, out responseMsg, out responseHeaders, out responseStream);
|
|
||||||
|
|
||||||
switch (proc)
|
|
||||||
{
|
|
||||||
case ServerProcessing.Complete:
|
|
||||||
UnixMessageIO.SendMessageStream (stream, responseStream, responseHeaders, connection.Buffer);
|
|
||||||
stream.Flush ();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ServerProcessing.Async:
|
|
||||||
case ServerProcessing.OneWay:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void AsyncProcessResponse(IServerResponseChannelSinkStack sinkStack, Object state,
|
||||||
|
IMessage msg, ITransportHeaders headers, Stream responseStream) {
|
||||||
|
ClientConnection connection = (ClientConnection)state;
|
||||||
|
NetworkStream stream = new NetworkStream(connection.Client);
|
||||||
|
UnixMessageIO.SendMessageStream(stream, responseStream, headers, connection.Buffer);
|
||||||
|
stream.Flush();
|
||||||
|
stream.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stream GetResponseStream(IServerResponseChannelSinkStack sinkStack, Object state,
|
||||||
|
IMessage msg, ITransportHeaders headers) => null;
|
||||||
|
|
||||||
|
public ServerProcessing ProcessMessage(IServerChannelSinkStack sinkStack,
|
||||||
|
IMessage requestMsg,
|
||||||
|
ITransportHeaders requestHeaders,
|
||||||
|
Stream requestStream,
|
||||||
|
out IMessage responseMsg,
|
||||||
|
out ITransportHeaders responseHeaders,
|
||||||
|
out Stream responseStream) =>
|
||||||
|
// this is the first sink, and UnixServerChannel does not call it.
|
||||||
|
throw new NotSupportedException();
|
||||||
|
|
||||||
|
internal void InternalProcessMessage(ClientConnection connection, Stream stream) {
|
||||||
|
// Reads the headers and the request stream
|
||||||
|
|
||||||
|
Stream requestStream;
|
||||||
|
|
||||||
|
requestStream = UnixMessageIO.ReceiveMessageStream(stream, out ITransportHeaders requestHeaders, connection.Buffer);
|
||||||
|
|
||||||
|
/* try {
|
||||||
|
PeerCred cred = connection.Client.PeerCredential;
|
||||||
|
requestHeaders["__uid"] = cred.UserID;
|
||||||
|
} catch (Exception e) {
|
||||||
|
Console.WriteLine ("Couldn't get the peer cred: " + e);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
// Pushes the connection object together with the sink. This information
|
||||||
|
// will be used for sending the response in an async call.
|
||||||
|
|
||||||
|
ServerChannelSinkStack sinkStack = new ServerChannelSinkStack();
|
||||||
|
sinkStack.Push(this, connection);
|
||||||
|
|
||||||
|
|
||||||
|
ServerProcessing proc = this.next_sink.ProcessMessage(sinkStack, null, requestHeaders, requestStream, out IMessage responseMsg, out ITransportHeaders responseHeaders, out Stream responseStream);
|
||||||
|
|
||||||
|
switch(proc) {
|
||||||
|
case ServerProcessing.Complete:
|
||||||
|
UnixMessageIO.SendMessageStream(stream, responseStream, responseHeaders, connection.Buffer);
|
||||||
|
stream.Flush();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ServerProcessing.Async:
|
||||||
|
case ServerProcessing.OneWay:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,154 +35,158 @@ using System.Text;
|
|||||||
|
|
||||||
namespace Mono.Unix.Native {
|
namespace Mono.Unix.Native {
|
||||||
|
|
||||||
// This class represents a single unmanaged function with "cdecl" calling
|
// This class represents a single unmanaged function with "cdecl" calling
|
||||||
// convention -- that is, it can accept a variable number of arguments which
|
// convention -- that is, it can accept a variable number of arguments which
|
||||||
// are passed on the runtime stack.
|
// are passed on the runtime stack.
|
||||||
//
|
//
|
||||||
// To use, create an instance:
|
// To use, create an instance:
|
||||||
//
|
//
|
||||||
// CdeclFunction printf = new CdeclFunction ("the library",
|
// CdeclFunction printf = new CdeclFunction ("the library",
|
||||||
// "the function name", /* optional */ typeof (ReturnType));
|
// "the function name", /* optional */ typeof (ReturnType));
|
||||||
//
|
//
|
||||||
// Then call the Invoke method with the appropriate number of arguments:
|
// Then call the Invoke method with the appropriate number of arguments:
|
||||||
//
|
//
|
||||||
// printf.Invoke (new object[]{"hello, %s\n", "world!"});
|
// printf.Invoke (new object[]{"hello, %s\n", "world!"});
|
||||||
//
|
//
|
||||||
// In the background a P/Invoke definition for the method with the
|
// In the background a P/Invoke definition for the method with the
|
||||||
// requested argument types will be generated and invoked, invoking the
|
// requested argument types will be generated and invoked, invoking the
|
||||||
// unmanaged function. The generated methods are cached, so that subsequent
|
// unmanaged function. The generated methods are cached, so that subsequent
|
||||||
// calls with the same argument list do not generate new code, speeding up
|
// calls with the same argument list do not generate new code, speeding up
|
||||||
// the call sequence.
|
// the call sequence.
|
||||||
//
|
//
|
||||||
// Invoking Cdecl functions is not guaranteed to be portable across all
|
// Invoking Cdecl functions is not guaranteed to be portable across all
|
||||||
// platforms. For example, AMD64 requires that the caller set EAX to the
|
// platforms. For example, AMD64 requires that the caller set EAX to the
|
||||||
// number of floating point arguments passed in the SSE registers. This
|
// number of floating point arguments passed in the SSE registers. This
|
||||||
// is only required for variable argument/cdecl functions; consequently,
|
// is only required for variable argument/cdecl functions; consequently,
|
||||||
// the overload technique used by this class wouldn't normally work.
|
// the overload technique used by this class wouldn't normally work.
|
||||||
// Mono's AMD64 JIT works around this by always setting EAX on P/Invoke
|
// Mono's AMD64 JIT works around this by always setting EAX on P/Invoke
|
||||||
// invocations, allowing CdeclFunction to work properly, but it will not
|
// invocations, allowing CdeclFunction to work properly, but it will not
|
||||||
// necessarily always work. See also:
|
// necessarily always work. See also:
|
||||||
//
|
//
|
||||||
// http://lwn.net/Articles/5201/?format=printable
|
// http://lwn.net/Articles/5201/?format=printable
|
||||||
//
|
//
|
||||||
// Due to potential portability issues, cdecl functions should be avoided
|
// Due to potential portability issues, cdecl functions should be avoided
|
||||||
// on most platforms.
|
// on most platforms.
|
||||||
//
|
//
|
||||||
// This class is intended to be thread-safe.
|
// This class is intended to be thread-safe.
|
||||||
public sealed class CdeclFunction
|
public sealed class CdeclFunction
|
||||||
{
|
{
|
||||||
// The readonly fields (1) shouldn't be modified, and (2) should only be
|
// The readonly fields (1) shouldn't be modified, and (2) should only be
|
||||||
// used when `overloads' is locked.
|
// used when `overloads' is locked.
|
||||||
private readonly string library;
|
private readonly String library;
|
||||||
private readonly string method;
|
private readonly String method;
|
||||||
private readonly Type returnType;
|
private readonly Type returnType;
|
||||||
private readonly AssemblyName assemblyName;
|
private readonly AssemblyName assemblyName;
|
||||||
private readonly AssemblyBuilder assemblyBuilder;
|
private readonly AssemblyBuilder assemblyBuilder;
|
||||||
private readonly ModuleBuilder moduleBuilder;
|
private readonly ModuleBuilder moduleBuilder;
|
||||||
|
|
||||||
private Hashtable overloads;
|
private readonly Hashtable overloads;
|
||||||
|
|
||||||
public CdeclFunction (string library, string method)
|
public CdeclFunction (String library, String method)
|
||||||
: this (library, method, typeof(void))
|
: this (library, method, typeof(void))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public CdeclFunction (string library, string method, Type returnType)
|
public CdeclFunction (String library, String method, Type returnType)
|
||||||
{
|
{
|
||||||
this.library = library;
|
this.library = library;
|
||||||
this.method = method;
|
this.method = method;
|
||||||
this.returnType = returnType;
|
this.returnType = returnType;
|
||||||
this.overloads = new Hashtable ();
|
this.overloads = new Hashtable ();
|
||||||
this.assemblyName = new AssemblyName ();
|
this.assemblyName = new AssemblyName {
|
||||||
this.assemblyName.Name = "Mono.Posix.Imports." + library;
|
Name = "Mono.Posix.Imports." + library
|
||||||
this.assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly (
|
};
|
||||||
assemblyName, AssemblyBuilderAccess.Run);
|
this.assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly (
|
||||||
this.moduleBuilder = assemblyBuilder.DefineDynamicModule (assemblyName.Name);
|
this.assemblyName, AssemblyBuilderAccess.Run);
|
||||||
}
|
this.moduleBuilder = this.assemblyBuilder.DefineDynamicModule (this.assemblyName.Name);
|
||||||
|
}
|
||||||
|
|
||||||
public object Invoke (object[] parameters)
|
public Object Invoke (Object[] parameters)
|
||||||
{
|
{
|
||||||
Type[] parameterTypes = GetParameterTypes (parameters);
|
Type[] parameterTypes = GetParameterTypes (parameters);
|
||||||
MethodInfo m = CreateMethod (parameterTypes);
|
MethodInfo m = this.CreateMethod (parameterTypes);
|
||||||
return m.Invoke (null, parameters);
|
return m.Invoke (null, parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
private MethodInfo CreateMethod (Type[] parameterTypes)
|
private MethodInfo CreateMethod (Type[] parameterTypes)
|
||||||
{
|
{
|
||||||
string typeName = GetTypeName (parameterTypes);
|
String typeName = this.GetTypeName (parameterTypes);
|
||||||
|
|
||||||
lock (overloads) {
|
lock (this.overloads) {
|
||||||
MethodInfo mi = (MethodInfo) overloads [typeName];
|
MethodInfo mi = (MethodInfo)this.overloads [typeName];
|
||||||
|
|
||||||
if (mi != null) {
|
if (mi != null) {
|
||||||
return mi;
|
return mi;
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeBuilder tb = CreateType (typeName);
|
TypeBuilder tb = this.CreateType (typeName);
|
||||||
/* MethodBuilder mb = */ tb.DefinePInvokeMethod (
|
/* MethodBuilder mb = */
|
||||||
method,
|
_ = tb.DefinePInvokeMethod(
|
||||||
library,
|
this.method,
|
||||||
MethodAttributes.PinvokeImpl | MethodAttributes.Static | MethodAttributes.Public,
|
this.library,
|
||||||
CallingConventions.Standard,
|
MethodAttributes.PinvokeImpl | MethodAttributes.Static | MethodAttributes.Public,
|
||||||
returnType,
|
CallingConventions.Standard,
|
||||||
parameterTypes,
|
this.returnType,
|
||||||
CallingConvention.Cdecl,
|
parameterTypes,
|
||||||
CharSet.Ansi);
|
CallingConvention.Cdecl,
|
||||||
mi = tb.CreateType ().GetMethod (method);
|
CharSet.Ansi);
|
||||||
overloads.Add (typeName, mi);
|
mi = tb.CreateType ().GetMethod (this.method);
|
||||||
return mi;
|
this.overloads.Add (typeName, mi);
|
||||||
}
|
return mi;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private TypeBuilder CreateType (string typeName)
|
private TypeBuilder CreateType(String typeName) => this.moduleBuilder.DefineType(typeName, TypeAttributes.Public);
|
||||||
{
|
|
||||||
return moduleBuilder.DefineType (typeName, TypeAttributes.Public);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Type GetMarshalType (Type t)
|
private static Type GetMarshalType (Type t)
|
||||||
{
|
{
|
||||||
switch (Type.GetTypeCode (t)) {
|
switch (Type.GetTypeCode (t)) {
|
||||||
// types < sizeof(int) are marshaled as ints
|
// types < sizeof(int) are marshaled as ints
|
||||||
case TypeCode.Boolean: case TypeCode.Char: case TypeCode.SByte:
|
case TypeCode.Boolean: case TypeCode.Char: case TypeCode.SByte:
|
||||||
case TypeCode.Int16: case TypeCode.Int32:
|
case TypeCode.Int16: case TypeCode.Int32:
|
||||||
return typeof(int);
|
return typeof(Int32);
|
||||||
case TypeCode.Byte: case TypeCode.UInt16: case TypeCode.UInt32:
|
case TypeCode.Byte: case TypeCode.UInt16: case TypeCode.UInt32:
|
||||||
return typeof(uint);
|
return typeof(UInt32);
|
||||||
case TypeCode.Int64:
|
case TypeCode.Int64:
|
||||||
return typeof(long);
|
return typeof(Int64);
|
||||||
case TypeCode.UInt64:
|
case TypeCode.UInt64:
|
||||||
return typeof(ulong);
|
return typeof(UInt64);
|
||||||
case TypeCode.Single: case TypeCode.Double:
|
case TypeCode.Single: case TypeCode.Double:
|
||||||
return typeof(double);
|
return typeof(Double);
|
||||||
default:
|
default:
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetTypeName (Type[] parameterTypes)
|
private String GetTypeName (Type[] parameterTypes)
|
||||||
{
|
{
|
||||||
StringBuilder sb = new StringBuilder ();
|
StringBuilder sb = new StringBuilder ();
|
||||||
|
|
||||||
sb.Append ("[").Append (library).Append ("] ").Append (method);
|
_ = sb.Append("[").Append(this.library).Append("] ").Append(this.method);
|
||||||
sb.Append ("(");
|
_ = sb.Append("(");
|
||||||
|
|
||||||
if (parameterTypes.Length > 0)
|
if (parameterTypes.Length > 0) {
|
||||||
sb.Append (parameterTypes [0]);
|
_ = sb.Append(parameterTypes[0]);
|
||||||
for (int i = 1; i < parameterTypes.Length; ++i)
|
}
|
||||||
sb.Append (",").Append (parameterTypes [i]);
|
|
||||||
|
|
||||||
sb.Append (") : ").Append (returnType.FullName);
|
for (Int32 i = 1; i < parameterTypes.Length; ++i) {
|
||||||
|
_ = sb.Append(",").Append(parameterTypes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
return sb.ToString ();
|
_ = sb.Append(") : ").Append(this.returnType.FullName);
|
||||||
}
|
|
||||||
|
|
||||||
private static Type[] GetParameterTypes (object[] parameters)
|
return sb.ToString ();
|
||||||
{
|
}
|
||||||
Type[] parameterTypes = new Type [parameters.Length];
|
|
||||||
for (int i = 0; i < parameters.Length; ++i)
|
private static Type[] GetParameterTypes (Object[] parameters)
|
||||||
parameterTypes [i] = GetMarshalType (parameters [i].GetType ());
|
{
|
||||||
return parameterTypes;
|
Type[] parameterTypes = new Type [parameters.Length];
|
||||||
}
|
for (Int32 i = 0; i < parameters.Length; ++i) {
|
||||||
}
|
parameterTypes [i] = GetMarshalType (parameters [i].GetType ());
|
||||||
|
}
|
||||||
|
|
||||||
|
return parameterTypes;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,48 +32,42 @@ using Mono.Unix;
|
|||||||
|
|
||||||
namespace Mono.Unix.Native {
|
namespace Mono.Unix.Native {
|
||||||
|
|
||||||
class FileNameMarshaler : ICustomMarshaler {
|
class FileNameMarshaler : ICustomMarshaler {
|
||||||
|
|
||||||
private static FileNameMarshaler Instance = new FileNameMarshaler ();
|
private static readonly FileNameMarshaler Instance = new FileNameMarshaler ();
|
||||||
|
|
||||||
public static ICustomMarshaler GetInstance (string s)
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE0060:Nicht verwendete Parameter entfernen", Justification = "<Ausstehend>")]
|
||||||
{
|
public static ICustomMarshaler GetInstance(String s) => Instance;
|
||||||
return Instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CleanUpManagedData (object o)
|
public void CleanUpManagedData (Object o)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CleanUpNativeData (IntPtr pNativeData)
|
public void CleanUpNativeData(IntPtr pNativeData) =>
|
||||||
{
|
// Console.WriteLine ("# FileNameMarshaler.CleanUpManagedData ({0:x})", pNativeData);
|
||||||
// Console.WriteLine ("# FileNameMarshaler.CleanUpManagedData ({0:x})", pNativeData);
|
UnixMarshal.FreeHeap(pNativeData);
|
||||||
UnixMarshal.FreeHeap (pNativeData);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int GetNativeDataSize ()
|
public Int32 GetNativeDataSize() => IntPtr.Size;
|
||||||
{
|
|
||||||
return IntPtr.Size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IntPtr MarshalManagedToNative (object obj)
|
public IntPtr MarshalManagedToNative (Object obj)
|
||||||
{
|
{
|
||||||
string s = obj as string;
|
if(!(obj is String s)) {
|
||||||
if (s == null)
|
return IntPtr.Zero;
|
||||||
return IntPtr.Zero;
|
}
|
||||||
IntPtr p = UnixMarshal.StringToHeap (s, UnixEncoding.Instance);
|
|
||||||
// Console.WriteLine ("# FileNameMarshaler.MarshalNativeToManaged for `{0}'={1:x}", s, p);
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
public object MarshalNativeToManaged (IntPtr pNativeData)
|
IntPtr p = UnixMarshal.StringToHeap (s, UnixEncoding.Instance);
|
||||||
{
|
// Console.WriteLine ("# FileNameMarshaler.MarshalNativeToManaged for `{0}'={1:x}", s, p);
|
||||||
string s = UnixMarshal.PtrToString (pNativeData, UnixEncoding.Instance);
|
return p;
|
||||||
// Console.WriteLine ("# FileNameMarshaler.MarshalNativeToManaged ({0:x})=`{1}'",
|
}
|
||||||
// pNativeData, s);
|
|
||||||
return s;
|
public Object MarshalNativeToManaged (IntPtr pNativeData)
|
||||||
}
|
{
|
||||||
}
|
String s = UnixMarshal.PtrToString (pNativeData, UnixEncoding.Instance);
|
||||||
|
// Console.WriteLine ("# FileNameMarshaler.MarshalNativeToManaged ({0:x})=`{1}'",
|
||||||
|
// pNativeData, s);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim: noexpandtab
|
// vim: noexpandtab
|
||||||
|
@ -30,31 +30,23 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
[AttributeUsage (
|
[AttributeUsage (
|
||||||
AttributeTargets.Class |
|
AttributeTargets.Class |
|
||||||
AttributeTargets.Delegate |
|
AttributeTargets.Delegate |
|
||||||
AttributeTargets.Enum |
|
AttributeTargets.Enum |
|
||||||
AttributeTargets.Field |
|
AttributeTargets.Field |
|
||||||
AttributeTargets.Struct)]
|
AttributeTargets.Struct)]
|
||||||
internal class MapAttribute : Attribute {
|
internal class MapAttribute : Attribute {
|
||||||
private string nativeType;
|
public MapAttribute ()
|
||||||
private string suppressFlags;
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public MapAttribute ()
|
public MapAttribute(String nativeType) => this.NativeType = nativeType;
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public MapAttribute (string nativeType)
|
public String NativeType {
|
||||||
{
|
get;
|
||||||
this.nativeType = nativeType;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public string NativeType {
|
public String SuppressFlags { get;
|
||||||
get {return nativeType;}
|
set; }
|
||||||
}
|
|
||||||
|
|
||||||
public string SuppressFlags {
|
|
||||||
get {return suppressFlags;}
|
|
||||||
set {suppressFlags = value;}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,470 +14,458 @@ using Mono.Unix.Android;
|
|||||||
|
|
||||||
namespace Mono.Unix.Native {
|
namespace Mono.Unix.Native {
|
||||||
|
|
||||||
[CLSCompliant (false)]
|
//[CLSCompliant (false)]
|
||||||
public sealed /* static */ partial class NativeConvert
|
public sealed /* static */ partial class NativeConvert
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
// Non-generated exports
|
// Non-generated exports
|
||||||
//
|
//
|
||||||
#if MONODROID
|
#if MONODROID
|
||||||
[DllImport (LIB, EntryPoint="Mono_Posix_FromRealTimeSignum")]
|
[DllImport (LIB, EntryPoint="Mono_Posix_FromRealTimeSignum")]
|
||||||
static extern int HelperFromRealTimeSignum (Int32 offset, out Int32 rval);
|
static extern int HelperFromRealTimeSignum (Int32 offset, out Int32 rval);
|
||||||
|
|
||||||
static int FromRealTimeSignum (Int32 offset, out Int32 rval)
|
static int FromRealTimeSignum (Int32 offset, out Int32 rval)
|
||||||
{
|
{
|
||||||
if (!AndroidUtils.AreRealTimeSignalsSafe ())
|
if (!AndroidUtils.AreRealTimeSignalsSafe ())
|
||||||
throw new PlatformNotSupportedException ("Real-time signals are not supported on this Android architecture");
|
throw new PlatformNotSupportedException ("Real-time signals are not supported on this Android architecture");
|
||||||
return HelperFromRealTimeSignum (offset, out rval);
|
return HelperFromRealTimeSignum (offset, out rval);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
[DllImport (LIB, EntryPoint="Mono_Posix_FromRealTimeSignum")]
|
[DllImport (LIB, EntryPoint="Mono_Posix_FromRealTimeSignum")]
|
||||||
private static extern int FromRealTimeSignum (Int32 offset, out Int32 rval);
|
private static extern Int32 FromRealTimeSignum (Int32 offset, out Int32 rval);
|
||||||
#endif
|
#endif
|
||||||
// convert a realtime signal to os signal
|
// convert a realtime signal to os signal
|
||||||
public static int FromRealTimeSignum (RealTimeSignum sig)
|
public static Int32 FromRealTimeSignum (RealTimeSignum sig)
|
||||||
{
|
{
|
||||||
int sigNum;
|
if(FromRealTimeSignum(sig.Offset, out Int32 sigNum) == -1) {
|
||||||
if (FromRealTimeSignum (sig.Offset, out sigNum) == -1)
|
ThrowArgumentException(sig.Offset);
|
||||||
ThrowArgumentException (sig.Offset);
|
}
|
||||||
return sigNum;
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert an offset to an rt signum
|
return sigNum;
|
||||||
public static RealTimeSignum ToRealTimeSignum (int offset)
|
}
|
||||||
{
|
|
||||||
return new RealTimeSignum (offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert from octal representation.
|
// convert an offset to an rt signum
|
||||||
public static FilePermissions FromOctalPermissionString (string value)
|
public static RealTimeSignum ToRealTimeSignum(Int32 offset) => new RealTimeSignum(offset);
|
||||||
{
|
|
||||||
uint n = Convert.ToUInt32 (value, 8);
|
|
||||||
return ToFilePermissions (n);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string ToOctalPermissionString (FilePermissions value)
|
// convert from octal representation.
|
||||||
{
|
public static FilePermissions FromOctalPermissionString (String value)
|
||||||
string s = Convert.ToString ((int) (value & ~FilePermissions.S_IFMT), 8);
|
{
|
||||||
return new string ('0', 4-s.Length) + s;
|
UInt32 n = Convert.ToUInt32 (value, 8);
|
||||||
}
|
return ToFilePermissions (n);
|
||||||
|
}
|
||||||
|
|
||||||
public static FilePermissions FromUnixPermissionString (string value)
|
public static String ToOctalPermissionString (FilePermissions value)
|
||||||
{
|
{
|
||||||
if (value == null)
|
String s = Convert.ToString ((Int32) (value & ~FilePermissions.S_IFMT), 8);
|
||||||
throw new ArgumentNullException ("value");
|
return new String('0', 4-s.Length) + s;
|
||||||
if (value.Length != 9 && value.Length != 10)
|
}
|
||||||
throw new ArgumentException ("value", "must contain 9 or 10 characters");
|
|
||||||
|
|
||||||
int i = 0;
|
public static FilePermissions FromUnixPermissionString (String value)
|
||||||
FilePermissions perms = new FilePermissions ();
|
{
|
||||||
|
if (value == null) {
|
||||||
|
throw new ArgumentNullException ("value");
|
||||||
|
}
|
||||||
|
|
||||||
if (value.Length == 10) {
|
if (value.Length != 9 && value.Length != 10) {
|
||||||
perms |= GetUnixPermissionDevice (value [i]);
|
throw new ArgumentException ("value", "must contain 9 or 10 characters");
|
||||||
++i;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
perms |= GetUnixPermissionGroup (
|
Int32 i = 0;
|
||||||
value [i++], FilePermissions.S_IRUSR,
|
FilePermissions perms = new FilePermissions ();
|
||||||
value [i++], FilePermissions.S_IWUSR,
|
|
||||||
value [i++], FilePermissions.S_IXUSR,
|
|
||||||
's', 'S', FilePermissions.S_ISUID);
|
|
||||||
|
|
||||||
perms |= GetUnixPermissionGroup (
|
if (value.Length == 10) {
|
||||||
value [i++], FilePermissions.S_IRGRP,
|
perms |= GetUnixPermissionDevice (value [i]);
|
||||||
value [i++], FilePermissions.S_IWGRP,
|
++i;
|
||||||
value [i++], FilePermissions.S_IXGRP,
|
}
|
||||||
's', 'S', FilePermissions.S_ISGID);
|
|
||||||
|
|
||||||
perms |= GetUnixPermissionGroup (
|
perms |= GetUnixPermissionGroup (
|
||||||
value [i++], FilePermissions.S_IROTH,
|
value [i++], FilePermissions.S_IRUSR,
|
||||||
value [i++], FilePermissions.S_IWOTH,
|
value [i++], FilePermissions.S_IWUSR,
|
||||||
value [i++], FilePermissions.S_IXOTH,
|
value [i++], FilePermissions.S_IXUSR,
|
||||||
't', 'T', FilePermissions.S_ISVTX);
|
's', 'S', FilePermissions.S_ISUID);
|
||||||
|
|
||||||
return perms;
|
perms |= GetUnixPermissionGroup (
|
||||||
}
|
value [i++], FilePermissions.S_IRGRP,
|
||||||
|
value [i++], FilePermissions.S_IWGRP,
|
||||||
|
value [i++], FilePermissions.S_IXGRP,
|
||||||
|
's', 'S', FilePermissions.S_ISGID);
|
||||||
|
|
||||||
private static FilePermissions GetUnixPermissionDevice (char value)
|
perms |= GetUnixPermissionGroup (
|
||||||
{
|
value [i++], FilePermissions.S_IROTH,
|
||||||
switch (value) {
|
value [i++], FilePermissions.S_IWOTH,
|
||||||
case 'd': return FilePermissions.S_IFDIR;
|
value [i++], FilePermissions.S_IXOTH,
|
||||||
case 'c': return FilePermissions.S_IFCHR;
|
't', 'T', FilePermissions.S_ISVTX);
|
||||||
case 'b': return FilePermissions.S_IFBLK;
|
|
||||||
case '-': return FilePermissions.S_IFREG;
|
|
||||||
case 'p': return FilePermissions.S_IFIFO;
|
|
||||||
case 'l': return FilePermissions.S_IFLNK;
|
|
||||||
case 's': return FilePermissions.S_IFSOCK;
|
|
||||||
}
|
|
||||||
throw new ArgumentException ("value", "invalid device specification: " +
|
|
||||||
value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static FilePermissions GetUnixPermissionGroup (
|
return perms;
|
||||||
char read, FilePermissions readb,
|
}
|
||||||
char write, FilePermissions writeb,
|
|
||||||
char exec, FilePermissions execb,
|
|
||||||
char xboth, char xbitonly, FilePermissions xbit)
|
|
||||||
{
|
|
||||||
FilePermissions perms = new FilePermissions ();
|
|
||||||
if (read == 'r')
|
|
||||||
perms |= readb;
|
|
||||||
if (write == 'w')
|
|
||||||
perms |= writeb;
|
|
||||||
if (exec == 'x')
|
|
||||||
perms |= execb;
|
|
||||||
else if (exec == xbitonly)
|
|
||||||
perms |= xbit;
|
|
||||||
else if (exec == xboth)
|
|
||||||
perms |= (execb | xbit);
|
|
||||||
return perms;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create ls(1) drwxrwxrwx permissions display
|
private static FilePermissions GetUnixPermissionDevice (Char value)
|
||||||
public static string ToUnixPermissionString (FilePermissions value)
|
{
|
||||||
{
|
switch (value) {
|
||||||
char [] access = new char[] {
|
case 'd': return FilePermissions.S_IFDIR;
|
||||||
'-', // device
|
case 'c': return FilePermissions.S_IFCHR;
|
||||||
'-', '-', '-', // owner
|
case 'b': return FilePermissions.S_IFBLK;
|
||||||
'-', '-', '-', // group
|
case '-': return FilePermissions.S_IFREG;
|
||||||
'-', '-', '-', // other
|
case 'p': return FilePermissions.S_IFIFO;
|
||||||
};
|
case 'l': return FilePermissions.S_IFLNK;
|
||||||
bool have_device = true;
|
case 's': return FilePermissions.S_IFSOCK;
|
||||||
switch (value & FilePermissions.S_IFMT) {
|
}
|
||||||
case FilePermissions.S_IFDIR: access [0] = 'd'; break;
|
throw new ArgumentException ("value", "invalid device specification: " +
|
||||||
case FilePermissions.S_IFCHR: access [0] = 'c'; break;
|
value);
|
||||||
case FilePermissions.S_IFBLK: access [0] = 'b'; break;
|
}
|
||||||
case FilePermissions.S_IFREG: access [0] = '-'; break;
|
|
||||||
case FilePermissions.S_IFIFO: access [0] = 'p'; break;
|
|
||||||
case FilePermissions.S_IFLNK: access [0] = 'l'; break;
|
|
||||||
case FilePermissions.S_IFSOCK: access [0] = 's'; break;
|
|
||||||
default: have_device = false; break;
|
|
||||||
}
|
|
||||||
SetUnixPermissionGroup (value, access, 1,
|
|
||||||
FilePermissions.S_IRUSR, FilePermissions.S_IWUSR, FilePermissions.S_IXUSR,
|
|
||||||
's', 'S', FilePermissions.S_ISUID);
|
|
||||||
SetUnixPermissionGroup (value, access, 4,
|
|
||||||
FilePermissions.S_IRGRP, FilePermissions.S_IWGRP, FilePermissions.S_IXGRP,
|
|
||||||
's', 'S', FilePermissions.S_ISGID);
|
|
||||||
SetUnixPermissionGroup (value, access, 7,
|
|
||||||
FilePermissions.S_IROTH, FilePermissions.S_IWOTH, FilePermissions.S_IXOTH,
|
|
||||||
't', 'T', FilePermissions.S_ISVTX);
|
|
||||||
return have_device
|
|
||||||
? new string (access)
|
|
||||||
: new string (access, 1, 9);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void SetUnixPermissionGroup (FilePermissions value,
|
private static FilePermissions GetUnixPermissionGroup (
|
||||||
char[] access, int index,
|
Char read, FilePermissions readb,
|
||||||
FilePermissions read, FilePermissions write, FilePermissions exec,
|
Char write, FilePermissions writeb,
|
||||||
char both, char setonly, FilePermissions setxbit)
|
Char exec, FilePermissions execb,
|
||||||
{
|
Char xboth, Char xbitonly, FilePermissions xbit)
|
||||||
if (UnixFileSystemInfo.IsSet (value, read))
|
{
|
||||||
access [index] = 'r';
|
FilePermissions perms = new FilePermissions ();
|
||||||
if (UnixFileSystemInfo.IsSet (value, write))
|
if (read == 'r') {
|
||||||
access [index+1] = 'w';
|
perms |= readb;
|
||||||
access [index+2] = GetSymbolicMode (value, exec, both, setonly, setxbit);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Implement the GNU ls(1) permissions spec; see `info coreutils ls`,
|
if (write == 'w') {
|
||||||
// section 10.1.2, the `-l' argument information.
|
perms |= writeb;
|
||||||
private static char GetSymbolicMode (FilePermissions value,
|
}
|
||||||
FilePermissions xbit, char both, char setonly, FilePermissions setxbit)
|
|
||||||
{
|
|
||||||
bool is_x = UnixFileSystemInfo.IsSet (value, xbit);
|
|
||||||
bool is_sx = UnixFileSystemInfo.IsSet (value, setxbit);
|
|
||||||
|
|
||||||
if (is_x && is_sx)
|
if (exec == 'x') {
|
||||||
return both;
|
perms |= execb;
|
||||||
if (is_sx)
|
} else if (exec == xbitonly) {
|
||||||
return setonly;
|
perms |= xbit;
|
||||||
if (is_x)
|
} else if (exec == xboth) {
|
||||||
return 'x';
|
perms |= execb | xbit;
|
||||||
return '-';
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public static readonly DateTime UnixEpoch =
|
return perms;
|
||||||
new DateTime (year:1970, month:1, day:1, hour:0, minute:0, second:0, kind:DateTimeKind.Utc);
|
}
|
||||||
public static readonly DateTime LocalUnixEpoch =
|
|
||||||
new DateTime (1970, 1, 1);
|
|
||||||
public static readonly TimeSpan LocalUtcOffset =
|
|
||||||
TimeZone.CurrentTimeZone.GetUtcOffset (DateTime.UtcNow);
|
|
||||||
|
|
||||||
public static DateTime ToDateTime (long time)
|
// Create ls(1) drwxrwxrwx permissions display
|
||||||
{
|
public static String ToUnixPermissionString (FilePermissions value)
|
||||||
return FromTimeT (time);
|
{
|
||||||
}
|
Char[] access = new Char[] {
|
||||||
|
'-', // device
|
||||||
|
'-', '-', '-', // owner
|
||||||
|
'-', '-', '-', // group
|
||||||
|
'-', '-', '-', // other
|
||||||
|
};
|
||||||
|
Boolean have_device = true;
|
||||||
|
switch (value & FilePermissions.S_IFMT) {
|
||||||
|
case FilePermissions.S_IFDIR: access [0] = 'd'; break;
|
||||||
|
case FilePermissions.S_IFCHR: access [0] = 'c'; break;
|
||||||
|
case FilePermissions.S_IFBLK: access [0] = 'b'; break;
|
||||||
|
case FilePermissions.S_IFREG: access [0] = '-'; break;
|
||||||
|
case FilePermissions.S_IFIFO: access [0] = 'p'; break;
|
||||||
|
case FilePermissions.S_IFLNK: access [0] = 'l'; break;
|
||||||
|
case FilePermissions.S_IFSOCK: access [0] = 's'; break;
|
||||||
|
default: have_device = false; break;
|
||||||
|
}
|
||||||
|
SetUnixPermissionGroup (value, access, 1,
|
||||||
|
FilePermissions.S_IRUSR, FilePermissions.S_IWUSR, FilePermissions.S_IXUSR,
|
||||||
|
's', 'S', FilePermissions.S_ISUID);
|
||||||
|
SetUnixPermissionGroup (value, access, 4,
|
||||||
|
FilePermissions.S_IRGRP, FilePermissions.S_IWGRP, FilePermissions.S_IXGRP,
|
||||||
|
's', 'S', FilePermissions.S_ISGID);
|
||||||
|
SetUnixPermissionGroup (value, access, 7,
|
||||||
|
FilePermissions.S_IROTH, FilePermissions.S_IWOTH, FilePermissions.S_IXOTH,
|
||||||
|
't', 'T', FilePermissions.S_ISVTX);
|
||||||
|
return have_device
|
||||||
|
? new String(access)
|
||||||
|
: new String(access, 1, 9);
|
||||||
|
}
|
||||||
|
|
||||||
public static DateTime ToDateTime (long time, long nanoTime)
|
private static void SetUnixPermissionGroup (FilePermissions value,
|
||||||
{
|
Char[] access, Int32 index,
|
||||||
return FromTimeT (time).AddMilliseconds (nanoTime / 1000);
|
FilePermissions read, FilePermissions write, FilePermissions exec,
|
||||||
}
|
Char both, Char setonly, FilePermissions setxbit)
|
||||||
|
{
|
||||||
|
if (UnixFileSystemInfo.IsSet (value, read)) {
|
||||||
|
access [index] = 'r';
|
||||||
|
}
|
||||||
|
|
||||||
public static long FromDateTime (DateTime time)
|
if (UnixFileSystemInfo.IsSet (value, write)) {
|
||||||
{
|
access [index+1] = 'w';
|
||||||
return ToTimeT (time);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public static DateTime FromTimeT (long time)
|
access [index+2] = GetSymbolicMode (value, exec, both, setonly, setxbit);
|
||||||
{
|
}
|
||||||
return UnixEpoch.AddSeconds (time).ToLocalTime ();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long ToTimeT (DateTime time)
|
// Implement the GNU ls(1) permissions spec; see `info coreutils ls`,
|
||||||
{
|
// section 10.1.2, the `-l' argument information.
|
||||||
if (time.Kind == DateTimeKind.Unspecified)
|
private static Char GetSymbolicMode (FilePermissions value,
|
||||||
throw new ArgumentException ("DateTimeKind.Unspecified is not supported. Use Local or Utc times.", "time");
|
FilePermissions xbit, Char both, Char setonly, FilePermissions setxbit)
|
||||||
|
{
|
||||||
|
Boolean is_x = UnixFileSystemInfo.IsSet (value, xbit);
|
||||||
|
Boolean is_sx = UnixFileSystemInfo.IsSet (value, setxbit);
|
||||||
|
|
||||||
if (time.Kind == DateTimeKind.Local)
|
return is_x && is_sx ? both : is_sx ? setonly : is_x ? 'x' : '-';
|
||||||
time = time.ToUniversalTime ();
|
}
|
||||||
|
|
||||||
return (long) (time - UnixEpoch).TotalSeconds;
|
public static readonly DateTime UnixEpoch =
|
||||||
}
|
new DateTime (year:1970, month:1, day:1, hour:0, minute:0, second:0, kind:DateTimeKind.Utc);
|
||||||
|
public static readonly DateTime LocalUnixEpoch =
|
||||||
|
new DateTime (1970, 1, 1);
|
||||||
|
public static readonly TimeSpan LocalUtcOffset =
|
||||||
|
TimeZone.CurrentTimeZone.GetUtcOffset (DateTime.UtcNow);
|
||||||
|
|
||||||
public static OpenFlags ToOpenFlags (FileMode mode, FileAccess access)
|
public static DateTime ToDateTime(Int64 time) => FromTimeT(time);
|
||||||
{
|
|
||||||
OpenFlags flags = 0;
|
|
||||||
switch (mode) {
|
|
||||||
case FileMode.CreateNew:
|
|
||||||
flags = OpenFlags.O_CREAT | OpenFlags.O_EXCL;
|
|
||||||
break;
|
|
||||||
case FileMode.Create:
|
|
||||||
flags = OpenFlags.O_CREAT | OpenFlags.O_TRUNC;
|
|
||||||
break;
|
|
||||||
case FileMode.Open:
|
|
||||||
// do nothing
|
|
||||||
break;
|
|
||||||
case FileMode.OpenOrCreate:
|
|
||||||
flags = OpenFlags.O_CREAT;
|
|
||||||
break;
|
|
||||||
case FileMode.Truncate:
|
|
||||||
flags = OpenFlags.O_TRUNC;
|
|
||||||
break;
|
|
||||||
case FileMode.Append:
|
|
||||||
flags = OpenFlags.O_APPEND;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new ArgumentException (Locale.GetText ("Unsupported mode value"), "mode");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is O_LARGEFILE supported?
|
public static DateTime ToDateTime(Int64 time, Int64 nanoTime) => FromTimeT(time).AddMilliseconds(nanoTime / 1000);
|
||||||
int _v;
|
|
||||||
if (TryFromOpenFlags (OpenFlags.O_LARGEFILE, out _v))
|
|
||||||
flags |= OpenFlags.O_LARGEFILE;
|
|
||||||
|
|
||||||
switch (access) {
|
public static Int64 FromDateTime(DateTime time) => ToTimeT(time);
|
||||||
case FileAccess.Read:
|
|
||||||
flags |= OpenFlags.O_RDONLY;
|
|
||||||
break;
|
|
||||||
case FileAccess.Write:
|
|
||||||
flags |= OpenFlags.O_WRONLY;
|
|
||||||
break;
|
|
||||||
case FileAccess.ReadWrite:
|
|
||||||
flags |= OpenFlags.O_RDWR;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new ArgumentOutOfRangeException (Locale.GetText ("Unsupported access value"), "access");
|
|
||||||
}
|
|
||||||
|
|
||||||
return flags;
|
public static DateTime FromTimeT(Int64 time) => UnixEpoch.AddSeconds(time).ToLocalTime();
|
||||||
}
|
|
||||||
|
|
||||||
public static string ToFopenMode (FileAccess access)
|
public static Int64 ToTimeT (DateTime time)
|
||||||
{
|
{
|
||||||
switch (access) {
|
if (time.Kind == DateTimeKind.Unspecified) {
|
||||||
case FileAccess.Read: return "rb";
|
throw new ArgumentException ("DateTimeKind.Unspecified is not supported. Use Local or Utc times.", "time");
|
||||||
case FileAccess.Write: return "wb";
|
}
|
||||||
case FileAccess.ReadWrite: return "r+b";
|
|
||||||
default: throw new ArgumentOutOfRangeException ("access");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string ToFopenMode (FileMode mode)
|
if (time.Kind == DateTimeKind.Local) {
|
||||||
{
|
time = time.ToUniversalTime ();
|
||||||
switch (mode) {
|
}
|
||||||
case FileMode.CreateNew: case FileMode.Create: return "w+b";
|
|
||||||
case FileMode.Open: case FileMode.OpenOrCreate: return "r+b";
|
|
||||||
case FileMode.Truncate: return "w+b";
|
|
||||||
case FileMode.Append: return "a+b";
|
|
||||||
default: throw new ArgumentOutOfRangeException ("mode");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static readonly string[][] fopen_modes = new string[][]{
|
return (Int64) (time - UnixEpoch).TotalSeconds;
|
||||||
// Read Write ReadWrite
|
}
|
||||||
/* FileMode.CreateNew: */ new string[]{"Can't Read+Create", "wb", "w+b"},
|
|
||||||
/* FileMode.Create: */ new string[]{"Can't Read+Create", "wb", "w+b"},
|
|
||||||
/* FileMode.Open: */ new string[]{"rb", "wb", "r+b"},
|
|
||||||
/* FileMode.OpenOrCreate: */ new string[]{"rb", "wb", "r+b"},
|
|
||||||
/* FileMode.Truncate: */ new string[]{"Cannot Truncate and Read","wb", "w+b"},
|
|
||||||
/* FileMode.Append: */ new string[]{"Cannot Append and Read", "ab", "a+b"},
|
|
||||||
};
|
|
||||||
|
|
||||||
public static string ToFopenMode (FileMode mode, FileAccess access)
|
public static OpenFlags ToOpenFlags (FileMode mode, FileAccess access)
|
||||||
{
|
{
|
||||||
int fm = -1, fa = -1;
|
OpenFlags flags = 0;
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case FileMode.CreateNew: fm = 0; break;
|
case FileMode.CreateNew:
|
||||||
case FileMode.Create: fm = 1; break;
|
flags = OpenFlags.O_CREAT | OpenFlags.O_EXCL;
|
||||||
case FileMode.Open: fm = 2; break;
|
break;
|
||||||
case FileMode.OpenOrCreate: fm = 3; break;
|
case FileMode.Create:
|
||||||
case FileMode.Truncate: fm = 4; break;
|
flags = OpenFlags.O_CREAT | OpenFlags.O_TRUNC;
|
||||||
case FileMode.Append: fm = 5; break;
|
break;
|
||||||
}
|
case FileMode.Open:
|
||||||
switch (access) {
|
// do nothing
|
||||||
case FileAccess.Read: fa = 0; break;
|
break;
|
||||||
case FileAccess.Write: fa = 1; break;
|
case FileMode.OpenOrCreate:
|
||||||
case FileAccess.ReadWrite: fa = 2; break;
|
flags = OpenFlags.O_CREAT;
|
||||||
}
|
break;
|
||||||
|
case FileMode.Truncate:
|
||||||
|
flags = OpenFlags.O_TRUNC;
|
||||||
|
break;
|
||||||
|
case FileMode.Append:
|
||||||
|
flags = OpenFlags.O_APPEND;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentException (Locale.GetText ("Unsupported mode value"), "mode");
|
||||||
|
}
|
||||||
|
|
||||||
if (fm == -1)
|
// Is O_LARGEFILE supported?
|
||||||
throw new ArgumentOutOfRangeException ("mode");
|
if(TryFromOpenFlags(OpenFlags.O_LARGEFILE, out _)) {
|
||||||
if (fa == -1)
|
flags |= OpenFlags.O_LARGEFILE;
|
||||||
throw new ArgumentOutOfRangeException ("access");
|
}
|
||||||
|
|
||||||
string fopen_mode = fopen_modes [fm][fa];
|
switch (access) {
|
||||||
if (fopen_mode [0] != 'r' && fopen_mode [0] != 'w' && fopen_mode [0] != 'a')
|
case FileAccess.Read:
|
||||||
throw new ArgumentException (fopen_mode);
|
flags |= OpenFlags.O_RDONLY;
|
||||||
return fopen_mode;
|
break;
|
||||||
}
|
case FileAccess.Write:
|
||||||
|
flags |= OpenFlags.O_WRONLY;
|
||||||
|
break;
|
||||||
|
case FileAccess.ReadWrite:
|
||||||
|
flags |= OpenFlags.O_RDWR;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException (Locale.GetText ("Unsupported access value"), "access");
|
||||||
|
}
|
||||||
|
|
||||||
[DllImport (LIB, EntryPoint="Mono_Posix_FromStat")]
|
return flags;
|
||||||
private static extern int FromStat (ref Stat source, IntPtr destination);
|
}
|
||||||
|
|
||||||
public static bool TryCopy (ref Stat source, IntPtr destination)
|
public static String ToFopenMode (FileAccess access)
|
||||||
{
|
{
|
||||||
return FromStat (ref source, destination) == 0;
|
switch (access) {
|
||||||
}
|
case FileAccess.Read: return "rb";
|
||||||
|
case FileAccess.Write: return "wb";
|
||||||
|
case FileAccess.ReadWrite: return "r+b";
|
||||||
|
default: throw new ArgumentOutOfRangeException ("access");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[DllImport (LIB, EntryPoint="Mono_Posix_ToStat")]
|
public static String ToFopenMode (FileMode mode)
|
||||||
private static extern int ToStat (IntPtr source, out Stat destination);
|
{
|
||||||
|
switch (mode) {
|
||||||
|
case FileMode.CreateNew: case FileMode.Create: return "w+b";
|
||||||
|
case FileMode.Open: case FileMode.OpenOrCreate: return "r+b";
|
||||||
|
case FileMode.Truncate: return "w+b";
|
||||||
|
case FileMode.Append: return "a+b";
|
||||||
|
default: throw new ArgumentOutOfRangeException ("mode");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static bool TryCopy (IntPtr source, out Stat destination)
|
private static readonly String[][] fopen_modes = new String[][]{
|
||||||
{
|
// Read Write ReadWrite
|
||||||
return ToStat (source, out destination) == 0;
|
/* FileMode.CreateNew: */ new String[]{"Can't Read+Create", "wb", "w+b"},
|
||||||
}
|
/* FileMode.Create: */ new String[]{"Can't Read+Create", "wb", "w+b"},
|
||||||
|
/* FileMode.Open: */ new String[]{"rb", "wb", "r+b"},
|
||||||
|
/* FileMode.OpenOrCreate: */ new String[]{"rb", "wb", "r+b"},
|
||||||
|
/* FileMode.Truncate: */ new String[]{"Cannot Truncate and Read","wb", "w+b"},
|
||||||
|
/* FileMode.Append: */ new String[]{"Cannot Append and Read", "ab", "a+b"},
|
||||||
|
};
|
||||||
|
|
||||||
[DllImport (LIB, EntryPoint="Mono_Posix_FromStatvfs")]
|
public static String ToFopenMode (FileMode mode, FileAccess access)
|
||||||
private static extern int FromStatvfs (ref Statvfs source, IntPtr destination);
|
{
|
||||||
|
Int32 fm = -1, fa = -1;
|
||||||
|
switch (mode) {
|
||||||
|
case FileMode.CreateNew: fm = 0; break;
|
||||||
|
case FileMode.Create: fm = 1; break;
|
||||||
|
case FileMode.Open: fm = 2; break;
|
||||||
|
case FileMode.OpenOrCreate: fm = 3; break;
|
||||||
|
case FileMode.Truncate: fm = 4; break;
|
||||||
|
case FileMode.Append: fm = 5; break;
|
||||||
|
}
|
||||||
|
switch (access) {
|
||||||
|
case FileAccess.Read: fa = 0; break;
|
||||||
|
case FileAccess.Write: fa = 1; break;
|
||||||
|
case FileAccess.ReadWrite: fa = 2; break;
|
||||||
|
}
|
||||||
|
|
||||||
public static bool TryCopy (ref Statvfs source, IntPtr destination)
|
if (fm == -1) {
|
||||||
{
|
throw new ArgumentOutOfRangeException ("mode");
|
||||||
return FromStatvfs (ref source, destination) == 0;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
[DllImport (LIB, EntryPoint="Mono_Posix_ToStatvfs")]
|
if (fa == -1) {
|
||||||
private static extern int ToStatvfs (IntPtr source, out Statvfs destination);
|
throw new ArgumentOutOfRangeException ("access");
|
||||||
|
}
|
||||||
|
|
||||||
public static bool TryCopy (IntPtr source, out Statvfs destination)
|
String fopen_mode = fopen_modes [fm][fa];
|
||||||
{
|
if (fopen_mode [0] != 'r' && fopen_mode [0] != 'w' && fopen_mode [0] != 'a') {
|
||||||
return ToStatvfs (source, out destination) == 0;
|
throw new ArgumentException (fopen_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
[DllImport (LIB, EntryPoint="Mono_Posix_FromInAddr")]
|
return fopen_mode;
|
||||||
private static extern int FromInAddr (ref InAddr source, IntPtr destination);
|
}
|
||||||
|
|
||||||
public static bool TryCopy (ref InAddr source, IntPtr destination)
|
[DllImport (LIB, EntryPoint="Mono_Posix_FromStat")]
|
||||||
{
|
private static extern Int32 FromStat (ref Stat source, IntPtr destination);
|
||||||
return FromInAddr (ref source, destination) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
[DllImport (LIB, EntryPoint="Mono_Posix_ToInAddr")]
|
public static Boolean TryCopy(ref Stat source, IntPtr destination) => FromStat(ref source, destination) == 0;
|
||||||
private static extern int ToInAddr (IntPtr source, out InAddr destination);
|
|
||||||
|
|
||||||
public static bool TryCopy (IntPtr source, out InAddr destination)
|
[DllImport (LIB, EntryPoint="Mono_Posix_ToStat")]
|
||||||
{
|
private static extern Int32 ToStat (IntPtr source, out Stat destination);
|
||||||
return ToInAddr (source, out destination) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
[DllImport (LIB, EntryPoint="Mono_Posix_FromIn6Addr")]
|
public static Boolean TryCopy(IntPtr source, out Stat destination) => ToStat(source, out destination) == 0;
|
||||||
private static extern int FromIn6Addr (ref In6Addr source, IntPtr destination);
|
|
||||||
|
|
||||||
public static bool TryCopy (ref In6Addr source, IntPtr destination)
|
[DllImport (LIB, EntryPoint="Mono_Posix_FromStatvfs")]
|
||||||
{
|
private static extern Int32 FromStatvfs (ref Statvfs source, IntPtr destination);
|
||||||
return FromIn6Addr (ref source, destination) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
[DllImport (LIB, EntryPoint="Mono_Posix_ToIn6Addr")]
|
public static Boolean TryCopy(ref Statvfs source, IntPtr destination) => FromStatvfs(ref source, destination) == 0;
|
||||||
private static extern int ToIn6Addr (IntPtr source, out In6Addr destination);
|
|
||||||
|
|
||||||
public static bool TryCopy (IntPtr source, out In6Addr destination)
|
[DllImport (LIB, EntryPoint="Mono_Posix_ToStatvfs")]
|
||||||
{
|
private static extern Int32 ToStatvfs (IntPtr source, out Statvfs destination);
|
||||||
return ToIn6Addr (source, out destination) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static InAddr ToInAddr (System.Net.IPAddress address)
|
public static Boolean TryCopy(IntPtr source, out Statvfs destination) => ToStatvfs(source, out destination) == 0;
|
||||||
{
|
|
||||||
if (address == null)
|
|
||||||
throw new ArgumentNullException ("address");
|
|
||||||
if (address.AddressFamily != System.Net.Sockets.AddressFamily.InterNetwork)
|
|
||||||
throw new ArgumentException ("address", "address.AddressFamily != System.Net.Sockets.AddressFamily.InterNetwork");
|
|
||||||
return new InAddr (address.GetAddressBytes ());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static System.Net.IPAddress ToIPAddress (InAddr address)
|
[DllImport (LIB, EntryPoint="Mono_Posix_FromInAddr")]
|
||||||
{
|
private static extern Int32 FromInAddr (ref InAddr source, IntPtr destination);
|
||||||
var bytes = new byte[4];
|
|
||||||
address.CopyTo (bytes, 0);
|
|
||||||
return new System.Net.IPAddress (bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static In6Addr ToIn6Addr (System.Net.IPAddress address)
|
public static Boolean TryCopy(ref InAddr source, IntPtr destination) => FromInAddr(ref source, destination) == 0;
|
||||||
{
|
|
||||||
if (address == null)
|
|
||||||
throw new ArgumentNullException ("address");
|
|
||||||
if (address.AddressFamily != System.Net.Sockets.AddressFamily.InterNetworkV6)
|
|
||||||
throw new ArgumentException ("address", "address.AddressFamily != System.Net.Sockets.AddressFamily.InterNetworkV6");
|
|
||||||
return new In6Addr (address.GetAddressBytes ());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static System.Net.IPAddress ToIPAddress (In6Addr address)
|
[DllImport (LIB, EntryPoint="Mono_Posix_ToInAddr")]
|
||||||
{
|
private static extern Int32 ToInAddr (IntPtr source, out InAddr destination);
|
||||||
var bytes = new byte[16];
|
|
||||||
address.CopyTo (bytes, 0);
|
|
||||||
return new System.Net.IPAddress (bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
[DllImport (LIB, EntryPoint="Mono_Posix_FromSockaddr")]
|
public static Boolean TryCopy(IntPtr source, out InAddr destination) => ToInAddr(source, out destination) == 0;
|
||||||
private static extern unsafe int FromSockaddr (_SockaddrHeader* source, IntPtr destination);
|
|
||||||
|
|
||||||
public static unsafe bool TryCopy (Sockaddr source, IntPtr destination)
|
[DllImport (LIB, EntryPoint="Mono_Posix_FromIn6Addr")]
|
||||||
{
|
private static extern Int32 FromIn6Addr (ref In6Addr source, IntPtr destination);
|
||||||
if (source == null)
|
|
||||||
throw new ArgumentNullException ("source");
|
|
||||||
byte[] array = Sockaddr.GetDynamicData (source);
|
|
||||||
// SockaddrStorage has to be handled extra because the native code assumes that SockaddrStorage input is used in-place
|
|
||||||
if (source.type == (SockaddrType.SockaddrStorage | SockaddrType.MustBeWrapped)) {
|
|
||||||
Marshal.Copy (array, 0, destination, (int) source.GetDynamicLength ());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
fixed (SockaddrType* addr = &Sockaddr.GetAddress (source).type)
|
|
||||||
fixed (byte* data = array) {
|
|
||||||
var dyn = new _SockaddrDynamic (source, data, useMaxLength: false);
|
|
||||||
return FromSockaddr (Sockaddr.GetNative (&dyn, addr), destination) == 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[DllImport (LIB, EntryPoint="Mono_Posix_ToSockaddr")]
|
public static Boolean TryCopy(ref In6Addr source, IntPtr destination) => FromIn6Addr(ref source, destination) == 0;
|
||||||
private static extern unsafe int ToSockaddr (IntPtr source, long size, _SockaddrHeader* destination);
|
|
||||||
|
|
||||||
public static unsafe bool TryCopy (IntPtr source, long size, Sockaddr destination)
|
[DllImport (LIB, EntryPoint="Mono_Posix_ToIn6Addr")]
|
||||||
{
|
private static extern Int32 ToIn6Addr (IntPtr source, out In6Addr destination);
|
||||||
if (destination == null)
|
|
||||||
throw new ArgumentNullException ("destination");
|
public static Boolean TryCopy(IntPtr source, out In6Addr destination) => ToIn6Addr(source, out destination) == 0;
|
||||||
byte[] array = Sockaddr.GetDynamicData (destination);
|
|
||||||
fixed (SockaddrType* addr = &Sockaddr.GetAddress (destination).type)
|
public static InAddr ToInAddr (System.Net.IPAddress address)
|
||||||
fixed (byte* data = Sockaddr.GetDynamicData (destination)) {
|
{
|
||||||
var dyn = new _SockaddrDynamic (destination, data, useMaxLength: true);
|
if (address == null) {
|
||||||
var r = ToSockaddr (source, size, Sockaddr.GetNative (&dyn, addr));
|
throw new ArgumentNullException ("address");
|
||||||
dyn.Update (destination);
|
}
|
||||||
// SockaddrStorage has to be handled extra because the native code assumes that SockaddrStorage input is used in-place
|
|
||||||
if (r == 0 && destination.type == (SockaddrType.SockaddrStorage | SockaddrType.MustBeWrapped)) {
|
if (address.AddressFamily != System.Net.Sockets.AddressFamily.InterNetwork) {
|
||||||
Marshal.Copy (source, array, 0, (int) destination.GetDynamicLength ());
|
throw new ArgumentException ("address", "address.AddressFamily != System.Net.Sockets.AddressFamily.InterNetwork");
|
||||||
}
|
}
|
||||||
return r == 0;
|
|
||||||
}
|
return new InAddr (address.GetAddressBytes ());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public static System.Net.IPAddress ToIPAddress (InAddr address)
|
||||||
|
{
|
||||||
|
Byte[] bytes = new Byte[4];
|
||||||
|
address.CopyTo (bytes, 0);
|
||||||
|
return new System.Net.IPAddress (bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static In6Addr ToIn6Addr (System.Net.IPAddress address)
|
||||||
|
{
|
||||||
|
if (address == null) {
|
||||||
|
throw new ArgumentNullException ("address");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (address.AddressFamily != System.Net.Sockets.AddressFamily.InterNetworkV6) {
|
||||||
|
throw new ArgumentException ("address", "address.AddressFamily != System.Net.Sockets.AddressFamily.InterNetworkV6");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new In6Addr (address.GetAddressBytes ());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static System.Net.IPAddress ToIPAddress (In6Addr address)
|
||||||
|
{
|
||||||
|
Byte[] bytes = new Byte[16];
|
||||||
|
address.CopyTo (bytes, 0);
|
||||||
|
return new System.Net.IPAddress (bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport (LIB, EntryPoint="Mono_Posix_FromSockaddr")]
|
||||||
|
private static extern unsafe Int32 FromSockaddr (_SockaddrHeader* source, IntPtr destination);
|
||||||
|
|
||||||
|
public static unsafe Boolean TryCopy (Sockaddr source, IntPtr destination)
|
||||||
|
{
|
||||||
|
if (source == null) {
|
||||||
|
throw new ArgumentNullException ("source");
|
||||||
|
}
|
||||||
|
|
||||||
|
Byte[] array = Sockaddr.GetDynamicData (source);
|
||||||
|
// SockaddrStorage has to be handled extra because the native code assumes that SockaddrStorage input is used in-place
|
||||||
|
if (source.type == (SockaddrType.SockaddrStorage | SockaddrType.MustBeWrapped)) {
|
||||||
|
Marshal.Copy (array, 0, destination, (Int32) source.GetDynamicLength ());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
fixed (SockaddrType* addr = &Sockaddr.GetAddress (source).type)
|
||||||
|
fixed (Byte* data = array) {
|
||||||
|
_SockaddrDynamic dyn = new _SockaddrDynamic (source, data, useMaxLength: false);
|
||||||
|
return FromSockaddr (Sockaddr.GetNative (&dyn, addr), destination) == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport (LIB, EntryPoint="Mono_Posix_ToSockaddr")]
|
||||||
|
private static extern unsafe Int32 ToSockaddr (IntPtr source, Int64 size, _SockaddrHeader* destination);
|
||||||
|
|
||||||
|
public static unsafe Boolean TryCopy (IntPtr source, Int64 size, Sockaddr destination)
|
||||||
|
{
|
||||||
|
if (destination == null) {
|
||||||
|
throw new ArgumentNullException ("destination");
|
||||||
|
}
|
||||||
|
|
||||||
|
Byte[] array = Sockaddr.GetDynamicData (destination);
|
||||||
|
fixed (SockaddrType* addr = &Sockaddr.GetAddress (destination).type)
|
||||||
|
fixed (Byte* data = Sockaddr.GetDynamicData (destination)) {
|
||||||
|
_SockaddrDynamic dyn = new _SockaddrDynamic (destination, data, useMaxLength: true);
|
||||||
|
Int32 r = ToSockaddr (source, size, Sockaddr.GetNative (&dyn, addr));
|
||||||
|
dyn.Update (destination);
|
||||||
|
// SockaddrStorage has to be handled extra because the native code assumes that SockaddrStorage input is used in-place
|
||||||
|
if (r == 0 && destination.type == (SockaddrType.SockaddrStorage | SockaddrType.MustBeWrapped)) {
|
||||||
|
Marshal.Copy (source, array, 0, (Int32) destination.GetDynamicLength ());
|
||||||
|
}
|
||||||
|
return r == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim: noexpandtab
|
// vim: noexpandtab
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -25,57 +25,39 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Mono.Unix.Native {
|
namespace Mono.Unix.Native {
|
||||||
|
|
||||||
public struct RealTimeSignum
|
public struct RealTimeSignum
|
||||||
: IEquatable <RealTimeSignum>
|
: IEquatable <RealTimeSignum>
|
||||||
{
|
{
|
||||||
private int rt_offset;
|
private static readonly Int32 MaxOffset = UnixSignal.GetSIGRTMAX () - UnixSignal.GetSIGRTMIN () - 1;
|
||||||
private static readonly int MaxOffset = UnixSignal.GetSIGRTMAX () - UnixSignal.GetSIGRTMIN () - 1;
|
public static readonly RealTimeSignum MinValue = new RealTimeSignum (0);
|
||||||
public static readonly RealTimeSignum MinValue = new RealTimeSignum (0);
|
public static readonly RealTimeSignum MaxValue = new RealTimeSignum (MaxOffset);
|
||||||
public static readonly RealTimeSignum MaxValue = new RealTimeSignum (MaxOffset);
|
|
||||||
|
|
||||||
public RealTimeSignum (int offset)
|
public RealTimeSignum (Int32 offset)
|
||||||
{
|
{
|
||||||
if (offset < 0)
|
if (offset < 0) {
|
||||||
throw new ArgumentOutOfRangeException ("Offset cannot be negative");
|
throw new ArgumentOutOfRangeException ("Offset cannot be negative");
|
||||||
if (offset > MaxOffset)
|
}
|
||||||
throw new ArgumentOutOfRangeException ("Offset greater than maximum supported SIGRT");
|
|
||||||
rt_offset = offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Offset {
|
if (offset > MaxOffset) {
|
||||||
get { return rt_offset; }
|
throw new ArgumentOutOfRangeException ("Offset greater than maximum supported SIGRT");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetHashCode ()
|
this.Offset = offset;
|
||||||
{
|
}
|
||||||
return rt_offset.GetHashCode ();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals (object obj)
|
public Int32 Offset { get; }
|
||||||
{
|
|
||||||
if ((obj == null) || (obj.GetType () != GetType ()))
|
|
||||||
return false;
|
|
||||||
return Equals ((RealTimeSignum)obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Equals (RealTimeSignum value)
|
public override Int32 GetHashCode() => this.Offset.GetHashCode();
|
||||||
{
|
|
||||||
return Offset == value.Offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator== (RealTimeSignum lhs, RealTimeSignum rhs)
|
public override Boolean Equals(Object obj) => obj == null || obj.GetType() != this.GetType() ? false : this.Equals((RealTimeSignum)obj);
|
||||||
{
|
|
||||||
return lhs.Equals (rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator!= (RealTimeSignum lhs, RealTimeSignum rhs)
|
public Boolean Equals(RealTimeSignum value) => this.Offset == value.Offset;
|
||||||
{
|
|
||||||
return !lhs.Equals (rhs);
|
public static Boolean operator ==(RealTimeSignum lhs, RealTimeSignum rhs) => lhs.Equals(rhs);
|
||||||
}
|
|
||||||
}
|
public static Boolean operator !=(RealTimeSignum lhs, RealTimeSignum rhs) => !lhs.Equals(rhs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -28,111 +28,125 @@
|
|||||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
//
|
//
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
namespace Mono.Unix.Native {
|
namespace Mono.Unix.Native {
|
||||||
|
|
||||||
[AttributeUsage (AttributeTargets.Field)]
|
[AttributeUsage (AttributeTargets.Field)]
|
||||||
internal class blkcnt_tAttribute : MapAttribute {
|
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||||
|
internal class blkcnt_tAttribute : MapAttribute {
|
||||||
|
|
||||||
public blkcnt_tAttribute () : base ("blkcnt_t")
|
public blkcnt_tAttribute () : base ("blkcnt_t")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[AttributeUsage (AttributeTargets.Field)]
|
[AttributeUsage (AttributeTargets.Field)]
|
||||||
internal class blksize_tAttribute : MapAttribute {
|
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||||
|
internal class blksize_tAttribute : MapAttribute {
|
||||||
|
|
||||||
public blksize_tAttribute () : base ("blksize_t")
|
public blksize_tAttribute () : base ("blksize_t")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[AttributeUsage (AttributeTargets.Field)]
|
[AttributeUsage (AttributeTargets.Field)]
|
||||||
internal class dev_tAttribute : MapAttribute {
|
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||||
|
internal class dev_tAttribute : MapAttribute {
|
||||||
|
|
||||||
public dev_tAttribute () : base ("dev_t")
|
public dev_tAttribute () : base ("dev_t")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[AttributeUsage (AttributeTargets.Field)]
|
[AttributeUsage (AttributeTargets.Field)]
|
||||||
internal class gid_tAttribute : MapAttribute {
|
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||||
|
internal class gid_tAttribute : MapAttribute {
|
||||||
|
|
||||||
public gid_tAttribute () : base ("gid_t")
|
public gid_tAttribute () : base ("gid_t")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[AttributeUsage (AttributeTargets.Field)]
|
[AttributeUsage (AttributeTargets.Field)]
|
||||||
internal class fsblkcnt_tAttribute : MapAttribute {
|
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||||
|
internal class fsblkcnt_tAttribute : MapAttribute {
|
||||||
|
|
||||||
public fsblkcnt_tAttribute () : base ("fsblkcnt_t")
|
public fsblkcnt_tAttribute () : base ("fsblkcnt_t")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[AttributeUsage (AttributeTargets.Field)]
|
[AttributeUsage (AttributeTargets.Field)]
|
||||||
internal class fsfilcnt_tAttribute : MapAttribute {
|
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||||
|
internal class fsfilcnt_tAttribute : MapAttribute {
|
||||||
|
|
||||||
public fsfilcnt_tAttribute () : base ("fsfilcnt_t")
|
public fsfilcnt_tAttribute () : base ("fsfilcnt_t")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[AttributeUsage (AttributeTargets.Field)]
|
[AttributeUsage (AttributeTargets.Field)]
|
||||||
internal class ino_tAttribute : MapAttribute {
|
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||||
|
internal class ino_tAttribute : MapAttribute {
|
||||||
|
|
||||||
public ino_tAttribute () : base ("ino_t")
|
public ino_tAttribute () : base ("ino_t")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[AttributeUsage (AttributeTargets.Field)]
|
[AttributeUsage (AttributeTargets.Field)]
|
||||||
internal class nlink_tAttribute : MapAttribute {
|
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||||
|
internal class nlink_tAttribute : MapAttribute {
|
||||||
|
|
||||||
public nlink_tAttribute () : base ("nlink_t")
|
public nlink_tAttribute () : base ("nlink_t")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[AttributeUsage (AttributeTargets.Field)]
|
[AttributeUsage (AttributeTargets.Field)]
|
||||||
internal class off_tAttribute : MapAttribute {
|
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||||
|
internal class off_tAttribute : MapAttribute {
|
||||||
|
|
||||||
public off_tAttribute () : base ("off_t")
|
public off_tAttribute () : base ("off_t")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[AttributeUsage (AttributeTargets.Field)]
|
[AttributeUsage (AttributeTargets.Field)]
|
||||||
internal class pid_tAttribute : MapAttribute {
|
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||||
|
internal class pid_tAttribute : MapAttribute {
|
||||||
|
|
||||||
public pid_tAttribute () : base ("pid_t")
|
public pid_tAttribute () : base ("pid_t")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[AttributeUsage (AttributeTargets.Field)]
|
[AttributeUsage (AttributeTargets.Field)]
|
||||||
internal class suseconds_tAttribute : MapAttribute {
|
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||||
|
internal class suseconds_tAttribute : MapAttribute {
|
||||||
|
|
||||||
public suseconds_tAttribute () : base ("suseconds_t")
|
public suseconds_tAttribute () : base ("suseconds_t")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[AttributeUsage (AttributeTargets.Field)]
|
[AttributeUsage (AttributeTargets.Field)]
|
||||||
internal class uid_tAttribute : MapAttribute {
|
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||||
|
internal class uid_tAttribute : MapAttribute {
|
||||||
|
|
||||||
public uid_tAttribute () : base ("uid_t")
|
public uid_tAttribute () : base ("uid_t")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[AttributeUsage (AttributeTargets.Field)]
|
[AttributeUsage (AttributeTargets.Field)]
|
||||||
internal class time_tAttribute : MapAttribute {
|
[SuppressMessage("Microsoft.Design","IDE1006", Justification = "Can not change name!")]
|
||||||
|
internal class time_tAttribute : MapAttribute {
|
||||||
|
|
||||||
public time_tAttribute () : base ("time_t")
|
public time_tAttribute () : base ("time_t")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,88 +36,82 @@ using System.Text;
|
|||||||
|
|
||||||
namespace Mono.Unix
|
namespace Mono.Unix
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class AbstractUnixEndPoint : EndPoint
|
public class AbstractUnixEndPoint : EndPoint
|
||||||
{
|
{
|
||||||
string path;
|
String path;
|
||||||
|
|
||||||
public AbstractUnixEndPoint (string path)
|
public AbstractUnixEndPoint (String path)
|
||||||
{
|
{
|
||||||
if (path == null)
|
if (path == null) {
|
||||||
throw new ArgumentNullException ("path");
|
throw new ArgumentNullException ("path");
|
||||||
|
}
|
||||||
|
|
||||||
if (path == "")
|
if (path == "") {
|
||||||
throw new ArgumentException ("Cannot be empty.", "path");
|
throw new ArgumentException ("Cannot be empty.", "path");
|
||||||
this.path = path;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public string Path {
|
this.path = path;
|
||||||
get {
|
}
|
||||||
return(path);
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
path=value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override AddressFamily AddressFamily {
|
public String Path {
|
||||||
get { return AddressFamily.Unix; }
|
get => this.path;
|
||||||
}
|
set => this.path = value;
|
||||||
|
}
|
||||||
|
|
||||||
public override EndPoint Create (SocketAddress socketAddress)
|
public override AddressFamily AddressFamily => AddressFamily.Unix;
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Should also check this
|
|
||||||
*
|
|
||||||
int addr = (int) AddressFamily.Unix;
|
|
||||||
if (socketAddress [0] != (addr & 0xFF))
|
|
||||||
throw new ArgumentException ("socketAddress is not a unix socket address.");
|
|
||||||
|
|
||||||
if (socketAddress [1] != ((addr & 0xFF00) >> 8))
|
public override EndPoint Create (SocketAddress socketAddress)
|
||||||
throw new ArgumentException ("socketAddress is not a unix socket address.");
|
{
|
||||||
*/
|
/*
|
||||||
|
* Should also check this
|
||||||
|
*
|
||||||
|
int addr = (int) AddressFamily.Unix;
|
||||||
|
if (socketAddress [0] != (addr & 0xFF))
|
||||||
|
throw new ArgumentException ("socketAddress is not a unix socket address.");
|
||||||
|
|
||||||
byte [] bytes = new byte [socketAddress.Size - 2 - 1];
|
if (socketAddress [1] != ((addr & 0xFF00) >> 8))
|
||||||
for (int i = 0; i < bytes.Length; i++) {
|
throw new ArgumentException ("socketAddress is not a unix socket address.");
|
||||||
bytes [i] = socketAddress [2 + 1 + i];
|
*/
|
||||||
}
|
|
||||||
|
|
||||||
string name = Encoding.Default.GetString (bytes);
|
Byte[] bytes = new Byte[socketAddress.Size - 2 - 1];
|
||||||
return new AbstractUnixEndPoint (name);
|
for (Int32 i = 0; i < bytes.Length; i++) {
|
||||||
}
|
bytes [i] = socketAddress [2 + 1 + i];
|
||||||
|
}
|
||||||
|
|
||||||
public override SocketAddress Serialize ()
|
String name = Encoding.Default.GetString (bytes);
|
||||||
{
|
return new AbstractUnixEndPoint (name);
|
||||||
byte [] bytes = Encoding.Default.GetBytes (path);
|
}
|
||||||
SocketAddress sa = new SocketAddress (AddressFamily, 2 + 1 + bytes.Length);
|
|
||||||
//NULL prefix denotes the abstract namespace, see unix(7)
|
|
||||||
//in this case, there is no NULL suffix
|
|
||||||
sa [2] = 0;
|
|
||||||
|
|
||||||
// sa [0] -> family low byte, sa [1] -> family high byte
|
public override SocketAddress Serialize ()
|
||||||
for (int i = 0; i < bytes.Length; i++)
|
{
|
||||||
sa [i + 2 + 1] = bytes [i];
|
Byte[] bytes = Encoding.Default.GetBytes (this.path);
|
||||||
|
SocketAddress sa = new SocketAddress (this.AddressFamily, 2 + 1 + bytes.Length);
|
||||||
|
//NULL prefix denotes the abstract namespace, see unix(7)
|
||||||
|
//in this case, there is no NULL suffix
|
||||||
|
sa [2] = 0;
|
||||||
|
|
||||||
return sa;
|
// sa [0] -> family low byte, sa [1] -> family high byte
|
||||||
}
|
for (Int32 i = 0; i < bytes.Length; i++) {
|
||||||
|
sa [i + 2 + 1] = bytes [i];
|
||||||
|
}
|
||||||
|
|
||||||
public override string ToString() {
|
return sa;
|
||||||
return(path);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode ()
|
public override String ToString() => this.path;
|
||||||
{
|
|
||||||
return path.GetHashCode ();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals (object o)
|
public override Int32 GetHashCode() => this.path.GetHashCode();
|
||||||
{
|
|
||||||
AbstractUnixEndPoint other = o as AbstractUnixEndPoint;
|
|
||||||
if (other == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return (other.path == path);
|
public override Boolean Equals (Object o)
|
||||||
}
|
{
|
||||||
}
|
AbstractUnixEndPoint other = o as AbstractUnixEndPoint;
|
||||||
|
if (other == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return other.path == this.path;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,104 +33,112 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Mono.Unix {
|
namespace Mono.Unix {
|
||||||
|
|
||||||
public class Catalog {
|
public class Catalog {
|
||||||
private Catalog () {}
|
private Catalog () {}
|
||||||
|
|
||||||
[DllImport("intl", CallingConvention=CallingConvention.Cdecl)]
|
[DllImport("intl", CallingConvention=CallingConvention.Cdecl)]
|
||||||
static extern IntPtr bindtextdomain (IntPtr domainname, IntPtr dirname);
|
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||||
[DllImport("intl", CallingConvention=CallingConvention.Cdecl)]
|
static extern IntPtr bindtextdomain (IntPtr domainname, IntPtr dirname);
|
||||||
static extern IntPtr bind_textdomain_codeset (IntPtr domainname,
|
[DllImport("intl", CallingConvention=CallingConvention.Cdecl)]
|
||||||
IntPtr codeset);
|
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||||
[DllImport("intl", CallingConvention=CallingConvention.Cdecl)]
|
static extern IntPtr bind_textdomain_codeset (IntPtr domainname,
|
||||||
static extern IntPtr textdomain (IntPtr domainname);
|
IntPtr codeset);
|
||||||
|
[DllImport("intl", CallingConvention=CallingConvention.Cdecl)]
|
||||||
|
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||||
|
static extern IntPtr textdomain (IntPtr domainname);
|
||||||
|
|
||||||
public static void Init (String package, String localedir)
|
public static void Init (String package, String localedir)
|
||||||
{
|
{
|
||||||
IntPtr ipackage, ilocaledir, iutf8;
|
MarshalStrings(package, out IntPtr ipackage, localedir, out IntPtr ilocaledir,
|
||||||
MarshalStrings (package, out ipackage, localedir, out ilocaledir,
|
"UTF-8", out IntPtr iutf8);
|
||||||
"UTF-8", out iutf8);
|
try {
|
||||||
try {
|
if (bindtextdomain (ipackage, ilocaledir) == IntPtr.Zero) {
|
||||||
if (bindtextdomain (ipackage, ilocaledir) == IntPtr.Zero)
|
throw new UnixIOException (Native.Errno.ENOMEM);
|
||||||
throw new UnixIOException (Native.Errno.ENOMEM);
|
}
|
||||||
if (bind_textdomain_codeset (ipackage, iutf8) == IntPtr.Zero)
|
|
||||||
throw new UnixIOException (Native.Errno.ENOMEM);
|
|
||||||
if (textdomain (ipackage) == IntPtr.Zero)
|
|
||||||
throw new UnixIOException (Native.Errno.ENOMEM);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
UnixMarshal.FreeHeap (ipackage);
|
|
||||||
UnixMarshal.FreeHeap (ilocaledir);
|
|
||||||
UnixMarshal.FreeHeap (iutf8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void MarshalStrings (string s1, out IntPtr p1,
|
if (bind_textdomain_codeset (ipackage, iutf8) == IntPtr.Zero) {
|
||||||
string s2, out IntPtr p2, string s3, out IntPtr p3)
|
throw new UnixIOException (Native.Errno.ENOMEM);
|
||||||
{
|
}
|
||||||
p1 = p2 = p3 = IntPtr.Zero;
|
|
||||||
|
|
||||||
bool cleanup = true;
|
if (textdomain (ipackage) == IntPtr.Zero) {
|
||||||
|
throw new UnixIOException (Native.Errno.ENOMEM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
UnixMarshal.FreeHeap (ipackage);
|
||||||
|
UnixMarshal.FreeHeap (ilocaledir);
|
||||||
|
UnixMarshal.FreeHeap (iutf8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
private static void MarshalStrings (String s1, out IntPtr p1,
|
||||||
p1 = UnixMarshal.StringToHeap (s1);
|
String s2, out IntPtr p2, String s3, out IntPtr p3)
|
||||||
p2 = UnixMarshal.StringToHeap (s2);
|
{
|
||||||
if (s3 != null)
|
p1 = p2 = p3 = IntPtr.Zero;
|
||||||
p3 = UnixMarshal.StringToHeap (s3);
|
|
||||||
cleanup = false;
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
if (cleanup) {
|
|
||||||
UnixMarshal.FreeHeap (p1);
|
|
||||||
UnixMarshal.FreeHeap (p2);
|
|
||||||
UnixMarshal.FreeHeap (p3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[DllImport("intl", CallingConvention=CallingConvention.Cdecl)]
|
Boolean cleanup = true;
|
||||||
static extern IntPtr gettext (IntPtr instring);
|
|
||||||
|
|
||||||
public static String GetString (String s)
|
try {
|
||||||
{
|
p1 = UnixMarshal.StringToHeap (s1);
|
||||||
IntPtr ints = UnixMarshal.StringToHeap (s);
|
p2 = UnixMarshal.StringToHeap (s2);
|
||||||
try {
|
if (s3 != null) {
|
||||||
// gettext(3) returns the input pointer if no translation is found
|
p3 = UnixMarshal.StringToHeap (s3);
|
||||||
IntPtr r = gettext (ints);
|
}
|
||||||
if (r != ints)
|
|
||||||
return UnixMarshal.PtrToStringUnix (r);
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
UnixMarshal.FreeHeap (ints);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[DllImport("intl", CallingConvention=CallingConvention.Cdecl)]
|
cleanup = false;
|
||||||
static extern IntPtr ngettext (IntPtr singular, IntPtr plural, Int32 n);
|
}
|
||||||
|
finally {
|
||||||
|
if (cleanup) {
|
||||||
|
UnixMarshal.FreeHeap (p1);
|
||||||
|
UnixMarshal.FreeHeap (p2);
|
||||||
|
UnixMarshal.FreeHeap (p3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static String GetPluralString (String s, String p, Int32 n)
|
[DllImport("intl", CallingConvention=CallingConvention.Cdecl)]
|
||||||
{
|
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||||
IntPtr ints, intp, _ignore;
|
static extern IntPtr gettext (IntPtr instring);
|
||||||
MarshalStrings (s, out ints, p, out intp, null, out _ignore);
|
|
||||||
|
|
||||||
try {
|
public static String GetString (String s)
|
||||||
// ngettext(3) returns an input pointer if no translation is found
|
{
|
||||||
IntPtr r = ngettext (ints, intp, n);
|
IntPtr ints = UnixMarshal.StringToHeap (s);
|
||||||
if (r == ints)
|
try {
|
||||||
return s;
|
// gettext(3) returns the input pointer if no translation is found
|
||||||
if (r == intp)
|
IntPtr r = gettext (ints);
|
||||||
return p;
|
if (r != ints) {
|
||||||
return UnixMarshal.PtrToStringUnix (r);
|
return UnixMarshal.PtrToStringUnix (r);
|
||||||
}
|
}
|
||||||
finally {
|
|
||||||
UnixMarshal.FreeHeap (ints);
|
return s;
|
||||||
UnixMarshal.FreeHeap (intp);
|
}
|
||||||
}
|
finally {
|
||||||
}
|
UnixMarshal.FreeHeap (ints);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport("intl", CallingConvention=CallingConvention.Cdecl)]
|
||||||
|
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||||
|
static extern IntPtr ngettext (IntPtr singular, IntPtr plural, Int32 n);
|
||||||
|
|
||||||
|
public static String GetPluralString (String s, String p, Int32 n)
|
||||||
|
{
|
||||||
|
MarshalStrings(s, out IntPtr ints, p, out IntPtr intp, null, out IntPtr _ignore);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// ngettext(3) returns an input pointer if no translation is found
|
||||||
|
IntPtr r = ngettext (ints, intp, n);
|
||||||
|
return r == ints ? s : r == intp ? p : UnixMarshal.PtrToStringUnix (r);
|
||||||
|
} finally {
|
||||||
|
UnixMarshal.FreeHeap (ints);
|
||||||
|
UnixMarshal.FreeHeap (intp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,56 +27,53 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Mono.Unix;
|
using Mono.Unix;
|
||||||
|
|
||||||
namespace Mono.Unix {
|
namespace Mono.Unix {
|
||||||
|
|
||||||
public sealed /* static */ class FileHandleOperations
|
public sealed /* static */ class FileHandleOperations
|
||||||
{
|
{
|
||||||
private FileHandleOperations () {}
|
private FileHandleOperations () {}
|
||||||
|
|
||||||
public static void AdviseFileAccessPattern (int fd, FileAccessPattern pattern, long offset, long len)
|
public static void AdviseFileAccessPattern (Int32 fd, FileAccessPattern pattern, Int64 offset, Int64 len)
|
||||||
{
|
{
|
||||||
int r = Native.Syscall.posix_fadvise (fd, offset, len,
|
Int32 r = Native.Syscall.posix_fadvise (fd, offset, len,
|
||||||
(Native.PosixFadviseAdvice) pattern);
|
(Native.PosixFadviseAdvice) pattern);
|
||||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void AdviseFileAccessPattern (int fd, FileAccessPattern pattern)
|
public static void AdviseFileAccessPattern(Int32 fd, FileAccessPattern pattern) => AdviseFileAccessPattern(fd, pattern, 0, 0);
|
||||||
{
|
|
||||||
AdviseFileAccessPattern (fd, pattern, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void AdviseFileAccessPattern (FileStream file, FileAccessPattern pattern, long offset, long len)
|
[SuppressMessage("Microsoft.Design", "CS0618", Justification = "Someone do shit")]
|
||||||
{
|
public static void AdviseFileAccessPattern (FileStream file, FileAccessPattern pattern, Int64 offset, Int64 len)
|
||||||
if (file == null)
|
{
|
||||||
throw new ArgumentNullException ("file");
|
if (file == null) {
|
||||||
int r = Native.Syscall.posix_fadvise (file.Handle.ToInt32(), offset, len,
|
throw new ArgumentNullException ("file");
|
||||||
(Native.PosixFadviseAdvice) pattern);
|
}
|
||||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void AdviseFileAccessPattern (FileStream file, FileAccessPattern pattern)
|
Int32 r = Native.Syscall.posix_fadvise (file.Handle.ToInt32(), offset, len,
|
||||||
{
|
(Native.PosixFadviseAdvice) pattern);
|
||||||
AdviseFileAccessPattern (file, pattern, 0, 0);
|
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void AdviseFileAccessPattern (UnixStream stream, FileAccessPattern pattern, long offset, long len)
|
public static void AdviseFileAccessPattern(FileStream file, FileAccessPattern pattern) => AdviseFileAccessPattern(file, pattern, 0, 0);
|
||||||
{
|
|
||||||
if (stream == null)
|
|
||||||
throw new ArgumentNullException ("stream");
|
|
||||||
int r = Native.Syscall.posix_fadvise (stream.Handle, offset, len,
|
|
||||||
(Native.PosixFadviseAdvice) pattern);
|
|
||||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void AdviseFileAccessPattern (UnixStream stream, FileAccessPattern pattern)
|
public static void AdviseFileAccessPattern (UnixStream stream, FileAccessPattern pattern, Int64 offset, Int64 len)
|
||||||
{
|
{
|
||||||
AdviseFileAccessPattern (stream, pattern, 0, 0);
|
if (stream == null) {
|
||||||
}
|
throw new ArgumentNullException ("stream");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Int32 r = Native.Syscall.posix_fadvise (stream.Handle, offset, len,
|
||||||
|
(Native.PosixFadviseAdvice) pattern);
|
||||||
|
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void AdviseFileAccessPattern(UnixStream stream, FileAccessPattern pattern) => AdviseFileAccessPattern(stream, pattern, 0, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim: noexpandtab
|
// vim: noexpandtab
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -34,48 +34,36 @@ using System.Net.Sockets;
|
|||||||
namespace Mono.Unix
|
namespace Mono.Unix
|
||||||
{
|
{
|
||||||
#pragma warning disable 649
|
#pragma warning disable 649
|
||||||
internal struct PeerCredData {
|
internal struct PeerCredData {
|
||||||
public int pid;
|
public Int32 pid;
|
||||||
public int uid;
|
public Int32 uid;
|
||||||
public int gid;
|
public Int32 gid;
|
||||||
}
|
}
|
||||||
#pragma warning restore 649
|
#pragma warning restore 649
|
||||||
|
|
||||||
public class PeerCred
|
public class PeerCred
|
||||||
{
|
{
|
||||||
/* Make sure this doesn't clash with anything in
|
/* Make sure this doesn't clash with anything in
|
||||||
* SocketOptionName, and keep it synchronised with the
|
* SocketOptionName, and keep it synchronised with the
|
||||||
* runtime
|
* runtime
|
||||||
*/
|
*/
|
||||||
private const int so_peercred=10001;
|
private const Int32 so_peercred =10001;
|
||||||
private PeerCredData data;
|
private PeerCredData data;
|
||||||
|
|
||||||
public PeerCred (Socket sock) {
|
public PeerCred (Socket sock) {
|
||||||
if (sock.AddressFamily != AddressFamily.Unix) {
|
if (sock.AddressFamily != AddressFamily.Unix) {
|
||||||
throw new ArgumentException ("Only Unix sockets are supported", "sock");
|
throw new ArgumentException ("Only Unix sockets are supported", "sock");
|
||||||
}
|
}
|
||||||
|
|
||||||
data = (PeerCredData)
|
this.data = (PeerCredData)
|
||||||
sock.GetSocketOption (SocketOptionLevel.Socket, (SocketOptionName)so_peercred);
|
sock.GetSocketOption (SocketOptionLevel.Socket, (SocketOptionName)so_peercred);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int ProcessID {
|
public Int32 ProcessID => this.data.pid;
|
||||||
get {
|
|
||||||
return(data.pid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int UserID {
|
public Int32 UserID => this.data.uid;
|
||||||
get {
|
|
||||||
return(data.uid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int GroupID {
|
public Int32 GroupID => this.data.gid;
|
||||||
get {
|
}
|
||||||
return(data.gid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,373 +34,424 @@ using Mono.Unix;
|
|||||||
|
|
||||||
namespace Mono.Unix {
|
namespace Mono.Unix {
|
||||||
|
|
||||||
public class StdioFileStream : Stream
|
public class StdioFileStream : Stream
|
||||||
{
|
{
|
||||||
public static readonly IntPtr InvalidFileStream = IntPtr.Zero;
|
public static readonly IntPtr InvalidFileStream = IntPtr.Zero;
|
||||||
public static readonly IntPtr StandardInput = Native.Stdlib.stdin;
|
public static readonly IntPtr StandardInput = Native.Stdlib.stdin;
|
||||||
public static readonly IntPtr StandardOutput = Native.Stdlib.stdout;
|
public static readonly IntPtr StandardOutput = Native.Stdlib.stdout;
|
||||||
public static readonly IntPtr StandardError = Native.Stdlib.stderr;
|
public static readonly IntPtr StandardError = Native.Stdlib.stderr;
|
||||||
|
|
||||||
public StdioFileStream (IntPtr fileStream)
|
public StdioFileStream (IntPtr fileStream)
|
||||||
: this (fileStream, true) {}
|
: this (fileStream, true) {}
|
||||||
|
|
||||||
public StdioFileStream (IntPtr fileStream, bool ownsHandle)
|
public StdioFileStream(IntPtr fileStream, Boolean ownsHandle) => this.InitStream(fileStream, ownsHandle);
|
||||||
{
|
|
||||||
InitStream (fileStream, ownsHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public StdioFileStream (IntPtr fileStream, FileAccess access)
|
public StdioFileStream (IntPtr fileStream, FileAccess access)
|
||||||
: this (fileStream, access, true) {}
|
: this (fileStream, access, true) {}
|
||||||
|
|
||||||
public StdioFileStream (IntPtr fileStream, FileAccess access, bool ownsHandle)
|
public StdioFileStream (IntPtr fileStream, FileAccess access, Boolean ownsHandle)
|
||||||
{
|
{
|
||||||
InitStream (fileStream, ownsHandle);
|
this.InitStream (fileStream, ownsHandle);
|
||||||
InitCanReadWrite (access);
|
this.InitCanReadWrite (access);
|
||||||
}
|
}
|
||||||
|
|
||||||
public StdioFileStream (string path)
|
public StdioFileStream (String path)
|
||||||
{
|
{
|
||||||
if (path == null)
|
if (path == null) {
|
||||||
throw new ArgumentNullException ("path");
|
throw new ArgumentNullException ("path");
|
||||||
InitStream (Fopen (path, "rb"), true);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public StdioFileStream (string path, string mode)
|
this.InitStream (Fopen (path, "rb"), true);
|
||||||
{
|
}
|
||||||
if (path == null)
|
|
||||||
throw new ArgumentNullException ("path");
|
|
||||||
InitStream (Fopen (path, mode), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public StdioFileStream (string path, FileMode mode)
|
public StdioFileStream (String path, String mode)
|
||||||
{
|
{
|
||||||
if (path == null)
|
if (path == null) {
|
||||||
throw new ArgumentNullException ("path");
|
throw new ArgumentNullException ("path");
|
||||||
InitStream (Fopen (path, ToFopenMode (path, mode)), true);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public StdioFileStream (string path, FileAccess access)
|
this.InitStream (Fopen (path, mode), true);
|
||||||
{
|
}
|
||||||
if (path == null)
|
|
||||||
throw new ArgumentNullException ("path");
|
|
||||||
InitStream (Fopen (path, ToFopenMode (path, access)), true);
|
|
||||||
InitCanReadWrite (access);
|
|
||||||
}
|
|
||||||
|
|
||||||
public StdioFileStream (string path, FileMode mode, FileAccess access)
|
public StdioFileStream (String path, FileMode mode)
|
||||||
{
|
{
|
||||||
if (path == null)
|
if (path == null) {
|
||||||
throw new ArgumentNullException ("path");
|
throw new ArgumentNullException ("path");
|
||||||
InitStream (Fopen (path, ToFopenMode (path, mode, access)), true);
|
}
|
||||||
InitCanReadWrite (access);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IntPtr Fopen (string path, string mode)
|
this.InitStream (Fopen (path, ToFopenMode (path, mode)), true);
|
||||||
{
|
}
|
||||||
if (path.Length == 0)
|
|
||||||
throw new ArgumentException ("path");
|
|
||||||
if (mode == null)
|
|
||||||
throw new ArgumentNullException ("mode");
|
|
||||||
IntPtr f = Native.Stdlib.fopen (path, mode);
|
|
||||||
if (f == IntPtr.Zero)
|
|
||||||
throw new DirectoryNotFoundException ("path",
|
|
||||||
UnixMarshal.CreateExceptionForLastError ());
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InitStream (IntPtr fileStream, bool ownsHandle)
|
public StdioFileStream (String path, FileAccess access)
|
||||||
{
|
{
|
||||||
if (InvalidFileStream == fileStream)
|
if (path == null) {
|
||||||
throw new ArgumentException (Locale.GetText ("Invalid file stream"), "fileStream");
|
throw new ArgumentNullException ("path");
|
||||||
|
}
|
||||||
|
|
||||||
this.file = fileStream;
|
this.InitStream (Fopen (path, ToFopenMode (path, access)), true);
|
||||||
this.owner = ownsHandle;
|
this.InitCanReadWrite (access);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
public StdioFileStream (String path, FileMode mode, FileAccess access)
|
||||||
long offset = Native.Stdlib.fseek (file, 0, Native.SeekFlags.SEEK_CUR);
|
{
|
||||||
if (offset != -1)
|
if (path == null) {
|
||||||
canSeek = true;
|
throw new ArgumentNullException ("path");
|
||||||
Native.Stdlib.fread (IntPtr.Zero, 0, 0, file);
|
}
|
||||||
if (Native.Stdlib.ferror (file) == 0)
|
|
||||||
canRead = true;
|
|
||||||
Native.Stdlib.fwrite (IntPtr.Zero, 0, 0, file);
|
|
||||||
if (Native.Stdlib.ferror (file) == 0)
|
|
||||||
canWrite = true;
|
|
||||||
Native.Stdlib.clearerr (file);
|
|
||||||
}
|
|
||||||
catch (Exception) {
|
|
||||||
throw new ArgumentException (Locale.GetText ("Invalid file stream"), "fileStream");
|
|
||||||
}
|
|
||||||
GC.KeepAlive (this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InitCanReadWrite (FileAccess access)
|
this.InitStream (Fopen (path, ToFopenMode (path, mode, access)), true);
|
||||||
{
|
this.InitCanReadWrite (access);
|
||||||
canRead = canRead &&
|
}
|
||||||
(access == FileAccess.Read || access == FileAccess.ReadWrite);
|
|
||||||
canWrite = canWrite &&
|
|
||||||
(access == FileAccess.Write || access == FileAccess.ReadWrite);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string ToFopenMode (string file, FileMode mode)
|
private static IntPtr Fopen (String path, String mode)
|
||||||
{
|
{
|
||||||
string cmode = Native.NativeConvert.ToFopenMode (mode);
|
if (path.Length == 0) {
|
||||||
AssertFileMode (file, mode);
|
throw new ArgumentException ("path");
|
||||||
return cmode;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private static string ToFopenMode (string file, FileAccess access)
|
if (mode == null) {
|
||||||
{
|
throw new ArgumentNullException ("mode");
|
||||||
return Native.NativeConvert.ToFopenMode (access);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private static string ToFopenMode (string file, FileMode mode, FileAccess access)
|
IntPtr f = Native.Stdlib.fopen (path, mode);
|
||||||
{
|
if (f == IntPtr.Zero) {
|
||||||
string cmode = Native.NativeConvert.ToFopenMode (mode, access);
|
throw new DirectoryNotFoundException ("path",
|
||||||
bool exists = AssertFileMode (file, mode);
|
UnixMarshal.CreateExceptionForLastError ());
|
||||||
// HACK: for open-or-create & read, mode is "rb", which doesn't create
|
}
|
||||||
// files. If the file doesn't exist, we need to use "w+b" to ensure
|
|
||||||
// file creation.
|
|
||||||
if (mode == FileMode.OpenOrCreate && access == FileAccess.Read && !exists)
|
|
||||||
cmode = "w+b";
|
|
||||||
return cmode;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool AssertFileMode (string file, FileMode mode)
|
return f;
|
||||||
{
|
}
|
||||||
bool exists = FileExists (file);
|
|
||||||
if (mode == FileMode.CreateNew && exists)
|
|
||||||
throw new IOException ("File exists and FileMode.CreateNew specified");
|
|
||||||
if ((mode == FileMode.Open || mode == FileMode.Truncate) && !exists)
|
|
||||||
throw new FileNotFoundException ("File doesn't exist and FileMode.Open specified", file);
|
|
||||||
return exists;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool FileExists (string file)
|
private void InitStream (IntPtr fileStream, Boolean ownsHandle)
|
||||||
{
|
{
|
||||||
bool found = false;
|
if (InvalidFileStream == fileStream) {
|
||||||
IntPtr f = Native.Stdlib.fopen (file, "r");
|
throw new ArgumentException (Locale.GetText ("Invalid file stream"), "fileStream");
|
||||||
found = f != IntPtr.Zero;
|
}
|
||||||
if (f != IntPtr.Zero)
|
|
||||||
Native.Stdlib.fclose (f);
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AssertNotDisposed ()
|
this.file = fileStream;
|
||||||
{
|
this.owner = ownsHandle;
|
||||||
if (file == InvalidFileStream)
|
|
||||||
throw new ObjectDisposedException ("Invalid File Stream");
|
|
||||||
GC.KeepAlive (this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IntPtr Handle {
|
try {
|
||||||
get {
|
Int64 offset = Native.Stdlib.fseek (this.file, 0, Native.SeekFlags.SEEK_CUR);
|
||||||
AssertNotDisposed ();
|
if (offset != -1) {
|
||||||
GC.KeepAlive (this);
|
this.canSeek = true;
|
||||||
return file;
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool CanRead {
|
_ = Native.Stdlib.fread(IntPtr.Zero, 0, 0, this.file);
|
||||||
get {return canRead;}
|
if (Native.Stdlib.ferror (this.file) == 0) {
|
||||||
}
|
this.canRead = true;
|
||||||
|
}
|
||||||
|
|
||||||
public override bool CanSeek {
|
_ = Native.Stdlib.fwrite(IntPtr.Zero, 0, 0, this.file);
|
||||||
get {return canSeek;}
|
if (Native.Stdlib.ferror (this.file) == 0) {
|
||||||
}
|
this.canWrite = true;
|
||||||
|
}
|
||||||
|
|
||||||
public override bool CanWrite {
|
_ = Native.Stdlib.clearerr(this.file);
|
||||||
get {return canWrite;}
|
}
|
||||||
}
|
catch (Exception) {
|
||||||
|
throw new ArgumentException (Locale.GetText ("Invalid file stream"), "fileStream");
|
||||||
|
}
|
||||||
|
GC.KeepAlive (this);
|
||||||
|
}
|
||||||
|
|
||||||
public override long Length {
|
private void InitCanReadWrite (FileAccess access)
|
||||||
get {
|
{
|
||||||
AssertNotDisposed ();
|
this.canRead = this.canRead &&
|
||||||
if (!CanSeek)
|
(access == FileAccess.Read || access == FileAccess.ReadWrite);
|
||||||
throw new NotSupportedException ("File Stream doesn't support seeking");
|
this.canWrite = this.canWrite &&
|
||||||
long curPos = Native.Stdlib.ftell (file);
|
(access == FileAccess.Write || access == FileAccess.ReadWrite);
|
||||||
if (curPos == -1)
|
}
|
||||||
throw new NotSupportedException ("Unable to obtain current file position");
|
|
||||||
int r = Native.Stdlib.fseek (file, 0, Native.SeekFlags.SEEK_END);
|
|
||||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
|
||||||
|
|
||||||
long endPos = Native.Stdlib.ftell (file);
|
private static String ToFopenMode (String file, FileMode mode)
|
||||||
if (endPos == -1)
|
{
|
||||||
UnixMarshal.ThrowExceptionForLastError ();
|
String cmode = Native.NativeConvert.ToFopenMode (mode);
|
||||||
|
_ = AssertFileMode(file, mode);
|
||||||
|
return cmode;
|
||||||
|
}
|
||||||
|
|
||||||
r = Native.Stdlib.fseek (file, curPos, Native.SeekFlags.SEEK_SET);
|
private static String ToFopenMode(String file, FileAccess access) => Native.NativeConvert.ToFopenMode(access);
|
||||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
|
||||||
|
|
||||||
GC.KeepAlive (this);
|
private static String ToFopenMode (String file, FileMode mode, FileAccess access)
|
||||||
return endPos;
|
{
|
||||||
}
|
String cmode = Native.NativeConvert.ToFopenMode (mode, access);
|
||||||
}
|
Boolean exists = AssertFileMode (file, mode);
|
||||||
|
// HACK: for open-or-create & read, mode is "rb", which doesn't create
|
||||||
|
// files. If the file doesn't exist, we need to use "w+b" to ensure
|
||||||
|
// file creation.
|
||||||
|
if (mode == FileMode.OpenOrCreate && access == FileAccess.Read && !exists) {
|
||||||
|
cmode = "w+b";
|
||||||
|
}
|
||||||
|
|
||||||
public override long Position {
|
return cmode;
|
||||||
get {
|
}
|
||||||
AssertNotDisposed ();
|
|
||||||
if (!CanSeek)
|
|
||||||
throw new NotSupportedException ("The stream does not support seeking");
|
|
||||||
long pos = Native.Stdlib.ftell (file);
|
|
||||||
if (pos == -1)
|
|
||||||
UnixMarshal.ThrowExceptionForLastError ();
|
|
||||||
GC.KeepAlive (this);
|
|
||||||
return (long) pos;
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
AssertNotDisposed ();
|
|
||||||
Seek (value, SeekOrigin.Begin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SaveFilePosition (Native.FilePosition pos)
|
private static Boolean AssertFileMode (String file, FileMode mode)
|
||||||
{
|
{
|
||||||
AssertNotDisposed ();
|
Boolean exists = FileExists (file);
|
||||||
int r = Native.Stdlib.fgetpos (file, pos);
|
if (mode == FileMode.CreateNew && exists) {
|
||||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
throw new IOException ("File exists and FileMode.CreateNew specified");
|
||||||
GC.KeepAlive (this);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void RestoreFilePosition (Native.FilePosition pos)
|
if ((mode == FileMode.Open || mode == FileMode.Truncate) && !exists) {
|
||||||
{
|
throw new FileNotFoundException ("File doesn't exist and FileMode.Open specified", file);
|
||||||
AssertNotDisposed ();
|
}
|
||||||
if (pos == null)
|
|
||||||
throw new ArgumentNullException ("value");
|
|
||||||
int r = Native.Stdlib.fsetpos (file, pos);
|
|
||||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
|
||||||
GC.KeepAlive (this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Flush ()
|
return exists;
|
||||||
{
|
}
|
||||||
AssertNotDisposed ();
|
|
||||||
int r = Native.Stdlib.fflush (file);
|
|
||||||
if (r != 0)
|
|
||||||
UnixMarshal.ThrowExceptionForLastError ();
|
|
||||||
GC.KeepAlive (this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override unsafe int Read ([In, Out] byte[] buffer, int offset, int count)
|
private static Boolean FileExists (String file)
|
||||||
{
|
{
|
||||||
AssertNotDisposed ();
|
Boolean found = false;
|
||||||
AssertValidBuffer (buffer, offset, count);
|
IntPtr f = Native.Stdlib.fopen (file, "r");
|
||||||
if (!CanRead)
|
found = f != IntPtr.Zero;
|
||||||
throw new NotSupportedException ("Stream does not support reading");
|
if (f != IntPtr.Zero) {
|
||||||
|
_ = Native.Stdlib.fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
ulong r = 0;
|
return found;
|
||||||
fixed (byte* buf = &buffer[offset]) {
|
}
|
||||||
r = Native.Stdlib.fread (buf, 1, (ulong) count, file);
|
|
||||||
}
|
|
||||||
if (r != (ulong) count) {
|
|
||||||
if (Native.Stdlib.ferror (file) != 0)
|
|
||||||
throw new IOException ();
|
|
||||||
}
|
|
||||||
GC.KeepAlive (this);
|
|
||||||
return (int) r;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AssertValidBuffer (byte[] buffer, int offset, int count)
|
private void AssertNotDisposed ()
|
||||||
{
|
{
|
||||||
if (buffer == null)
|
if (this.file == InvalidFileStream) {
|
||||||
throw new ArgumentNullException ("buffer");
|
throw new ObjectDisposedException ("Invalid File Stream");
|
||||||
if (offset < 0)
|
}
|
||||||
throw new ArgumentOutOfRangeException ("offset", "< 0");
|
|
||||||
if (count < 0)
|
|
||||||
throw new ArgumentOutOfRangeException ("count", "< 0");
|
|
||||||
if (offset > buffer.Length)
|
|
||||||
throw new ArgumentException ("destination offset is beyond array size");
|
|
||||||
if (offset > (buffer.Length - count))
|
|
||||||
throw new ArgumentException ("would overrun buffer");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Rewind ()
|
GC.KeepAlive (this);
|
||||||
{
|
}
|
||||||
AssertNotDisposed ();
|
|
||||||
Native.Stdlib.rewind (file);
|
|
||||||
GC.KeepAlive (this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override long Seek (long offset, SeekOrigin origin)
|
public IntPtr Handle {
|
||||||
{
|
get {
|
||||||
AssertNotDisposed ();
|
this.AssertNotDisposed ();
|
||||||
if (!CanSeek)
|
GC.KeepAlive (this);
|
||||||
throw new NotSupportedException ("The File Stream does not support seeking");
|
return this.file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Native.SeekFlags sf = Native.SeekFlags.SEEK_CUR;
|
public override Boolean CanRead => this.canRead;
|
||||||
switch (origin) {
|
|
||||||
case SeekOrigin.Begin: sf = Native.SeekFlags.SEEK_SET; break;
|
|
||||||
case SeekOrigin.Current: sf = Native.SeekFlags.SEEK_CUR; break;
|
|
||||||
case SeekOrigin.End: sf = Native.SeekFlags.SEEK_END; break;
|
|
||||||
default: throw new ArgumentException ("origin");
|
|
||||||
}
|
|
||||||
|
|
||||||
int r = Native.Stdlib.fseek (file, offset, sf);
|
public override Boolean CanSeek => this.canSeek;
|
||||||
if (r != 0)
|
|
||||||
throw new IOException ("Unable to seek",
|
|
||||||
UnixMarshal.CreateExceptionForLastError ());
|
|
||||||
|
|
||||||
long pos = Native.Stdlib.ftell (file);
|
public override Boolean CanWrite => this.canWrite;
|
||||||
if (pos == -1)
|
|
||||||
throw new IOException ("Unable to get current file position",
|
|
||||||
UnixMarshal.CreateExceptionForLastError ());
|
|
||||||
|
|
||||||
GC.KeepAlive (this);
|
public override Int64 Length {
|
||||||
return pos;
|
get {
|
||||||
}
|
this.AssertNotDisposed ();
|
||||||
|
if (!this.CanSeek) {
|
||||||
|
throw new NotSupportedException ("File Stream doesn't support seeking");
|
||||||
|
}
|
||||||
|
|
||||||
public override void SetLength (long value)
|
Int64 curPos = Native.Stdlib.ftell (this.file);
|
||||||
{
|
if (curPos == -1) {
|
||||||
throw new NotSupportedException ("ANSI C doesn't provide a way to truncate a file");
|
throw new NotSupportedException ("Unable to obtain current file position");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override unsafe void Write (byte[] buffer, int offset, int count)
|
Int32 r = Native.Stdlib.fseek (this.file, 0, Native.SeekFlags.SEEK_END);
|
||||||
{
|
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||||
AssertNotDisposed ();
|
|
||||||
AssertValidBuffer (buffer, offset, count);
|
|
||||||
if (!CanWrite)
|
|
||||||
throw new NotSupportedException ("File Stream does not support writing");
|
|
||||||
|
|
||||||
ulong r = 0;
|
Int64 endPos = Native.Stdlib.ftell (this.file);
|
||||||
fixed (byte* buf = &buffer[offset]) {
|
if (endPos == -1) {
|
||||||
r = Native.Stdlib.fwrite (buf, (ulong) 1, (ulong) count, file);
|
UnixMarshal.ThrowExceptionForLastError ();
|
||||||
}
|
}
|
||||||
if (r != (ulong) count)
|
|
||||||
UnixMarshal.ThrowExceptionForLastError ();
|
|
||||||
GC.KeepAlive (this);
|
|
||||||
}
|
|
||||||
|
|
||||||
~StdioFileStream ()
|
r = Native.Stdlib.fseek (this.file, curPos, Native.SeekFlags.SEEK_SET);
|
||||||
{
|
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||||
Close ();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Close ()
|
GC.KeepAlive (this);
|
||||||
{
|
return endPos;
|
||||||
if (file == InvalidFileStream)
|
}
|
||||||
return;
|
}
|
||||||
|
|
||||||
if (owner) {
|
public override Int64 Position {
|
||||||
int r = Native.Stdlib.fclose (file);
|
get {
|
||||||
if (r != 0)
|
this.AssertNotDisposed ();
|
||||||
UnixMarshal.ThrowExceptionForLastError ();
|
if (!this.CanSeek) {
|
||||||
} else
|
throw new NotSupportedException ("The stream does not support seeking");
|
||||||
Flush ();
|
}
|
||||||
|
|
||||||
file = InvalidFileStream;
|
Int64 pos = Native.Stdlib.ftell (this.file);
|
||||||
canRead = false;
|
if (pos == -1) {
|
||||||
canSeek = false;
|
UnixMarshal.ThrowExceptionForLastError ();
|
||||||
canWrite = false;
|
}
|
||||||
|
|
||||||
GC.SuppressFinalize (this);
|
GC.KeepAlive (this);
|
||||||
GC.KeepAlive (this);
|
return (Int64) pos;
|
||||||
}
|
}
|
||||||
|
set {
|
||||||
|
this.AssertNotDisposed ();
|
||||||
|
_ = this.Seek(value, SeekOrigin.Begin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private bool canSeek = false;
|
public void SaveFilePosition (Native.FilePosition pos)
|
||||||
private bool canRead = false;
|
{
|
||||||
private bool canWrite = false;
|
this.AssertNotDisposed ();
|
||||||
private bool owner = true;
|
Int32 r = Native.Stdlib.fgetpos (this.file, pos);
|
||||||
private IntPtr file = InvalidFileStream;
|
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||||
}
|
GC.KeepAlive (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RestoreFilePosition (Native.FilePosition pos)
|
||||||
|
{
|
||||||
|
this.AssertNotDisposed ();
|
||||||
|
if (pos == null) {
|
||||||
|
throw new ArgumentNullException ("value");
|
||||||
|
}
|
||||||
|
|
||||||
|
Int32 r = Native.Stdlib.fsetpos (this.file, pos);
|
||||||
|
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||||
|
GC.KeepAlive (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Flush ()
|
||||||
|
{
|
||||||
|
this.AssertNotDisposed ();
|
||||||
|
Int32 r = Native.Stdlib.fflush (this.file);
|
||||||
|
if (r != 0) {
|
||||||
|
UnixMarshal.ThrowExceptionForLastError ();
|
||||||
|
}
|
||||||
|
|
||||||
|
GC.KeepAlive (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override unsafe Int32 Read ([In, Out] Byte[] buffer, Int32 offset, Int32 count)
|
||||||
|
{
|
||||||
|
this.AssertNotDisposed ();
|
||||||
|
this.AssertValidBuffer (buffer, offset, count);
|
||||||
|
if (!this.CanRead) {
|
||||||
|
throw new NotSupportedException ("Stream does not support reading");
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt64 r = 0;
|
||||||
|
fixed (Byte* buf = &buffer[offset]) {
|
||||||
|
r = Native.Stdlib.fread (buf, 1, (UInt64) count, this.file);
|
||||||
|
}
|
||||||
|
if (r != (UInt64) count) {
|
||||||
|
if (Native.Stdlib.ferror (this.file) != 0) {
|
||||||
|
throw new IOException ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GC.KeepAlive (this);
|
||||||
|
return (Int32) r;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AssertValidBuffer (Byte[] buffer, Int32 offset, Int32 count)
|
||||||
|
{
|
||||||
|
if (buffer == null) {
|
||||||
|
throw new ArgumentNullException ("buffer");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset < 0) {
|
||||||
|
throw new ArgumentOutOfRangeException ("offset", "< 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count < 0) {
|
||||||
|
throw new ArgumentOutOfRangeException ("count", "< 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset > buffer.Length) {
|
||||||
|
throw new ArgumentException ("destination offset is beyond array size");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset > buffer.Length - count) {
|
||||||
|
throw new ArgumentException ("would overrun buffer");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Rewind ()
|
||||||
|
{
|
||||||
|
this.AssertNotDisposed ();
|
||||||
|
_ = Native.Stdlib.rewind(this.file);
|
||||||
|
GC.KeepAlive (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Int64 Seek (Int64 offset, SeekOrigin origin)
|
||||||
|
{
|
||||||
|
this.AssertNotDisposed ();
|
||||||
|
if (!this.CanSeek) {
|
||||||
|
throw new NotSupportedException ("The File Stream does not support seeking");
|
||||||
|
}
|
||||||
|
|
||||||
|
Native.SeekFlags sf = Native.SeekFlags.SEEK_CUR;
|
||||||
|
switch (origin) {
|
||||||
|
case SeekOrigin.Begin: sf = Native.SeekFlags.SEEK_SET; break;
|
||||||
|
case SeekOrigin.Current: sf = Native.SeekFlags.SEEK_CUR; break;
|
||||||
|
case SeekOrigin.End: sf = Native.SeekFlags.SEEK_END; break;
|
||||||
|
default: throw new ArgumentException ("origin");
|
||||||
|
}
|
||||||
|
|
||||||
|
Int32 r = Native.Stdlib.fseek (this.file, offset, sf);
|
||||||
|
if (r != 0) {
|
||||||
|
throw new IOException ("Unable to seek",
|
||||||
|
UnixMarshal.CreateExceptionForLastError ());
|
||||||
|
}
|
||||||
|
|
||||||
|
Int64 pos = Native.Stdlib.ftell (this.file);
|
||||||
|
if (pos == -1) {
|
||||||
|
throw new IOException ("Unable to get current file position",
|
||||||
|
UnixMarshal.CreateExceptionForLastError ());
|
||||||
|
}
|
||||||
|
|
||||||
|
GC.KeepAlive (this);
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetLength(Int64 value) => throw new NotSupportedException("ANSI C doesn't provide a way to truncate a file");
|
||||||
|
|
||||||
|
public override unsafe void Write (Byte[] buffer, Int32 offset, Int32 count)
|
||||||
|
{
|
||||||
|
this.AssertNotDisposed ();
|
||||||
|
this.AssertValidBuffer (buffer, offset, count);
|
||||||
|
if (!this.CanWrite) {
|
||||||
|
throw new NotSupportedException ("File Stream does not support writing");
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt64 r = 0;
|
||||||
|
fixed (Byte* buf = &buffer[offset]) {
|
||||||
|
r = Native.Stdlib.fwrite (buf, (UInt64) 1, (UInt64) count, this.file);
|
||||||
|
}
|
||||||
|
if (r != (UInt64) count) {
|
||||||
|
UnixMarshal.ThrowExceptionForLastError ();
|
||||||
|
}
|
||||||
|
|
||||||
|
GC.KeepAlive (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
~StdioFileStream ()
|
||||||
|
{
|
||||||
|
this.Close ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Close ()
|
||||||
|
{
|
||||||
|
if (this.file == InvalidFileStream) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.owner) {
|
||||||
|
Int32 r = Native.Stdlib.fclose (this.file);
|
||||||
|
if (r != 0) {
|
||||||
|
UnixMarshal.ThrowExceptionForLastError ();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.Flush ();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.file = InvalidFileStream;
|
||||||
|
this.canRead = false;
|
||||||
|
this.canSeek = false;
|
||||||
|
this.canWrite = false;
|
||||||
|
|
||||||
|
GC.SuppressFinalize (this);
|
||||||
|
GC.KeepAlive (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Boolean canSeek = false;
|
||||||
|
private Boolean canRead = false;
|
||||||
|
private Boolean canWrite = false;
|
||||||
|
private Boolean owner = true;
|
||||||
|
private IntPtr file = InvalidFileStream;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim: noexpandtab
|
// vim: noexpandtab
|
||||||
|
@ -35,196 +35,198 @@ using System.Runtime.InteropServices;
|
|||||||
|
|
||||||
namespace Mono.Unix {
|
namespace Mono.Unix {
|
||||||
|
|
||||||
public class UnixClient : MarshalByRefObject, IDisposable {
|
public class UnixClient : MarshalByRefObject, IDisposable {
|
||||||
NetworkStream stream;
|
NetworkStream stream;
|
||||||
Socket client;
|
Socket client;
|
||||||
bool disposed;
|
Boolean disposed;
|
||||||
|
|
||||||
public UnixClient ()
|
public UnixClient ()
|
||||||
{
|
{
|
||||||
if (client != null) {
|
if (this.client != null) {
|
||||||
client.Close ();
|
this.client.Close ();
|
||||||
client = null;
|
this.client = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
client = new Socket (AddressFamily.Unix, SocketType.Stream, 0);
|
this.client = new Socket (AddressFamily.Unix, SocketType.Stream, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public UnixClient (string path) : this ()
|
public UnixClient (String path) : this ()
|
||||||
{
|
{
|
||||||
if (path == null)
|
if (path == null) {
|
||||||
throw new ArgumentNullException ("ep");
|
throw new ArgumentNullException ("ep");
|
||||||
|
}
|
||||||
|
|
||||||
Connect (path);
|
this.Connect (path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public UnixClient (UnixEndPoint ep) : this ()
|
public UnixClient (UnixEndPoint ep) : this ()
|
||||||
{
|
{
|
||||||
if (ep == null)
|
if (ep == null) {
|
||||||
throw new ArgumentNullException ("ep");
|
throw new ArgumentNullException ("ep");
|
||||||
|
}
|
||||||
|
|
||||||
Connect (ep);
|
this.Connect (ep);
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnixListener uses this when accepting a connection.
|
// UnixListener uses this when accepting a connection.
|
||||||
internal UnixClient (Socket sock)
|
internal UnixClient(Socket sock) => this.Client = sock;
|
||||||
{
|
|
||||||
Client = sock;
|
|
||||||
}
|
|
||||||
|
|
||||||
public
|
public
|
||||||
Socket Client {
|
Socket Client {
|
||||||
get { return client; }
|
get => this.client;
|
||||||
set {
|
set {
|
||||||
client = value;
|
this.client = value;
|
||||||
stream = null;
|
this.stream = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public PeerCred PeerCredential {
|
public PeerCred PeerCredential {
|
||||||
get {
|
get {
|
||||||
CheckDisposed ();
|
this.CheckDisposed ();
|
||||||
return new PeerCred (client);
|
return new PeerCred (this.client);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public LingerOption LingerState {
|
public LingerOption LingerState {
|
||||||
get {
|
get {
|
||||||
CheckDisposed ();
|
this.CheckDisposed ();
|
||||||
return (LingerOption) client.GetSocketOption (SocketOptionLevel.Socket,
|
return (LingerOption)this.client.GetSocketOption (SocketOptionLevel.Socket,
|
||||||
SocketOptionName.Linger);
|
SocketOptionName.Linger);
|
||||||
}
|
}
|
||||||
|
|
||||||
set {
|
set {
|
||||||
CheckDisposed ();
|
this.CheckDisposed ();
|
||||||
client.SetSocketOption (SocketOptionLevel.Socket,
|
this.client.SetSocketOption (SocketOptionLevel.Socket,
|
||||||
SocketOptionName.Linger, value);
|
SocketOptionName.Linger, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int ReceiveBufferSize {
|
public Int32 ReceiveBufferSize {
|
||||||
get {
|
get {
|
||||||
CheckDisposed ();
|
this.CheckDisposed ();
|
||||||
return (int) client.GetSocketOption (SocketOptionLevel.Socket,
|
return (Int32)this.client.GetSocketOption (SocketOptionLevel.Socket,
|
||||||
SocketOptionName.ReceiveBuffer);
|
SocketOptionName.ReceiveBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
set {
|
set {
|
||||||
CheckDisposed ();
|
this.CheckDisposed ();
|
||||||
client.SetSocketOption (SocketOptionLevel.Socket,
|
this.client.SetSocketOption (SocketOptionLevel.Socket,
|
||||||
SocketOptionName.ReceiveBuffer, value);
|
SocketOptionName.ReceiveBuffer, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int ReceiveTimeout {
|
public Int32 ReceiveTimeout {
|
||||||
get {
|
get {
|
||||||
CheckDisposed ();
|
this.CheckDisposed ();
|
||||||
return (int) client.GetSocketOption (SocketOptionLevel.Socket,
|
return (Int32)this.client.GetSocketOption (SocketOptionLevel.Socket,
|
||||||
SocketOptionName.ReceiveTimeout);
|
SocketOptionName.ReceiveTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
set {
|
set {
|
||||||
CheckDisposed ();
|
this.CheckDisposed ();
|
||||||
client.SetSocketOption (SocketOptionLevel.Socket,
|
this.client.SetSocketOption (SocketOptionLevel.Socket,
|
||||||
SocketOptionName.ReceiveTimeout, value);
|
SocketOptionName.ReceiveTimeout, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int SendBufferSize {
|
public Int32 SendBufferSize {
|
||||||
get {
|
get {
|
||||||
CheckDisposed ();
|
this.CheckDisposed ();
|
||||||
return (int) client.GetSocketOption (SocketOptionLevel.Socket,
|
return (Int32)this.client.GetSocketOption (SocketOptionLevel.Socket,
|
||||||
SocketOptionName.SendBuffer);
|
SocketOptionName.SendBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
set {
|
set {
|
||||||
CheckDisposed ();
|
this.CheckDisposed ();
|
||||||
client.SetSocketOption (SocketOptionLevel.Socket,
|
this.client.SetSocketOption (SocketOptionLevel.Socket,
|
||||||
SocketOptionName.SendBuffer, value);
|
SocketOptionName.SendBuffer, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int SendTimeout {
|
public Int32 SendTimeout {
|
||||||
get {
|
get {
|
||||||
CheckDisposed ();
|
this.CheckDisposed ();
|
||||||
return (int) client.GetSocketOption (SocketOptionLevel.Socket,
|
return (Int32)this.client.GetSocketOption (SocketOptionLevel.Socket,
|
||||||
SocketOptionName.SendTimeout);
|
SocketOptionName.SendTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
set {
|
set {
|
||||||
CheckDisposed ();
|
this.CheckDisposed ();
|
||||||
client.SetSocketOption (SocketOptionLevel.Socket,
|
this.client.SetSocketOption (SocketOptionLevel.Socket,
|
||||||
SocketOptionName.SendTimeout, value);
|
SocketOptionName.SendTimeout, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Close ()
|
public void Close ()
|
||||||
{
|
{
|
||||||
CheckDisposed ();
|
this.CheckDisposed ();
|
||||||
Dispose ();
|
this.Dispose ();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Connect (UnixEndPoint remoteEndPoint)
|
public void Connect (UnixEndPoint remoteEndPoint)
|
||||||
{
|
{
|
||||||
CheckDisposed ();
|
this.CheckDisposed ();
|
||||||
client.Connect (remoteEndPoint);
|
this.client.Connect (remoteEndPoint);
|
||||||
stream = new NetworkStream (client, true);
|
this.stream = new NetworkStream (this.client, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Connect (string path)
|
public void Connect (String path)
|
||||||
{
|
{
|
||||||
CheckDisposed ();
|
this.CheckDisposed ();
|
||||||
Connect (new UnixEndPoint (path));
|
this.Connect (new UnixEndPoint (path));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose ()
|
public void Dispose ()
|
||||||
{
|
{
|
||||||
Dispose (true);
|
this.Dispose (true);
|
||||||
GC.SuppressFinalize (this);
|
GC.SuppressFinalize (this);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void Dispose (bool disposing)
|
protected virtual void Dispose (Boolean disposing)
|
||||||
{
|
{
|
||||||
if (disposed)
|
if (this.disposed) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (disposing) {
|
if (disposing) {
|
||||||
// release managed resources
|
// release managed resources
|
||||||
NetworkStream s = stream;
|
NetworkStream s = this.stream;
|
||||||
stream = null;
|
this.stream = null;
|
||||||
if (s != null) {
|
if (s != null) {
|
||||||
// This closes the socket as well, as the NetworkStream
|
// This closes the socket as well, as the NetworkStream
|
||||||
// owns the socket.
|
// owns the socket.
|
||||||
s.Close();
|
s.Close();
|
||||||
s = null;
|
s = null;
|
||||||
} else if (client != null){
|
} else if (this.client != null){
|
||||||
client.Close ();
|
this.client.Close ();
|
||||||
}
|
}
|
||||||
client = null;
|
this.client = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
disposed = true;
|
this.disposed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public NetworkStream GetStream ()
|
public NetworkStream GetStream ()
|
||||||
{
|
{
|
||||||
CheckDisposed ();
|
this.CheckDisposed ();
|
||||||
if (stream == null)
|
if (this.stream == null) {
|
||||||
stream = new NetworkStream (client, true);
|
this.stream = new NetworkStream (this.client, true);
|
||||||
|
}
|
||||||
|
|
||||||
return stream;
|
return this.stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckDisposed ()
|
void CheckDisposed ()
|
||||||
{
|
{
|
||||||
if (disposed)
|
if (this.disposed) {
|
||||||
throw new ObjectDisposedException (GetType().FullName);
|
throw new ObjectDisposedException (this.GetType().FullName);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
~UnixClient ()
|
~UnixClient ()
|
||||||
{
|
{
|
||||||
Dispose (false);
|
this.Dispose (false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,216 +35,223 @@ using Mono.Unix;
|
|||||||
|
|
||||||
namespace Mono.Unix {
|
namespace Mono.Unix {
|
||||||
|
|
||||||
public sealed class UnixDirectoryInfo : UnixFileSystemInfo
|
public sealed class UnixDirectoryInfo : UnixFileSystemInfo
|
||||||
{
|
{
|
||||||
public UnixDirectoryInfo (string path)
|
public UnixDirectoryInfo (String path)
|
||||||
: base (path)
|
: base (path)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
internal UnixDirectoryInfo (string path, Native.Stat stat)
|
internal UnixDirectoryInfo (String path, Native.Stat stat)
|
||||||
: base (path, stat)
|
: base (path, stat)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string Name {
|
public override String Name {
|
||||||
get {
|
get {
|
||||||
string r = UnixPath.GetFileName (FullPath);
|
String r = UnixPath.GetFileName (this.FullPath);
|
||||||
if (r == null || r.Length == 0)
|
return r == null || r.Length == 0 ? this.FullPath : r;
|
||||||
return FullPath;
|
}
|
||||||
return r;
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnixDirectoryInfo Parent {
|
public UnixDirectoryInfo Parent {
|
||||||
get {
|
get {
|
||||||
if (FullPath == "/")
|
if (this.FullPath == "/") {
|
||||||
return this;
|
return this;
|
||||||
string dirname = UnixPath.GetDirectoryName (FullPath);
|
}
|
||||||
if (dirname == "")
|
|
||||||
throw new InvalidOperationException ("Do not know parent directory for path `" + FullPath + "'");
|
|
||||||
return new UnixDirectoryInfo (dirname);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnixDirectoryInfo Root {
|
String dirname = UnixPath.GetDirectoryName (this.FullPath);
|
||||||
get {
|
if (dirname == "") {
|
||||||
string root = UnixPath.GetPathRoot (FullPath);
|
throw new InvalidOperationException ("Do not know parent directory for path `" + this.FullPath + "'");
|
||||||
if (root == null)
|
}
|
||||||
return null;
|
|
||||||
return new UnixDirectoryInfo (root);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[CLSCompliant (false)]
|
return new UnixDirectoryInfo (dirname);
|
||||||
public void Create (Mono.Unix.Native.FilePermissions mode)
|
}
|
||||||
{
|
}
|
||||||
int r = Mono.Unix.Native.Syscall.mkdir (FullPath, mode);
|
|
||||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
|
||||||
base.Refresh ();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Create (FileAccessPermissions mode)
|
public UnixDirectoryInfo Root {
|
||||||
{
|
get {
|
||||||
Create ((Native.FilePermissions) mode);
|
String root = UnixPath.GetPathRoot (this.FullPath);
|
||||||
}
|
return root == null ? null : new UnixDirectoryInfo (root);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Create ()
|
//[CLSCompliant (false)]
|
||||||
{
|
public void Create (Mono.Unix.Native.FilePermissions mode)
|
||||||
Mono.Unix.Native.FilePermissions mode =
|
{
|
||||||
Mono.Unix.Native.FilePermissions.ACCESSPERMS;
|
Int32 r = Mono.Unix.Native.Syscall.mkdir (this.FullPath, mode);
|
||||||
Create (mode);
|
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||||
}
|
base.Refresh ();
|
||||||
|
}
|
||||||
|
|
||||||
public override void Delete ()
|
public void Create(FileAccessPermissions mode) => this.Create((Native.FilePermissions)mode);
|
||||||
{
|
|
||||||
Delete (false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Delete (bool recursive)
|
public void Create ()
|
||||||
{
|
{
|
||||||
if (recursive) {
|
Mono.Unix.Native.FilePermissions mode =
|
||||||
foreach (UnixFileSystemInfo e in GetFileSystemEntries ()) {
|
Mono.Unix.Native.FilePermissions.ACCESSPERMS;
|
||||||
UnixDirectoryInfo d = e as UnixDirectoryInfo;
|
this.Create (mode);
|
||||||
if (d != null)
|
}
|
||||||
d.Delete (true);
|
|
||||||
else
|
|
||||||
e.Delete ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int r = Native.Syscall.rmdir (FullPath);
|
|
||||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
|
||||||
base.Refresh ();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Native.Dirent[] GetEntries ()
|
public override void Delete() => this.Delete(false);
|
||||||
{
|
|
||||||
IntPtr dirp = Native.Syscall.opendir (FullPath);
|
|
||||||
if (dirp == IntPtr.Zero)
|
|
||||||
UnixMarshal.ThrowExceptionForLastError ();
|
|
||||||
|
|
||||||
bool complete = false;
|
public void Delete (Boolean recursive)
|
||||||
try {
|
{
|
||||||
Native.Dirent[] entries = GetEntries (dirp);
|
if (recursive) {
|
||||||
complete = true;
|
foreach (UnixFileSystemInfo e in this.GetFileSystemEntries ()) {
|
||||||
return entries;
|
UnixDirectoryInfo d = e as UnixDirectoryInfo;
|
||||||
}
|
if (d != null) {
|
||||||
finally {
|
d.Delete (true);
|
||||||
int r = Native.Syscall.closedir (dirp);
|
} else {
|
||||||
// don't throw an exception if an exception is in progress
|
e.Delete ();
|
||||||
if (complete)
|
}
|
||||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
}
|
||||||
}
|
}
|
||||||
}
|
Int32 r = Native.Syscall.rmdir (this.FullPath);
|
||||||
|
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||||
|
base.Refresh ();
|
||||||
|
}
|
||||||
|
|
||||||
private static Native.Dirent[] GetEntries (IntPtr dirp)
|
public Native.Dirent[] GetEntries ()
|
||||||
{
|
{
|
||||||
ArrayList entries = new ArrayList ();
|
IntPtr dirp = Native.Syscall.opendir (this.FullPath);
|
||||||
|
if (dirp == IntPtr.Zero) {
|
||||||
|
UnixMarshal.ThrowExceptionForLastError ();
|
||||||
|
}
|
||||||
|
|
||||||
int r;
|
Boolean complete = false;
|
||||||
IntPtr result;
|
try {
|
||||||
do {
|
Native.Dirent[] entries = GetEntries (dirp);
|
||||||
Native.Dirent d = new Native.Dirent ();
|
complete = true;
|
||||||
r = Native.Syscall.readdir_r (dirp, d, out result);
|
return entries;
|
||||||
if (r == 0 && result != IntPtr.Zero)
|
}
|
||||||
// don't include current & parent dirs
|
finally {
|
||||||
if (d.d_name != "." && d.d_name != "..")
|
Int32 r = Native.Syscall.closedir (dirp);
|
||||||
entries.Add (d);
|
// don't throw an exception if an exception is in progress
|
||||||
} while (r == 0 && result != IntPtr.Zero);
|
if (complete) {
|
||||||
if (r != 0)
|
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (Native.Dirent[]) entries.ToArray (typeof(Native.Dirent));
|
private static Native.Dirent[] GetEntries (IntPtr dirp)
|
||||||
}
|
{
|
||||||
|
ArrayList entries = new ArrayList ();
|
||||||
|
|
||||||
public Native.Dirent[] GetEntries (Regex regex)
|
Int32 r;
|
||||||
{
|
IntPtr result;
|
||||||
IntPtr dirp = Native.Syscall.opendir (FullPath);
|
do {
|
||||||
if (dirp == IntPtr.Zero)
|
Native.Dirent d = new Native.Dirent ();
|
||||||
UnixMarshal.ThrowExceptionForLastError ();
|
r = Native.Syscall.readdir_r (dirp, d, out result);
|
||||||
|
if (r == 0 && result != IntPtr.Zero) {
|
||||||
|
// don't include current & parent dirs
|
||||||
|
if (d.d_name != "." && d.d_name != "..") {
|
||||||
|
_ = entries.Add(d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (r == 0 && result != IntPtr.Zero);
|
||||||
|
if (r != 0) {
|
||||||
|
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
return (Native.Dirent[]) entries.ToArray (typeof(Native.Dirent));
|
||||||
return GetEntries (dirp, regex);
|
}
|
||||||
}
|
|
||||||
finally {
|
|
||||||
int r = Native.Syscall.closedir (dirp);
|
|
||||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Native.Dirent[] GetEntries (IntPtr dirp, Regex regex)
|
public Native.Dirent[] GetEntries (Regex regex)
|
||||||
{
|
{
|
||||||
ArrayList entries = new ArrayList ();
|
IntPtr dirp = Native.Syscall.opendir (this.FullPath);
|
||||||
|
if (dirp == IntPtr.Zero) {
|
||||||
|
UnixMarshal.ThrowExceptionForLastError ();
|
||||||
|
}
|
||||||
|
|
||||||
int r;
|
try {
|
||||||
IntPtr result;
|
return GetEntries (dirp, regex);
|
||||||
do {
|
}
|
||||||
Native.Dirent d = new Native.Dirent ();
|
finally {
|
||||||
r = Native.Syscall.readdir_r (dirp, d, out result);
|
Int32 r = Native.Syscall.closedir (dirp);
|
||||||
if (r == 0 && result != IntPtr.Zero && regex.Match (d.d_name).Success) {
|
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||||
// don't include current & parent dirs
|
}
|
||||||
if (d.d_name != "." && d.d_name != "..")
|
}
|
||||||
entries.Add (d);
|
|
||||||
}
|
|
||||||
} while (r == 0 && result != IntPtr.Zero);
|
|
||||||
if (r != 0)
|
|
||||||
UnixMarshal.ThrowExceptionForLastError ();
|
|
||||||
|
|
||||||
return (Native.Dirent[]) entries.ToArray (typeof(Native.Dirent));
|
private static Native.Dirent[] GetEntries (IntPtr dirp, Regex regex)
|
||||||
}
|
{
|
||||||
|
ArrayList entries = new ArrayList ();
|
||||||
|
|
||||||
public Native.Dirent[] GetEntries (string regex)
|
Int32 r;
|
||||||
{
|
IntPtr result;
|
||||||
Regex re = new Regex (regex);
|
do {
|
||||||
return GetEntries (re);
|
Native.Dirent d = new Native.Dirent ();
|
||||||
}
|
r = Native.Syscall.readdir_r (dirp, d, out result);
|
||||||
|
if (r == 0 && result != IntPtr.Zero && regex.Match (d.d_name).Success) {
|
||||||
|
// don't include current & parent dirs
|
||||||
|
if (d.d_name != "." && d.d_name != "..") {
|
||||||
|
_ = entries.Add(d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (r == 0 && result != IntPtr.Zero);
|
||||||
|
if (r != 0) {
|
||||||
|
UnixMarshal.ThrowExceptionForLastError ();
|
||||||
|
}
|
||||||
|
|
||||||
public UnixFileSystemInfo[] GetFileSystemEntries ()
|
return (Native.Dirent[]) entries.ToArray (typeof(Native.Dirent));
|
||||||
{
|
}
|
||||||
Native.Dirent[] dentries = GetEntries ();
|
|
||||||
return GetFileSystemEntries (dentries);
|
|
||||||
}
|
|
||||||
|
|
||||||
private UnixFileSystemInfo[] GetFileSystemEntries (Native.Dirent[] dentries)
|
public Native.Dirent[] GetEntries (String regex)
|
||||||
{
|
{
|
||||||
UnixFileSystemInfo[] entries = new UnixFileSystemInfo[dentries.Length];
|
Regex re = new Regex (regex);
|
||||||
for (int i = 0; i != entries.Length; ++i)
|
return this.GetEntries (re);
|
||||||
entries [i] = UnixFileSystemInfo.GetFileSystemEntry (
|
}
|
||||||
UnixPath.Combine (FullPath, dentries[i].d_name));
|
|
||||||
return entries;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnixFileSystemInfo[] GetFileSystemEntries (Regex regex)
|
public UnixFileSystemInfo[] GetFileSystemEntries ()
|
||||||
{
|
{
|
||||||
Native.Dirent[] dentries = GetEntries (regex);
|
Native.Dirent[] dentries = this.GetEntries ();
|
||||||
return GetFileSystemEntries (dentries);
|
return this.GetFileSystemEntries (dentries);
|
||||||
}
|
}
|
||||||
|
|
||||||
public UnixFileSystemInfo[] GetFileSystemEntries (string regex)
|
private UnixFileSystemInfo[] GetFileSystemEntries (Native.Dirent[] dentries)
|
||||||
{
|
{
|
||||||
Regex re = new Regex (regex);
|
UnixFileSystemInfo[] entries = new UnixFileSystemInfo[dentries.Length];
|
||||||
return GetFileSystemEntries (re);
|
for (Int32 i = 0; i != entries.Length; ++i) {
|
||||||
}
|
entries [i] = UnixFileSystemInfo.GetFileSystemEntry (
|
||||||
|
UnixPath.Combine (this.FullPath, dentries[i].d_name));
|
||||||
|
}
|
||||||
|
|
||||||
public static string GetCurrentDirectory ()
|
return entries;
|
||||||
{
|
}
|
||||||
StringBuilder buf = new StringBuilder (16);
|
|
||||||
IntPtr r = IntPtr.Zero;
|
|
||||||
do {
|
|
||||||
buf.Capacity *= 2;
|
|
||||||
r = Native.Syscall.getcwd (buf, (ulong) buf.Capacity);
|
|
||||||
} while (r == IntPtr.Zero && Native.Syscall.GetLastError() == Native.Errno.ERANGE);
|
|
||||||
if (r == IntPtr.Zero)
|
|
||||||
UnixMarshal.ThrowExceptionForLastError ();
|
|
||||||
return buf.ToString ();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SetCurrentDirectory (string path)
|
public UnixFileSystemInfo[] GetFileSystemEntries (Regex regex)
|
||||||
{
|
{
|
||||||
int r = Native.Syscall.chdir (path);
|
Native.Dirent[] dentries = this.GetEntries (regex);
|
||||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
return this.GetFileSystemEntries (dentries);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public UnixFileSystemInfo[] GetFileSystemEntries (String regex)
|
||||||
|
{
|
||||||
|
Regex re = new Regex (regex);
|
||||||
|
return this.GetFileSystemEntries (re);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String GetCurrentDirectory ()
|
||||||
|
{
|
||||||
|
StringBuilder buf = new StringBuilder (16);
|
||||||
|
IntPtr r = IntPtr.Zero;
|
||||||
|
do {
|
||||||
|
buf.Capacity *= 2;
|
||||||
|
r = Native.Syscall.getcwd (buf, (UInt64) buf.Capacity);
|
||||||
|
} while (r == IntPtr.Zero && Native.Syscall.GetLastError() == Native.Errno.ERANGE);
|
||||||
|
if (r == IntPtr.Zero) {
|
||||||
|
UnixMarshal.ThrowExceptionForLastError ();
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.ToString ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetCurrentDirectory (String path)
|
||||||
|
{
|
||||||
|
Int32 r = Native.Syscall.chdir (path);
|
||||||
|
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim: noexpandtab
|
// vim: noexpandtab
|
||||||
|
@ -33,163 +33,157 @@ using Mono.Unix;
|
|||||||
|
|
||||||
namespace Mono.Unix {
|
namespace Mono.Unix {
|
||||||
|
|
||||||
public enum UnixDriveType {
|
public enum UnixDriveType {
|
||||||
Unknown,
|
Unknown,
|
||||||
NoRootDirectory,
|
NoRootDirectory,
|
||||||
Removable,
|
Removable,
|
||||||
Fixed,
|
Fixed,
|
||||||
Network,
|
Network,
|
||||||
CDRom,
|
CDRom,
|
||||||
Ram
|
Ram
|
||||||
}
|
}
|
||||||
|
|
||||||
// All methods & properties can throw IOException
|
// All methods & properties can throw IOException
|
||||||
public sealed class UnixDriveInfo
|
public sealed class UnixDriveInfo
|
||||||
{
|
{
|
||||||
private Native.Statvfs stat;
|
private Native.Statvfs stat;
|
||||||
private string fstype, mount_point, block_device;
|
private String fstype, mount_point, block_device;
|
||||||
|
|
||||||
public UnixDriveInfo (string mountPoint)
|
public UnixDriveInfo (String mountPoint)
|
||||||
{
|
{
|
||||||
if (mountPoint == null)
|
if (mountPoint == null) {
|
||||||
throw new ArgumentNullException ("mountPoint");
|
throw new ArgumentNullException ("mountPoint");
|
||||||
Native.Fstab fstab = Native.Syscall.getfsfile (mountPoint);
|
}
|
||||||
if (fstab != null) {
|
|
||||||
FromFstab (fstab);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.mount_point = mountPoint;
|
|
||||||
this.block_device = "";
|
|
||||||
this.fstype = "Unknown";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void FromFstab (Native.Fstab fstab)
|
Native.Fstab fstab = Native.Syscall.getfsfile (mountPoint);
|
||||||
{
|
if (fstab != null) {
|
||||||
this.fstype = fstab.fs_vfstype;
|
this.FromFstab (fstab);
|
||||||
this.mount_point = fstab.fs_file;
|
}
|
||||||
this.block_device = fstab.fs_spec;
|
else {
|
||||||
}
|
this.mount_point = mountPoint;
|
||||||
|
this.block_device = "";
|
||||||
|
this.fstype = "Unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static UnixDriveInfo GetForSpecialFile (string specialFile)
|
private void FromFstab (Native.Fstab fstab)
|
||||||
{
|
{
|
||||||
if (specialFile == null)
|
this.fstype = fstab.fs_vfstype;
|
||||||
throw new ArgumentNullException ("specialFile");
|
this.mount_point = fstab.fs_file;
|
||||||
Native.Fstab f = Native.Syscall.getfsspec (specialFile);
|
this.block_device = fstab.fs_spec;
|
||||||
if (f == null)
|
}
|
||||||
throw new ArgumentException ("specialFile isn't valid: " + specialFile);
|
|
||||||
return new UnixDriveInfo (f);
|
|
||||||
}
|
|
||||||
|
|
||||||
private UnixDriveInfo (Native.Fstab fstab)
|
public static UnixDriveInfo GetForSpecialFile (String specialFile)
|
||||||
{
|
{
|
||||||
FromFstab (fstab);
|
if (specialFile == null) {
|
||||||
}
|
throw new ArgumentNullException ("specialFile");
|
||||||
|
}
|
||||||
|
|
||||||
public long AvailableFreeSpace {
|
Native.Fstab f = Native.Syscall.getfsspec (specialFile);
|
||||||
get {Refresh (); return Convert.ToInt64 (stat.f_bavail * stat.f_frsize);}
|
if (f == null) {
|
||||||
}
|
throw new ArgumentException ("specialFile isn't valid: " + specialFile);
|
||||||
|
}
|
||||||
|
|
||||||
public string DriveFormat {
|
return new UnixDriveInfo (f);
|
||||||
get {return fstype;}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public UnixDriveType DriveType {
|
private UnixDriveInfo(Native.Fstab fstab) => this.FromFstab(fstab);
|
||||||
get {return UnixDriveType.Unknown;}
|
|
||||||
}
|
|
||||||
|
|
||||||
// this throws no exceptions
|
public Int64 AvailableFreeSpace {
|
||||||
public bool IsReady {
|
get {
|
||||||
get {
|
this.Refresh (); return Convert.ToInt64 (this.stat.f_bavail * this.stat.f_frsize);}
|
||||||
bool ready = Refresh (false);
|
}
|
||||||
if (mount_point == "/" || !ready)
|
|
||||||
return ready;
|
|
||||||
Native.Statvfs parent;
|
|
||||||
int r = Native.Syscall.statvfs (RootDirectory.Parent.FullName,
|
|
||||||
out parent);
|
|
||||||
if (r != 0)
|
|
||||||
return false;
|
|
||||||
return parent.f_fsid != stat.f_fsid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Name {
|
public String DriveFormat => this.fstype;
|
||||||
get {return mount_point;}
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnixDirectoryInfo RootDirectory {
|
public UnixDriveType DriveType => UnixDriveType.Unknown;
|
||||||
get {return new UnixDirectoryInfo (mount_point);}
|
|
||||||
}
|
|
||||||
|
|
||||||
public long TotalFreeSpace {
|
// this throws no exceptions
|
||||||
get {Refresh (); return (long) (stat.f_bfree * stat.f_frsize);}
|
public Boolean IsReady {
|
||||||
}
|
get {
|
||||||
|
Boolean ready = this.Refresh (false);
|
||||||
|
if (this.mount_point == "/" || !ready) {
|
||||||
|
return ready;
|
||||||
|
}
|
||||||
|
|
||||||
public long TotalSize {
|
Int32 r = Native.Syscall.statvfs(this.RootDirectory.Parent.FullName,
|
||||||
get {Refresh (); return (long) (stat.f_frsize * stat.f_blocks);}
|
out Native.Statvfs parent);
|
||||||
}
|
return r != 0 ? false : parent.f_fsid != this.stat.f_fsid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// also throws SecurityException if caller lacks perms
|
public String Name => this.mount_point;
|
||||||
public string VolumeLabel {
|
|
||||||
get {return block_device;}
|
|
||||||
// set {}
|
|
||||||
}
|
|
||||||
|
|
||||||
public long MaximumFilenameLength {
|
public UnixDirectoryInfo RootDirectory => new UnixDirectoryInfo(this.mount_point);
|
||||||
get {Refresh (); return Convert.ToInt64 (stat.f_namemax);}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UnixDriveInfo[] GetDrives ()
|
public Int64 TotalFreeSpace {
|
||||||
{
|
get {
|
||||||
// TODO: Return any drives mentioned by getmntent(3) once getmntent(3)
|
this.Refresh (); return (Int64) (this.stat.f_bfree * this.stat.f_frsize);}
|
||||||
// is exported by Syscall.
|
}
|
||||||
|
|
||||||
// throws IOException, UnauthorizedAccessException (no permission)
|
public Int64 TotalSize {
|
||||||
ArrayList entries = new ArrayList ();
|
get {
|
||||||
|
this.Refresh (); return (Int64) (this.stat.f_frsize * this.stat.f_blocks);}
|
||||||
|
}
|
||||||
|
|
||||||
lock (Native.Syscall.fstab_lock) {
|
// also throws SecurityException if caller lacks perms
|
||||||
int r = Native.Syscall.setfsent ();
|
public String VolumeLabel => this.block_device;
|
||||||
if (r != 1)
|
|
||||||
throw new IOException ("Error calling setfsent(3)", new UnixIOException ());
|
|
||||||
try {
|
|
||||||
Native.Fstab fs;
|
|
||||||
while ((fs = Native.Syscall.getfsent()) != null) {
|
|
||||||
// avoid virtual entries, such as "swap"
|
|
||||||
if (fs.fs_file != null && fs.fs_file.StartsWith ("/"))
|
|
||||||
entries.Add (new UnixDriveInfo (fs));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
Native.Syscall.endfsent ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (UnixDriveInfo[]) entries.ToArray (typeof(UnixDriveInfo));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString ()
|
public Int64 MaximumFilenameLength {
|
||||||
{
|
get {
|
||||||
return VolumeLabel;
|
this.Refresh (); return Convert.ToInt64 (this.stat.f_namemax);}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Refresh ()
|
public static UnixDriveInfo[] GetDrives ()
|
||||||
{
|
{
|
||||||
Refresh (true);
|
// TODO: Return any drives mentioned by getmntent(3) once getmntent(3)
|
||||||
}
|
// is exported by Syscall.
|
||||||
|
|
||||||
private bool Refresh (bool throwException)
|
// throws IOException, UnauthorizedAccessException (no permission)
|
||||||
{
|
ArrayList entries = new ArrayList ();
|
||||||
int r = Native.Syscall.statvfs (mount_point, out stat);
|
|
||||||
if (r == -1 && throwException) {
|
lock (Native.Syscall.fstab_lock) {
|
||||||
Native.Errno e = Native.Syscall.GetLastError ();
|
Int32 r = Native.Syscall.setfsent ();
|
||||||
throw new InvalidOperationException (
|
if (r != 1) {
|
||||||
UnixMarshal.GetErrorDescription (e),
|
throw new IOException ("Error calling setfsent(3)", new UnixIOException ());
|
||||||
new UnixIOException (e));
|
}
|
||||||
}
|
|
||||||
else if (r == -1)
|
try {
|
||||||
return false;
|
Native.Fstab fs;
|
||||||
return true;
|
while ((fs = Native.Syscall.getfsent()) != null) {
|
||||||
}
|
// avoid virtual entries, such as "swap"
|
||||||
}
|
if (fs.fs_file != null && fs.fs_file.StartsWith ("/")) {
|
||||||
|
_ = entries.Add(new UnixDriveInfo(fs));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
_ = Native.Syscall.endfsent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (UnixDriveInfo[]) entries.ToArray (typeof(UnixDriveInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override String ToString() => this.VolumeLabel;
|
||||||
|
|
||||||
|
private void Refresh() => this.Refresh(true);
|
||||||
|
|
||||||
|
private Boolean Refresh (Boolean throwException)
|
||||||
|
{
|
||||||
|
Int32 r = Native.Syscall.statvfs (this.mount_point, out this.stat);
|
||||||
|
if (r == -1 && throwException) {
|
||||||
|
Native.Errno e = Native.Syscall.GetLastError ();
|
||||||
|
throw new InvalidOperationException (
|
||||||
|
UnixMarshal.GetErrorDescription (e),
|
||||||
|
new UnixIOException (e));
|
||||||
|
}
|
||||||
|
else if (r == -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim: noexpandtab
|
// vim: noexpandtab
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -34,100 +34,95 @@ using System.Text;
|
|||||||
|
|
||||||
namespace Mono.Unix
|
namespace Mono.Unix
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class UnixEndPoint : EndPoint
|
public class UnixEndPoint : EndPoint
|
||||||
{
|
{
|
||||||
string filename;
|
String filename;
|
||||||
|
|
||||||
public UnixEndPoint (string filename)
|
public UnixEndPoint (String filename)
|
||||||
{
|
{
|
||||||
if (filename == null)
|
if (filename == null) {
|
||||||
throw new ArgumentNullException ("filename");
|
throw new ArgumentNullException ("filename");
|
||||||
|
}
|
||||||
|
|
||||||
if (filename == "")
|
if (filename == "") {
|
||||||
throw new ArgumentException ("Cannot be empty.", "filename");
|
throw new ArgumentException ("Cannot be empty.", "filename");
|
||||||
this.filename = filename;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public string Filename {
|
this.filename = filename;
|
||||||
get {
|
}
|
||||||
return(filename);
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
filename=value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override AddressFamily AddressFamily {
|
public String Filename {
|
||||||
get { return AddressFamily.Unix; }
|
get => this.filename;
|
||||||
}
|
set => this.filename = value;
|
||||||
|
}
|
||||||
|
|
||||||
public override EndPoint Create (SocketAddress socketAddress)
|
public override AddressFamily AddressFamily => AddressFamily.Unix;
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Should also check this
|
|
||||||
*
|
|
||||||
int addr = (int) AddressFamily.Unix;
|
|
||||||
if (socketAddress [0] != (addr & 0xFF))
|
|
||||||
throw new ArgumentException ("socketAddress is not a unix socket address.");
|
|
||||||
|
|
||||||
if (socketAddress [1] != ((addr & 0xFF00) >> 8))
|
public override EndPoint Create (SocketAddress socketAddress)
|
||||||
throw new ArgumentException ("socketAddress is not a unix socket address.");
|
{
|
||||||
*/
|
/*
|
||||||
|
* Should also check this
|
||||||
|
*
|
||||||
|
int addr = (int) AddressFamily.Unix;
|
||||||
|
if (socketAddress [0] != (addr & 0xFF))
|
||||||
|
throw new ArgumentException ("socketAddress is not a unix socket address.");
|
||||||
|
|
||||||
if (socketAddress.Size == 2) {
|
if (socketAddress [1] != ((addr & 0xFF00) >> 8))
|
||||||
// Empty filename.
|
throw new ArgumentException ("socketAddress is not a unix socket address.");
|
||||||
// Probably from RemoteEndPoint which on linux does not return the file name.
|
*/
|
||||||
UnixEndPoint uep = new UnixEndPoint ("a");
|
|
||||||
uep.filename = "";
|
|
||||||
return uep;
|
|
||||||
}
|
|
||||||
int size = socketAddress.Size - 2;
|
|
||||||
byte [] bytes = new byte [size];
|
|
||||||
for (int i = 0; i < bytes.Length; i++) {
|
|
||||||
bytes [i] = socketAddress [i + 2];
|
|
||||||
// There may be junk after the null terminator, so ignore it all.
|
|
||||||
if (bytes [i] == 0) {
|
|
||||||
size = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
string name = Encoding.Default.GetString (bytes, 0, size);
|
if (socketAddress.Size == 2) {
|
||||||
return new UnixEndPoint (name);
|
// Empty filename.
|
||||||
}
|
// Probably from RemoteEndPoint which on linux does not return the file name.
|
||||||
|
UnixEndPoint uep = new UnixEndPoint("a") {
|
||||||
|
filename = ""
|
||||||
|
};
|
||||||
|
return uep;
|
||||||
|
}
|
||||||
|
Int32 size = socketAddress.Size - 2;
|
||||||
|
Byte[] bytes = new Byte[size];
|
||||||
|
for (Int32 i = 0; i < bytes.Length; i++) {
|
||||||
|
bytes [i] = socketAddress [i + 2];
|
||||||
|
// There may be junk after the null terminator, so ignore it all.
|
||||||
|
if (bytes [i] == 0) {
|
||||||
|
size = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override SocketAddress Serialize ()
|
String name = Encoding.Default.GetString (bytes, 0, size);
|
||||||
{
|
return new UnixEndPoint (name);
|
||||||
byte [] bytes = Encoding.Default.GetBytes (filename);
|
}
|
||||||
SocketAddress sa = new SocketAddress (AddressFamily, 2 + bytes.Length + 1);
|
|
||||||
// sa [0] -> family low byte, sa [1] -> family high byte
|
|
||||||
for (int i = 0; i < bytes.Length; i++)
|
|
||||||
sa [2 + i] = bytes [i];
|
|
||||||
|
|
||||||
//NULL suffix for non-abstract path
|
public override SocketAddress Serialize ()
|
||||||
sa[2 + bytes.Length] = 0;
|
{
|
||||||
|
Byte[] bytes = Encoding.Default.GetBytes (this.filename);
|
||||||
|
SocketAddress sa = new SocketAddress (this.AddressFamily, 2 + bytes.Length + 1);
|
||||||
|
// sa [0] -> family low byte, sa [1] -> family high byte
|
||||||
|
for (Int32 i = 0; i < bytes.Length; i++) {
|
||||||
|
sa [2 + i] = bytes [i];
|
||||||
|
}
|
||||||
|
|
||||||
return sa;
|
//NULL suffix for non-abstract path
|
||||||
}
|
sa[2 + bytes.Length] = 0;
|
||||||
|
|
||||||
public override string ToString() {
|
return sa;
|
||||||
return(filename);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode ()
|
public override String ToString() => this.filename;
|
||||||
{
|
|
||||||
return filename.GetHashCode ();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals (object o)
|
public override Int32 GetHashCode() => this.filename.GetHashCode();
|
||||||
{
|
|
||||||
UnixEndPoint other = o as UnixEndPoint;
|
|
||||||
if (other == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return (other.filename == filename);
|
public override Boolean Equals (Object o)
|
||||||
}
|
{
|
||||||
}
|
UnixEndPoint other = o as UnixEndPoint;
|
||||||
|
if (other == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return other.filename == this.filename;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,211 +28,204 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Mono.Unix;
|
using Mono.Unix;
|
||||||
|
|
||||||
namespace Mono.Unix {
|
namespace Mono.Unix {
|
||||||
|
|
||||||
public sealed /* static */ class UnixEnvironment
|
public sealed /* static */ class UnixEnvironment
|
||||||
{
|
{
|
||||||
private UnixEnvironment () {}
|
private UnixEnvironment () {}
|
||||||
|
|
||||||
public static string CurrentDirectory {
|
public static String CurrentDirectory {
|
||||||
get {
|
get => UnixDirectoryInfo.GetCurrentDirectory();
|
||||||
return UnixDirectoryInfo.GetCurrentDirectory ();
|
set => UnixDirectoryInfo.SetCurrentDirectory(value);
|
||||||
}
|
}
|
||||||
set {
|
|
||||||
UnixDirectoryInfo.SetCurrentDirectory (value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string MachineName {
|
public static String MachineName {
|
||||||
get {
|
get {
|
||||||
Native.Utsname buf;
|
if(Native.Syscall.uname(out Native.Utsname buf) != 0) {
|
||||||
if (Native.Syscall.uname (out buf) != 0)
|
throw UnixMarshal.CreateExceptionForLastError();
|
||||||
throw UnixMarshal.CreateExceptionForLastError ();
|
}
|
||||||
return buf.nodename;
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
int r = Native.Syscall.sethostname (value);
|
|
||||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string UserName {
|
return buf.nodename;
|
||||||
get {return UnixUserInfo.GetRealUser ().UserName;}
|
}
|
||||||
}
|
set {
|
||||||
|
Int32 r = Native.Syscall.sethostname (value);
|
||||||
|
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static UnixGroupInfo RealGroup {
|
public static String UserName => UnixUserInfo.GetRealUser().UserName;
|
||||||
get {return new UnixGroupInfo (RealGroupId);}
|
|
||||||
// set can't be done as setgid(2) modifies effective gid as well
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long RealGroupId {
|
public static UnixGroupInfo RealGroup => new UnixGroupInfo(RealGroupId);
|
||||||
get {return Native.Syscall.getgid ();}
|
|
||||||
// set can't be done as setgid(2) modifies effective gid as well
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UnixUserInfo RealUser {
|
public static Int64 RealGroupId => Native.Syscall.getgid();
|
||||||
get {return new UnixUserInfo (RealUserId);}
|
|
||||||
// set can't be done as setuid(2) modifies effective uid as well
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long RealUserId {
|
public static UnixUserInfo RealUser => new UnixUserInfo(RealUserId);
|
||||||
get {return Native.Syscall.getuid ();}
|
|
||||||
// set can't be done as setuid(2) modifies effective uid as well
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UnixGroupInfo EffectiveGroup {
|
public static Int64 RealUserId => Native.Syscall.getuid();
|
||||||
get {return new UnixGroupInfo (EffectiveGroupId);}
|
|
||||||
set {EffectiveGroupId = value.GroupId;}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long EffectiveGroupId {
|
public static UnixGroupInfo EffectiveGroup {
|
||||||
get {return Native.Syscall.getegid ();}
|
get => new UnixGroupInfo(EffectiveGroupId);
|
||||||
set {Native.Syscall.setegid (Convert.ToUInt32 (value));}
|
set => EffectiveGroupId = value.GroupId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UnixUserInfo EffectiveUser {
|
public static Int64 EffectiveGroupId {
|
||||||
get {return new UnixUserInfo (EffectiveUserId);}
|
get => Native.Syscall.getegid();
|
||||||
set {EffectiveUserId = value.UserId;}
|
set => _ = Native.Syscall.setegid(Convert.ToUInt32(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long EffectiveUserId {
|
public static UnixUserInfo EffectiveUser {
|
||||||
get {return Native.Syscall.geteuid ();}
|
get => new UnixUserInfo(EffectiveUserId);
|
||||||
set {Native.Syscall.seteuid (Convert.ToUInt32 (value));}
|
set => EffectiveUserId = value.UserId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string Login {
|
public static Int64 EffectiveUserId {
|
||||||
get {return UnixUserInfo.GetRealUser ().UserName;}
|
get => Native.Syscall.geteuid();
|
||||||
}
|
set => _ = Native.Syscall.seteuid(Convert.ToUInt32(value));
|
||||||
|
}
|
||||||
|
|
||||||
[CLSCompliant (false)]
|
public static String Login => UnixUserInfo.GetRealUser().UserName;
|
||||||
public static long GetConfigurationValue (Native.SysconfName name)
|
|
||||||
{
|
|
||||||
long r = Native.Syscall.sysconf (name);
|
|
||||||
if (r == -1 && Native.Stdlib.GetLastError() != (Native.Errno) 0)
|
|
||||||
UnixMarshal.ThrowExceptionForLastError ();
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
[CLSCompliant (false)]
|
//[CLSCompliant (false)]
|
||||||
public static string GetConfigurationString (Native.ConfstrName name)
|
public static Int64 GetConfigurationValue (Native.SysconfName name)
|
||||||
{
|
{
|
||||||
ulong len = Native.Syscall.confstr (name, null, 0);
|
Int64 r = Native.Syscall.sysconf (name);
|
||||||
if (len == unchecked ((ulong) (-1)))
|
if (r == -1 && Native.Stdlib.GetLastError() != (Native.Errno) 0) {
|
||||||
UnixMarshal.ThrowExceptionForLastError ();
|
UnixMarshal.ThrowExceptionForLastError ();
|
||||||
if (len == 0)
|
}
|
||||||
return "";
|
|
||||||
StringBuilder buf = new StringBuilder ((int) len+1);
|
|
||||||
len = Native.Syscall.confstr (name, buf, len);
|
|
||||||
if (len == unchecked ((ulong) (-1)))
|
|
||||||
UnixMarshal.ThrowExceptionForLastError ();
|
|
||||||
return buf.ToString ();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SetNiceValue (int inc)
|
return r;
|
||||||
{
|
}
|
||||||
int r = Native.Syscall.nice (inc);
|
|
||||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int CreateSession ()
|
//[CLSCompliant (false)]
|
||||||
{
|
public static String GetConfigurationString (Native.ConfstrName name)
|
||||||
int s = Native.Syscall.setsid ();
|
{
|
||||||
UnixMarshal.ThrowExceptionForLastErrorIf (s);
|
UInt64 len = Native.Syscall.confstr (name, null, 0);
|
||||||
return s;
|
if (len == unchecked ((UInt64) (-1))) {
|
||||||
}
|
UnixMarshal.ThrowExceptionForLastError ();
|
||||||
|
}
|
||||||
|
|
||||||
public static void SetProcessGroup ()
|
if (len == 0) {
|
||||||
{
|
return "";
|
||||||
int r = Native.Syscall.setpgrp ();
|
}
|
||||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int GetProcessGroup ()
|
StringBuilder buf = new StringBuilder ((Int32) len+1);
|
||||||
{
|
len = Native.Syscall.confstr (name, buf, len);
|
||||||
return Native.Syscall.getpgrp ();
|
if (len == unchecked ((UInt64) (-1))) {
|
||||||
}
|
UnixMarshal.ThrowExceptionForLastError ();
|
||||||
|
}
|
||||||
|
|
||||||
public static UnixGroupInfo[] GetSupplementaryGroups ()
|
return buf.ToString ();
|
||||||
{
|
}
|
||||||
uint[] ids = _GetSupplementaryGroupIds ();
|
|
||||||
UnixGroupInfo[] groups = new UnixGroupInfo [ids.Length];
|
|
||||||
for (int i = 0; i < groups.Length; ++i)
|
|
||||||
groups [i] = new UnixGroupInfo (ids [i]);
|
|
||||||
return groups;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static uint[] _GetSupplementaryGroupIds ()
|
public static void SetNiceValue (Int32 inc)
|
||||||
{
|
{
|
||||||
int ngroups = Native.Syscall.getgroups (0, new uint[]{});
|
Int32 r = Native.Syscall.nice (inc);
|
||||||
if (ngroups == -1)
|
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||||
UnixMarshal.ThrowExceptionForLastError ();
|
}
|
||||||
uint[] groups = new uint[ngroups];
|
|
||||||
int r = Native.Syscall.getgroups (groups);
|
|
||||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
|
||||||
return groups;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SetSupplementaryGroups (UnixGroupInfo[] groups)
|
public static Int32 CreateSession ()
|
||||||
{
|
{
|
||||||
uint[] list = new uint [groups.Length];
|
Int32 s = Native.Syscall.setsid ();
|
||||||
for (int i = 0; i < list.Length; ++i) {
|
UnixMarshal.ThrowExceptionForLastErrorIf (s);
|
||||||
list [i] = Convert.ToUInt32 (groups [i].GroupId);
|
return s;
|
||||||
}
|
}
|
||||||
int r = Native.Syscall.setgroups (list);
|
|
||||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long[] GetSupplementaryGroupIds ()
|
public static void SetProcessGroup ()
|
||||||
{
|
{
|
||||||
uint[] _groups = _GetSupplementaryGroupIds ();
|
Int32 r = Native.Syscall.setpgrp ();
|
||||||
long[] groups = new long [_groups.Length];
|
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||||
for (int i = 0; i < groups.Length; ++i)
|
}
|
||||||
groups [i] = _groups [i];
|
|
||||||
return groups;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SetSupplementaryGroupIds (long[] list)
|
public static Int32 GetProcessGroup() => Native.Syscall.getpgrp();
|
||||||
{
|
|
||||||
uint[] _list = new uint [list.Length];
|
|
||||||
for (int i = 0; i < _list.Length; ++i)
|
|
||||||
_list [i] = Convert.ToUInt32 (list [i]);
|
|
||||||
int r = Native.Syscall.setgroups (_list);
|
|
||||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int GetParentProcessId ()
|
public static UnixGroupInfo[] GetSupplementaryGroups ()
|
||||||
{
|
{
|
||||||
return Native.Syscall.getppid ();
|
UInt32[] ids = _GetSupplementaryGroupIds ();
|
||||||
}
|
UnixGroupInfo[] groups = new UnixGroupInfo [ids.Length];
|
||||||
|
for (Int32 i = 0; i < groups.Length; ++i) {
|
||||||
|
groups [i] = new UnixGroupInfo (ids [i]);
|
||||||
|
}
|
||||||
|
|
||||||
public static UnixProcess GetParentProcess ()
|
return groups;
|
||||||
{
|
}
|
||||||
return new UnixProcess (GetParentProcessId ());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string[] GetUserShells ()
|
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||||
{
|
private static UInt32[] _GetSupplementaryGroupIds ()
|
||||||
ArrayList shells = new ArrayList ();
|
{
|
||||||
|
Int32 ngroups = Native.Syscall.getgroups (0, new UInt32[]{});
|
||||||
|
if (ngroups == -1) {
|
||||||
|
UnixMarshal.ThrowExceptionForLastError ();
|
||||||
|
}
|
||||||
|
|
||||||
lock (Native.Syscall.usershell_lock) {
|
UInt32[] groups = new UInt32[ngroups];
|
||||||
try {
|
Int32 r = Native.Syscall.getgroups (groups);
|
||||||
if (Native.Syscall.setusershell () != 0)
|
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||||
UnixMarshal.ThrowExceptionForLastError ();
|
return groups;
|
||||||
string shell;
|
}
|
||||||
while ((shell = Native.Syscall.getusershell ()) != null)
|
|
||||||
shells.Add (shell);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
Native.Syscall.endusershell ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (string[]) shells.ToArray (typeof(string));
|
public static void SetSupplementaryGroups (UnixGroupInfo[] groups)
|
||||||
}
|
{
|
||||||
}
|
UInt32[] list = new UInt32[groups.Length];
|
||||||
|
for (Int32 i = 0; i < list.Length; ++i) {
|
||||||
|
list [i] = Convert.ToUInt32 (groups [i].GroupId);
|
||||||
|
}
|
||||||
|
Int32 r = Native.Syscall.setgroups (list);
|
||||||
|
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Int64[] GetSupplementaryGroupIds ()
|
||||||
|
{
|
||||||
|
UInt32[] _groups = _GetSupplementaryGroupIds ();
|
||||||
|
Int64[] groups = new Int64[_groups.Length];
|
||||||
|
for (Int32 i = 0; i < groups.Length; ++i) {
|
||||||
|
groups [i] = _groups [i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return groups;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetSupplementaryGroupIds (Int64[] list)
|
||||||
|
{
|
||||||
|
UInt32[] _list = new UInt32[list.Length];
|
||||||
|
for (Int32 i = 0; i < _list.Length; ++i) {
|
||||||
|
_list [i] = Convert.ToUInt32 (list [i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Int32 r = Native.Syscall.setgroups (_list);
|
||||||
|
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Int32 GetParentProcessId() => Native.Syscall.getppid();
|
||||||
|
|
||||||
|
public static UnixProcess GetParentProcess() => new UnixProcess(GetParentProcessId());
|
||||||
|
|
||||||
|
public static String[] GetUserShells ()
|
||||||
|
{
|
||||||
|
ArrayList shells = new ArrayList ();
|
||||||
|
|
||||||
|
lock (Native.Syscall.usershell_lock) {
|
||||||
|
try {
|
||||||
|
if (Native.Syscall.setusershell () != 0) {
|
||||||
|
UnixMarshal.ThrowExceptionForLastError ();
|
||||||
|
}
|
||||||
|
|
||||||
|
String shell;
|
||||||
|
while ((shell = Native.Syscall.getusershell ()) != null) {
|
||||||
|
_ = shells.Add(shell);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
_ = Native.Syscall.endusershell();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (String[]) shells.ToArray (typeof(String));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim: noexpandtab
|
// vim: noexpandtab
|
||||||
|
@ -33,115 +33,110 @@ using Mono.Unix;
|
|||||||
|
|
||||||
namespace Mono.Unix {
|
namespace Mono.Unix {
|
||||||
|
|
||||||
public sealed class UnixFileInfo : UnixFileSystemInfo
|
public sealed class UnixFileInfo : UnixFileSystemInfo
|
||||||
{
|
{
|
||||||
public UnixFileInfo (string path)
|
public UnixFileInfo (String path)
|
||||||
: base (path)
|
: base (path)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
internal UnixFileInfo (string path, Native.Stat stat)
|
internal UnixFileInfo (String path, Native.Stat stat)
|
||||||
: base (path, stat)
|
: base (path, stat)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string Name {
|
public override String Name => UnixPath.GetFileName(this.FullPath);
|
||||||
get {return UnixPath.GetFileName (FullPath);}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string DirectoryName {
|
public String DirectoryName => UnixPath.GetDirectoryName(this.FullPath);
|
||||||
get {return UnixPath.GetDirectoryName (FullPath);}
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnixDirectoryInfo Directory {
|
public UnixDirectoryInfo Directory => new UnixDirectoryInfo(this.DirectoryName);
|
||||||
get {return new UnixDirectoryInfo (DirectoryName);}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Delete ()
|
public override void Delete ()
|
||||||
{
|
{
|
||||||
int r = Native.Syscall.unlink (FullPath);
|
Int32 r = Native.Syscall.unlink (this.FullPath);
|
||||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||||
base.Refresh ();
|
base.Refresh ();
|
||||||
}
|
}
|
||||||
|
|
||||||
public UnixStream Create ()
|
public UnixStream Create ()
|
||||||
{
|
{
|
||||||
Native.FilePermissions mode = // 0644
|
Native.FilePermissions mode = // 0644
|
||||||
Native.FilePermissions.S_IRUSR | Native.FilePermissions.S_IWUSR |
|
Native.FilePermissions.S_IRUSR | Native.FilePermissions.S_IWUSR |
|
||||||
Native.FilePermissions.S_IRGRP | Native.FilePermissions.S_IROTH;
|
Native.FilePermissions.S_IRGRP | Native.FilePermissions.S_IROTH;
|
||||||
return Create (mode);
|
return this.Create (mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
[CLSCompliant (false)]
|
//[CLSCompliant (false)]
|
||||||
public UnixStream Create (Native.FilePermissions mode)
|
public UnixStream Create (Native.FilePermissions mode)
|
||||||
{
|
{
|
||||||
int fd = Native.Syscall.creat (FullPath, mode);
|
Int32 fd = Native.Syscall.creat (this.FullPath, mode);
|
||||||
if (fd < 0)
|
if (fd < 0) {
|
||||||
UnixMarshal.ThrowExceptionForLastError ();
|
UnixMarshal.ThrowExceptionForLastError ();
|
||||||
base.Refresh ();
|
}
|
||||||
return new UnixStream (fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnixStream Create (FileAccessPermissions mode)
|
base.Refresh ();
|
||||||
{
|
return new UnixStream (fd);
|
||||||
return Create ((Native.FilePermissions) mode);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
[CLSCompliant (false)]
|
public UnixStream Create(FileAccessPermissions mode) => this.Create((Native.FilePermissions)mode);
|
||||||
public UnixStream Open (Native.OpenFlags flags)
|
|
||||||
{
|
|
||||||
if ((flags & Native.OpenFlags.O_CREAT) != 0)
|
|
||||||
throw new ArgumentException (
|
|
||||||
"Cannot specify OpenFlags.O_CREAT without providing " +
|
|
||||||
"FilePermissions. Use the Open(OpenFlags, FilePermissions) " +
|
|
||||||
"method instead");
|
|
||||||
int fd = Native.Syscall.open (FullPath, flags);
|
|
||||||
if (fd < 0)
|
|
||||||
UnixMarshal.ThrowExceptionForLastError ();
|
|
||||||
return new UnixStream (fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
[CLSCompliant (false)]
|
//[CLSCompliant (false)]
|
||||||
public UnixStream Open (Native.OpenFlags flags, Native.FilePermissions mode)
|
public UnixStream Open (Native.OpenFlags flags)
|
||||||
{
|
{
|
||||||
int fd = Native.Syscall.open (FullPath, flags, mode);
|
if ((flags & Native.OpenFlags.O_CREAT) != 0) {
|
||||||
if (fd < 0)
|
throw new ArgumentException (
|
||||||
UnixMarshal.ThrowExceptionForLastError ();
|
"Cannot specify OpenFlags.O_CREAT without providing " +
|
||||||
return new UnixStream (fd);
|
"FilePermissions. Use the Open(OpenFlags, FilePermissions) " +
|
||||||
}
|
"method instead");
|
||||||
|
}
|
||||||
|
|
||||||
public UnixStream Open (FileMode mode)
|
Int32 fd = Native.Syscall.open (this.FullPath, flags);
|
||||||
{
|
if (fd < 0) {
|
||||||
Native.OpenFlags flags = Native.NativeConvert.ToOpenFlags (mode, FileAccess.ReadWrite);
|
UnixMarshal.ThrowExceptionForLastError ();
|
||||||
return Open (flags);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public UnixStream Open (FileMode mode, FileAccess access)
|
return new UnixStream (fd);
|
||||||
{
|
}
|
||||||
Native.OpenFlags flags = Native.NativeConvert.ToOpenFlags (mode, access);
|
|
||||||
return Open (flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
[CLSCompliant (false)]
|
//[CLSCompliant (false)]
|
||||||
public UnixStream Open (FileMode mode, FileAccess access, Native.FilePermissions perms)
|
public UnixStream Open (Native.OpenFlags flags, Native.FilePermissions mode)
|
||||||
{
|
{
|
||||||
Native.OpenFlags flags = Native.NativeConvert.ToOpenFlags (mode, access);
|
Int32 fd = Native.Syscall.open (this.FullPath, flags, mode);
|
||||||
int fd = Native.Syscall.open (FullPath, flags, perms);
|
if (fd < 0) {
|
||||||
if (fd < 0)
|
UnixMarshal.ThrowExceptionForLastError ();
|
||||||
UnixMarshal.ThrowExceptionForLastError ();
|
}
|
||||||
return new UnixStream (fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnixStream OpenRead ()
|
return new UnixStream (fd);
|
||||||
{
|
}
|
||||||
return Open (FileMode.Open, FileAccess.Read);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnixStream OpenWrite ()
|
public UnixStream Open (FileMode mode)
|
||||||
{
|
{
|
||||||
return Open (FileMode.OpenOrCreate, FileAccess.Write);
|
Native.OpenFlags flags = Native.NativeConvert.ToOpenFlags (mode, FileAccess.ReadWrite);
|
||||||
}
|
return this.Open (flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public UnixStream Open (FileMode mode, FileAccess access)
|
||||||
|
{
|
||||||
|
Native.OpenFlags flags = Native.NativeConvert.ToOpenFlags (mode, access);
|
||||||
|
return this.Open (flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
//[CLSCompliant (false)]
|
||||||
|
public UnixStream Open (FileMode mode, FileAccess access, Native.FilePermissions perms)
|
||||||
|
{
|
||||||
|
Native.OpenFlags flags = Native.NativeConvert.ToOpenFlags (mode, access);
|
||||||
|
Int32 fd = Native.Syscall.open (this.FullPath, flags, perms);
|
||||||
|
if (fd < 0) {
|
||||||
|
UnixMarshal.ThrowExceptionForLastError ();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new UnixStream (fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnixStream OpenRead() => this.Open(FileMode.Open, FileAccess.Read);
|
||||||
|
|
||||||
|
public UnixStream OpenWrite() => this.Open(FileMode.OpenOrCreate, FileAccess.Write);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim: noexpandtab
|
// vim: noexpandtab
|
||||||
|
@ -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
|
||||||
|
@ -33,117 +33,91 @@ using Mono.Unix;
|
|||||||
|
|
||||||
namespace Mono.Unix {
|
namespace Mono.Unix {
|
||||||
|
|
||||||
public sealed class UnixGroupInfo
|
public sealed class UnixGroupInfo
|
||||||
{
|
{
|
||||||
private Native.Group group;
|
private readonly Native.Group group;
|
||||||
|
|
||||||
public UnixGroupInfo (string group)
|
public UnixGroupInfo (String group)
|
||||||
{
|
{
|
||||||
this.group = new Native.Group ();
|
this.group = new Native.Group ();
|
||||||
Native.Group gr;
|
Int32 r = Native.Syscall.getgrnam_r(group, this.group, out Native.Group gr);
|
||||||
int r = Native.Syscall.getgrnam_r (group, this.group, out gr);
|
if (r != 0 || gr == null) {
|
||||||
if (r != 0 || gr == null)
|
throw new ArgumentException (Locale.GetText ("invalid group name"), "group");
|
||||||
throw new ArgumentException (Locale.GetText ("invalid group name"), "group");
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public UnixGroupInfo (long group)
|
public UnixGroupInfo (Int64 group)
|
||||||
{
|
{
|
||||||
this.group = new Native.Group ();
|
this.group = new Native.Group ();
|
||||||
Native.Group gr;
|
Int32 r = Native.Syscall.getgrgid_r(Convert.ToUInt32(group), this.group, out Native.Group gr);
|
||||||
int r = Native.Syscall.getgrgid_r (Convert.ToUInt32 (group), this.group, out gr);
|
if (r != 0 || gr == null) {
|
||||||
if (r != 0 || gr == null)
|
throw new ArgumentException (Locale.GetText ("invalid group id"), "group");
|
||||||
throw new ArgumentException (Locale.GetText ("invalid group id"), "group");
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public UnixGroupInfo (Native.Group group)
|
public UnixGroupInfo(Native.Group group) => this.group = CopyGroup(group);
|
||||||
{
|
|
||||||
this.group = CopyGroup (group);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Native.Group CopyGroup (Native.Group group)
|
private static Native.Group CopyGroup(Native.Group group) => new Native.Group {
|
||||||
{
|
gr_gid = group.gr_gid,
|
||||||
Native.Group g = new Native.Group ();
|
gr_mem = group.gr_mem,
|
||||||
|
gr_name = group.gr_name,
|
||||||
|
gr_passwd = group.gr_passwd
|
||||||
|
};
|
||||||
|
|
||||||
g.gr_gid = group.gr_gid;
|
public String GroupName => this.group.gr_name;
|
||||||
g.gr_mem = group.gr_mem;
|
|
||||||
g.gr_name = group.gr_name;
|
|
||||||
g.gr_passwd = group.gr_passwd;
|
|
||||||
|
|
||||||
return g;
|
public String Password => this.group.gr_passwd;
|
||||||
}
|
|
||||||
|
|
||||||
public string GroupName {
|
public Int64 GroupId => this.group.gr_gid;
|
||||||
get {return group.gr_name;}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Password {
|
public UnixUserInfo[] GetMembers ()
|
||||||
get {return group.gr_passwd;}
|
{
|
||||||
}
|
ArrayList members = new ArrayList (this.group.gr_mem.Length);
|
||||||
|
for (Int32 i = 0; i < this.group.gr_mem.Length; ++i) {
|
||||||
|
try {
|
||||||
|
_ = members.Add(new UnixUserInfo(this.group.gr_mem[i]));
|
||||||
|
} catch (ArgumentException) {
|
||||||
|
// ignore invalid users
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (UnixUserInfo[]) members.ToArray (typeof (UnixUserInfo));
|
||||||
|
}
|
||||||
|
|
||||||
public long GroupId {
|
public String[] GetMemberNames() => (String[])this.group.gr_mem.Clone();
|
||||||
get {return group.gr_gid;}
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnixUserInfo[] GetMembers ()
|
public override Int32 GetHashCode() => this.group.GetHashCode();
|
||||||
{
|
|
||||||
ArrayList members = new ArrayList (group.gr_mem.Length);
|
|
||||||
for (int i = 0; i < group.gr_mem.Length; ++i) {
|
|
||||||
try {
|
|
||||||
members.Add (new UnixUserInfo (group.gr_mem [i]));
|
|
||||||
} catch (ArgumentException) {
|
|
||||||
// ignore invalid users
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (UnixUserInfo[]) members.ToArray (typeof (UnixUserInfo));
|
|
||||||
}
|
|
||||||
|
|
||||||
public string[] GetMemberNames ()
|
public override Boolean Equals(Object obj) => obj == null || this.GetType() != obj.GetType() ? false : this.group.Equals(((UnixGroupInfo)obj).group);
|
||||||
{
|
|
||||||
return (string[]) group.gr_mem.Clone ();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode ()
|
public override String ToString() => this.group.ToString();
|
||||||
{
|
|
||||||
return group.GetHashCode ();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals (object obj)
|
public Native.Group ToGroup() => CopyGroup(this.group);
|
||||||
{
|
|
||||||
if (obj == null || GetType () != obj.GetType())
|
|
||||||
return false;
|
|
||||||
return group.Equals (((UnixGroupInfo) obj).group);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString ()
|
public static UnixGroupInfo[] GetLocalGroups ()
|
||||||
{
|
{
|
||||||
return group.ToString();
|
ArrayList entries = new ArrayList ();
|
||||||
}
|
lock (Native.Syscall.grp_lock) {
|
||||||
|
if (Native.Syscall.setgrent () != 0) {
|
||||||
|
UnixMarshal.ThrowExceptionForLastError ();
|
||||||
|
}
|
||||||
|
|
||||||
public Native.Group ToGroup ()
|
try {
|
||||||
{
|
Native.Group g;
|
||||||
return CopyGroup (group);
|
while ((g = Native.Syscall.getgrent()) != null) {
|
||||||
}
|
_ = entries.Add(new UnixGroupInfo(g));
|
||||||
|
}
|
||||||
|
|
||||||
public static UnixGroupInfo[] GetLocalGroups ()
|
if (Native.Syscall.GetLastError() != (Native.Errno) 0) {
|
||||||
{
|
UnixMarshal.ThrowExceptionForLastError ();
|
||||||
ArrayList entries = new ArrayList ();
|
}
|
||||||
lock (Native.Syscall.grp_lock) {
|
}
|
||||||
if (Native.Syscall.setgrent () != 0)
|
finally {
|
||||||
UnixMarshal.ThrowExceptionForLastError ();
|
_ = Native.Syscall.endgrent();
|
||||||
try {
|
}
|
||||||
Native.Group g;
|
}
|
||||||
while ((g = Native.Syscall.getgrent()) != null)
|
return (UnixGroupInfo[]) entries.ToArray (typeof(UnixGroupInfo));
|
||||||
entries.Add (new UnixGroupInfo (g));
|
}
|
||||||
if (Native.Syscall.GetLastError() != (Native.Errno) 0)
|
}
|
||||||
UnixMarshal.ThrowExceptionForLastError ();
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
Native.Syscall.endgrent ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (UnixGroupInfo[]) entries.ToArray (typeof(UnixGroupInfo));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim: noexpandtab
|
// vim: noexpandtab
|
||||||
|
@ -30,75 +30,49 @@ using System;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
using Mono.Unix;
|
|
||||||
|
|
||||||
namespace Mono.Unix {
|
namespace Mono.Unix {
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class UnixIOException : IOException
|
public class UnixIOException : IOException
|
||||||
{
|
{
|
||||||
private int errno;
|
private Int32 errno;
|
||||||
|
|
||||||
public UnixIOException ()
|
public UnixIOException ()
|
||||||
: this (Marshal.GetLastWin32Error())
|
: this (Marshal.GetLastWin32Error())
|
||||||
{}
|
{}
|
||||||
|
|
||||||
public UnixIOException (int errno)
|
public UnixIOException(Int32 errno)
|
||||||
: base (GetMessage (Native.NativeConvert.ToErrno (errno)))
|
: base(GetMessage(Native.NativeConvert.ToErrno(errno))) => this.errno = errno;
|
||||||
{
|
|
||||||
this.errno = errno;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnixIOException (int errno, Exception inner)
|
public UnixIOException(Int32 errno, Exception inner)
|
||||||
: base (GetMessage (Native.NativeConvert.ToErrno (errno)), inner)
|
: base(GetMessage(Native.NativeConvert.ToErrno(errno)), inner) => this.errno = errno;
|
||||||
{
|
|
||||||
this.errno = errno;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnixIOException (Native.Errno errno)
|
public UnixIOException(Native.Errno errno)
|
||||||
: base (GetMessage (errno))
|
: base(GetMessage(errno)) => this.errno = Native.NativeConvert.FromErrno(errno);
|
||||||
{
|
|
||||||
this.errno = Native.NativeConvert.FromErrno (errno);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnixIOException (Native.Errno errno, Exception inner)
|
public UnixIOException(Native.Errno errno, Exception inner)
|
||||||
: base (GetMessage (errno), inner)
|
: base(GetMessage(errno), inner) => this.errno = Native.NativeConvert.FromErrno(errno);
|
||||||
{
|
|
||||||
this.errno = Native.NativeConvert.FromErrno (errno);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnixIOException (string message)
|
public UnixIOException(String message)
|
||||||
: base (message)
|
: base(message) => this.errno = 0;
|
||||||
{
|
|
||||||
this.errno = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnixIOException (string message, Exception inner)
|
public UnixIOException(String message, Exception inner)
|
||||||
: base (message, inner)
|
: base(message, inner) => this.errno = 0;
|
||||||
{
|
|
||||||
this.errno = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected UnixIOException (SerializationInfo info, StreamingContext context)
|
protected UnixIOException (SerializationInfo info, StreamingContext context)
|
||||||
: base (info, context)
|
: base (info, context)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public int NativeErrorCode {
|
public Int32 NativeErrorCode => this.errno;
|
||||||
get {return errno;}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Native.Errno ErrorCode {
|
public Native.Errno ErrorCode => Native.NativeConvert.ToErrno(this.errno);
|
||||||
get {return Native.NativeConvert.ToErrno (errno);}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetMessage (Native.Errno errno)
|
private static String GetMessage(Native.Errno errno) => String.Format("{0} [{1}].",
|
||||||
{
|
UnixMarshal.GetErrorDescription(errno),
|
||||||
return string.Format ("{0} [{1}].",
|
errno);
|
||||||
UnixMarshal.GetErrorDescription (errno),
|
}
|
||||||
errno);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim: noexpandtab
|
// vim: noexpandtab
|
||||||
|
@ -35,139 +35,141 @@ using System.IO;
|
|||||||
|
|
||||||
namespace Mono.Unix {
|
namespace Mono.Unix {
|
||||||
|
|
||||||
public class UnixListener : MarshalByRefObject, IDisposable {
|
public class UnixListener : MarshalByRefObject, IDisposable {
|
||||||
bool disposed;
|
Boolean disposed;
|
||||||
bool listening;
|
Boolean listening;
|
||||||
Socket server;
|
Socket server;
|
||||||
EndPoint savedEP;
|
EndPoint savedEP;
|
||||||
|
|
||||||
void Init (UnixEndPoint ep)
|
void Init (UnixEndPoint ep)
|
||||||
{
|
{
|
||||||
listening = false;
|
this.listening = false;
|
||||||
string filename = ep.Filename;
|
String filename = ep.Filename;
|
||||||
if (File.Exists (filename)) {
|
if (File.Exists (filename)) {
|
||||||
Socket conn = new Socket (AddressFamily.Unix, SocketType.Stream, 0);
|
Socket conn = new Socket (AddressFamily.Unix, SocketType.Stream, 0);
|
||||||
try {
|
try {
|
||||||
conn.Connect (ep);
|
conn.Connect (ep);
|
||||||
conn.Close ();
|
conn.Close ();
|
||||||
throw new InvalidOperationException ("There's already a server listening on " + filename);
|
throw new InvalidOperationException ("There's already a server listening on " + filename);
|
||||||
} catch (SocketException) {
|
} catch (SocketException) {
|
||||||
}
|
}
|
||||||
File.Delete (filename);
|
File.Delete (filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
server = new Socket (AddressFamily.Unix, SocketType.Stream, 0);
|
this.server = new Socket (AddressFamily.Unix, SocketType.Stream, 0);
|
||||||
server.Bind (ep);
|
this.server.Bind (ep);
|
||||||
savedEP = server.LocalEndPoint;
|
this.savedEP = this.server.LocalEndPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UnixListener (string path)
|
public UnixListener (String path)
|
||||||
{
|
{
|
||||||
if (!Directory.Exists (Path.GetDirectoryName (path)))
|
if (!Directory.Exists (Path.GetDirectoryName (path))) {
|
||||||
Directory.CreateDirectory (Path.GetDirectoryName (path));
|
_ = Directory.CreateDirectory(Path.GetDirectoryName(path));
|
||||||
|
}
|
||||||
|
|
||||||
Init (new UnixEndPoint (path));
|
this.Init (new UnixEndPoint (path));
|
||||||
}
|
}
|
||||||
|
|
||||||
public UnixListener (UnixEndPoint localEndPoint)
|
public UnixListener (UnixEndPoint localEndPoint)
|
||||||
{
|
{
|
||||||
if (localEndPoint == null)
|
if (localEndPoint == null) {
|
||||||
throw new ArgumentNullException ("localendPoint");
|
throw new ArgumentNullException ("localendPoint");
|
||||||
|
}
|
||||||
|
|
||||||
Init (localEndPoint);
|
this.Init (localEndPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
public EndPoint LocalEndpoint {
|
public EndPoint LocalEndpoint => this.savedEP;
|
||||||
get { return savedEP; }
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Socket Server {
|
protected Socket Server => this.server;
|
||||||
get { return server; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public Socket AcceptSocket ()
|
public Socket AcceptSocket ()
|
||||||
{
|
{
|
||||||
CheckDisposed ();
|
this.CheckDisposed ();
|
||||||
if (!listening)
|
if (!this.listening) {
|
||||||
throw new InvalidOperationException ("Socket is not listening");
|
throw new InvalidOperationException ("Socket is not listening");
|
||||||
|
}
|
||||||
|
|
||||||
return server.Accept ();
|
return this.server.Accept ();
|
||||||
}
|
}
|
||||||
|
|
||||||
public UnixClient AcceptUnixClient ()
|
public UnixClient AcceptUnixClient ()
|
||||||
{
|
{
|
||||||
CheckDisposed ();
|
this.CheckDisposed ();
|
||||||
if (!listening)
|
if (!this.listening) {
|
||||||
throw new InvalidOperationException ("Socket is not listening");
|
throw new InvalidOperationException ("Socket is not listening");
|
||||||
|
}
|
||||||
|
|
||||||
return new UnixClient (AcceptSocket ());
|
return new UnixClient (this.AcceptSocket ());
|
||||||
}
|
}
|
||||||
|
|
||||||
~UnixListener ()
|
~UnixListener ()
|
||||||
{
|
{
|
||||||
Dispose (false);
|
this.Dispose (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Pending ()
|
public Boolean Pending ()
|
||||||
{
|
{
|
||||||
CheckDisposed ();
|
this.CheckDisposed ();
|
||||||
if (!listening)
|
if (!this.listening) {
|
||||||
throw new InvalidOperationException ("Socket is not listening");
|
throw new InvalidOperationException ("Socket is not listening");
|
||||||
|
}
|
||||||
|
|
||||||
return server.Poll (1000, SelectMode.SelectRead);
|
return this.server.Poll (1000, SelectMode.SelectRead);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Start ()
|
public void Start() => this.Start(5);
|
||||||
{
|
|
||||||
Start (5);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Start (int backlog)
|
public void Start (Int32 backlog)
|
||||||
{
|
{
|
||||||
CheckDisposed ();
|
this.CheckDisposed ();
|
||||||
if (listening)
|
if (this.listening) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
server.Listen (backlog);
|
this.server.Listen (backlog);
|
||||||
listening = true;
|
this.listening = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Stop ()
|
public void Stop ()
|
||||||
{
|
{
|
||||||
CheckDisposed ();
|
this.CheckDisposed ();
|
||||||
Dispose (true);
|
this.Dispose (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose ()
|
public void Dispose ()
|
||||||
{
|
{
|
||||||
Dispose (true);
|
this.Dispose (true);
|
||||||
GC.SuppressFinalize (this);
|
GC.SuppressFinalize (this);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void Dispose (bool disposing)
|
protected void Dispose (Boolean disposing)
|
||||||
{
|
{
|
||||||
if (disposed)
|
if (this.disposed) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (disposing) {
|
if (disposing) {
|
||||||
try {
|
try {
|
||||||
File.Delete (((UnixEndPoint) savedEP).Filename);
|
File.Delete (((UnixEndPoint)this.savedEP).Filename);
|
||||||
} catch {
|
} catch {
|
||||||
}
|
}
|
||||||
if (server != null)
|
if (this.server != null) {
|
||||||
server.Close ();
|
this.server.Close ();
|
||||||
|
}
|
||||||
|
|
||||||
server = null;
|
this.server = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
disposed = true;
|
this.disposed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckDisposed ()
|
void CheckDisposed ()
|
||||||
{
|
{
|
||||||
if (disposed)
|
if (this.disposed) {
|
||||||
throw new ObjectDisposedException (GetType().FullName);
|
throw new ObjectDisposedException (this.GetType().FullName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -28,259 +28,272 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Mono.Unix;
|
using Mono.Unix;
|
||||||
|
|
||||||
namespace Mono.Unix {
|
namespace Mono.Unix {
|
||||||
|
|
||||||
public sealed class UnixPath
|
public sealed class UnixPath
|
||||||
{
|
{
|
||||||
private UnixPath () {}
|
private UnixPath () {}
|
||||||
|
|
||||||
public static readonly char DirectorySeparatorChar = '/';
|
public static readonly Char DirectorySeparatorChar = '/';
|
||||||
public static readonly char AltDirectorySeparatorChar = '/';
|
public static readonly Char AltDirectorySeparatorChar = '/';
|
||||||
public static readonly char PathSeparator = ':';
|
public static readonly Char PathSeparator = ':';
|
||||||
public static readonly char VolumeSeparatorChar = '/';
|
public static readonly Char VolumeSeparatorChar = '/';
|
||||||
|
|
||||||
private static readonly char[] _InvalidPathChars = new char[]{};
|
private static readonly Char[] _InvalidPathChars = new Char[]{};
|
||||||
|
|
||||||
public static char[] GetInvalidPathChars ()
|
public static Char[] GetInvalidPathChars() => (Char[])_InvalidPathChars.Clone();
|
||||||
{
|
|
||||||
return (char[]) _InvalidPathChars.Clone ();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string Combine (string path1, params string[] paths)
|
public static String Combine (String path1, params String[] paths)
|
||||||
{
|
{
|
||||||
if (path1 == null)
|
if (path1 == null) {
|
||||||
throw new ArgumentNullException ("path1");
|
throw new ArgumentNullException ("path1");
|
||||||
if (paths == null)
|
}
|
||||||
throw new ArgumentNullException ("paths");
|
|
||||||
if (path1.IndexOfAny (_InvalidPathChars) != -1)
|
|
||||||
throw new ArgumentException ("Illegal characters in path", "path1");
|
|
||||||
|
|
||||||
int len = path1.Length;
|
if (paths == null) {
|
||||||
int start = -1;
|
throw new ArgumentNullException ("paths");
|
||||||
for (int i = 0; i < paths.Length; ++i) {
|
}
|
||||||
if (paths [i] == null)
|
|
||||||
throw new ArgumentNullException ("paths[" + i + "]");
|
|
||||||
if (paths [i].IndexOfAny (_InvalidPathChars) != -1)
|
|
||||||
throw new ArgumentException ("Illegal characters in path", "paths[" + i + "]");
|
|
||||||
if (IsPathRooted (paths [i])) {
|
|
||||||
len = 0;
|
|
||||||
start = i;
|
|
||||||
}
|
|
||||||
len += paths [i].Length + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder (len);
|
if (path1.IndexOfAny (_InvalidPathChars) != -1) {
|
||||||
if (start == -1) {
|
throw new ArgumentException ("Illegal characters in path", "path1");
|
||||||
sb.Append (path1);
|
}
|
||||||
start = 0;
|
|
||||||
}
|
|
||||||
for (int i = start; i < paths.Length; ++i)
|
|
||||||
Combine (sb, paths [i]);
|
|
||||||
return sb.ToString ();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void Combine (StringBuilder path, string part)
|
Int32 len = path1.Length;
|
||||||
{
|
Int32 start = -1;
|
||||||
if (path.Length > 0 && part.Length > 0) {
|
for (Int32 i = 0; i < paths.Length; ++i) {
|
||||||
char end = path [path.Length-1];
|
if (paths [i] == null) {
|
||||||
if (end != DirectorySeparatorChar &&
|
throw new ArgumentNullException ("paths[" + i + "]");
|
||||||
end != AltDirectorySeparatorChar &&
|
}
|
||||||
end != VolumeSeparatorChar)
|
|
||||||
path.Append (DirectorySeparatorChar);
|
|
||||||
}
|
|
||||||
path.Append (part);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetDirectoryName (string path)
|
if (paths [i].IndexOfAny (_InvalidPathChars) != -1) {
|
||||||
{
|
throw new ArgumentException ("Illegal characters in path", "paths[" + i + "]");
|
||||||
CheckPath (path);
|
}
|
||||||
|
|
||||||
int lastDir = path.LastIndexOf (DirectorySeparatorChar);
|
if (IsPathRooted (paths [i])) {
|
||||||
if (lastDir > 0)
|
len = 0;
|
||||||
return path.Substring (0, lastDir);
|
start = i;
|
||||||
if (lastDir == 0)
|
}
|
||||||
return "/";
|
len += paths [i].Length + 1;
|
||||||
return "";
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetFileName (string path)
|
StringBuilder sb = new StringBuilder (len);
|
||||||
{
|
if (start == -1) {
|
||||||
if (path == null || path.Length == 0)
|
_ = sb.Append(path1);
|
||||||
return path;
|
start = 0;
|
||||||
|
}
|
||||||
|
for (Int32 i = start; i < paths.Length; ++i) {
|
||||||
|
Combine (sb, paths [i]);
|
||||||
|
}
|
||||||
|
|
||||||
int lastDir = path.LastIndexOf (DirectorySeparatorChar);
|
return sb.ToString ();
|
||||||
if (lastDir >= 0)
|
}
|
||||||
return path.Substring (lastDir+1);
|
|
||||||
|
|
||||||
return path;
|
private static void Combine (StringBuilder path, String part)
|
||||||
}
|
{
|
||||||
|
if (path.Length > 0 && part.Length > 0) {
|
||||||
|
Char end = path [path.Length-1];
|
||||||
|
if (end != DirectorySeparatorChar &&
|
||||||
|
end != AltDirectorySeparatorChar &&
|
||||||
|
end != VolumeSeparatorChar) {
|
||||||
|
_ = path.Append(DirectorySeparatorChar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ = path.Append(part);
|
||||||
|
}
|
||||||
|
|
||||||
public static string GetFullPath (string path)
|
public static String GetDirectoryName (String path)
|
||||||
{
|
{
|
||||||
path = _GetFullPath (path);
|
CheckPath (path);
|
||||||
return GetCanonicalPath (path);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string _GetFullPath (string path)
|
Int32 lastDir = path.LastIndexOf (DirectorySeparatorChar);
|
||||||
{
|
return lastDir > 0 ? path.Substring (0, lastDir) : lastDir == 0 ? "/" : "";
|
||||||
if (path == null)
|
}
|
||||||
throw new ArgumentNullException ("path");
|
|
||||||
if (!IsPathRooted (path))
|
|
||||||
path = UnixDirectoryInfo.GetCurrentDirectory() + DirectorySeparatorChar + path;
|
|
||||||
|
|
||||||
return path;
|
public static String GetFileName (String path)
|
||||||
}
|
{
|
||||||
|
if (path == null || path.Length == 0) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
public static string GetCanonicalPath (string path)
|
Int32 lastDir = path.LastIndexOf (DirectorySeparatorChar);
|
||||||
{
|
return lastDir >= 0 ? path.Substring (lastDir+1) : path;
|
||||||
string [] dirs;
|
}
|
||||||
int lastIndex;
|
|
||||||
GetPathComponents (path, out dirs, out lastIndex);
|
|
||||||
string end = string.Join ("/", dirs, 0, lastIndex);
|
|
||||||
return IsPathRooted (path) ? "/" + end : end;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void GetPathComponents (string path,
|
public static String GetFullPath (String path)
|
||||||
out string[] components, out int lastIndex)
|
{
|
||||||
{
|
path = _GetFullPath (path);
|
||||||
string [] dirs = path.Split (DirectorySeparatorChar);
|
return GetCanonicalPath (path);
|
||||||
int target = 0;
|
}
|
||||||
for (int i = 0; i < dirs.Length; ++i) {
|
|
||||||
if (dirs [i] == "." || dirs [i] == string.Empty) continue;
|
|
||||||
else if (dirs [i] == "..") {
|
|
||||||
if (target != 0) --target;
|
|
||||||
else ++target;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
dirs [target++] = dirs [i];
|
|
||||||
}
|
|
||||||
components = dirs;
|
|
||||||
lastIndex = target;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetPathRoot (string path)
|
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||||
{
|
private static String _GetFullPath (String path)
|
||||||
if (path == null)
|
{
|
||||||
return null;
|
if (path == null) {
|
||||||
if (!IsPathRooted (path))
|
throw new ArgumentNullException ("path");
|
||||||
return "";
|
}
|
||||||
return "/";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetCompleteRealPath (string path)
|
if (!IsPathRooted (path)) {
|
||||||
{
|
path = UnixDirectoryInfo.GetCurrentDirectory() + DirectorySeparatorChar + path;
|
||||||
if (path == null)
|
}
|
||||||
throw new ArgumentNullException ("path");
|
|
||||||
string [] dirs;
|
|
||||||
int lastIndex;
|
|
||||||
GetPathComponents (path, out dirs, out lastIndex);
|
|
||||||
StringBuilder realPath = new StringBuilder ();
|
|
||||||
if (dirs.Length > 0) {
|
|
||||||
string dir = IsPathRooted (path) ? "/" : "";
|
|
||||||
dir += dirs [0];
|
|
||||||
realPath.Append (GetRealPath (dir));
|
|
||||||
}
|
|
||||||
for (int i = 1; i < lastIndex; ++i) {
|
|
||||||
realPath.Append ("/").Append (dirs [i]);
|
|
||||||
string p = GetRealPath (realPath.ToString());
|
|
||||||
realPath.Remove (0, realPath.Length);
|
|
||||||
realPath.Append (p);
|
|
||||||
}
|
|
||||||
return realPath.ToString ();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetRealPath (string path)
|
return path;
|
||||||
{
|
}
|
||||||
do {
|
|
||||||
string name = ReadSymbolicLink (path);
|
|
||||||
if (name == null)
|
|
||||||
return path;
|
|
||||||
if (IsPathRooted (name))
|
|
||||||
path = name;
|
|
||||||
else {
|
|
||||||
path = GetDirectoryName (path) + DirectorySeparatorChar + name;
|
|
||||||
path = GetCanonicalPath (path);
|
|
||||||
}
|
|
||||||
} while (true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the specified symbolic link. If the file isn't a symbolic link,
|
public static String GetCanonicalPath (String path)
|
||||||
// return null; otherwise, return the contents of the symbolic link.
|
{
|
||||||
internal static string ReadSymbolicLink (string path)
|
GetPathComponents(path, out String[] dirs, out Int32 lastIndex);
|
||||||
{
|
String end = String.Join ("/", dirs, 0, lastIndex);
|
||||||
string target = TryReadLink (path);
|
return IsPathRooted (path) ? "/" + end : end;
|
||||||
if (target == null) {
|
}
|
||||||
Native.Errno errno = Native.Stdlib.GetLastError ();
|
|
||||||
if (errno != Native.Errno.EINVAL)
|
|
||||||
UnixMarshal.ThrowExceptionForError (errno);
|
|
||||||
}
|
|
||||||
return target;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string TryReadLink (string path)
|
private static void GetPathComponents (String path,
|
||||||
{
|
out String[] components, out Int32 lastIndex)
|
||||||
byte[] buf = new byte[256];
|
{
|
||||||
do {
|
String[] dirs = path.Split (DirectorySeparatorChar);
|
||||||
long r = Native.Syscall.readlink (path, buf);
|
Int32 target = 0;
|
||||||
if (r < 0)
|
for (Int32 i = 0; i < dirs.Length; ++i) {
|
||||||
return null;
|
if (dirs [i] == "." || dirs [i] == String.Empty) {
|
||||||
else if (r == buf.Length)
|
continue;
|
||||||
buf = new byte[checked (buf.LongLength * 2)];
|
} else if (dirs [i] == "..") {
|
||||||
else
|
if (target != 0) {
|
||||||
return UnixEncoding.Instance.GetString (buf, 0, checked ((int) r));
|
--target;
|
||||||
} while (true);
|
} else {
|
||||||
}
|
++target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dirs [target++] = dirs [i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
components = dirs;
|
||||||
|
lastIndex = target;
|
||||||
|
}
|
||||||
|
|
||||||
public static string TryReadLinkAt (int dirfd, string path)
|
public static String GetPathRoot(String path) => path == null ? null : !IsPathRooted(path) ? "" : "/";
|
||||||
{
|
|
||||||
byte[] buf = new byte[256];
|
|
||||||
do {
|
|
||||||
long r = Native.Syscall.readlinkat (dirfd, path, buf);
|
|
||||||
if (r < 0)
|
|
||||||
return null;
|
|
||||||
else if (r == buf.Length)
|
|
||||||
buf = new byte[checked (buf.LongLength * 2)];
|
|
||||||
else
|
|
||||||
return UnixEncoding.Instance.GetString (buf, 0, checked ((int) r));
|
|
||||||
} while (true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string ReadLink (string path)
|
public static String GetCompleteRealPath (String path)
|
||||||
{
|
{
|
||||||
string target = TryReadLink (path);
|
if (path == null) {
|
||||||
if (target == null)
|
throw new ArgumentNullException ("path");
|
||||||
UnixMarshal.ThrowExceptionForLastError ();
|
}
|
||||||
return target;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string ReadLinkAt (int dirfd, string path)
|
GetPathComponents(path, out String[] dirs, out Int32 lastIndex);
|
||||||
{
|
StringBuilder realPath = new StringBuilder ();
|
||||||
string target = TryReadLinkAt (dirfd, path);
|
if (dirs.Length > 0) {
|
||||||
if (target == null)
|
String dir = IsPathRooted (path) ? "/" : "";
|
||||||
UnixMarshal.ThrowExceptionForLastError ();
|
dir += dirs [0];
|
||||||
return target;
|
_ = realPath.Append(GetRealPath(dir));
|
||||||
}
|
}
|
||||||
|
for (Int32 i = 1; i < lastIndex; ++i) {
|
||||||
|
_ = realPath.Append("/").Append(dirs[i]);
|
||||||
|
String p = GetRealPath (realPath.ToString());
|
||||||
|
_ = realPath.Remove(0, realPath.Length);
|
||||||
|
_ = realPath.Append(p);
|
||||||
|
}
|
||||||
|
return realPath.ToString ();
|
||||||
|
}
|
||||||
|
|
||||||
public static bool IsPathRooted (string path)
|
public static String GetRealPath (String path)
|
||||||
{
|
{
|
||||||
if (path == null || path.Length == 0)
|
do {
|
||||||
return false;
|
String name = ReadSymbolicLink (path);
|
||||||
return path [0] == DirectorySeparatorChar;
|
if (name == null) {
|
||||||
}
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
internal static void CheckPath (string path)
|
if (IsPathRooted (name)) {
|
||||||
{
|
path = name;
|
||||||
if (path == null)
|
} else {
|
||||||
throw new ArgumentNullException ();
|
path = GetDirectoryName (path) + DirectorySeparatorChar + name;
|
||||||
if (path.Length == 0)
|
path = GetCanonicalPath (path);
|
||||||
throw new ArgumentException ("Path cannot contain a zero-length string", "path");
|
}
|
||||||
if (path.IndexOfAny (_InvalidPathChars) != -1)
|
} while (true);
|
||||||
throw new ArgumentException ("Invalid characters in path.", "path");
|
}
|
||||||
}
|
|
||||||
}
|
// Read the specified symbolic link. If the file isn't a symbolic link,
|
||||||
|
// return null; otherwise, return the contents of the symbolic link.
|
||||||
|
internal static String ReadSymbolicLink (String path)
|
||||||
|
{
|
||||||
|
String target = TryReadLink (path);
|
||||||
|
if (target == null) {
|
||||||
|
Native.Errno errno = Native.Stdlib.GetLastError ();
|
||||||
|
if (errno != Native.Errno.EINVAL) {
|
||||||
|
UnixMarshal.ThrowExceptionForError (errno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String TryReadLink (String path)
|
||||||
|
{
|
||||||
|
Byte[] buf = new Byte[256];
|
||||||
|
do {
|
||||||
|
Int64 r = Native.Syscall.readlink (path, buf);
|
||||||
|
if (r < 0) {
|
||||||
|
return null;
|
||||||
|
} else if (r == buf.Length) {
|
||||||
|
buf = new Byte[checked (buf.LongLength * 2)];
|
||||||
|
} else {
|
||||||
|
return UnixEncoding.Instance.GetString (buf, 0, checked ((Int32) r));
|
||||||
|
}
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String TryReadLinkAt (Int32 dirfd, String path)
|
||||||
|
{
|
||||||
|
Byte[] buf = new Byte[256];
|
||||||
|
do {
|
||||||
|
Int64 r = Native.Syscall.readlinkat (dirfd, path, buf);
|
||||||
|
if (r < 0) {
|
||||||
|
return null;
|
||||||
|
} else if (r == buf.Length) {
|
||||||
|
buf = new Byte[checked (buf.LongLength * 2)];
|
||||||
|
} else {
|
||||||
|
return UnixEncoding.Instance.GetString (buf, 0, checked ((Int32) r));
|
||||||
|
}
|
||||||
|
} while (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String ReadLink (String path)
|
||||||
|
{
|
||||||
|
String target = TryReadLink (path);
|
||||||
|
if (target == null) {
|
||||||
|
UnixMarshal.ThrowExceptionForLastError ();
|
||||||
|
}
|
||||||
|
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String ReadLinkAt (Int32 dirfd, String path)
|
||||||
|
{
|
||||||
|
String target = TryReadLinkAt (dirfd, path);
|
||||||
|
if (target == null) {
|
||||||
|
UnixMarshal.ThrowExceptionForLastError ();
|
||||||
|
}
|
||||||
|
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Boolean IsPathRooted(String path) => path == null || path.Length == 0 ? false : path[0] == DirectorySeparatorChar;
|
||||||
|
|
||||||
|
internal static void CheckPath (String path)
|
||||||
|
{
|
||||||
|
if (path == null) {
|
||||||
|
throw new ArgumentNullException ();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path.Length == 0) {
|
||||||
|
throw new ArgumentException ("Path cannot contain a zero-length string", "path");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path.IndexOfAny (_InvalidPathChars) != -1) {
|
||||||
|
throw new ArgumentException ("Invalid characters in path.", "path");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim: noexpandtab
|
// vim: noexpandtab
|
||||||
|
@ -33,56 +33,45 @@ using Mono.Unix;
|
|||||||
|
|
||||||
namespace Mono.Unix {
|
namespace Mono.Unix {
|
||||||
|
|
||||||
public struct UnixPipes
|
public struct UnixPipes
|
||||||
: IEquatable <UnixPipes>
|
: IEquatable <UnixPipes>
|
||||||
{
|
{
|
||||||
public UnixPipes (UnixStream reading, UnixStream writing)
|
public UnixPipes (UnixStream reading, UnixStream writing)
|
||||||
{
|
{
|
||||||
Reading = reading;
|
this.Reading = reading;
|
||||||
Writing = writing;
|
this.Writing = writing;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UnixStream Reading;
|
public UnixStream Reading;
|
||||||
public UnixStream Writing;
|
public UnixStream Writing;
|
||||||
|
|
||||||
public static UnixPipes CreatePipes ()
|
public static UnixPipes CreatePipes ()
|
||||||
{
|
{
|
||||||
int reading, writing;
|
Int32 r = Native.Syscall.pipe(out Int32 reading, out Int32 writing);
|
||||||
int r = Native.Syscall.pipe (out reading, out writing);
|
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
return new UnixPipes (new UnixStream (reading), new UnixStream (writing));
|
||||||
return new UnixPipes (new UnixStream (reading), new UnixStream (writing));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals (object value)
|
public override Boolean Equals (Object value)
|
||||||
{
|
{
|
||||||
if ((value == null) || (value.GetType () != GetType ()))
|
if (value == null || value.GetType () != this.GetType ()) {
|
||||||
return false;
|
return false;
|
||||||
UnixPipes other = (UnixPipes) value;
|
}
|
||||||
return Reading.Handle == other.Reading.Handle &&
|
|
||||||
Writing.Handle == other.Writing.Handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Equals (UnixPipes value)
|
UnixPipes other = (UnixPipes) value;
|
||||||
{
|
return this.Reading.Handle == other.Reading.Handle &&
|
||||||
return Reading.Handle == value.Reading.Handle &&
|
this.Writing.Handle == other.Writing.Handle;
|
||||||
Writing.Handle == value.Writing.Handle;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode ()
|
public Boolean Equals(UnixPipes value) => this.Reading.Handle == value.Reading.Handle &&
|
||||||
{
|
this.Writing.Handle == value.Writing.Handle;
|
||||||
return Reading.Handle.GetHashCode () ^ Writing.Handle.GetHashCode ();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator== (UnixPipes lhs, UnixPipes rhs)
|
public override Int32 GetHashCode() => this.Reading.Handle.GetHashCode() ^ this.Writing.Handle.GetHashCode();
|
||||||
{
|
|
||||||
return lhs.Equals (rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator!= (UnixPipes lhs, UnixPipes rhs)
|
public static Boolean operator ==(UnixPipes lhs, UnixPipes rhs) => lhs.Equals(rhs);
|
||||||
{
|
|
||||||
return !lhs.Equals (rhs);
|
public static Boolean operator !=(UnixPipes lhs, UnixPipes rhs) => !lhs.Equals(rhs);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim: noexpandtab
|
// vim: noexpandtab
|
||||||
|
@ -31,127 +31,117 @@ using Mono.Unix;
|
|||||||
|
|
||||||
namespace Mono.Unix {
|
namespace Mono.Unix {
|
||||||
|
|
||||||
public sealed class UnixProcess
|
public sealed class UnixProcess
|
||||||
{
|
{
|
||||||
private int pid;
|
private Int32 pid;
|
||||||
|
|
||||||
internal UnixProcess (int pid)
|
internal UnixProcess(Int32 pid) => this.pid = pid;
|
||||||
{
|
|
||||||
this.pid = pid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Id {
|
public Int32 Id => this.pid;
|
||||||
get {return pid;}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool HasExited {
|
public Boolean HasExited {
|
||||||
get {
|
get {
|
||||||
int status = GetProcessStatus ();
|
Int32 status = this.GetProcessStatus ();
|
||||||
return Native.Syscall.WIFEXITED (status);
|
return Native.Syscall.WIFEXITED (status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetProcessStatus ()
|
private Int32 GetProcessStatus ()
|
||||||
{
|
{
|
||||||
int status;
|
Int32 r = Native.Syscall.waitpid(this.pid, out Int32 status,
|
||||||
int r = Native.Syscall.waitpid (pid, out status,
|
Native.WaitOptions.WNOHANG | Native.WaitOptions.WUNTRACED);
|
||||||
Native.WaitOptions.WNOHANG | Native.WaitOptions.WUNTRACED);
|
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
return r;
|
||||||
return r;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public int ExitCode {
|
public Int32 ExitCode {
|
||||||
get {
|
get {
|
||||||
if (!HasExited)
|
if (!this.HasExited) {
|
||||||
throw new InvalidOperationException (
|
throw new InvalidOperationException (
|
||||||
Locale.GetText ("Process hasn't exited"));
|
Locale.GetText ("Process hasn't exited"));
|
||||||
int status = GetProcessStatus ();
|
}
|
||||||
return Native.Syscall.WEXITSTATUS (status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool HasSignaled {
|
Int32 status = this.GetProcessStatus ();
|
||||||
get {
|
return Native.Syscall.WEXITSTATUS (status);
|
||||||
int status = GetProcessStatus ();
|
}
|
||||||
return Native.Syscall.WIFSIGNALED (status);
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Native.Signum TerminationSignal {
|
public Boolean HasSignaled {
|
||||||
get {
|
get {
|
||||||
if (!HasSignaled)
|
Int32 status = this.GetProcessStatus ();
|
||||||
throw new InvalidOperationException (
|
return Native.Syscall.WIFSIGNALED (status);
|
||||||
Locale.GetText ("Process wasn't terminated by a signal"));
|
}
|
||||||
int status = GetProcessStatus ();
|
}
|
||||||
return Native.Syscall.WTERMSIG (status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool HasStopped {
|
public Native.Signum TerminationSignal {
|
||||||
get {
|
get {
|
||||||
int status = GetProcessStatus ();
|
if (!this.HasSignaled) {
|
||||||
return Native.Syscall.WIFSTOPPED (status);
|
throw new InvalidOperationException (
|
||||||
}
|
Locale.GetText ("Process wasn't terminated by a signal"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Native.Signum StopSignal {
|
Int32 status = this.GetProcessStatus ();
|
||||||
get {
|
return Native.Syscall.WTERMSIG (status);
|
||||||
if (!HasStopped)
|
}
|
||||||
throw new InvalidOperationException (
|
}
|
||||||
Locale.GetText ("Process isn't stopped"));
|
|
||||||
int status = GetProcessStatus ();
|
|
||||||
return Native.Syscall.WSTOPSIG (status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int ProcessGroupId {
|
public Boolean HasStopped {
|
||||||
get {return Native.Syscall.getpgid (pid);}
|
get {
|
||||||
set {
|
Int32 status = this.GetProcessStatus ();
|
||||||
int r = Native.Syscall.setpgid (pid, value);
|
return Native.Syscall.WIFSTOPPED (status);
|
||||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public int SessionId {
|
public Native.Signum StopSignal {
|
||||||
get {
|
get {
|
||||||
int r = Native.Syscall.getsid (pid);
|
if (!this.HasStopped) {
|
||||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
throw new InvalidOperationException (
|
||||||
return r;
|
Locale.GetText ("Process isn't stopped"));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public static UnixProcess GetCurrentProcess ()
|
Int32 status = this.GetProcessStatus ();
|
||||||
{
|
return Native.Syscall.WSTOPSIG (status);
|
||||||
return new UnixProcess (GetCurrentProcessId ());
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int GetCurrentProcessId ()
|
public Int32 ProcessGroupId {
|
||||||
{
|
get => Native.Syscall.getpgid(this.pid);
|
||||||
return Native.Syscall.getpid ();
|
set {
|
||||||
}
|
Int32 r = Native.Syscall.setpgid(this.pid, value);
|
||||||
|
UnixMarshal.ThrowExceptionForLastErrorIf(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Kill ()
|
public Int32 SessionId {
|
||||||
{
|
get {
|
||||||
Signal (Native.Signum.SIGKILL);
|
Int32 r = Native.Syscall.getsid (this.pid);
|
||||||
}
|
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[CLSCompliant (false)]
|
public static UnixProcess GetCurrentProcess() => new UnixProcess(GetCurrentProcessId());
|
||||||
public void Signal (Native.Signum signal)
|
|
||||||
{
|
|
||||||
int r = Native.Syscall.kill (pid, signal);
|
|
||||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void WaitForExit ()
|
public static Int32 GetCurrentProcessId() => Native.Syscall.getpid();
|
||||||
{
|
|
||||||
int status;
|
public void Kill() => this.Signal(Native.Signum.SIGKILL);
|
||||||
int r;
|
|
||||||
do {
|
//[CLSCompliant (false)]
|
||||||
r = Native.Syscall.waitpid (pid, out status, (Native.WaitOptions) 0);
|
public void Signal (Native.Signum signal)
|
||||||
} while (UnixMarshal.ShouldRetrySyscall (r));
|
{
|
||||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
Int32 r = Native.Syscall.kill (this.pid, signal);
|
||||||
}
|
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WaitForExit ()
|
||||||
|
{
|
||||||
|
Int32 r;
|
||||||
|
do {
|
||||||
|
r = Native.Syscall.waitpid (this.pid, out Int32 status, (Native.WaitOptions) 0);
|
||||||
|
} while (UnixMarshal.ShouldRetrySyscall (r));
|
||||||
|
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim: noexpandtab
|
// vim: noexpandtab
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
@ -35,193 +36,195 @@ using Mono.Unix.Native;
|
|||||||
|
|
||||||
namespace Mono.Unix {
|
namespace Mono.Unix {
|
||||||
|
|
||||||
public class UnixSignal : WaitHandle {
|
public class UnixSignal : WaitHandle {
|
||||||
private int signum;
|
private readonly Int32 signum;
|
||||||
private IntPtr signal_info;
|
private IntPtr signal_info;
|
||||||
|
|
||||||
static UnixSignal ()
|
static UnixSignal() => Stdlib.VersionCheck();
|
||||||
{
|
|
||||||
Stdlib.VersionCheck ();
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnixSignal (Signum signum)
|
public UnixSignal (Signum signum)
|
||||||
{
|
{
|
||||||
this.signum = NativeConvert.FromSignum (signum);
|
this.signum = NativeConvert.FromSignum (signum);
|
||||||
this.signal_info = install (this.signum);
|
this.signal_info = install (this.signum);
|
||||||
if (this.signal_info == IntPtr.Zero) {
|
if (this.signal_info == IntPtr.Zero) {
|
||||||
throw new ArgumentException ("Unable to handle signal", "signum");
|
throw new ArgumentException ("Unable to handle signal", "signum");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public UnixSignal (Mono.Unix.Native.RealTimeSignum rtsig)
|
public UnixSignal (RealTimeSignum rtsig)
|
||||||
{
|
{
|
||||||
signum = NativeConvert.FromRealTimeSignum (rtsig);
|
this.signum = NativeConvert.FromRealTimeSignum (rtsig);
|
||||||
this.signal_info = install (this.signum);
|
this.signal_info = install (this.signum);
|
||||||
Native.Errno err = Native.Stdlib.GetLastError ();
|
Native.Errno err = Native.Stdlib.GetLastError ();
|
||||||
if (this.signal_info == IntPtr.Zero) {
|
if (this.signal_info == IntPtr.Zero) {
|
||||||
if (err == Native.Errno.EADDRINUSE)
|
if (err == Native.Errno.EADDRINUSE) {
|
||||||
throw new ArgumentException ("Signal registered outside of Mono.Posix", "signum");
|
throw new ArgumentException ("Signal registered outside of Mono.Posix", "signum");
|
||||||
throw new ArgumentException ("Unable to handle signal", "signum");
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Signum Signum {
|
throw new ArgumentException ("Unable to handle signal", "signum");
|
||||||
get {
|
}
|
||||||
if (IsRealTimeSignal)
|
}
|
||||||
throw new InvalidOperationException ("This signal is a RealTimeSignum");
|
|
||||||
return NativeConvert.ToSignum (signum);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public RealTimeSignum RealTimeSignum {
|
public Signum Signum {
|
||||||
get {
|
get {
|
||||||
if (!IsRealTimeSignal)
|
if (this.IsRealTimeSignal) {
|
||||||
throw new InvalidOperationException ("This signal is not a RealTimeSignum");
|
throw new InvalidOperationException ("This signal is a RealTimeSignum");
|
||||||
return NativeConvert.ToRealTimeSignum (signum-GetSIGRTMIN ());
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsRealTimeSignal {
|
return NativeConvert.ToSignum (this.signum);
|
||||||
get {
|
}
|
||||||
AssertValid ();
|
}
|
||||||
int sigrtmin = GetSIGRTMIN ();
|
|
||||||
if (sigrtmin == -1)
|
|
||||||
return false;
|
|
||||||
return signum >= sigrtmin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl,
|
public RealTimeSignum RealTimeSignum {
|
||||||
EntryPoint="Mono_Unix_UnixSignal_install", SetLastError=true)]
|
get {
|
||||||
private static extern IntPtr install (int signum);
|
if (!this.IsRealTimeSignal) {
|
||||||
|
throw new InvalidOperationException ("This signal is not a RealTimeSignum");
|
||||||
|
}
|
||||||
|
|
||||||
[DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl,
|
return NativeConvert.ToRealTimeSignum (this.signum -GetSIGRTMIN ());
|
||||||
EntryPoint="Mono_Unix_UnixSignal_uninstall")]
|
}
|
||||||
private static extern int uninstall (IntPtr info);
|
}
|
||||||
|
|
||||||
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
|
public Boolean IsRealTimeSignal {
|
||||||
delegate int Mono_Posix_RuntimeIsShuttingDown ();
|
get {
|
||||||
static Mono_Posix_RuntimeIsShuttingDown ShuttingDown = RuntimeShuttingDownCallback;
|
this.AssertValid ();
|
||||||
|
Int32 sigrtmin = GetSIGRTMIN ();
|
||||||
|
return sigrtmin == -1 ? false : this.signum >= sigrtmin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int RuntimeShuttingDownCallback ()
|
[DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl,
|
||||||
{
|
EntryPoint="Mono_Unix_UnixSignal_install", SetLastError=true)]
|
||||||
return Environment.HasShutdownStarted ? 1 : 0;
|
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||||
}
|
private static extern IntPtr install (Int32 signum);
|
||||||
|
|
||||||
[DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl,
|
[DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl,
|
||||||
EntryPoint="Mono_Unix_UnixSignal_WaitAny")]
|
EntryPoint="Mono_Unix_UnixSignal_uninstall")]
|
||||||
private static extern int WaitAny (IntPtr[] infos, int count, int timeout, Mono_Posix_RuntimeIsShuttingDown shutting_down);
|
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||||
|
private static extern Int32 uninstall (IntPtr info);
|
||||||
|
|
||||||
[DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl,
|
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
|
||||||
|
delegate Int32 Mono_Posix_RuntimeIsShuttingDown ();
|
||||||
|
static Mono_Posix_RuntimeIsShuttingDown ShuttingDown = RuntimeShuttingDownCallback;
|
||||||
|
|
||||||
|
static Int32 RuntimeShuttingDownCallback() => Environment.HasShutdownStarted ? 1 : 0;
|
||||||
|
|
||||||
|
[DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl,
|
||||||
|
EntryPoint="Mono_Unix_UnixSignal_WaitAny")]
|
||||||
|
private static extern Int32 WaitAny (IntPtr[] infos, Int32 count, Int32 timeout, Mono_Posix_RuntimeIsShuttingDown shutting_down);
|
||||||
|
|
||||||
|
[DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl,
|
||||||
EntryPoint="Mono_Posix_SIGRTMIN")]
|
EntryPoint="Mono_Posix_SIGRTMIN")]
|
||||||
internal static extern int GetSIGRTMIN ();
|
internal static extern Int32 GetSIGRTMIN ();
|
||||||
|
|
||||||
[DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl,
|
[DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl,
|
||||||
EntryPoint="Mono_Posix_SIGRTMAX")]
|
EntryPoint="Mono_Posix_SIGRTMAX")]
|
||||||
internal static extern int GetSIGRTMAX ();
|
internal static extern Int32 GetSIGRTMAX ();
|
||||||
|
|
||||||
private void AssertValid ()
|
private void AssertValid ()
|
||||||
{
|
{
|
||||||
if (signal_info == IntPtr.Zero)
|
if (this.signal_info == IntPtr.Zero) {
|
||||||
throw new ObjectDisposedException (GetType().FullName);
|
throw new ObjectDisposedException (this.GetType().FullName);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private unsafe SignalInfo* Info {
|
private unsafe SignalInfo* Info {
|
||||||
get {
|
get {
|
||||||
AssertValid ();
|
this.AssertValid ();
|
||||||
return (SignalInfo*) signal_info;
|
return (SignalInfo*)this.signal_info;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsSet {
|
public Boolean IsSet => this.Count > 0;
|
||||||
get {
|
|
||||||
return Count > 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public unsafe bool Reset ()
|
public unsafe Boolean Reset ()
|
||||||
{
|
{
|
||||||
int n = Interlocked.Exchange (ref Info->count, 0);
|
Int32 n = Interlocked.Exchange (ref this.Info->count, 0);
|
||||||
return n != 0;
|
return n != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe int Count {
|
public unsafe Int32 Count {
|
||||||
get {return Info->count;}
|
get => this.Info->count;
|
||||||
set {Interlocked.Exchange (ref Info->count, value);}
|
set => Interlocked.Exchange(ref this.Info->count, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// signum, count, write_fd, pipecnt, and pipelock are read from a signal handler thread
|
// signum, count, write_fd, pipecnt, and pipelock are read from a signal handler thread
|
||||||
// count and pipelock are both read and written from the signal handler thread
|
// count and pipelock are both read and written from the signal handler thread
|
||||||
#pragma warning disable 649
|
#pragma warning disable 649
|
||||||
[Map]
|
[Map]
|
||||||
struct SignalInfo {
|
struct SignalInfo {
|
||||||
public int signum, count, read_fd, write_fd, pipecnt, pipelock, have_handler;
|
public Int32 signum, count, read_fd, write_fd, pipecnt, pipelock, have_handler;
|
||||||
public IntPtr handler; // Backed-up handler to restore when signal unregistered
|
public IntPtr handler; // Backed-up handler to restore when signal unregistered
|
||||||
}
|
}
|
||||||
#pragma warning restore 649
|
#pragma warning restore 649
|
||||||
|
|
||||||
#region WaitHandle overrides
|
#region WaitHandle overrides
|
||||||
protected unsafe override void Dispose (bool disposing)
|
protected unsafe override void Dispose (Boolean disposing)
|
||||||
{
|
{
|
||||||
base.Dispose (disposing);
|
base.Dispose (disposing);
|
||||||
if (signal_info == IntPtr.Zero)
|
if (this.signal_info == IntPtr.Zero) {
|
||||||
return;
|
return;
|
||||||
uninstall (signal_info);
|
}
|
||||||
signal_info = IntPtr.Zero;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool WaitOne ()
|
_ = uninstall(this.signal_info);
|
||||||
{
|
this.signal_info = IntPtr.Zero;
|
||||||
return WaitOne (-1, false);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public override bool WaitOne (TimeSpan timeout, bool exitContext)
|
public override Boolean WaitOne() => this.WaitOne(-1, false);
|
||||||
{
|
|
||||||
long ms = (long) timeout.TotalMilliseconds;
|
|
||||||
if (ms < -1 || ms > Int32.MaxValue)
|
|
||||||
throw new ArgumentOutOfRangeException ("timeout");
|
|
||||||
return WaitOne ((int) ms, exitContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool WaitOne (int millisecondsTimeout, bool exitContext)
|
public override Boolean WaitOne (TimeSpan timeout, Boolean exitContext)
|
||||||
{
|
{
|
||||||
AssertValid ();
|
Int64 ms = (Int64) timeout.TotalMilliseconds;
|
||||||
if (exitContext)
|
if (ms < -1 || ms > Int32.MaxValue) {
|
||||||
throw new InvalidOperationException ("exitContext is not supported");
|
throw new ArgumentOutOfRangeException ("timeout");
|
||||||
if (millisecondsTimeout == 0)
|
}
|
||||||
return IsSet;
|
|
||||||
return WaitAny (new UnixSignal[]{this}, millisecondsTimeout) == 0;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
public static int WaitAny (UnixSignal[] signals)
|
return this.WaitOne ((Int32) ms, exitContext);
|
||||||
{
|
}
|
||||||
return WaitAny (signals, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int WaitAny (UnixSignal[] signals, TimeSpan timeout)
|
public override Boolean WaitOne (Int32 millisecondsTimeout, Boolean exitContext)
|
||||||
{
|
{
|
||||||
long ms = (long) timeout.TotalMilliseconds;
|
this.AssertValid ();
|
||||||
if (ms < -1 || ms > Int32.MaxValue)
|
if (exitContext) {
|
||||||
throw new ArgumentOutOfRangeException ("timeout");
|
throw new InvalidOperationException ("exitContext is not supported");
|
||||||
return WaitAny (signals, (int) ms);
|
}
|
||||||
}
|
|
||||||
|
return millisecondsTimeout == 0 ? this.IsSet : WaitAny (new UnixSignal[]{this}, millisecondsTimeout) == 0;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public static Int32 WaitAny(UnixSignal[] signals) => WaitAny(signals, -1);
|
||||||
|
|
||||||
|
public static Int32 WaitAny (UnixSignal[] signals, TimeSpan timeout)
|
||||||
|
{
|
||||||
|
Int64 ms = (Int64) timeout.TotalMilliseconds;
|
||||||
|
if (ms < -1 || ms > Int32.MaxValue) {
|
||||||
|
throw new ArgumentOutOfRangeException ("timeout");
|
||||||
|
}
|
||||||
|
|
||||||
|
return WaitAny (signals, (Int32) ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static unsafe int WaitAny (UnixSignal[] signals, int millisecondsTimeout)
|
public static unsafe Int32 WaitAny (UnixSignal[] signals, Int32 millisecondsTimeout)
|
||||||
{
|
{
|
||||||
if (signals == null)
|
if (signals == null) {
|
||||||
throw new ArgumentNullException ("signals");
|
throw new ArgumentNullException ("signals");
|
||||||
if (millisecondsTimeout < -1)
|
}
|
||||||
throw new ArgumentOutOfRangeException ("millisecondsTimeout");
|
|
||||||
IntPtr[] infos = new IntPtr [signals.Length];
|
if (millisecondsTimeout < -1) {
|
||||||
for (int i = 0; i < signals.Length; ++i) {
|
throw new ArgumentOutOfRangeException ("millisecondsTimeout");
|
||||||
infos [i] = signals [i].signal_info;
|
}
|
||||||
if (infos [i] == IntPtr.Zero)
|
|
||||||
throw new InvalidOperationException ("Disposed UnixSignal");
|
IntPtr[] infos = new IntPtr [signals.Length];
|
||||||
}
|
for (Int32 i = 0; i < signals.Length; ++i) {
|
||||||
return WaitAny (infos, infos.Length, millisecondsTimeout, ShuttingDown);
|
infos [i] = signals [i].signal_info;
|
||||||
}
|
if (infos [i] == IntPtr.Zero) {
|
||||||
}
|
throw new InvalidOperationException ("Disposed UnixSignal");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return WaitAny (infos, infos.Length, millisecondsTimeout, ShuttingDown);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,400 +36,427 @@ using Mono.Unix;
|
|||||||
|
|
||||||
namespace Mono.Unix {
|
namespace Mono.Unix {
|
||||||
|
|
||||||
public sealed class UnixStream : Stream, IDisposable
|
public sealed class UnixStream : Stream, IDisposable {
|
||||||
{
|
public const Int32 InvalidFileDescriptor = -1;
|
||||||
public const int InvalidFileDescriptor = -1;
|
public const Int32 StandardInputFileDescriptor = 0;
|
||||||
public const int StandardInputFileDescriptor = 0;
|
public const Int32 StandardOutputFileDescriptor = 1;
|
||||||
public const int StandardOutputFileDescriptor = 1;
|
public const Int32 StandardErrorFileDescriptor = 2;
|
||||||
public const int StandardErrorFileDescriptor = 2;
|
|
||||||
|
|
||||||
public UnixStream (int fileDescriptor)
|
public UnixStream(Int32 fileDescriptor)
|
||||||
: this (fileDescriptor, true) {}
|
: this(fileDescriptor, true) { }
|
||||||
|
|
||||||
public UnixStream (int fileDescriptor, bool ownsHandle)
|
public UnixStream(Int32 fileDescriptor, Boolean ownsHandle) {
|
||||||
{
|
if(InvalidFileDescriptor == fileDescriptor) {
|
||||||
if (InvalidFileDescriptor == fileDescriptor)
|
throw new ArgumentException(Locale.GetText("Invalid file descriptor"), "fileDescriptor");
|
||||||
throw new ArgumentException (Locale.GetText ("Invalid file descriptor"), "fileDescriptor");
|
}
|
||||||
|
|
||||||
this.fileDescriptor = fileDescriptor;
|
this.fileDescriptor = fileDescriptor;
|
||||||
this.owner = ownsHandle;
|
this.owner = ownsHandle;
|
||||||
|
|
||||||
long offset = Native.Syscall.lseek (fileDescriptor, 0, Native.SeekFlags.SEEK_CUR);
|
Int64 offset = Native.Syscall.lseek(fileDescriptor, 0, Native.SeekFlags.SEEK_CUR);
|
||||||
if (offset != -1)
|
if(offset != -1) {
|
||||||
canSeek = true;
|
this.canSeek = true;
|
||||||
long read = Native.Syscall.read (fileDescriptor, IntPtr.Zero, 0);
|
}
|
||||||
if (read != -1)
|
|
||||||
canRead = true;
|
|
||||||
long write = Native.Syscall.write (fileDescriptor, IntPtr.Zero, 0);
|
|
||||||
if (write != -1)
|
|
||||||
canWrite = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AssertNotDisposed ()
|
Int64 read = Native.Syscall.read(fileDescriptor, IntPtr.Zero, 0);
|
||||||
{
|
if(read != -1) {
|
||||||
if (fileDescriptor == InvalidFileDescriptor)
|
this.canRead = true;
|
||||||
throw new ObjectDisposedException ("Invalid File Descriptor");
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public int Handle {
|
Int64 write = Native.Syscall.write(fileDescriptor, IntPtr.Zero, 0);
|
||||||
get {return fileDescriptor;}
|
if(write != -1) {
|
||||||
}
|
this.canWrite = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override bool CanRead {
|
private void AssertNotDisposed() {
|
||||||
get {return canRead;}
|
if(this.fileDescriptor == InvalidFileDescriptor) {
|
||||||
}
|
throw new ObjectDisposedException("Invalid File Descriptor");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override bool CanSeek {
|
public Int32 Handle => this.fileDescriptor;
|
||||||
get {return canSeek;}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool CanWrite {
|
public override Boolean CanRead => this.canRead;
|
||||||
get {return canWrite;}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override long Length {
|
public override Boolean CanSeek => this.canSeek;
|
||||||
get {
|
|
||||||
AssertNotDisposed ();
|
|
||||||
if (!CanSeek)
|
|
||||||
throw new NotSupportedException ("File descriptor doesn't support seeking");
|
|
||||||
RefreshStat ();
|
|
||||||
return stat.st_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override long Position {
|
public override Boolean CanWrite => this.canWrite;
|
||||||
get {
|
|
||||||
AssertNotDisposed ();
|
|
||||||
if (!CanSeek)
|
|
||||||
throw new NotSupportedException ("The stream does not support seeking");
|
|
||||||
long pos = Native.Syscall.lseek (fileDescriptor, 0, Native.SeekFlags.SEEK_CUR);
|
|
||||||
if (pos == -1)
|
|
||||||
UnixMarshal.ThrowExceptionForLastError ();
|
|
||||||
return (long) pos;
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
Seek (value, SeekOrigin.Begin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[CLSCompliant (false)]
|
public override Int64 Length {
|
||||||
public Native.FilePermissions Protection {
|
get {
|
||||||
get {
|
this.AssertNotDisposed();
|
||||||
RefreshStat ();
|
if(!this.CanSeek) {
|
||||||
return stat.st_mode;
|
throw new NotSupportedException("File descriptor doesn't support seeking");
|
||||||
}
|
}
|
||||||
set {
|
|
||||||
// we can't change file type with fchmod, so clear out that portion
|
|
||||||
value &= ~Native.FilePermissions.S_IFMT;
|
|
||||||
int r = Native.Syscall.fchmod (fileDescriptor, value);
|
|
||||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public FileTypes FileType {
|
this.RefreshStat();
|
||||||
get {
|
return this.stat.st_size;
|
||||||
int type = (int) Protection;
|
}
|
||||||
return (FileTypes) (type & (int) UnixFileSystemInfo.AllFileTypes);
|
}
|
||||||
}
|
|
||||||
// no set as fchmod(2) won't accept changing the file type.
|
|
||||||
}
|
|
||||||
|
|
||||||
public FileAccessPermissions FileAccessPermissions {
|
public override Int64 Position {
|
||||||
get {
|
get {
|
||||||
int perms = (int) Protection;
|
this.AssertNotDisposed();
|
||||||
return (FileAccessPermissions) (perms & (int) FileAccessPermissions.AllPermissions);
|
if(!this.CanSeek) {
|
||||||
}
|
throw new NotSupportedException("The stream does not support seeking");
|
||||||
set {
|
}
|
||||||
int perms = (int) Protection;
|
|
||||||
perms &= (int) ~FileAccessPermissions.AllPermissions;
|
|
||||||
perms |= (int) value;
|
|
||||||
Protection = (Native.FilePermissions) perms;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public FileSpecialAttributes FileSpecialAttributes {
|
Int64 pos = Native.Syscall.lseek(this.fileDescriptor, 0, Native.SeekFlags.SEEK_CUR);
|
||||||
get {
|
if(pos == -1) {
|
||||||
int attrs = (int) Protection;
|
UnixMarshal.ThrowExceptionForLastError();
|
||||||
return (FileSpecialAttributes) (attrs & (int) UnixFileSystemInfo.AllSpecialAttributes);
|
}
|
||||||
}
|
|
||||||
set {
|
|
||||||
int perms = (int) Protection;
|
|
||||||
perms &= (int) ~UnixFileSystemInfo.AllSpecialAttributes;
|
|
||||||
perms |= (int) value;
|
|
||||||
Protection = (Native.FilePermissions) perms;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnixUserInfo OwnerUser {
|
return (Int64)pos;
|
||||||
get {RefreshStat (); return new UnixUserInfo (stat.st_uid);}
|
}
|
||||||
}
|
set => _ = this.Seek(value, SeekOrigin.Begin);
|
||||||
|
}
|
||||||
|
|
||||||
public long OwnerUserId {
|
//[CLSCompliant(false)]
|
||||||
get {RefreshStat (); return stat.st_uid;}
|
public Native.FilePermissions Protection {
|
||||||
}
|
get {
|
||||||
|
this.RefreshStat();
|
||||||
|
return this.stat.st_mode;
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
// we can't change file type with fchmod, so clear out that portion
|
||||||
|
value &= ~Native.FilePermissions.S_IFMT;
|
||||||
|
Int32 r = Native.Syscall.fchmod(this.fileDescriptor, value);
|
||||||
|
UnixMarshal.ThrowExceptionForLastErrorIf(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public UnixGroupInfo OwnerGroup {
|
public FileTypes FileType {
|
||||||
get {RefreshStat (); return new UnixGroupInfo (stat.st_gid);}
|
get {
|
||||||
}
|
Int32 type = (Int32)this.Protection;
|
||||||
|
return (FileTypes)(type & (Int32)UnixFileSystemInfo.AllFileTypes);
|
||||||
|
}
|
||||||
|
// no set as fchmod(2) won't accept changing the file type.
|
||||||
|
}
|
||||||
|
|
||||||
public long OwnerGroupId {
|
public FileAccessPermissions FileAccessPermissions {
|
||||||
get {RefreshStat (); return stat.st_gid;}
|
get {
|
||||||
}
|
Int32 perms = (Int32)this.Protection;
|
||||||
|
return (FileAccessPermissions)(perms & (Int32)FileAccessPermissions.AllPermissions);
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
Int32 perms = (Int32)this.Protection;
|
||||||
|
perms &= (Int32)~FileAccessPermissions.AllPermissions;
|
||||||
|
perms |= (Int32)value;
|
||||||
|
this.Protection = (Native.FilePermissions)perms;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void RefreshStat ()
|
public FileSpecialAttributes FileSpecialAttributes {
|
||||||
{
|
get {
|
||||||
AssertNotDisposed ();
|
Int32 attrs = (Int32)this.Protection;
|
||||||
int r = Native.Syscall.fstat (fileDescriptor, out stat);
|
return (FileSpecialAttributes)(attrs & (Int32)UnixFileSystemInfo.AllSpecialAttributes);
|
||||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
}
|
||||||
}
|
set {
|
||||||
|
Int32 perms = (Int32)this.Protection;
|
||||||
|
perms &= (Int32)~UnixFileSystemInfo.AllSpecialAttributes;
|
||||||
|
perms |= (Int32)value;
|
||||||
|
this.Protection = (Native.FilePermissions)perms;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void AdviseFileAccessPattern (FileAccessPattern pattern, long offset, long len)
|
public UnixUserInfo OwnerUser {
|
||||||
{
|
get {
|
||||||
FileHandleOperations.AdviseFileAccessPattern (fileDescriptor, pattern, offset, len);
|
this.RefreshStat();
|
||||||
}
|
return new UnixUserInfo(this.stat.st_uid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void AdviseFileAccessPattern (FileAccessPattern pattern)
|
public Int64 OwnerUserId {
|
||||||
{
|
get {
|
||||||
AdviseFileAccessPattern (pattern, 0, 0);
|
this.RefreshStat();
|
||||||
}
|
return this.stat.st_uid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override void Flush ()
|
public UnixGroupInfo OwnerGroup {
|
||||||
{
|
get {
|
||||||
}
|
this.RefreshStat();
|
||||||
|
return new UnixGroupInfo(this.stat.st_gid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override unsafe int Read ([In, Out] byte[] buffer, int offset, int count)
|
public Int64 OwnerGroupId {
|
||||||
{
|
get {
|
||||||
AssertNotDisposed ();
|
this.RefreshStat();
|
||||||
AssertValidBuffer (buffer, offset, count);
|
return this.stat.st_gid;
|
||||||
if (!CanRead)
|
}
|
||||||
throw new NotSupportedException ("Stream does not support reading");
|
}
|
||||||
|
|
||||||
if (buffer.Length == 0)
|
private void RefreshStat() {
|
||||||
return 0;
|
this.AssertNotDisposed();
|
||||||
|
Int32 r = Native.Syscall.fstat(this.fileDescriptor, out this.stat);
|
||||||
|
UnixMarshal.ThrowExceptionForLastErrorIf(r);
|
||||||
|
}
|
||||||
|
|
||||||
long r = 0;
|
public void AdviseFileAccessPattern(FileAccessPattern pattern, Int64 offset, Int64 len) => FileHandleOperations.AdviseFileAccessPattern(this.fileDescriptor, pattern, offset, len);
|
||||||
fixed (byte* buf = &buffer[offset]) {
|
|
||||||
do {
|
|
||||||
r = Native.Syscall.read (fileDescriptor, buf, (ulong) count);
|
|
||||||
} while (UnixMarshal.ShouldRetrySyscall ((int) r));
|
|
||||||
}
|
|
||||||
if (r == -1)
|
|
||||||
UnixMarshal.ThrowExceptionForLastError ();
|
|
||||||
return (int) r;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AssertValidBuffer (byte[] buffer, int offset, int count)
|
public void AdviseFileAccessPattern(FileAccessPattern pattern) => this.AdviseFileAccessPattern(pattern, 0, 0);
|
||||||
{
|
|
||||||
if (buffer == null)
|
|
||||||
throw new ArgumentNullException ("buffer");
|
|
||||||
if (offset < 0)
|
|
||||||
throw new ArgumentOutOfRangeException ("offset", "< 0");
|
|
||||||
if (count < 0)
|
|
||||||
throw new ArgumentOutOfRangeException ("count", "< 0");
|
|
||||||
if (offset > buffer.Length)
|
|
||||||
throw new ArgumentException ("destination offset is beyond array size");
|
|
||||||
if (offset > (buffer.Length - count))
|
|
||||||
throw new ArgumentException ("would overrun buffer");
|
|
||||||
}
|
|
||||||
|
|
||||||
public unsafe int ReadAtOffset ([In, Out] byte[] buffer,
|
public override void Flush() {
|
||||||
int offset, int count, long fileOffset)
|
}
|
||||||
{
|
|
||||||
AssertNotDisposed ();
|
|
||||||
AssertValidBuffer (buffer, offset, count);
|
|
||||||
if (!CanRead)
|
|
||||||
throw new NotSupportedException ("Stream does not support reading");
|
|
||||||
|
|
||||||
if (buffer.Length == 0)
|
public override unsafe Int32 Read([In, Out] Byte[] buffer, Int32 offset, Int32 count) {
|
||||||
return 0;
|
this.AssertNotDisposed();
|
||||||
|
this.AssertValidBuffer(buffer, offset, count);
|
||||||
|
if(!this.CanRead) {
|
||||||
|
throw new NotSupportedException("Stream does not support reading");
|
||||||
|
}
|
||||||
|
|
||||||
long r = 0;
|
if(buffer.Length == 0) {
|
||||||
fixed (byte* buf = &buffer[offset]) {
|
return 0;
|
||||||
do {
|
}
|
||||||
r = Native.Syscall.pread (fileDescriptor, buf, (ulong) count, fileOffset);
|
|
||||||
} while (UnixMarshal.ShouldRetrySyscall ((int) r));
|
|
||||||
}
|
|
||||||
if (r == -1)
|
|
||||||
UnixMarshal.ThrowExceptionForLastError ();
|
|
||||||
return (int) r;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override long Seek (long offset, SeekOrigin origin)
|
Int64 r = 0;
|
||||||
{
|
fixed(Byte* buf = &buffer[offset]) {
|
||||||
AssertNotDisposed ();
|
do {
|
||||||
if (!CanSeek)
|
r = Native.Syscall.read(this.fileDescriptor, buf, (UInt64)count);
|
||||||
throw new NotSupportedException ("The File Descriptor does not support seeking");
|
} while(UnixMarshal.ShouldRetrySyscall((Int32)r));
|
||||||
|
}
|
||||||
|
if(r == -1) {
|
||||||
|
UnixMarshal.ThrowExceptionForLastError();
|
||||||
|
}
|
||||||
|
|
||||||
Native.SeekFlags sf = Native.SeekFlags.SEEK_CUR;
|
return (Int32)r;
|
||||||
switch (origin) {
|
}
|
||||||
case SeekOrigin.Begin: sf = Native.SeekFlags.SEEK_SET; break;
|
|
||||||
case SeekOrigin.Current: sf = Native.SeekFlags.SEEK_CUR; break;
|
|
||||||
case SeekOrigin.End: sf = Native.SeekFlags.SEEK_END; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
long pos = Native.Syscall.lseek (fileDescriptor, offset, sf);
|
private void AssertValidBuffer(Byte[] buffer, Int32 offset, Int32 count) {
|
||||||
if (pos == -1)
|
if(buffer == null) {
|
||||||
UnixMarshal.ThrowExceptionForLastError ();
|
throw new ArgumentNullException("buffer");
|
||||||
return (long) pos;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public override void SetLength (long value)
|
if(offset < 0) {
|
||||||
{
|
throw new ArgumentOutOfRangeException("offset", "< 0");
|
||||||
AssertNotDisposed ();
|
}
|
||||||
if (value < 0)
|
|
||||||
throw new ArgumentOutOfRangeException ("value", "< 0");
|
|
||||||
if (!CanSeek && !CanWrite)
|
|
||||||
throw new NotSupportedException ("You can't truncating the current file descriptor");
|
|
||||||
|
|
||||||
int r;
|
if(count < 0) {
|
||||||
do {
|
throw new ArgumentOutOfRangeException("count", "< 0");
|
||||||
r = Native.Syscall.ftruncate (fileDescriptor, value);
|
}
|
||||||
} while (UnixMarshal.ShouldRetrySyscall (r));
|
|
||||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override unsafe void Write (byte[] buffer, int offset, int count)
|
if(offset > buffer.Length) {
|
||||||
{
|
throw new ArgumentException("destination offset is beyond array size");
|
||||||
AssertNotDisposed ();
|
}
|
||||||
AssertValidBuffer (buffer, offset, count);
|
|
||||||
if (!CanWrite)
|
|
||||||
throw new NotSupportedException ("File Descriptor does not support writing");
|
|
||||||
|
|
||||||
if (buffer.Length == 0)
|
if(offset > buffer.Length - count) {
|
||||||
return;
|
throw new ArgumentException("would overrun buffer");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
long r = 0;
|
public unsafe Int32 ReadAtOffset([In, Out] Byte[] buffer,
|
||||||
fixed (byte* buf = &buffer[offset]) {
|
Int32 offset, Int32 count, Int64 fileOffset) {
|
||||||
do {
|
this.AssertNotDisposed();
|
||||||
r = Native.Syscall.write (fileDescriptor, buf, (ulong) count);
|
this.AssertValidBuffer(buffer, offset, count);
|
||||||
} while (UnixMarshal.ShouldRetrySyscall ((int) r));
|
if(!this.CanRead) {
|
||||||
}
|
throw new NotSupportedException("Stream does not support reading");
|
||||||
if (r == -1)
|
}
|
||||||
UnixMarshal.ThrowExceptionForLastError ();
|
|
||||||
}
|
|
||||||
|
|
||||||
public unsafe void WriteAtOffset (byte[] buffer,
|
if(buffer.Length == 0) {
|
||||||
int offset, int count, long fileOffset)
|
return 0;
|
||||||
{
|
}
|
||||||
AssertNotDisposed ();
|
|
||||||
AssertValidBuffer (buffer, offset, count);
|
|
||||||
if (!CanWrite)
|
|
||||||
throw new NotSupportedException ("File Descriptor does not support writing");
|
|
||||||
|
|
||||||
if (buffer.Length == 0)
|
Int64 r = 0;
|
||||||
return;
|
fixed(Byte* buf = &buffer[offset]) {
|
||||||
|
do {
|
||||||
|
r = Native.Syscall.pread(this.fileDescriptor, buf, (UInt64)count, fileOffset);
|
||||||
|
} while(UnixMarshal.ShouldRetrySyscall((Int32)r));
|
||||||
|
}
|
||||||
|
if(r == -1) {
|
||||||
|
UnixMarshal.ThrowExceptionForLastError();
|
||||||
|
}
|
||||||
|
|
||||||
long r = 0;
|
return (Int32)r;
|
||||||
fixed (byte* buf = &buffer[offset]) {
|
}
|
||||||
do {
|
|
||||||
r = Native.Syscall.pwrite (fileDescriptor, buf, (ulong) count, fileOffset);
|
|
||||||
} while (UnixMarshal.ShouldRetrySyscall ((int) r));
|
|
||||||
}
|
|
||||||
if (r == -1)
|
|
||||||
UnixMarshal.ThrowExceptionForLastError ();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SendTo (UnixStream output)
|
public override Int64 Seek(Int64 offset, SeekOrigin origin) {
|
||||||
{
|
this.AssertNotDisposed();
|
||||||
SendTo (output, (ulong) output.Length);
|
if(!this.CanSeek) {
|
||||||
}
|
throw new NotSupportedException("The File Descriptor does not support seeking");
|
||||||
|
}
|
||||||
|
|
||||||
[CLSCompliant (false)]
|
Native.SeekFlags sf = Native.SeekFlags.SEEK_CUR;
|
||||||
public void SendTo (UnixStream output, ulong count)
|
switch(origin) {
|
||||||
{
|
case SeekOrigin.Begin:
|
||||||
SendTo (output.Handle, count);
|
sf = Native.SeekFlags.SEEK_SET;
|
||||||
}
|
break;
|
||||||
|
case SeekOrigin.Current:
|
||||||
|
sf = Native.SeekFlags.SEEK_CUR;
|
||||||
|
break;
|
||||||
|
case SeekOrigin.End:
|
||||||
|
sf = Native.SeekFlags.SEEK_END;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
[CLSCompliant (false)]
|
Int64 pos = Native.Syscall.lseek(this.fileDescriptor, offset, sf);
|
||||||
public void SendTo (int out_fd, ulong count)
|
if(pos == -1) {
|
||||||
{
|
UnixMarshal.ThrowExceptionForLastError();
|
||||||
if (!CanWrite)
|
}
|
||||||
throw new NotSupportedException ("Unable to write to the current file descriptor");
|
|
||||||
long offset = Position;
|
|
||||||
long r = Native.Syscall.sendfile (out_fd, fileDescriptor, ref offset, count);
|
|
||||||
if (r == -1)
|
|
||||||
UnixMarshal.ThrowExceptionForLastError ();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetOwner (long user, long group)
|
return (Int64)pos;
|
||||||
{
|
}
|
||||||
AssertNotDisposed ();
|
|
||||||
|
|
||||||
int r = Native.Syscall.fchown (fileDescriptor,
|
public override void SetLength(Int64 value) {
|
||||||
Convert.ToUInt32 (user), Convert.ToUInt32 (group));
|
this.AssertNotDisposed();
|
||||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
if(value < 0) {
|
||||||
}
|
throw new ArgumentOutOfRangeException("value", "< 0");
|
||||||
|
}
|
||||||
|
|
||||||
public void SetOwner (string user, string group)
|
if(!this.CanSeek && !this.CanWrite) {
|
||||||
{
|
throw new NotSupportedException("You can't truncating the current file descriptor");
|
||||||
AssertNotDisposed ();
|
}
|
||||||
|
|
||||||
long uid = new UnixUserInfo (user).UserId;
|
Int32 r;
|
||||||
long gid = new UnixGroupInfo (group).GroupId;
|
do {
|
||||||
SetOwner (uid, gid);
|
r = Native.Syscall.ftruncate(this.fileDescriptor, value);
|
||||||
}
|
} while(UnixMarshal.ShouldRetrySyscall(r));
|
||||||
|
UnixMarshal.ThrowExceptionForLastErrorIf(r);
|
||||||
|
}
|
||||||
|
|
||||||
public void SetOwner (string user)
|
public override unsafe void Write(Byte[] buffer, Int32 offset, Int32 count) {
|
||||||
{
|
this.AssertNotDisposed();
|
||||||
AssertNotDisposed ();
|
this.AssertValidBuffer(buffer, offset, count);
|
||||||
|
if(!this.CanWrite) {
|
||||||
|
throw new NotSupportedException("File Descriptor does not support writing");
|
||||||
|
}
|
||||||
|
|
||||||
Native.Passwd pw = Native.Syscall.getpwnam (user);
|
if(buffer.Length == 0) {
|
||||||
if (pw == null)
|
return;
|
||||||
throw new ArgumentException (Locale.GetText ("invalid username"), "user");
|
}
|
||||||
long uid = pw.pw_uid;
|
|
||||||
long gid = pw.pw_gid;
|
|
||||||
SetOwner (uid, gid);
|
|
||||||
}
|
|
||||||
|
|
||||||
[CLSCompliant (false)]
|
Int64 r = 0;
|
||||||
public long GetConfigurationValue (Native.PathconfName name)
|
fixed(Byte* buf = &buffer[offset]) {
|
||||||
{
|
do {
|
||||||
AssertNotDisposed ();
|
r = Native.Syscall.write(this.fileDescriptor, buf, (UInt64)count);
|
||||||
long r = Native.Syscall.fpathconf (fileDescriptor, name);
|
} while(UnixMarshal.ShouldRetrySyscall((Int32)r));
|
||||||
if (r == -1 && Native.Syscall.GetLastError() != (Native.Errno) 0)
|
}
|
||||||
UnixMarshal.ThrowExceptionForLastError ();
|
if(r == -1) {
|
||||||
return r;
|
UnixMarshal.ThrowExceptionForLastError();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
~UnixStream ()
|
public unsafe void WriteAtOffset(Byte[] buffer,
|
||||||
{
|
Int32 offset, Int32 count, Int64 fileOffset) {
|
||||||
Close ();
|
this.AssertNotDisposed();
|
||||||
}
|
this.AssertValidBuffer(buffer, offset, count);
|
||||||
|
if(!this.CanWrite) {
|
||||||
|
throw new NotSupportedException("File Descriptor does not support writing");
|
||||||
|
}
|
||||||
|
|
||||||
public override void Close ()
|
if(buffer.Length == 0) {
|
||||||
{
|
return;
|
||||||
if (fileDescriptor == InvalidFileDescriptor)
|
}
|
||||||
return;
|
|
||||||
|
|
||||||
Flush ();
|
Int64 r = 0;
|
||||||
|
fixed(Byte* buf = &buffer[offset]) {
|
||||||
|
do {
|
||||||
|
r = Native.Syscall.pwrite(this.fileDescriptor, buf, (UInt64)count, fileOffset);
|
||||||
|
} while(UnixMarshal.ShouldRetrySyscall((Int32)r));
|
||||||
|
}
|
||||||
|
if(r == -1) {
|
||||||
|
UnixMarshal.ThrowExceptionForLastError();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!owner)
|
public void SendTo(UnixStream output) => this.SendTo(output, (UInt64)output.Length);
|
||||||
return;
|
|
||||||
|
|
||||||
int r;
|
//[CLSCompliant(false)]
|
||||||
do {
|
public void SendTo(UnixStream output, UInt64 count) => this.SendTo(output.Handle, count);
|
||||||
r = Native.Syscall.close (fileDescriptor);
|
|
||||||
} while (UnixMarshal.ShouldRetrySyscall (r));
|
|
||||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
|
||||||
fileDescriptor = InvalidFileDescriptor;
|
|
||||||
GC.SuppressFinalize (this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IDisposable.Dispose ()
|
//[CLSCompliant(false)]
|
||||||
{
|
public void SendTo(Int32 out_fd, UInt64 count) {
|
||||||
if (fileDescriptor != InvalidFileDescriptor && owner) {
|
if(!this.CanWrite) {
|
||||||
Close ();
|
throw new NotSupportedException("Unable to write to the current file descriptor");
|
||||||
}
|
}
|
||||||
GC.SuppressFinalize (this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool canSeek = false;
|
Int64 offset = this.Position;
|
||||||
private bool canRead = false;
|
Int64 r = Native.Syscall.sendfile(out_fd, this.fileDescriptor, ref offset, count);
|
||||||
private bool canWrite = false;
|
if(r == -1) {
|
||||||
private bool owner = true;
|
UnixMarshal.ThrowExceptionForLastError();
|
||||||
private int fileDescriptor = InvalidFileDescriptor;
|
}
|
||||||
private Native.Stat stat;
|
}
|
||||||
}
|
|
||||||
|
public void SetOwner(Int64 user, Int64 group) {
|
||||||
|
this.AssertNotDisposed();
|
||||||
|
|
||||||
|
Int32 r = Native.Syscall.fchown(this.fileDescriptor,
|
||||||
|
Convert.ToUInt32(user), Convert.ToUInt32(group));
|
||||||
|
UnixMarshal.ThrowExceptionForLastErrorIf(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetOwner(String user, String group) {
|
||||||
|
this.AssertNotDisposed();
|
||||||
|
|
||||||
|
Int64 uid = new UnixUserInfo(user).UserId;
|
||||||
|
Int64 gid = new UnixGroupInfo(group).GroupId;
|
||||||
|
this.SetOwner(uid, gid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetOwner(String user) {
|
||||||
|
this.AssertNotDisposed();
|
||||||
|
|
||||||
|
Native.Passwd pw = Native.Syscall.getpwnam(user);
|
||||||
|
if(pw == null) {
|
||||||
|
throw new ArgumentException(Locale.GetText("invalid username"), "user");
|
||||||
|
}
|
||||||
|
|
||||||
|
Int64 uid = pw.pw_uid;
|
||||||
|
Int64 gid = pw.pw_gid;
|
||||||
|
this.SetOwner(uid, gid);
|
||||||
|
}
|
||||||
|
|
||||||
|
//[CLSCompliant(false)]
|
||||||
|
public Int64 GetConfigurationValue(Native.PathconfName name) {
|
||||||
|
this.AssertNotDisposed();
|
||||||
|
Int64 r = Native.Syscall.fpathconf(this.fileDescriptor, name);
|
||||||
|
if(r == -1 && Native.Syscall.GetLastError() != (Native.Errno)0) {
|
||||||
|
UnixMarshal.ThrowExceptionForLastError();
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
~UnixStream() {
|
||||||
|
this.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Close() {
|
||||||
|
if(this.fileDescriptor == InvalidFileDescriptor) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Flush();
|
||||||
|
|
||||||
|
if(!this.owner) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Int32 r;
|
||||||
|
do {
|
||||||
|
r = Native.Syscall.close(this.fileDescriptor);
|
||||||
|
} while(UnixMarshal.ShouldRetrySyscall(r));
|
||||||
|
UnixMarshal.ThrowExceptionForLastErrorIf(r);
|
||||||
|
this.fileDescriptor = InvalidFileDescriptor;
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IDisposable.Dispose() {
|
||||||
|
if(this.fileDescriptor != InvalidFileDescriptor && this.owner) {
|
||||||
|
this.Close();
|
||||||
|
}
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Boolean canSeek = false;
|
||||||
|
private Boolean canRead = false;
|
||||||
|
private Boolean canWrite = false;
|
||||||
|
private Boolean owner = true;
|
||||||
|
private Int32 fileDescriptor = InvalidFileDescriptor;
|
||||||
|
private Native.Stat stat;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim: noexpandtab
|
// vim: noexpandtab
|
||||||
|
@ -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
|
||||||
|
@ -29,165 +29,121 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Mono.Unix;
|
|
||||||
|
|
||||||
namespace Mono.Unix {
|
namespace Mono.Unix {
|
||||||
|
|
||||||
public sealed class UnixUserInfo
|
public sealed class UnixUserInfo
|
||||||
{
|
{
|
||||||
private Native.Passwd passwd;
|
private readonly Native.Passwd passwd;
|
||||||
|
|
||||||
public UnixUserInfo (string user)
|
public UnixUserInfo (String user)
|
||||||
{
|
{
|
||||||
passwd = new Native.Passwd ();
|
this.passwd = new Native.Passwd ();
|
||||||
Native.Passwd pw;
|
Int32 r = Native.Syscall.getpwnam_r(user, this.passwd, out Native.Passwd pw);
|
||||||
int r = Native.Syscall.getpwnam_r (user, passwd, out pw);
|
if (r != 0 || pw == null) {
|
||||||
if (r != 0 || pw == null)
|
throw new ArgumentException (Locale.GetText ("invalid username"), "user");
|
||||||
throw new ArgumentException (Locale.GetText ("invalid username"), "user");
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[CLSCompliant (false)]
|
//[CLSCompliant (false)]
|
||||||
public UnixUserInfo (uint user)
|
public UnixUserInfo (UInt32 user)
|
||||||
{
|
{
|
||||||
passwd = new Native.Passwd ();
|
this.passwd = new Native.Passwd ();
|
||||||
Native.Passwd pw;
|
Int32 r = Native.Syscall.getpwuid_r(user, this.passwd, out Native.Passwd pw);
|
||||||
int r = Native.Syscall.getpwuid_r (user, passwd, out pw);
|
if (r != 0 || pw == null) {
|
||||||
if (r != 0 || pw == null)
|
throw new ArgumentException (Locale.GetText ("invalid user id"), "user");
|
||||||
throw new ArgumentException (Locale.GetText ("invalid user id"), "user");
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public UnixUserInfo (long user)
|
public UnixUserInfo (Int64 user)
|
||||||
{
|
{
|
||||||
passwd = new Native.Passwd ();
|
this.passwd = new Native.Passwd ();
|
||||||
Native.Passwd pw;
|
Int32 r = Native.Syscall.getpwuid_r(Convert.ToUInt32(user), this.passwd, out Native.Passwd pw);
|
||||||
int r = Native.Syscall.getpwuid_r (Convert.ToUInt32 (user), passwd, out pw);
|
if (r != 0 || pw == null) {
|
||||||
if (r != 0 || pw == null)
|
throw new ArgumentException (Locale.GetText ("invalid user id"), "user");
|
||||||
throw new ArgumentException (Locale.GetText ("invalid user id"), "user");
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public UnixUserInfo (Native.Passwd passwd)
|
public UnixUserInfo(Native.Passwd passwd) => this.passwd = CopyPasswd(passwd);
|
||||||
{
|
|
||||||
this.passwd = CopyPasswd (passwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Native.Passwd CopyPasswd (Native.Passwd pw)
|
private static Native.Passwd CopyPasswd(Native.Passwd pw) => new Native.Passwd {
|
||||||
{
|
pw_name = pw.pw_name,
|
||||||
Native.Passwd p = new Native.Passwd ();
|
pw_passwd = pw.pw_passwd,
|
||||||
|
pw_uid = pw.pw_uid,
|
||||||
|
pw_gid = pw.pw_gid,
|
||||||
|
pw_gecos = pw.pw_gecos,
|
||||||
|
pw_dir = pw.pw_dir,
|
||||||
|
pw_shell = pw.pw_shell
|
||||||
|
};
|
||||||
|
|
||||||
p.pw_name = pw.pw_name;
|
public String UserName => this.passwd.pw_name;
|
||||||
p.pw_passwd = pw.pw_passwd;
|
|
||||||
p.pw_uid = pw.pw_uid;
|
|
||||||
p.pw_gid = pw.pw_gid;
|
|
||||||
p.pw_gecos = pw.pw_gecos;
|
|
||||||
p.pw_dir = pw.pw_dir;
|
|
||||||
p.pw_shell = pw.pw_shell;
|
|
||||||
|
|
||||||
return p;
|
public String Password => this.passwd.pw_passwd;
|
||||||
}
|
|
||||||
|
|
||||||
public string UserName {
|
public Int64 UserId => this.passwd.pw_uid;
|
||||||
get {return passwd.pw_name;}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Password {
|
public UnixGroupInfo Group => new UnixGroupInfo(this.passwd.pw_gid);
|
||||||
get {return passwd.pw_passwd;}
|
|
||||||
}
|
|
||||||
|
|
||||||
public long UserId {
|
public Int64 GroupId => this.passwd.pw_gid;
|
||||||
get {return passwd.pw_uid;}
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnixGroupInfo Group {
|
public String GroupName => this.Group.GroupName;
|
||||||
get {return new UnixGroupInfo (passwd.pw_gid);}
|
|
||||||
}
|
|
||||||
|
|
||||||
public long GroupId {
|
public String RealName => this.passwd.pw_gecos;
|
||||||
get {return passwd.pw_gid;}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GroupName {
|
public String HomeDirectory => this.passwd.pw_dir;
|
||||||
get {return Group.GroupName;}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string RealName {
|
public String ShellProgram => this.passwd.pw_shell;
|
||||||
get {return passwd.pw_gecos;}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string HomeDirectory {
|
public override Int32 GetHashCode() => this.passwd.GetHashCode();
|
||||||
get {return passwd.pw_dir;}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string ShellProgram {
|
public override Boolean Equals(Object obj) => obj == null || this.GetType() != obj.GetType() ? false : this.passwd.Equals(((UnixUserInfo)obj).passwd);
|
||||||
get {return passwd.pw_shell;}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode ()
|
public override String ToString() => this.passwd.ToString();
|
||||||
{
|
|
||||||
return passwd.GetHashCode ();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals (object obj)
|
public static UnixUserInfo GetRealUser() => new UnixUserInfo(GetRealUserId());
|
||||||
{
|
|
||||||
if (obj == null || GetType () != obj.GetType())
|
|
||||||
return false;
|
|
||||||
return passwd.Equals (((UnixUserInfo) obj).passwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString ()
|
public static Int64 GetRealUserId() => Native.Syscall.getuid();
|
||||||
{
|
|
||||||
return passwd.ToString ();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UnixUserInfo GetRealUser ()
|
// I would hope that this is the same as GetCurrentUserName, but it is a
|
||||||
{
|
// different syscall, so who knows.
|
||||||
return new UnixUserInfo (GetRealUserId ());
|
public static String GetLoginName ()
|
||||||
}
|
{
|
||||||
|
StringBuilder buf = new StringBuilder (4);
|
||||||
|
Int32 r;
|
||||||
|
do {
|
||||||
|
buf.Capacity *= 2;
|
||||||
|
r = Native.Syscall.getlogin_r (buf, (UInt64) buf.Capacity);
|
||||||
|
} while (r == -1 && Native.Stdlib.GetLastError() == Native.Errno.ERANGE);
|
||||||
|
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||||
|
return buf.ToString ();
|
||||||
|
}
|
||||||
|
|
||||||
public static long GetRealUserId ()
|
public Native.Passwd ToPasswd() => CopyPasswd(this.passwd);
|
||||||
{
|
|
||||||
return Native.Syscall.getuid ();
|
|
||||||
}
|
|
||||||
|
|
||||||
// I would hope that this is the same as GetCurrentUserName, but it is a
|
public static UnixUserInfo[] GetLocalUsers ()
|
||||||
// different syscall, so who knows.
|
{
|
||||||
public static string GetLoginName ()
|
ArrayList entries = new ArrayList ();
|
||||||
{
|
lock (Native.Syscall.pwd_lock) {
|
||||||
StringBuilder buf = new StringBuilder (4);
|
if (Native.Syscall.setpwent () != 0) {
|
||||||
int r;
|
UnixMarshal.ThrowExceptionForLastError ();
|
||||||
do {
|
}
|
||||||
buf.Capacity *= 2;
|
try {
|
||||||
r = Native.Syscall.getlogin_r (buf, (ulong) buf.Capacity);
|
Native.Passwd p;
|
||||||
} while (r == (-1) && Native.Stdlib.GetLastError() == Native.Errno.ERANGE);
|
while ((p = Native.Syscall.getpwent()) != null) {
|
||||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
_ = entries.Add(new UnixUserInfo(p));
|
||||||
return buf.ToString ();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public Native.Passwd ToPasswd ()
|
if (Native.Syscall.GetLastError () != (Native.Errno) 0) {
|
||||||
{
|
UnixMarshal.ThrowExceptionForLastError ();
|
||||||
return CopyPasswd (passwd);
|
}
|
||||||
}
|
}
|
||||||
|
finally {
|
||||||
public static UnixUserInfo[] GetLocalUsers ()
|
_ = Native.Syscall.endpwent();
|
||||||
{
|
}
|
||||||
ArrayList entries = new ArrayList ();
|
}
|
||||||
lock (Native.Syscall.pwd_lock) {
|
return (UnixUserInfo[]) entries.ToArray (typeof(UnixUserInfo));
|
||||||
if (Native.Syscall.setpwent () != 0) {
|
}
|
||||||
UnixMarshal.ThrowExceptionForLastError ();
|
}
|
||||||
}
|
|
||||||
try {
|
|
||||||
Native.Passwd p;
|
|
||||||
while ((p = Native.Syscall.getpwent()) != null)
|
|
||||||
entries.Add (new UnixUserInfo (p));
|
|
||||||
if (Native.Syscall.GetLastError () != (Native.Errno) 0)
|
|
||||||
UnixMarshal.ThrowExceptionForLastError ();
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
Native.Syscall.endpwent ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (UnixUserInfo[]) entries.ToArray (typeof(UnixUserInfo));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim: noexpandtab
|
// vim: noexpandtab
|
||||||
|
Loading…
Reference in New Issue
Block a user