huge refactoring
This commit is contained in:
parent
6b5d3e07cc
commit
2f0ae844d0
@ -1,136 +1,138 @@
|
||||
//
|
||||
// Consts.cs.in
|
||||
//
|
||||
// Author:
|
||||
// Kornél Pál <http://www.kornelpal.hu/>
|
||||
//
|
||||
// Copyright (C) 2005-2006 Kornél Pál
|
||||
//
|
||||
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
static partial class Consts
|
||||
{
|
||||
public const string MonoCorlibVersion = "@MONO_CORLIB_VERSION@";
|
||||
}
|
||||
|
||||
#if !NETCORE
|
||||
|
||||
static partial class Consts
|
||||
{
|
||||
//
|
||||
// Use these assembly version constants to make code more maintainable.
|
||||
//
|
||||
|
||||
public const string MonoVersion = "@MONO_VERSION@";
|
||||
public const string MonoCompany = "Mono development team";
|
||||
public const string MonoProduct = "Mono Common Language Infrastructure";
|
||||
public const string MonoCopyright = "(c) Various Mono authors";
|
||||
|
||||
#if MOBILE
|
||||
// Versions of .NET Framework for Silverlight 4.0
|
||||
public const string FxVersion = "2.0.5.0";
|
||||
public const string VsVersion = "9.0.0.0"; // unused, but needed for compilation
|
||||
public const string FxFileVersion = "4.0.50524.0";
|
||||
public const string EnvironmentVersion = FxFileVersion;
|
||||
|
||||
public const string VsFileVersion = "9.0.50727.42"; // unused, but needed for compilation
|
||||
#elif NET_4_6
|
||||
public const string FxVersion = "4.0.0.0";
|
||||
public const string FxFileVersion = "4.6.57.0";
|
||||
public const string EnvironmentVersion = "4.0.30319.42000";
|
||||
|
||||
public const string VsVersion = "0.0.0.0"; // Useless ?
|
||||
public const string VsFileVersion = "11.0.0.0"; // TODO:
|
||||
#elif NET_4_5
|
||||
public const string FxVersion = "4.0.0.0";
|
||||
public const string FxFileVersion = "4.0.30319.17020";
|
||||
public const string EnvironmentVersion = FxFileVersion;
|
||||
|
||||
public const string VsVersion = "0.0.0.0"; // Useless ?
|
||||
public const string VsFileVersion = "11.0.0.0"; // TODO:
|
||||
#elif NETCORE
|
||||
public const string FxVersion = "";
|
||||
public const string FxFileVersion = "";
|
||||
public const string EnvironmentVersion = FxFileVersion;
|
||||
|
||||
public const string VsVersion = "";
|
||||
public const string VsFileVersion = "";
|
||||
#elif NET_4_0
|
||||
#error Profile NET_4_0 is not supported.
|
||||
#elif NET_3_5
|
||||
#error Profile NET_3_5 is not supported.
|
||||
#elif NET_3_0
|
||||
#error Profile NET_3_0 is not supported.
|
||||
#elif NET_2_0
|
||||
#error Profile NET_2_0 is not supported.
|
||||
#elif NET_1_1
|
||||
#error Profile NET_1_1 is not supported.
|
||||
#elif NET_1_0
|
||||
#error Profile NET_1_0 is not supported.
|
||||
#else
|
||||
#error No profile symbols defined.
|
||||
#endif
|
||||
|
||||
#if MOBILE
|
||||
const string PublicKeyToken = "7cec85d7bea7798e";
|
||||
#else
|
||||
const string PublicKeyToken = "b77a5c561934e089";
|
||||
#endif
|
||||
|
||||
//
|
||||
// Use these assembly name constants to make code more maintainable.
|
||||
//
|
||||
|
||||
public const string AssemblyI18N = "I18N, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756";
|
||||
public const string AssemblyMicrosoft_JScript = "Microsoft.JScript, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||
public const string AssemblyMicrosoft_VisualStudio = "Microsoft.VisualStudio, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||
public const string AssemblyMicrosoft_VisualStudio_Web = "Microsoft.VisualStudio.Web, Version=" + VsVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||
public const string AssemblyMicrosoft_VSDesigner = "Microsoft.VSDesigner, Version=" + VsVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||
public const string AssemblyMono_Http = "Mono.Http, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756";
|
||||
public const string AssemblyMono_Posix = "Mono.Posix, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756";
|
||||
public const string AssemblyMono_Security = "Mono.Security, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756";
|
||||
public const string AssemblyMono_Messaging_RabbitMQ = "Mono.Messaging.RabbitMQ, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756";
|
||||
public const string AssemblyCorlib = "mscorlib, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=" + PublicKeyToken;
|
||||
public const string AssemblySystem = "System, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=" + PublicKeyToken;
|
||||
public const string AssemblySystem_Data = "System.Data, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b77a5c561934e089";
|
||||
public const string AssemblySystem_Design = "System.Design, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||
public const string AssemblySystem_DirectoryServices = "System.DirectoryServices, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||
public const string AssemblySystem_Drawing = "System.Drawing, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||
public const string AssemblySystem_Drawing_Design = "System.Drawing.Design, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||
public const string AssemblySystem_Messaging = "System.Messaging, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||
public const string AssemblySystem_Security = "System.Security, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||
public const string AssemblySystem_ServiceProcess = "System.ServiceProcess, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||
public const string AssemblySystem_Web = "System.Web, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||
public const string AssemblySystem_Windows_Forms = "System.Windows.Forms, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b77a5c561934e089";
|
||||
public const string AssemblySystem_2_0 = "System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
|
||||
public const string AssemblySystemCore_3_5 = "System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
|
||||
public const string AssemblySystem_Core = "System.Core, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=" + PublicKeyToken;
|
||||
public const string WindowsBase_3_0 = "WindowsBase, Version=3.0.0.0, PublicKeyToken=31bf3856ad364e35";
|
||||
public const string AssemblyWindowsBase = "WindowsBase, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35";
|
||||
public const string AssemblyPresentationCore_3_5 = "PresentationCore, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35";
|
||||
public const string AssemblyPresentationCore_4_0 = "PresentationCore, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35";
|
||||
public const string AssemblyPresentationFramework_3_5 = "PresentationFramework, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35";
|
||||
public const string AssemblySystemServiceModel_3_0 = "System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
|
||||
}
|
||||
|
||||
using System;
|
||||
|
||||
//
|
||||
// Consts.cs.in
|
||||
//
|
||||
// Author:
|
||||
// Kornél Pál <http://www.kornelpal.hu/>
|
||||
//
|
||||
// Copyright (C) 2005-2006 Kornél Pál
|
||||
//
|
||||
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
static partial class Consts
|
||||
{
|
||||
public const String MonoCorlibVersion = "@MONO_CORLIB_VERSION@";
|
||||
}
|
||||
|
||||
#if !NETCORE
|
||||
|
||||
static partial class Consts
|
||||
{
|
||||
//
|
||||
// Use these assembly version constants to make code more maintainable.
|
||||
//
|
||||
|
||||
public const String MonoVersion = "@MONO_VERSION@";
|
||||
public const String MonoCompany = "Mono development team";
|
||||
public const String MonoProduct = "Mono Common Language Infrastructure";
|
||||
public const String MonoCopyright = "(c) Various Mono authors";
|
||||
|
||||
#if MOBILE
|
||||
// Versions of .NET Framework for Silverlight 4.0
|
||||
public const string FxVersion = "2.0.5.0";
|
||||
public const string VsVersion = "9.0.0.0"; // unused, but needed for compilation
|
||||
public const string FxFileVersion = "4.0.50524.0";
|
||||
public const string EnvironmentVersion = FxFileVersion;
|
||||
|
||||
public const string VsFileVersion = "9.0.50727.42"; // unused, but needed for compilation
|
||||
#elif NET_4_6
|
||||
public const String FxVersion = "4.0.0.0";
|
||||
public const String FxFileVersion = "4.6.57.0";
|
||||
public const String EnvironmentVersion = "4.0.30319.42000";
|
||||
|
||||
public const String VsVersion = "0.0.0.0"; // Useless ?
|
||||
public const String VsFileVersion = "11.0.0.0"; // TODO:
|
||||
#elif NET_4_5
|
||||
public const string FxVersion = "4.0.0.0";
|
||||
public const string FxFileVersion = "4.0.30319.17020";
|
||||
public const string EnvironmentVersion = FxFileVersion;
|
||||
|
||||
public const string VsVersion = "0.0.0.0"; // Useless ?
|
||||
public const string VsFileVersion = "11.0.0.0"; // TODO:
|
||||
#elif NETCORE
|
||||
public const string FxVersion = "";
|
||||
public const string FxFileVersion = "";
|
||||
public const string EnvironmentVersion = FxFileVersion;
|
||||
|
||||
public const string VsVersion = "";
|
||||
public const string VsFileVersion = "";
|
||||
#elif NET_4_0
|
||||
#error Profile NET_4_0 is not supported.
|
||||
#elif NET_3_5
|
||||
#error Profile NET_3_5 is not supported.
|
||||
#elif NET_3_0
|
||||
#error Profile NET_3_0 is not supported.
|
||||
#elif NET_2_0
|
||||
#error Profile NET_2_0 is not supported.
|
||||
#elif NET_1_1
|
||||
#error Profile NET_1_1 is not supported.
|
||||
#elif NET_1_0
|
||||
#error Profile NET_1_0 is not supported.
|
||||
#else
|
||||
#error No profile symbols defined.
|
||||
#endif
|
||||
|
||||
#if MOBILE
|
||||
const string PublicKeyToken = "7cec85d7bea7798e";
|
||||
#else
|
||||
const String PublicKeyToken = "b77a5c561934e089";
|
||||
#endif
|
||||
|
||||
//
|
||||
// Use these assembly name constants to make code more maintainable.
|
||||
//
|
||||
|
||||
public const String AssemblyI18N = "I18N, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756";
|
||||
public const String AssemblyMicrosoft_JScript = "Microsoft.JScript, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||
public const String AssemblyMicrosoft_VisualStudio = "Microsoft.VisualStudio, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||
public const String AssemblyMicrosoft_VisualStudio_Web = "Microsoft.VisualStudio.Web, Version=" + VsVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||
public const String AssemblyMicrosoft_VSDesigner = "Microsoft.VSDesigner, Version=" + VsVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||
public const String AssemblyMono_Http = "Mono.Http, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756";
|
||||
public const String AssemblyMono_Posix = "Mono.Posix, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756";
|
||||
public const String AssemblyMono_Security = "Mono.Security, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756";
|
||||
public const String AssemblyMono_Messaging_RabbitMQ = "Mono.Messaging.RabbitMQ, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=0738eb9f132ed756";
|
||||
public const String AssemblyCorlib = "mscorlib, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=" + PublicKeyToken;
|
||||
public const String AssemblySystem = "System, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=" + PublicKeyToken;
|
||||
public const String AssemblySystem_Data = "System.Data, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b77a5c561934e089";
|
||||
public const String AssemblySystem_Design = "System.Design, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||
public const String AssemblySystem_DirectoryServices = "System.DirectoryServices, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||
public const String AssemblySystem_Drawing = "System.Drawing, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||
public const String AssemblySystem_Drawing_Design = "System.Drawing.Design, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||
public const String AssemblySystem_Messaging = "System.Messaging, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||
public const String AssemblySystem_Security = "System.Security, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||
public const String AssemblySystem_ServiceProcess = "System.ServiceProcess, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||
public const String AssemblySystem_Web = "System.Web, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
|
||||
public const String AssemblySystem_Windows_Forms = "System.Windows.Forms, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=b77a5c561934e089";
|
||||
public const String AssemblySystem_2_0 = "System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
|
||||
public const String AssemblySystemCore_3_5 = "System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
|
||||
public const String AssemblySystem_Core = "System.Core, Version=" + FxVersion + ", Culture=neutral, PublicKeyToken=" + PublicKeyToken;
|
||||
public const String WindowsBase_3_0 = "WindowsBase, Version=3.0.0.0, PublicKeyToken=31bf3856ad364e35";
|
||||
public const String AssemblyWindowsBase = "WindowsBase, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35";
|
||||
public const String AssemblyPresentationCore_3_5 = "PresentationCore, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35";
|
||||
public const String AssemblyPresentationCore_4_0 = "PresentationCore, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35";
|
||||
public const String AssemblyPresentationFramework_3_5 = "PresentationFramework, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35";
|
||||
public const String AssemblySystemServiceModel_3_0 = "System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
|
||||
}
|
||||
|
||||
#endif
|
@ -35,17 +35,11 @@ using System;
|
||||
|
||||
internal sealed class Locale {
|
||||
|
||||
private Locale ()
|
||||
{
|
||||
}
|
||||
|
||||
public static string GetText (string msg)
|
||||
{
|
||||
return msg;
|
||||
}
|
||||
|
||||
public static string GetText (string fmt, params object [] args)
|
||||
{
|
||||
return String.Format (fmt, args);
|
||||
}
|
||||
private Locale ()
|
||||
{
|
||||
}
|
||||
|
||||
public static String GetText(String msg) => msg;
|
||||
|
||||
public static String GetText(String fmt, params Object[] args) => String.Format(fmt, args);
|
||||
}
|
||||
|
@ -31,56 +31,62 @@
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Mono.Posix {
|
||||
|
||||
[Obsolete ("Use Mono.Unix.Catalog")]
|
||||
public class Catalog {
|
||||
[DllImport("intl")]
|
||||
static extern IntPtr bindtextdomain (IntPtr domainname, IntPtr dirname);
|
||||
[DllImport("intl")]
|
||||
static extern IntPtr bind_textdomain_codeset (IntPtr domainname,
|
||||
IntPtr codeset);
|
||||
[DllImport("intl")]
|
||||
static extern IntPtr textdomain (IntPtr domainname);
|
||||
|
||||
public static void Init (String package, String localedir)
|
||||
{
|
||||
IntPtr ipackage = Marshal.StringToHGlobalAuto (package);
|
||||
IntPtr ilocaledir = Marshal.StringToHGlobalAuto (localedir);
|
||||
IntPtr iutf8 = Marshal.StringToHGlobalAuto ("UTF-8");
|
||||
bindtextdomain (ipackage, ilocaledir);
|
||||
bind_textdomain_codeset (ipackage, iutf8);
|
||||
textdomain (ipackage);
|
||||
Marshal.FreeHGlobal (ipackage);
|
||||
Marshal.FreeHGlobal (ilocaledir);
|
||||
Marshal.FreeHGlobal (iutf8);
|
||||
}
|
||||
|
||||
[DllImport("intl")]
|
||||
static extern IntPtr gettext (IntPtr instring);
|
||||
|
||||
public static String GetString (String s)
|
||||
{
|
||||
IntPtr ints = Marshal.StringToHGlobalAuto (s);
|
||||
String t = Marshal.PtrToStringAuto (gettext (ints));
|
||||
Marshal.FreeHGlobal (ints);
|
||||
return t;
|
||||
}
|
||||
|
||||
[DllImport("intl")]
|
||||
static extern IntPtr ngettext (IntPtr singular, IntPtr plural, Int32 n);
|
||||
|
||||
public static String GetPluralString (String s, String p, Int32 n)
|
||||
{
|
||||
IntPtr ints = Marshal.StringToHGlobalAuto (s);
|
||||
IntPtr intp = Marshal.StringToHGlobalAuto (p);
|
||||
String t = Marshal.PtrToStringAnsi (ngettext (ints, intp, n));
|
||||
Marshal.FreeHGlobal (ints);
|
||||
Marshal.FreeHGlobal (intp);
|
||||
return t;
|
||||
}
|
||||
|
||||
}
|
||||
[Obsolete ("Use Mono.Unix.Catalog")]
|
||||
public class Catalog {
|
||||
[DllImport("intl")]
|
||||
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||
static extern IntPtr bindtextdomain (IntPtr domainname, IntPtr dirname);
|
||||
[DllImport("intl")]
|
||||
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||
static extern IntPtr bind_textdomain_codeset (IntPtr domainname,
|
||||
IntPtr codeset);
|
||||
[DllImport("intl")]
|
||||
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||
static extern IntPtr textdomain (IntPtr domainname);
|
||||
|
||||
public static void Init (String package, String localedir)
|
||||
{
|
||||
IntPtr ipackage = Marshal.StringToHGlobalAuto (package);
|
||||
IntPtr ilocaledir = Marshal.StringToHGlobalAuto (localedir);
|
||||
IntPtr iutf8 = Marshal.StringToHGlobalAuto ("UTF-8");
|
||||
_ = bindtextdomain(ipackage, ilocaledir);
|
||||
_ = bind_textdomain_codeset(ipackage, iutf8);
|
||||
_ = textdomain(ipackage);
|
||||
Marshal.FreeHGlobal (ipackage);
|
||||
Marshal.FreeHGlobal (ilocaledir);
|
||||
Marshal.FreeHGlobal (iutf8);
|
||||
}
|
||||
|
||||
[DllImport("intl")]
|
||||
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||
static extern IntPtr gettext (IntPtr instring);
|
||||
|
||||
public static String GetString (String s)
|
||||
{
|
||||
IntPtr ints = Marshal.StringToHGlobalAuto (s);
|
||||
String t = Marshal.PtrToStringAuto (gettext (ints));
|
||||
Marshal.FreeHGlobal (ints);
|
||||
return t;
|
||||
}
|
||||
|
||||
[DllImport("intl")]
|
||||
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||
static extern IntPtr ngettext (IntPtr singular, IntPtr plural, Int32 n);
|
||||
|
||||
public static String GetPluralString (String s, String p, Int32 n)
|
||||
{
|
||||
IntPtr ints = Marshal.StringToHGlobalAuto (s);
|
||||
IntPtr intp = Marshal.StringToHGlobalAuto (p);
|
||||
String t = Marshal.PtrToStringAnsi (ngettext (ints, intp, n));
|
||||
Marshal.FreeHGlobal (ints);
|
||||
Marshal.FreeHGlobal (intp);
|
||||
return t;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -34,48 +34,36 @@ using System.Net.Sockets;
|
||||
namespace Mono.Posix
|
||||
{
|
||||
#pragma warning disable 649
|
||||
internal struct PeerCredData {
|
||||
public int pid;
|
||||
public int uid;
|
||||
public int gid;
|
||||
}
|
||||
internal struct PeerCredData {
|
||||
public Int32 pid;
|
||||
public Int32 uid;
|
||||
public Int32 gid;
|
||||
}
|
||||
#pragma warning restore 649
|
||||
|
||||
[Obsolete ("Use Mono.Unix.PeerCred")]
|
||||
public class PeerCred
|
||||
{
|
||||
/* Make sure this doesn't clash with anything in
|
||||
* SocketOptionName, and keep it synchronised with the
|
||||
* runtime
|
||||
*/
|
||||
private const int so_peercred=10001;
|
||||
private PeerCredData data;
|
||||
|
||||
public PeerCred (Socket sock) {
|
||||
if (sock.AddressFamily != AddressFamily.Unix) {
|
||||
throw new ArgumentException ("Only Unix sockets are supported", "sock");
|
||||
}
|
||||
|
||||
data = (PeerCredData)sock.GetSocketOption (SocketOptionLevel.Socket, (SocketOptionName)so_peercred);
|
||||
}
|
||||
|
||||
public int ProcessID {
|
||||
get {
|
||||
return(data.pid);
|
||||
}
|
||||
}
|
||||
|
||||
public int UserID {
|
||||
get {
|
||||
return(data.uid);
|
||||
}
|
||||
}
|
||||
|
||||
public int GroupID {
|
||||
get {
|
||||
return(data.gid);
|
||||
}
|
||||
}
|
||||
}
|
||||
[Obsolete ("Use Mono.Unix.PeerCred")]
|
||||
public class PeerCred
|
||||
{
|
||||
/* Make sure this doesn't clash with anything in
|
||||
* SocketOptionName, and keep it synchronised with the
|
||||
* runtime
|
||||
*/
|
||||
private const Int32 so_peercred =10001;
|
||||
private PeerCredData data;
|
||||
|
||||
public PeerCred (Socket sock) {
|
||||
if (sock.AddressFamily != AddressFamily.Unix) {
|
||||
throw new ArgumentException ("Only Unix sockets are supported", "sock");
|
||||
}
|
||||
|
||||
this.data = (PeerCredData)sock.GetSocketOption (SocketOptionLevel.Socket, (SocketOptionName)so_peercred);
|
||||
}
|
||||
|
||||
public Int32 ProcessID => this.data.pid;
|
||||
|
||||
public Int32 UserID => this.data.uid;
|
||||
|
||||
public Int32 GroupID => this.data.gid;
|
||||
}
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -34,85 +34,79 @@ using System.Text;
|
||||
|
||||
namespace Mono.Posix
|
||||
{
|
||||
[Serializable]
|
||||
[Obsolete ("Use Mono.Unix.UnixEndPoint")]
|
||||
public class UnixEndPoint : EndPoint
|
||||
{
|
||||
string filename;
|
||||
|
||||
public UnixEndPoint (string filename)
|
||||
{
|
||||
if (filename == null)
|
||||
throw new ArgumentNullException ("filename");
|
||||
[Serializable]
|
||||
[Obsolete ("Use Mono.Unix.UnixEndPoint")]
|
||||
public class UnixEndPoint : EndPoint
|
||||
{
|
||||
String filename;
|
||||
|
||||
public UnixEndPoint (String filename)
|
||||
{
|
||||
if (filename == null) {
|
||||
throw new ArgumentNullException ("filename");
|
||||
}
|
||||
|
||||
if (filename == "") {
|
||||
throw new ArgumentException ("Cannot be empty.", "filename");
|
||||
}
|
||||
|
||||
this.filename = filename;
|
||||
}
|
||||
|
||||
public String Filename {
|
||||
get => this.filename;
|
||||
set => this.filename = value;
|
||||
}
|
||||
|
||||
public override AddressFamily AddressFamily => AddressFamily.Unix;
|
||||
|
||||
public override EndPoint Create (SocketAddress socketAddress)
|
||||
{
|
||||
/*
|
||||
* Should also check this
|
||||
*
|
||||
int addr = (int) AddressFamily.Unix;
|
||||
if (socketAddress [0] != (addr & 0xFF))
|
||||
throw new ArgumentException ("socketAddress is not a unix socket address.");
|
||||
|
||||
if (filename == "")
|
||||
throw new ArgumentException ("Cannot be empty.", "filename");
|
||||
this.filename = filename;
|
||||
}
|
||||
|
||||
public string Filename {
|
||||
get {
|
||||
return(filename);
|
||||
}
|
||||
set {
|
||||
filename=value;
|
||||
}
|
||||
}
|
||||
if (socketAddress [1] != ((addr & 0xFF00) >> 8))
|
||||
throw new ArgumentException ("socketAddress is not a unix socket address.");
|
||||
*/
|
||||
|
||||
Byte[] bytes = new Byte[socketAddress.Size - 2];
|
||||
for (Int32 i = 0; i < bytes.Length; i++) {
|
||||
bytes [i] = socketAddress [i + 2];
|
||||
}
|
||||
|
||||
String name = Encoding.Default.GetString (bytes);
|
||||
return new UnixEndPoint (name);
|
||||
}
|
||||
|
||||
public override AddressFamily AddressFamily {
|
||||
get { return AddressFamily.Unix; }
|
||||
}
|
||||
|
||||
public override EndPoint Create (SocketAddress socketAddress)
|
||||
{
|
||||
/*
|
||||
* Should also check this
|
||||
*
|
||||
int addr = (int) AddressFamily.Unix;
|
||||
if (socketAddress [0] != (addr & 0xFF))
|
||||
throw new ArgumentException ("socketAddress is not a unix socket address.");
|
||||
|
||||
if (socketAddress [1] != ((addr & 0xFF00) >> 8))
|
||||
throw new ArgumentException ("socketAddress is not a unix socket address.");
|
||||
*/
|
||||
|
||||
byte [] bytes = new byte [socketAddress.Size - 2];
|
||||
for (int i = 0; i < bytes.Length; i++) {
|
||||
bytes [i] = socketAddress [i + 2];
|
||||
}
|
||||
|
||||
string name = Encoding.Default.GetString (bytes);
|
||||
return new UnixEndPoint (name);
|
||||
}
|
||||
|
||||
public override SocketAddress Serialize ()
|
||||
{
|
||||
byte [] bytes = Encoding.Default.GetBytes (filename);
|
||||
SocketAddress sa = new SocketAddress (AddressFamily, bytes.Length + 2);
|
||||
// sa [0] -> family low byte, sa [1] -> family high byte
|
||||
for (int i = 0; i < bytes.Length; i++)
|
||||
sa [i + 2] = bytes [i];
|
||||
|
||||
return sa;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return(filename);
|
||||
}
|
||||
|
||||
public override int GetHashCode ()
|
||||
{
|
||||
return filename.GetHashCode ();
|
||||
}
|
||||
|
||||
public override bool Equals (object o)
|
||||
{
|
||||
UnixEndPoint other = o as UnixEndPoint;
|
||||
if (other == null)
|
||||
return false;
|
||||
|
||||
return (other.filename == filename);
|
||||
}
|
||||
}
|
||||
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];
|
||||
}
|
||||
|
||||
return sa;
|
||||
}
|
||||
|
||||
public override String ToString() => this.filename;
|
||||
|
||||
public override Int32 GetHashCode() => this.filename.GetHashCode();
|
||||
|
||||
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
|
||||
{
|
||||
internal class UnixBinaryClientFormatterSink : IClientFormatterSink, IMessageSink, IClientChannelSink, IChannelSinkBase
|
||||
{
|
||||
UnixBinaryCore _binaryCore = UnixBinaryCore.DefaultInstance;
|
||||
IClientChannelSink _nextInChain;
|
||||
internal class UnixBinaryClientFormatterSink : IClientFormatterSink, IMessageSink, IClientChannelSink, IChannelSinkBase
|
||||
{
|
||||
UnixBinaryCore _binaryCore = UnixBinaryCore.DefaultInstance;
|
||||
IClientChannelSink _nextInChain;
|
||||
|
||||
public UnixBinaryClientFormatterSink(IClientChannelSink nextSink) => this._nextInChain = nextSink;
|
||||
|
||||
internal UnixBinaryCore BinaryCore {
|
||||
get => this._binaryCore;
|
||||
set => this._binaryCore = value;
|
||||
}
|
||||
|
||||
public IClientChannelSink NextChannelSink => this._nextInChain;
|
||||
|
||||
public IMessageSink NextSink =>
|
||||
// This is the last sink in the IMessageSink sink chain
|
||||
null;
|
||||
|
||||
public IDictionary Properties => null;
|
||||
|
||||
public void AsyncProcessRequest(IClientChannelSinkStack sinkStack,
|
||||
IMessage msg,
|
||||
ITransportHeaders headers,
|
||||
Stream stream) =>
|
||||
// never called because the formatter sink is
|
||||
// always the first in the chain
|
||||
throw new NotSupportedException("UnixBinaryClientFormatterSink must be the first sink in the IClientChannelSink chain");
|
||||
|
||||
public void AsyncProcessResponse (IClientResponseChannelSinkStack sinkStack,
|
||||
Object state,
|
||||
ITransportHeaders headers,
|
||||
Stream stream)
|
||||
{
|
||||
IMessage replyMessage = (IMessage)this._binaryCore.Deserializer.DeserializeMethodResponse (stream, null, (IMethodCallMessage)state);
|
||||
sinkStack.DispatchReplyMessage (replyMessage);
|
||||
}
|
||||
|
||||
public Stream GetRequestStream(IMessage msg,
|
||||
ITransportHeaders headers) =>
|
||||
// never called
|
||||
throw new NotSupportedException();
|
||||
|
||||
public void ProcessMessage(IMessage msg,
|
||||
ITransportHeaders requestHeaders,
|
||||
Stream requestStream,
|
||||
out ITransportHeaders responseHeaders,
|
||||
out Stream responseStream) =>
|
||||
// never called because the formatter sink is
|
||||
// always the first in the chain
|
||||
throw new NotSupportedException();
|
||||
|
||||
public IMessageCtrl AsyncProcessMessage (IMessage msg,
|
||||
IMessageSink replySink)
|
||||
{
|
||||
ITransportHeaders transportHeaders = new TransportHeaders();
|
||||
Stream stream = this._nextInChain.GetRequestStream(msg, transportHeaders);
|
||||
if (stream == null) {
|
||||
stream = new MemoryStream ();
|
||||
}
|
||||
|
||||
this._binaryCore.Serializer.Serialize (stream, msg, null);
|
||||
if (stream is MemoryStream) {
|
||||
stream.Position = 0;
|
||||
}
|
||||
|
||||
ClientChannelSinkStack stack = new ClientChannelSinkStack(replySink);
|
||||
stack.Push (this, msg);
|
||||
|
||||
this._nextInChain.AsyncProcessRequest (stack, msg, transportHeaders, stream);
|
||||
|
||||
public UnixBinaryClientFormatterSink (IClientChannelSink nextSink)
|
||||
{
|
||||
_nextInChain = nextSink;
|
||||
}
|
||||
// FIXME: No idea about how to implement IMessageCtrl
|
||||
return null;
|
||||
}
|
||||
|
||||
internal UnixBinaryCore BinaryCore
|
||||
{
|
||||
get { return _binaryCore; }
|
||||
set { _binaryCore = value; }
|
||||
}
|
||||
public IMessage SyncProcessMessage (IMessage msg)
|
||||
{
|
||||
try {
|
||||
|
||||
public IClientChannelSink NextChannelSink
|
||||
{
|
||||
get {
|
||||
return _nextInChain;
|
||||
}
|
||||
}
|
||||
ITransportHeaders call_headers = new TransportHeaders();
|
||||
call_headers["__RequestUri"] = ((IMethodCallMessage)msg).Uri;
|
||||
call_headers["Content-Type"] = "application/octet-stream";
|
||||
|
||||
public IMessageSink NextSink
|
||||
{
|
||||
get {
|
||||
// This is the last sink in the IMessageSink sink chain
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public IDictionary Properties
|
||||
{
|
||||
get {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void AsyncProcessRequest (IClientChannelSinkStack sinkStack,
|
||||
IMessage msg,
|
||||
ITransportHeaders headers,
|
||||
Stream stream)
|
||||
{
|
||||
// never called because the formatter sink is
|
||||
// always the first in the chain
|
||||
throw new NotSupportedException("UnixBinaryClientFormatterSink must be the first sink in the IClientChannelSink chain");
|
||||
}
|
||||
|
||||
public void AsyncProcessResponse (IClientResponseChannelSinkStack sinkStack,
|
||||
object state,
|
||||
ITransportHeaders headers,
|
||||
Stream stream)
|
||||
{
|
||||
IMessage replyMessage = (IMessage)_binaryCore.Deserializer.DeserializeMethodResponse (stream, null, (IMethodCallMessage)state);
|
||||
sinkStack.DispatchReplyMessage (replyMessage);
|
||||
}
|
||||
|
||||
public Stream GetRequestStream (IMessage msg,
|
||||
ITransportHeaders headers)
|
||||
{
|
||||
// never called
|
||||
throw new NotSupportedException ();
|
||||
}
|
||||
|
||||
public void ProcessMessage (IMessage msg,
|
||||
ITransportHeaders requestHeaders,
|
||||
Stream requestStream,
|
||||
out ITransportHeaders responseHeaders,
|
||||
out Stream responseStream)
|
||||
{
|
||||
// never called because the formatter sink is
|
||||
// always the first in the chain
|
||||
throw new NotSupportedException ();
|
||||
}
|
||||
|
||||
public IMessageCtrl AsyncProcessMessage (IMessage msg,
|
||||
IMessageSink replySink)
|
||||
{
|
||||
ITransportHeaders transportHeaders = new TransportHeaders();
|
||||
Stream stream = _nextInChain.GetRequestStream(msg, transportHeaders);
|
||||
if (stream == null) stream = new MemoryStream ();
|
||||
|
||||
_binaryCore.Serializer.Serialize (stream, msg, null);
|
||||
if (stream is MemoryStream) stream.Position = 0;
|
||||
|
||||
ClientChannelSinkStack stack = new ClientChannelSinkStack(replySink);
|
||||
stack.Push (this, msg);
|
||||
|
||||
_nextInChain.AsyncProcessRequest (stack, msg, transportHeaders, stream);
|
||||
|
||||
// FIXME: No idea about how to implement IMessageCtrl
|
||||
return null;
|
||||
}
|
||||
|
||||
public IMessage SyncProcessMessage (IMessage msg)
|
||||
{
|
||||
try {
|
||||
|
||||
ITransportHeaders call_headers = new TransportHeaders();
|
||||
call_headers["__RequestUri"] = ((IMethodCallMessage)msg).Uri;
|
||||
call_headers["Content-Type"] = "application/octet-stream";
|
||||
|
||||
Stream call_stream = _nextInChain.GetRequestStream(msg, call_headers);
|
||||
if (call_stream == null) call_stream = new MemoryStream ();
|
||||
|
||||
// Serialize msg to the stream
|
||||
|
||||
_binaryCore.Serializer.Serialize (call_stream, msg, null);
|
||||
if (call_stream is MemoryStream) call_stream.Position = 0;
|
||||
|
||||
Stream response_stream;
|
||||
ITransportHeaders response_headers;
|
||||
|
||||
_nextInChain.ProcessMessage (msg, call_headers, call_stream, out response_headers,
|
||||
out response_stream);
|
||||
|
||||
// Deserialize response_stream
|
||||
|
||||
return (IMessage) _binaryCore.Deserializer.DeserializeMethodResponse (response_stream, null, (IMethodCallMessage)msg);
|
||||
|
||||
} catch (Exception e) {
|
||||
return new ReturnMessage (e, (IMethodCallMessage)msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
Stream call_stream = this._nextInChain.GetRequestStream(msg, call_headers);
|
||||
if (call_stream == null) {
|
||||
call_stream = new MemoryStream ();
|
||||
}
|
||||
|
||||
// Serialize msg to the stream
|
||||
|
||||
this._binaryCore.Serializer.Serialize (call_stream, msg, null);
|
||||
if (call_stream is MemoryStream) {
|
||||
call_stream.Position = 0;
|
||||
}
|
||||
|
||||
|
||||
this._nextInChain.ProcessMessage(msg, call_headers, call_stream, out ITransportHeaders response_headers,
|
||||
out Stream response_stream);
|
||||
|
||||
// Deserialize response_stream
|
||||
|
||||
return (IMessage)this._binaryCore.Deserializer.DeserializeMethodResponse (response_stream, null, (IMethodCallMessage)msg);
|
||||
|
||||
} catch (Exception e) {
|
||||
return new ReturnMessage (e, (IMethodCallMessage)msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,48 +33,38 @@ using System.Runtime.Remoting.Channels;
|
||||
|
||||
namespace Mono.Remoting.Channels.Unix
|
||||
{
|
||||
internal class UnixBinaryClientFormatterSinkProvider: IClientFormatterSinkProvider, IClientChannelSinkProvider
|
||||
{
|
||||
IClientChannelSinkProvider next = null;
|
||||
UnixBinaryCore _binaryCore;
|
||||
static string[] allowedProperties = new string [] { "includeVersions", "strictBinding" };
|
||||
internal class UnixBinaryClientFormatterSinkProvider: IClientFormatterSinkProvider, IClientChannelSinkProvider
|
||||
{
|
||||
IClientChannelSinkProvider next = null;
|
||||
UnixBinaryCore _binaryCore;
|
||||
static System.String[] allowedProperties = new System.String[] { "includeVersions", "strictBinding" };
|
||||
|
||||
public UnixBinaryClientFormatterSinkProvider() => this._binaryCore = UnixBinaryCore.DefaultInstance;
|
||||
|
||||
public UnixBinaryClientFormatterSinkProvider(IDictionary properties,
|
||||
ICollection providerData) => this._binaryCore = new UnixBinaryCore(this, properties, allowedProperties);
|
||||
|
||||
public IClientChannelSinkProvider Next {
|
||||
get => this.next;
|
||||
|
||||
set => this.next = value;
|
||||
}
|
||||
|
||||
public IClientChannelSink CreateSink (IChannelSender channel,
|
||||
System.String url,
|
||||
System.Object remoteChannelData)
|
||||
{
|
||||
IClientChannelSink next_sink = null;
|
||||
UnixBinaryClientFormatterSink result;
|
||||
|
||||
if (this.next != null) {
|
||||
next_sink = this.next.CreateSink (channel, url, remoteChannelData);
|
||||
}
|
||||
|
||||
result = new UnixBinaryClientFormatterSink (next_sink);
|
||||
result.BinaryCore = this._binaryCore;
|
||||
|
||||
public UnixBinaryClientFormatterSinkProvider ()
|
||||
{
|
||||
_binaryCore = UnixBinaryCore.DefaultInstance;
|
||||
}
|
||||
|
||||
public UnixBinaryClientFormatterSinkProvider (IDictionary properties,
|
||||
ICollection providerData)
|
||||
{
|
||||
_binaryCore = new UnixBinaryCore (this, properties, allowedProperties);
|
||||
}
|
||||
|
||||
public IClientChannelSinkProvider Next
|
||||
{
|
||||
get {
|
||||
return next;
|
||||
}
|
||||
|
||||
set {
|
||||
next = value;
|
||||
}
|
||||
}
|
||||
|
||||
public IClientChannelSink CreateSink (IChannelSender channel,
|
||||
string url,
|
||||
object remoteChannelData)
|
||||
{
|
||||
IClientChannelSink next_sink = null;
|
||||
UnixBinaryClientFormatterSink result;
|
||||
|
||||
if (next != null)
|
||||
next_sink = next.CreateSink (channel, url, remoteChannelData);
|
||||
|
||||
result = new UnixBinaryClientFormatterSink (next_sink);
|
||||
result.BinaryCore = _binaryCore;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,114 +35,116 @@ using System.Runtime.Remoting.Messaging;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Runtime.Serialization.Formatters;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Mono.Remoting.Channels.Unix
|
||||
{
|
||||
internal class UnixBinaryCore
|
||||
{
|
||||
BinaryFormatter _serializationFormatter;
|
||||
BinaryFormatter _deserializationFormatter;
|
||||
bool _includeVersions = true;
|
||||
bool _strictBinding = false;
|
||||
IDictionary _properties;
|
||||
|
||||
public static UnixBinaryCore DefaultInstance = new UnixBinaryCore ();
|
||||
|
||||
public UnixBinaryCore (object owner, IDictionary properties, string[] allowedProperties)
|
||||
{
|
||||
_properties = properties;
|
||||
|
||||
foreach(DictionaryEntry property in properties)
|
||||
{
|
||||
string key = (string) property.Key;
|
||||
if (Array.IndexOf (allowedProperties, key) == -1)
|
||||
throw new RemotingException (owner.GetType().Name + " does not recognize '" + key + "' configuration property");
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case "includeVersions":
|
||||
_includeVersions = Convert.ToBoolean (property.Value);
|
||||
break;
|
||||
|
||||
case "strictBinding":
|
||||
_strictBinding = Convert.ToBoolean (property.Value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Init ();
|
||||
}
|
||||
|
||||
public UnixBinaryCore ()
|
||||
{
|
||||
_properties = new Hashtable ();
|
||||
Init ();
|
||||
}
|
||||
|
||||
public void Init ()
|
||||
{
|
||||
RemotingSurrogateSelector surrogateSelector = new RemotingSurrogateSelector ();
|
||||
StreamingContext context = new StreamingContext (StreamingContextStates.Remoting, null);
|
||||
internal class UnixBinaryCore
|
||||
{
|
||||
BinaryFormatter _serializationFormatter;
|
||||
BinaryFormatter _deserializationFormatter;
|
||||
Boolean _includeVersions = true;
|
||||
Boolean _strictBinding = false;
|
||||
IDictionary _properties;
|
||||
|
||||
public static UnixBinaryCore DefaultInstance = new UnixBinaryCore ();
|
||||
|
||||
public UnixBinaryCore (Object owner, IDictionary properties, String[] allowedProperties)
|
||||
{
|
||||
this._properties = properties;
|
||||
|
||||
foreach(DictionaryEntry property in properties)
|
||||
{
|
||||
String key = (String) property.Key;
|
||||
if (Array.IndexOf (allowedProperties, key) == -1) {
|
||||
throw new RemotingException (owner.GetType().Name + " does not recognize '" + key + "' configuration property");
|
||||
}
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case "includeVersions":
|
||||
this._includeVersions = Convert.ToBoolean (property.Value);
|
||||
break;
|
||||
|
||||
case "strictBinding":
|
||||
this._strictBinding = Convert.ToBoolean (property.Value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.Init ();
|
||||
}
|
||||
|
||||
public UnixBinaryCore ()
|
||||
{
|
||||
this._properties = new Hashtable ();
|
||||
this.Init ();
|
||||
}
|
||||
|
||||
public void Init ()
|
||||
{
|
||||
RemotingSurrogateSelector surrogateSelector = new RemotingSurrogateSelector ();
|
||||
StreamingContext context = new StreamingContext (StreamingContextStates.Remoting, null);
|
||||
|
||||
this._serializationFormatter = new BinaryFormatter (surrogateSelector, context);
|
||||
this._deserializationFormatter = new BinaryFormatter (null, context);
|
||||
|
||||
if (!this._includeVersions)
|
||||
{
|
||||
this._serializationFormatter.AssemblyFormat = FormatterAssemblyStyle.Simple;
|
||||
this._deserializationFormatter.AssemblyFormat = FormatterAssemblyStyle.Simple;
|
||||
}
|
||||
|
||||
_serializationFormatter = new BinaryFormatter (surrogateSelector, context);
|
||||
_deserializationFormatter = new BinaryFormatter (null, context);
|
||||
|
||||
if (!_includeVersions)
|
||||
{
|
||||
_serializationFormatter.AssemblyFormat = FormatterAssemblyStyle.Simple;
|
||||
_deserializationFormatter.AssemblyFormat = FormatterAssemblyStyle.Simple;
|
||||
}
|
||||
|
||||
if (!_strictBinding)
|
||||
{
|
||||
_serializationFormatter.Binder = SimpleBinder.Instance;
|
||||
_deserializationFormatter.Binder = SimpleBinder.Instance;
|
||||
}
|
||||
}
|
||||
|
||||
public BinaryFormatter Serializer
|
||||
{
|
||||
get { return _serializationFormatter; }
|
||||
}
|
||||
|
||||
public BinaryFormatter Deserializer
|
||||
{
|
||||
get { return _deserializationFormatter; }
|
||||
}
|
||||
|
||||
public IDictionary Properties
|
||||
{
|
||||
get { return _properties; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal class SimpleBinder: SerializationBinder
|
||||
{
|
||||
public static SimpleBinder Instance = new SimpleBinder ();
|
||||
|
||||
public override Type BindToType (String assemblyName, string typeName)
|
||||
{
|
||||
Assembly asm;
|
||||
|
||||
if (assemblyName.IndexOf (',') != -1)
|
||||
{
|
||||
// Try using the full name
|
||||
try
|
||||
{
|
||||
asm = Assembly.Load (assemblyName);
|
||||
if (asm == null) return null;
|
||||
Type t = asm.GetType (typeName);
|
||||
if (t != null) return t;
|
||||
}
|
||||
catch {}
|
||||
}
|
||||
|
||||
// Try using the simple name
|
||||
asm = Assembly.LoadWithPartialName (assemblyName);
|
||||
if (asm == null) return null;
|
||||
return asm.GetType (typeName, true);
|
||||
}
|
||||
}
|
||||
if (!this._strictBinding)
|
||||
{
|
||||
this._serializationFormatter.Binder = SimpleBinder.Instance;
|
||||
this._deserializationFormatter.Binder = SimpleBinder.Instance;
|
||||
}
|
||||
}
|
||||
|
||||
public BinaryFormatter Serializer => this._serializationFormatter;
|
||||
|
||||
public BinaryFormatter Deserializer => this._deserializationFormatter;
|
||||
|
||||
public IDictionary Properties => this._properties;
|
||||
}
|
||||
|
||||
|
||||
internal class SimpleBinder: SerializationBinder
|
||||
{
|
||||
public static SimpleBinder Instance = new SimpleBinder ();
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CS0618", Justification = "Someone do shit")]
|
||||
public override Type BindToType (String assemblyName, String typeName)
|
||||
{
|
||||
Assembly asm;
|
||||
|
||||
if (assemblyName.IndexOf (',') != -1)
|
||||
{
|
||||
// Try using the full name
|
||||
try
|
||||
{
|
||||
asm = Assembly.Load (assemblyName);
|
||||
if (asm == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Type t = asm.GetType (typeName);
|
||||
if (t != null) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
catch {}
|
||||
}
|
||||
|
||||
// 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 {
|
||||
|
||||
internal class UnixBinaryServerFormatterSink : IServerChannelSink, IChannelSinkBase
|
||||
{
|
||||
UnixBinaryCore _binaryCore = UnixBinaryCore.DefaultInstance;
|
||||
internal class UnixBinaryServerFormatterSink : IServerChannelSink, IChannelSinkBase
|
||||
{
|
||||
UnixBinaryCore _binaryCore = UnixBinaryCore.DefaultInstance;
|
||||
|
||||
IServerChannelSink next_sink;
|
||||
IChannelReceiver receiver;
|
||||
IServerChannelSink next_sink;
|
||||
IChannelReceiver receiver;
|
||||
|
||||
public UnixBinaryServerFormatterSink (IServerChannelSink nextSink, IChannelReceiver receiver)
|
||||
{
|
||||
this.next_sink = nextSink;
|
||||
this.receiver = receiver;
|
||||
}
|
||||
public UnixBinaryServerFormatterSink (IServerChannelSink nextSink, IChannelReceiver receiver)
|
||||
{
|
||||
this.next_sink = nextSink;
|
||||
this.receiver = receiver;
|
||||
}
|
||||
|
||||
internal UnixBinaryCore BinaryCore
|
||||
{
|
||||
get { return _binaryCore; }
|
||||
set { _binaryCore = value; }
|
||||
}
|
||||
|
||||
public IServerChannelSink NextChannelSink {
|
||||
get {
|
||||
return next_sink;
|
||||
}
|
||||
}
|
||||
internal UnixBinaryCore BinaryCore {
|
||||
get => this._binaryCore;
|
||||
set => this._binaryCore = value;
|
||||
}
|
||||
|
||||
public IServerChannelSink NextChannelSink => this.next_sink;
|
||||
|
||||
public IDictionary Properties => null;
|
||||
|
||||
public void AsyncProcessResponse (IServerResponseChannelSinkStack sinkStack, Object state,
|
||||
IMessage message, ITransportHeaders headers, Stream stream)
|
||||
{
|
||||
ITransportHeaders responseHeaders = new TransportHeaders();
|
||||
|
||||
public IDictionary Properties {
|
||||
get {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (sinkStack != null) {
|
||||
stream = sinkStack.GetResponseStream (message, responseHeaders);
|
||||
}
|
||||
|
||||
if (stream == null) {
|
||||
stream = new MemoryStream();
|
||||
}
|
||||
|
||||
this._binaryCore.Serializer.Serialize (stream, message, null);
|
||||
if (stream is MemoryStream) {
|
||||
stream.Position = 0;
|
||||
}
|
||||
|
||||
sinkStack.AsyncProcessResponse (message, responseHeaders, stream);
|
||||
}
|
||||
|
||||
public Stream GetResponseStream(IServerResponseChannelSinkStack sinkStack, Object state,
|
||||
IMessage msg, ITransportHeaders headers) => null;
|
||||
|
||||
public ServerProcessing ProcessMessage (IServerChannelSinkStack sinkStack,
|
||||
IMessage requestMsg, ITransportHeaders requestHeaders, Stream requestStream,
|
||||
out IMessage responseMsg, out ITransportHeaders responseHeaders, out Stream responseStream)
|
||||
{
|
||||
sinkStack.Push (this, null);
|
||||
ServerProcessing res;
|
||||
|
||||
public void AsyncProcessResponse (IServerResponseChannelSinkStack sinkStack, object state,
|
||||
IMessage message, ITransportHeaders headers, Stream stream)
|
||||
{
|
||||
ITransportHeaders responseHeaders = new TransportHeaders();
|
||||
try
|
||||
{
|
||||
String url = (String)requestHeaders["__RequestUri"];
|
||||
_ = this.receiver.Parse(url, out String uri);
|
||||
if (uri == null) {
|
||||
uri = url;
|
||||
}
|
||||
|
||||
MethodCallHeaderHandler mhh = new MethodCallHeaderHandler(uri);
|
||||
requestMsg = (IMessage)this._binaryCore.Deserializer.Deserialize (requestStream, new HeaderHandler(mhh.HandleHeaders));
|
||||
|
||||
if (sinkStack != null) stream = sinkStack.GetResponseStream (message, responseHeaders);
|
||||
if (stream == null) stream = new MemoryStream();
|
||||
res = this.next_sink.ProcessMessage (sinkStack, requestMsg, requestHeaders, null, out responseMsg, out responseHeaders, out responseStream);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseMsg = new ReturnMessage (ex, (IMethodCallMessage)requestMsg);
|
||||
res = ServerProcessing.Complete;
|
||||
responseHeaders = null;
|
||||
responseStream = null;
|
||||
}
|
||||
|
||||
if (res == ServerProcessing.Complete)
|
||||
{
|
||||
for (Int32 n =0; n<3; n++) {
|
||||
responseStream = null;
|
||||
responseHeaders = new TransportHeaders();
|
||||
|
||||
_binaryCore.Serializer.Serialize (stream, message, null);
|
||||
if (stream is MemoryStream) stream.Position = 0;
|
||||
if (sinkStack != null) {
|
||||
responseStream = sinkStack.GetResponseStream (responseMsg, responseHeaders);
|
||||
}
|
||||
|
||||
if (responseStream == null) {
|
||||
responseStream = new MemoryStream();
|
||||
}
|
||||
|
||||
try {
|
||||
this._binaryCore.Serializer.Serialize (responseStream, responseMsg);
|
||||
break;
|
||||
} catch (Exception ex) {
|
||||
if (n == 2) {
|
||||
throw ex;
|
||||
} else {
|
||||
responseMsg = new ReturnMessage (ex, (IMethodCallMessage)requestMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (responseStream is MemoryStream) {
|
||||
responseStream.Position = 0;
|
||||
}
|
||||
|
||||
_ = sinkStack.Pop(this);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
sinkStack.AsyncProcessResponse (message, responseHeaders, stream);
|
||||
}
|
||||
}
|
||||
|
||||
public Stream GetResponseStream (IServerResponseChannelSinkStack sinkStack, object state,
|
||||
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)
|
||||
{
|
||||
sinkStack.Push (this, null);
|
||||
ServerProcessing res;
|
||||
|
||||
try
|
||||
{
|
||||
string url = (string)requestHeaders["__RequestUri"];
|
||||
string uri;
|
||||
receiver.Parse (url, out uri);
|
||||
if (uri == null) uri = url;
|
||||
|
||||
MethodCallHeaderHandler mhh = new MethodCallHeaderHandler(uri);
|
||||
requestMsg = (IMessage) _binaryCore.Deserializer.Deserialize (requestStream, new HeaderHandler(mhh.HandleHeaders));
|
||||
|
||||
res = next_sink.ProcessMessage (sinkStack, requestMsg, requestHeaders, null, out responseMsg, out responseHeaders, out responseStream);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
responseMsg = new ReturnMessage (ex, (IMethodCallMessage)requestMsg);
|
||||
res = ServerProcessing.Complete;
|
||||
responseHeaders = null;
|
||||
responseStream = null;
|
||||
}
|
||||
|
||||
if (res == ServerProcessing.Complete)
|
||||
{
|
||||
for (int n=0; n<3; n++) {
|
||||
responseStream = null;
|
||||
responseHeaders = new TransportHeaders();
|
||||
|
||||
if (sinkStack != null) responseStream = sinkStack.GetResponseStream (responseMsg, responseHeaders);
|
||||
if (responseStream == null) responseStream = new MemoryStream();
|
||||
|
||||
try {
|
||||
_binaryCore.Serializer.Serialize (responseStream, responseMsg);
|
||||
break;
|
||||
} catch (Exception ex) {
|
||||
if (n == 2) throw ex;
|
||||
else responseMsg = new ReturnMessage (ex, (IMethodCallMessage)requestMsg);
|
||||
}
|
||||
}
|
||||
|
||||
if (responseStream is MemoryStream) responseStream.Position = 0;
|
||||
|
||||
|
||||
sinkStack.Pop (this);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal class MethodCallHeaderHandler
|
||||
{
|
||||
string _uri;
|
||||
|
||||
public MethodCallHeaderHandler (string uri)
|
||||
{
|
||||
_uri = uri;
|
||||
}
|
||||
|
||||
public object HandleHeaders (Header[] headers)
|
||||
{
|
||||
return _uri;
|
||||
}
|
||||
}
|
||||
internal class MethodCallHeaderHandler
|
||||
{
|
||||
String _uri;
|
||||
|
||||
public MethodCallHeaderHandler(String uri) => this._uri = uri;
|
||||
|
||||
public Object HandleHeaders(Header[] headers) => this._uri;
|
||||
}
|
||||
}
|
||||
|
@ -35,51 +35,41 @@ using System.Runtime.Remoting.Channels;
|
||||
|
||||
namespace Mono.Remoting.Channels.Unix
|
||||
{
|
||||
internal class UnixBinaryServerFormatterSinkProvider: IServerFormatterSinkProvider, IServerChannelSinkProvider
|
||||
{
|
||||
IServerChannelSinkProvider next = null;
|
||||
UnixBinaryCore _binaryCore;
|
||||
|
||||
internal static string[] AllowedProperties = new string [] { "includeVersions", "strictBinding" };
|
||||
internal class UnixBinaryServerFormatterSinkProvider: IServerFormatterSinkProvider, IServerChannelSinkProvider
|
||||
{
|
||||
IServerChannelSinkProvider next = null;
|
||||
UnixBinaryCore _binaryCore;
|
||||
|
||||
internal static System.String[] AllowedProperties = new System.String[] { "includeVersions", "strictBinding" };
|
||||
|
||||
public UnixBinaryServerFormatterSinkProvider() => this._binaryCore = UnixBinaryCore.DefaultInstance;
|
||||
|
||||
public UnixBinaryServerFormatterSinkProvider(IDictionary properties, ICollection providerData) => this._binaryCore = new UnixBinaryCore(this, properties, AllowedProperties);
|
||||
|
||||
public IServerChannelSinkProvider Next {
|
||||
get => this.next;
|
||||
|
||||
set => this.next = value;
|
||||
}
|
||||
|
||||
public IServerChannelSink CreateSink (IChannelReceiver channel)
|
||||
{
|
||||
IServerChannelSink next_sink = null;
|
||||
UnixBinaryServerFormatterSink result;
|
||||
|
||||
if (this.next != null) {
|
||||
next_sink = this.next.CreateSink (channel);
|
||||
}
|
||||
|
||||
result = new UnixBinaryServerFormatterSink (next_sink, channel);
|
||||
|
||||
public UnixBinaryServerFormatterSinkProvider ()
|
||||
{
|
||||
_binaryCore = UnixBinaryCore.DefaultInstance;
|
||||
}
|
||||
result.BinaryCore = this._binaryCore;
|
||||
return result;
|
||||
}
|
||||
|
||||
public UnixBinaryServerFormatterSinkProvider (IDictionary properties, ICollection providerData)
|
||||
{
|
||||
_binaryCore = new UnixBinaryCore (this, properties, AllowedProperties);
|
||||
}
|
||||
|
||||
public IServerChannelSinkProvider Next
|
||||
{
|
||||
get {
|
||||
return next;
|
||||
}
|
||||
|
||||
set {
|
||||
next = value;
|
||||
}
|
||||
}
|
||||
|
||||
public IServerChannelSink CreateSink (IChannelReceiver channel)
|
||||
{
|
||||
IServerChannelSink next_sink = null;
|
||||
UnixBinaryServerFormatterSink result;
|
||||
|
||||
if (next != null)
|
||||
next_sink = next.CreateSink (channel);
|
||||
|
||||
result = new UnixBinaryServerFormatterSink (next_sink, channel);
|
||||
|
||||
result.BinaryCore = _binaryCore;
|
||||
return result;
|
||||
}
|
||||
|
||||
public void GetChannelData (IChannelDataStore channelData)
|
||||
{
|
||||
// Nothing to add here
|
||||
}
|
||||
}
|
||||
public void GetChannelData (IChannelDataStore channelData)
|
||||
{
|
||||
// Nothing to add here
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,104 +40,109 @@ namespace Mono.Remoting.Channels.Unix
|
||||
{
|
||||
private UnixClientChannel _clientChannel;
|
||||
private UnixServerChannel _serverChannel = null;
|
||||
private string _name = "unix";
|
||||
private int _priority = 1;
|
||||
private String _name = "unix";
|
||||
private Int32 _priority = 1;
|
||||
|
||||
public UnixChannel (): this (null)
|
||||
{
|
||||
}
|
||||
|
||||
public UnixChannel (string path)
|
||||
public UnixChannel (String path)
|
||||
{
|
||||
Hashtable ht = new Hashtable();
|
||||
ht["path"] = path;
|
||||
Init(ht, null, null);
|
||||
ht["path"] = path;
|
||||
this.Init(ht, null, null);
|
||||
}
|
||||
|
||||
void Init (IDictionary properties, IClientChannelSinkProvider clientSink, IServerChannelSinkProvider serverSink)
|
||||
{
|
||||
this._clientChannel = new UnixClientChannel (properties,clientSink);
|
||||
|
||||
if(properties["path"] != null) {
|
||||
this._serverChannel = new UnixServerChannel(properties, serverSink);
|
||||
}
|
||||
|
||||
Object val = properties ["name"];
|
||||
if (val != null) {
|
||||
this._name = val as String;
|
||||
}
|
||||
|
||||
val = properties ["priority"];
|
||||
if (val != null) {
|
||||
this._priority = Convert.ToInt32 (val);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public UnixChannel(IDictionary properties,
|
||||
IClientChannelSinkProvider clientSinkProvider,
|
||||
IServerChannelSinkProvider serverSinkProvider) => this.Init(properties, clientSinkProvider, serverSinkProvider);
|
||||
|
||||
public IMessageSink CreateMessageSink(String url, Object remoteChannelData, out String objectURI) => this._clientChannel.CreateMessageSink(url, remoteChannelData, out objectURI);
|
||||
|
||||
public String ChannelName => this._name;
|
||||
|
||||
public Int32 ChannelPriority => this._priority;
|
||||
|
||||
public void StartListening (Object data)
|
||||
{
|
||||
_clientChannel = new UnixClientChannel (properties,clientSink);
|
||||
|
||||
if(properties["path"] != null)
|
||||
_serverChannel = new UnixServerChannel(properties, serverSink);
|
||||
|
||||
object val = properties ["name"];
|
||||
if (val != null) _name = val as string;
|
||||
|
||||
val = properties ["priority"];
|
||||
if (val != null) _priority = Convert.ToInt32 (val);
|
||||
}
|
||||
|
||||
|
||||
public UnixChannel (IDictionary properties,
|
||||
IClientChannelSinkProvider clientSinkProvider,
|
||||
IServerChannelSinkProvider serverSinkProvider)
|
||||
{
|
||||
Init (properties, clientSinkProvider, serverSinkProvider);
|
||||
}
|
||||
|
||||
public IMessageSink CreateMessageSink(string url, object remoteChannelData, out string objectURI)
|
||||
{
|
||||
return _clientChannel.CreateMessageSink(url, remoteChannelData, out objectURI);
|
||||
}
|
||||
|
||||
public string ChannelName
|
||||
{
|
||||
get { return _name; }
|
||||
}
|
||||
|
||||
public int ChannelPriority
|
||||
{
|
||||
get { return _priority; }
|
||||
}
|
||||
|
||||
public void StartListening (object data)
|
||||
{
|
||||
if (_serverChannel != null) _serverChannel.StartListening (data);
|
||||
}
|
||||
if (this._serverChannel != null) {
|
||||
this._serverChannel.StartListening (data);
|
||||
}
|
||||
}
|
||||
|
||||
public void StopListening (object data)
|
||||
public void StopListening (Object data)
|
||||
{
|
||||
if (_serverChannel != null) _serverChannel.StopListening(data);
|
||||
}
|
||||
if (this._serverChannel != null) {
|
||||
this._serverChannel.StopListening(data);
|
||||
}
|
||||
}
|
||||
|
||||
public string[] GetUrlsForUri (string uri)
|
||||
public String[] GetUrlsForUri (String uri)
|
||||
{
|
||||
if (_serverChannel != null) return _serverChannel.GetUrlsForUri(uri);
|
||||
else return null;
|
||||
}
|
||||
if (this._serverChannel != null) {
|
||||
return this._serverChannel.GetUrlsForUri(uri);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public object ChannelData
|
||||
public Object ChannelData
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_serverChannel != null) return _serverChannel.ChannelData;
|
||||
else return null;
|
||||
}
|
||||
}
|
||||
|
||||
public string Parse (string url, out string objectURI)
|
||||
{
|
||||
return UnixChannel.ParseUnixURL (url, out objectURI);
|
||||
}
|
||||
|
||||
internal static string ParseUnixURL (string url, out string objectURI)
|
||||
if (this._serverChannel != null) {
|
||||
return this._serverChannel.ChannelData;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String Parse(String url, out String objectURI) => UnixChannel.ParseUnixURL(url, out objectURI);
|
||||
|
||||
internal static String ParseUnixURL (String url, out String objectURI)
|
||||
{
|
||||
// format: "unix:///path/to/unix/socket?/path/to/object"
|
||||
|
||||
|
||||
objectURI = null;
|
||||
|
||||
if (!url.StartsWith ("unix://")) return null;
|
||||
|
||||
int i = url.IndexOf ('?');
|
||||
if (i == -1) return url.Substring (7);
|
||||
|
||||
objectURI = url.Substring (i+1);
|
||||
|
||||
if (objectURI.Length == 0)
|
||||
objectURI = null;
|
||||
|
||||
return url.Substring (7, i - 7);
|
||||
|
||||
if (!url.StartsWith ("unix://")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Int32 i = url.IndexOf ('?');
|
||||
if (i == -1) {
|
||||
return url.Substring (7);
|
||||
}
|
||||
|
||||
objectURI = url.Substring (i+1);
|
||||
|
||||
if (objectURI.Length == 0) {
|
||||
objectURI = null;
|
||||
}
|
||||
|
||||
return url.Substring (7, i - 7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,96 +39,95 @@ using System.Threading;
|
||||
namespace Mono.Remoting.Channels.Unix
|
||||
{
|
||||
public class UnixClientChannel : IChannelSender, IChannel
|
||||
{
|
||||
int priority = 1;
|
||||
string name = "unix";
|
||||
{
|
||||
Int32 priority = 1;
|
||||
String name = "unix";
|
||||
IClientChannelSinkProvider _sinkProvider;
|
||||
|
||||
public UnixClientChannel ()
|
||||
{
|
||||
_sinkProvider = new UnixBinaryClientFormatterSinkProvider ();
|
||||
_sinkProvider.Next = new UnixClientTransportSinkProvider ();
|
||||
{
|
||||
this._sinkProvider = new UnixBinaryClientFormatterSinkProvider ();
|
||||
this._sinkProvider.Next = new UnixClientTransportSinkProvider ();
|
||||
}
|
||||
|
||||
public UnixClientChannel (IDictionary properties, IClientChannelSinkProvider sinkProvider)
|
||||
{
|
||||
object val = properties ["name"];
|
||||
if (val != null) name = val as string;
|
||||
|
||||
val = properties ["priority"];
|
||||
if (val != null) priority = Convert.ToInt32 (val);
|
||||
|
||||
if (sinkProvider != null)
|
||||
{
|
||||
_sinkProvider = sinkProvider;
|
||||
{
|
||||
Object val = properties ["name"];
|
||||
if (val != null) {
|
||||
this.name = val as String;
|
||||
}
|
||||
|
||||
val = properties ["priority"];
|
||||
if (val != null) {
|
||||
this.priority = Convert.ToInt32 (val);
|
||||
}
|
||||
|
||||
if (sinkProvider != null)
|
||||
{
|
||||
this._sinkProvider = sinkProvider;
|
||||
|
||||
// add the unix provider at the end of the chain
|
||||
IClientChannelSinkProvider prov = sinkProvider;
|
||||
while (prov.Next != null) prov = prov.Next;
|
||||
prov.Next = new UnixClientTransportSinkProvider ();
|
||||
while (prov.Next != null) {
|
||||
prov = prov.Next;
|
||||
}
|
||||
|
||||
prov.Next = new UnixClientTransportSinkProvider ();
|
||||
|
||||
// Note: a default formatter is added only when
|
||||
// no sink providers are specified in the config file.
|
||||
}
|
||||
else
|
||||
{
|
||||
_sinkProvider = new UnixBinaryClientFormatterSinkProvider ();
|
||||
_sinkProvider.Next = new UnixClientTransportSinkProvider ();
|
||||
{
|
||||
this._sinkProvider = new UnixBinaryClientFormatterSinkProvider ();
|
||||
this._sinkProvider.Next = new UnixClientTransportSinkProvider ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public UnixClientChannel (string name, IClientChannelSinkProvider sinkProvider)
|
||||
public UnixClientChannel (String name, IClientChannelSinkProvider sinkProvider)
|
||||
{
|
||||
this.name = name;
|
||||
_sinkProvider = sinkProvider;
|
||||
this.name = name;
|
||||
this._sinkProvider = sinkProvider;
|
||||
|
||||
// add the unix provider at the end of the chain
|
||||
IClientChannelSinkProvider prov = sinkProvider;
|
||||
while (prov.Next != null) prov = prov.Next;
|
||||
prov.Next = new UnixClientTransportSinkProvider ();
|
||||
}
|
||||
|
||||
public string ChannelName
|
||||
while (prov.Next != null) {
|
||||
prov = prov.Next;
|
||||
}
|
||||
|
||||
prov.Next = new UnixClientTransportSinkProvider ();
|
||||
}
|
||||
|
||||
public String ChannelName => this.name;
|
||||
|
||||
public Int32 ChannelPriority => this.priority;
|
||||
|
||||
public IMessageSink CreateMessageSink (String url,
|
||||
Object remoteChannelData,
|
||||
out String objectURI)
|
||||
{
|
||||
get {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
public int ChannelPriority
|
||||
{
|
||||
get {
|
||||
return priority;
|
||||
}
|
||||
}
|
||||
|
||||
public IMessageSink CreateMessageSink (string url,
|
||||
object remoteChannelData,
|
||||
out string objectURI)
|
||||
{
|
||||
if (url != null && Parse (url, out objectURI) != null)
|
||||
return (IMessageSink) _sinkProvider.CreateSink (this, url, remoteChannelData);
|
||||
|
||||
if (remoteChannelData != null) {
|
||||
if (url != null && this.Parse (url, out objectURI) != null) {
|
||||
return (IMessageSink)this._sinkProvider.CreateSink (this, url, remoteChannelData);
|
||||
}
|
||||
|
||||
if (remoteChannelData != null) {
|
||||
IChannelDataStore ds = remoteChannelData as IChannelDataStore;
|
||||
if (ds != null && ds.ChannelUris.Length > 0)
|
||||
url = ds.ChannelUris [0];
|
||||
else {
|
||||
if (ds != null && ds.ChannelUris.Length > 0) {
|
||||
url = ds.ChannelUris [0];
|
||||
} else {
|
||||
objectURI = null;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (Parse (url, out objectURI) == null)
|
||||
return null;
|
||||
|
||||
return (IMessageSink) _sinkProvider.CreateSink (this, url, remoteChannelData);
|
||||
}
|
||||
|
||||
public string Parse (string url, out string objectURI)
|
||||
{
|
||||
return UnixChannel.ParseUnixURL (url, out objectURI);
|
||||
}
|
||||
}
|
||||
if (this.Parse (url, out objectURI) == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (IMessageSink)this._sinkProvider.CreateSink (this, url, remoteChannelData);
|
||||
}
|
||||
|
||||
public String Parse(String url, out String objectURI) => UnixChannel.ParseUnixURL(url, out objectURI);
|
||||
}
|
||||
}
|
||||
|
@ -38,156 +38,156 @@ using System.Runtime.Remoting;
|
||||
|
||||
namespace Mono.Remoting.Channels.Unix
|
||||
{
|
||||
internal class UnixClientTransportSink : IClientChannelSink
|
||||
{
|
||||
string _path;
|
||||
|
||||
public UnixClientTransportSink (string url)
|
||||
{
|
||||
string objectUri;
|
||||
_path = UnixChannel.ParseUnixURL (url, out objectUri);
|
||||
}
|
||||
internal class UnixClientTransportSink : IClientChannelSink
|
||||
{
|
||||
String _path;
|
||||
|
||||
public UnixClientTransportSink (String url)
|
||||
{
|
||||
this._path = UnixChannel.ParseUnixURL(url, out String objectUri);
|
||||
}
|
||||
|
||||
public IDictionary Properties => null;
|
||||
|
||||
public IClientChannelSink NextChannelSink =>
|
||||
// we are the last one
|
||||
null;
|
||||
|
||||
public void AsyncProcessRequest (IClientChannelSinkStack sinkStack, IMessage msg,
|
||||
ITransportHeaders headers, Stream requestStream)
|
||||
{
|
||||
UnixConnection connection = null;
|
||||
Boolean isOneWay = RemotingServices.IsOneWay (((IMethodMessage)msg).MethodBase);
|
||||
|
||||
public IDictionary Properties
|
||||
{
|
||||
get
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
if (headers == null) {
|
||||
headers = new TransportHeaders();
|
||||
}
|
||||
|
||||
headers ["__RequestUri"] = ((IMethodMessage)msg).Uri;
|
||||
|
||||
// Sends the stream using a connection from the pool
|
||||
// and creates a WorkItem that will wait for the
|
||||
// response of the server
|
||||
|
||||
public IClientChannelSink NextChannelSink
|
||||
{
|
||||
get
|
||||
{
|
||||
// we are the last one
|
||||
return null;
|
||||
}
|
||||
}
|
||||
connection = UnixConnectionPool.GetConnection (this._path);
|
||||
UnixMessageIO.SendMessageStream (connection.Stream, requestStream, headers, connection.Buffer);
|
||||
connection.Stream.Flush ();
|
||||
|
||||
public void AsyncProcessRequest (IClientChannelSinkStack sinkStack, IMessage msg,
|
||||
ITransportHeaders headers, Stream requestStream)
|
||||
{
|
||||
UnixConnection connection = null;
|
||||
bool isOneWay = RemotingServices.IsOneWay (((IMethodMessage)msg).MethodBase);
|
||||
if (!isOneWay)
|
||||
{
|
||||
sinkStack.Push (this, connection);
|
||||
_ = ThreadPool.QueueUserWorkItem(new WaitCallback(data => {
|
||||
try {
|
||||
this.ReadAsyncUnixMessage(data);
|
||||
} catch { }
|
||||
}), sinkStack);
|
||||
}
|
||||
else {
|
||||
connection.Release();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (connection != null) {
|
||||
connection.Release();
|
||||
}
|
||||
|
||||
if (!isOneWay) {
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (headers == null) headers = new TransportHeaders();
|
||||
headers ["__RequestUri"] = ((IMethodMessage)msg).Uri;
|
||||
|
||||
// Sends the stream using a connection from the pool
|
||||
// and creates a WorkItem that will wait for the
|
||||
// response of the server
|
||||
private void ReadAsyncUnixMessage(Object data)
|
||||
{
|
||||
// This method is called by a new thread to asynchronously
|
||||
// read the response to a request
|
||||
|
||||
connection = UnixConnectionPool.GetConnection (_path);
|
||||
UnixMessageIO.SendMessageStream (connection.Stream, requestStream, headers, connection.Buffer);
|
||||
connection.Stream.Flush ();
|
||||
// The stack was provided as state data in QueueUserWorkItem
|
||||
IClientChannelSinkStack stack = (IClientChannelSinkStack)data;
|
||||
|
||||
if (!isOneWay)
|
||||
{
|
||||
sinkStack.Push (this, connection);
|
||||
ThreadPool.QueueUserWorkItem (new WaitCallback(data => {
|
||||
try {
|
||||
ReadAsyncUnixMessage (data);
|
||||
} catch {}
|
||||
}), sinkStack);
|
||||
}
|
||||
else
|
||||
connection.Release();
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (connection != null) connection.Release();
|
||||
if (!isOneWay) throw;
|
||||
}
|
||||
}
|
||||
// The first sink in the stack is this sink. Pop it and
|
||||
// get the status data, which is the UnixConnection used to send
|
||||
// the request
|
||||
UnixConnection connection = (UnixConnection)stack.Pop(this);
|
||||
|
||||
private void ReadAsyncUnixMessage(object data)
|
||||
{
|
||||
// This method is called by a new thread to asynchronously
|
||||
// read the response to a request
|
||||
try
|
||||
{
|
||||
|
||||
// Read the response, blocking if necessary
|
||||
MessageStatus status = UnixMessageIO.ReceiveMessageStatus(connection.Stream, connection.Buffer);
|
||||
|
||||
if (status != MessageStatus.MethodMessage) {
|
||||
throw new RemotingException ("Unknown response message from server");
|
||||
}
|
||||
|
||||
Stream responseStream = UnixMessageIO.ReceiveMessageStream (connection.Stream, out ITransportHeaders responseHeaders, connection.Buffer);
|
||||
|
||||
// The stack was provided as state data in QueueUserWorkItem
|
||||
IClientChannelSinkStack stack = (IClientChannelSinkStack)data;
|
||||
// Free the connection, so it can be reused
|
||||
connection.Release();
|
||||
connection = null;
|
||||
|
||||
// The first sink in the stack is this sink. Pop it and
|
||||
// get the status data, which is the UnixConnection used to send
|
||||
// the request
|
||||
UnixConnection connection = (UnixConnection)stack.Pop(this);
|
||||
// Ok, proceed with the other sinks
|
||||
stack.AsyncProcessResponse (responseHeaders, responseStream);
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (connection != null) {
|
||||
connection.Release();
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void AsyncProcessResponse(IClientResponseChannelSinkStack sinkStack,
|
||||
Object state, ITransportHeaders headers,
|
||||
Stream stream) =>
|
||||
// Should never be called
|
||||
throw new NotSupportedException();
|
||||
|
||||
public Stream GetRequestStream(IMessage msg, ITransportHeaders headers) => null;
|
||||
|
||||
public void ProcessMessage (IMessage msg,
|
||||
ITransportHeaders requestHeaders,
|
||||
Stream requestStream,
|
||||
out ITransportHeaders responseHeaders,
|
||||
out Stream responseStream)
|
||||
{
|
||||
UnixConnection connection = null;
|
||||
try
|
||||
{
|
||||
if (requestHeaders == null) {
|
||||
requestHeaders = new TransportHeaders();
|
||||
}
|
||||
|
||||
requestHeaders ["__RequestUri"] = ((IMethodMessage)msg).Uri;
|
||||
|
||||
// Sends the message
|
||||
connection = UnixConnectionPool.GetConnection (this._path);
|
||||
UnixMessageIO.SendMessageStream (connection.Stream, requestStream, requestHeaders, connection.Buffer);
|
||||
connection.Stream.Flush ();
|
||||
|
||||
try
|
||||
{
|
||||
ITransportHeaders responseHeaders;
|
||||
// Reads the response
|
||||
MessageStatus status = UnixMessageIO.ReceiveMessageStatus (connection.Stream, connection.Buffer);
|
||||
|
||||
// Read the response, blocking if necessary
|
||||
MessageStatus status = UnixMessageIO.ReceiveMessageStatus (connection.Stream, connection.Buffer);
|
||||
if (status != MessageStatus.MethodMessage) {
|
||||
throw new RemotingException ("Unknown response message from server");
|
||||
}
|
||||
|
||||
responseStream = UnixMessageIO.ReceiveMessageStream (connection.Stream, out responseHeaders, connection.Buffer);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (connection != null) {
|
||||
connection.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (status != MessageStatus.MethodMessage)
|
||||
throw new RemotingException ("Unknown response message from server");
|
||||
|
||||
Stream responseStream = UnixMessageIO.ReceiveMessageStream (connection.Stream, out responseHeaders, connection.Buffer);
|
||||
|
||||
// Free the connection, so it can be reused
|
||||
connection.Release();
|
||||
connection = null;
|
||||
|
||||
// Ok, proceed with the other sinks
|
||||
stack.AsyncProcessResponse (responseHeaders, responseStream);
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (connection != null) connection.Release();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void AsyncProcessResponse (IClientResponseChannelSinkStack sinkStack,
|
||||
object state, ITransportHeaders headers,
|
||||
Stream stream)
|
||||
{
|
||||
// Should never be called
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public Stream GetRequestStream (IMessage msg, ITransportHeaders headers)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public void ProcessMessage (IMessage msg,
|
||||
ITransportHeaders requestHeaders,
|
||||
Stream requestStream,
|
||||
out ITransportHeaders responseHeaders,
|
||||
out Stream responseStream)
|
||||
{
|
||||
UnixConnection connection = null;
|
||||
try
|
||||
{
|
||||
if (requestHeaders == null) requestHeaders = new TransportHeaders();
|
||||
requestHeaders ["__RequestUri"] = ((IMethodMessage)msg).Uri;
|
||||
|
||||
// Sends the message
|
||||
connection = UnixConnectionPool.GetConnection (_path);
|
||||
UnixMessageIO.SendMessageStream (connection.Stream, requestStream, requestHeaders, connection.Buffer);
|
||||
connection.Stream.Flush ();
|
||||
|
||||
// Reads the response
|
||||
MessageStatus status = UnixMessageIO.ReceiveMessageStatus (connection.Stream, connection.Buffer);
|
||||
|
||||
if (status != MessageStatus.MethodMessage)
|
||||
throw new RemotingException ("Unknown response message from server");
|
||||
|
||||
responseStream = UnixMessageIO.ReceiveMessageStream (connection.Stream, out responseHeaders, connection.Buffer);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (connection != null)
|
||||
connection.Release();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -40,23 +40,15 @@ namespace Mono.Remoting.Channels.Unix
|
||||
// what should we do here ?
|
||||
}
|
||||
|
||||
public IClientChannelSinkProvider Next
|
||||
{
|
||||
get
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
// ignore, we are always the last in the chain
|
||||
}
|
||||
}
|
||||
|
||||
public IClientChannelSink CreateSink (IChannelSender channel, string url,
|
||||
object remoteChannelData)
|
||||
{
|
||||
return new UnixClientTransportSink (url);
|
||||
}
|
||||
}
|
||||
public IClientChannelSinkProvider Next {
|
||||
get => null;
|
||||
|
||||
set {
|
||||
// ignore, we are always the last in the chain
|
||||
}
|
||||
}
|
||||
|
||||
public IClientChannelSink CreateSink(IChannelSender channel, String url,
|
||||
Object remoteChannelData) => new UnixClientTransportSink(url);
|
||||
}
|
||||
}
|
||||
|
@ -37,275 +37,254 @@ using Mono.Unix;
|
||||
|
||||
namespace Mono.Remoting.Channels.Unix
|
||||
{
|
||||
// This is a pool of Unix connections. Connections requested
|
||||
// by the TCP channel are pooled after their use, and can
|
||||
// be reused later. Connections are automaticaly closed
|
||||
// if not used after some time, specified in KeepAliveSeconds.
|
||||
// The number of allowed open connections can also be specified
|
||||
// in MaxOpenConnections. The limit is per host.
|
||||
// If a thread requests a connection and the limit has been
|
||||
// reached, the thread is suspended until one is released.
|
||||
// This is a pool of Unix connections. Connections requested
|
||||
// by the TCP channel are pooled after their use, and can
|
||||
// be reused later. Connections are automaticaly closed
|
||||
// if not used after some time, specified in KeepAliveSeconds.
|
||||
// The number of allowed open connections can also be specified
|
||||
// in MaxOpenConnections. The limit is per host.
|
||||
// If a thread requests a connection and the limit has been
|
||||
// reached, the thread is suspended until one is released.
|
||||
|
||||
internal class UnixConnectionPool
|
||||
{
|
||||
// Table of pools. There is a HostConnectionPool
|
||||
// instance for each host
|
||||
static Hashtable _pools = new Hashtable();
|
||||
internal class UnixConnectionPool
|
||||
{
|
||||
// Table of pools. There is a HostConnectionPool
|
||||
// instance for each host
|
||||
static Hashtable _pools = new Hashtable();
|
||||
|
||||
static int _maxOpenConnections = int.MaxValue;
|
||||
static int _keepAliveSeconds = 15;
|
||||
static Int32 _maxOpenConnections = Int32.MaxValue;
|
||||
static Int32 _keepAliveSeconds = 15;
|
||||
|
||||
static Thread _poolThread;
|
||||
static Thread _poolThread;
|
||||
|
||||
static UnixConnectionPool()
|
||||
{
|
||||
// This thread will close unused connections
|
||||
_poolThread = new Thread (new ThreadStart (ConnectionCollector));
|
||||
_poolThread.Start();
|
||||
_poolThread.IsBackground = true;
|
||||
}
|
||||
static UnixConnectionPool()
|
||||
{
|
||||
// This thread will close unused connections
|
||||
_poolThread = new Thread (new ThreadStart (ConnectionCollector));
|
||||
_poolThread.Start();
|
||||
_poolThread.IsBackground = true;
|
||||
}
|
||||
|
||||
public static void Shutdown ()
|
||||
{
|
||||
if (_poolThread != null)
|
||||
_poolThread.Abort();
|
||||
}
|
||||
public static void Shutdown ()
|
||||
{
|
||||
if (_poolThread != null) {
|
||||
_poolThread.Abort();
|
||||
}
|
||||
}
|
||||
|
||||
public static int MaxOpenConnections
|
||||
{
|
||||
get { return _maxOpenConnections; }
|
||||
set
|
||||
{
|
||||
if (value < 1) throw new RemotingException ("MaxOpenConnections must be greater than zero");
|
||||
_maxOpenConnections = value;
|
||||
}
|
||||
}
|
||||
public static Int32 MaxOpenConnections {
|
||||
get => _maxOpenConnections;
|
||||
set {
|
||||
if(value < 1) {
|
||||
throw new RemotingException("MaxOpenConnections must be greater than zero");
|
||||
}
|
||||
|
||||
public static int KeepAliveSeconds
|
||||
{
|
||||
get { return _keepAliveSeconds; }
|
||||
set { _keepAliveSeconds = value; }
|
||||
}
|
||||
_maxOpenConnections = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static UnixConnection GetConnection (string path)
|
||||
{
|
||||
HostConnectionPool hostPool;
|
||||
public static Int32 KeepAliveSeconds {
|
||||
get => _keepAliveSeconds;
|
||||
set => _keepAliveSeconds = value;
|
||||
}
|
||||
|
||||
lock (_pools)
|
||||
{
|
||||
hostPool = (HostConnectionPool) _pools[path];
|
||||
if (hostPool == null)
|
||||
{
|
||||
hostPool = new HostConnectionPool(path);
|
||||
_pools[path] = hostPool;
|
||||
}
|
||||
}
|
||||
public static UnixConnection GetConnection (String path)
|
||||
{
|
||||
HostConnectionPool hostPool;
|
||||
|
||||
return hostPool.GetConnection();
|
||||
}
|
||||
lock (_pools)
|
||||
{
|
||||
hostPool = (HostConnectionPool) _pools[path];
|
||||
if (hostPool == null)
|
||||
{
|
||||
hostPool = new HostConnectionPool(path);
|
||||
_pools[path] = hostPool;
|
||||
}
|
||||
}
|
||||
|
||||
private static void ConnectionCollector ()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
Thread.Sleep(3000);
|
||||
lock (_pools)
|
||||
{
|
||||
ICollection values = _pools.Values;
|
||||
foreach (HostConnectionPool pool in values)
|
||||
pool.PurgeConnections();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return hostPool.GetConnection();
|
||||
}
|
||||
|
||||
internal class ReusableUnixClient : UnixClient
|
||||
{
|
||||
public ReusableUnixClient (string path): base (path)
|
||||
{
|
||||
}
|
||||
|
||||
public bool IsAlive
|
||||
{
|
||||
get
|
||||
{
|
||||
// This Poll will return true if there is data pending to
|
||||
// be read. It prob. means that a client object using this
|
||||
// connection got an exception and did not finish to read
|
||||
// the data. It can also mean that the connection has been
|
||||
// closed in the server. In both cases, the connection cannot
|
||||
// be reused.
|
||||
return !Client.Poll (0, SelectMode.SelectRead);
|
||||
}
|
||||
}
|
||||
}
|
||||
private static void ConnectionCollector ()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
Thread.Sleep(3000);
|
||||
lock (_pools)
|
||||
{
|
||||
ICollection values = _pools.Values;
|
||||
foreach (HostConnectionPool pool in values) {
|
||||
pool.PurgeConnections();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class UnixConnection
|
||||
{
|
||||
DateTime _controlTime;
|
||||
Stream _stream;
|
||||
ReusableUnixClient _client;
|
||||
HostConnectionPool _pool;
|
||||
byte[] _buffer;
|
||||
internal class ReusableUnixClient : UnixClient
|
||||
{
|
||||
public ReusableUnixClient (String path): base (path)
|
||||
{
|
||||
}
|
||||
|
||||
public UnixConnection (HostConnectionPool pool, ReusableUnixClient client)
|
||||
{
|
||||
_pool = pool;
|
||||
_client = client;
|
||||
_stream = new BufferedStream (client.GetStream());
|
||||
_controlTime = DateTime.UtcNow;
|
||||
_buffer = new byte[UnixMessageIO.DefaultStreamBufferSize];
|
||||
}
|
||||
public Boolean IsAlive =>
|
||||
// This Poll will return true if there is data pending to
|
||||
// be read. It prob. means that a client object using this
|
||||
// connection got an exception and did not finish to read
|
||||
// the data. It can also mean that the connection has been
|
||||
// closed in the server. In both cases, the connection cannot
|
||||
// be reused.
|
||||
!this.Client.Poll(0, SelectMode.SelectRead);
|
||||
}
|
||||
|
||||
public Stream Stream
|
||||
{
|
||||
get { return _stream; }
|
||||
}
|
||||
internal class UnixConnection
|
||||
{
|
||||
DateTime _controlTime;
|
||||
Stream _stream;
|
||||
ReusableUnixClient _client;
|
||||
HostConnectionPool _pool;
|
||||
Byte[] _buffer;
|
||||
|
||||
public DateTime ControlTime
|
||||
{
|
||||
get { return _controlTime; }
|
||||
set { _controlTime = value; }
|
||||
}
|
||||
public UnixConnection (HostConnectionPool pool, ReusableUnixClient client)
|
||||
{
|
||||
this._pool = pool;
|
||||
this._client = client;
|
||||
this._stream = new BufferedStream (client.GetStream());
|
||||
this._controlTime = DateTime.UtcNow;
|
||||
this._buffer = new Byte[UnixMessageIO.DefaultStreamBufferSize];
|
||||
}
|
||||
|
||||
public bool IsAlive
|
||||
{
|
||||
get { return _client.IsAlive; }
|
||||
}
|
||||
public Stream Stream => this._stream;
|
||||
|
||||
// This is a "thread safe" buffer that can be used by
|
||||
// UnixClientTransportSink to read or send data to the stream.
|
||||
// The buffer is "thread safe" since only one thread can
|
||||
// use a connection at a given time.
|
||||
public byte[] Buffer
|
||||
{
|
||||
get { return _buffer; }
|
||||
}
|
||||
public DateTime ControlTime {
|
||||
get => this._controlTime;
|
||||
set => this._controlTime = value;
|
||||
}
|
||||
|
||||
// Returns the connection to the pool
|
||||
public void Release()
|
||||
{
|
||||
_pool.ReleaseConnection (this);
|
||||
}
|
||||
public Boolean IsAlive => this._client.IsAlive;
|
||||
|
||||
public void Close()
|
||||
{
|
||||
_client.Close();
|
||||
}
|
||||
}
|
||||
// This is a "thread safe" buffer that can be used by
|
||||
// UnixClientTransportSink to read or send data to the stream.
|
||||
// The buffer is "thread safe" since only one thread can
|
||||
// use a connection at a given time.
|
||||
public Byte[] Buffer => this._buffer;
|
||||
|
||||
internal class HostConnectionPool
|
||||
{
|
||||
ArrayList _pool = new ArrayList();
|
||||
int _activeConnections = 0;
|
||||
// Returns the connection to the pool
|
||||
public void Release() => this._pool.ReleaseConnection(this);
|
||||
|
||||
string _path;
|
||||
public void Close() => this._client.Close();
|
||||
}
|
||||
|
||||
public HostConnectionPool (string path)
|
||||
{
|
||||
_path = path;
|
||||
}
|
||||
internal class HostConnectionPool
|
||||
{
|
||||
ArrayList _pool = new ArrayList();
|
||||
Int32 _activeConnections = 0;
|
||||
|
||||
public UnixConnection GetConnection ()
|
||||
{
|
||||
UnixConnection connection = null;
|
||||
lock (_pool)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (_pool.Count > 0)
|
||||
{
|
||||
// There are available connections
|
||||
String _path;
|
||||
|
||||
connection = (UnixConnection)_pool[_pool.Count - 1];
|
||||
_pool.RemoveAt(_pool.Count - 1);
|
||||
if (!connection.IsAlive) {
|
||||
CancelConnection (connection);
|
||||
connection = null;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
public HostConnectionPool(String path) => this._path = path;
|
||||
|
||||
if (connection == null && _activeConnections < UnixConnectionPool.MaxOpenConnections)
|
||||
{
|
||||
// No connections available, but the max connections
|
||||
// has not been reached yet, so a new one can be created
|
||||
// Create the connection outside the lock
|
||||
break;
|
||||
}
|
||||
public UnixConnection GetConnection ()
|
||||
{
|
||||
UnixConnection connection = null;
|
||||
lock (this._pool)
|
||||
{
|
||||
do
|
||||
{
|
||||
if (this._pool.Count > 0)
|
||||
{
|
||||
// There are available connections
|
||||
|
||||
// No available connections in the pool
|
||||
// Wait for somewone to release one.
|
||||
connection = (UnixConnection)this._pool[this._pool.Count - 1];
|
||||
this._pool.RemoveAt(this._pool.Count - 1);
|
||||
if (!connection.IsAlive) {
|
||||
this.CancelConnection (connection);
|
||||
connection = null;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (connection == null)
|
||||
{
|
||||
Monitor.Wait(_pool);
|
||||
}
|
||||
}
|
||||
while (connection == null);
|
||||
}
|
||||
if (connection == null && this._activeConnections < UnixConnectionPool.MaxOpenConnections)
|
||||
{
|
||||
// No connections available, but the max connections
|
||||
// has not been reached yet, so a new one can be created
|
||||
// Create the connection outside the lock
|
||||
break;
|
||||
}
|
||||
|
||||
if (connection == null)
|
||||
return CreateConnection ();
|
||||
else
|
||||
return connection;
|
||||
}
|
||||
// No available connections in the pool
|
||||
// Wait for somewone to release one.
|
||||
|
||||
private UnixConnection CreateConnection()
|
||||
{
|
||||
try
|
||||
{
|
||||
ReusableUnixClient client = new ReusableUnixClient (_path);
|
||||
UnixConnection entry = new UnixConnection(this, client);
|
||||
_activeConnections++;
|
||||
return entry;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new RemotingException (ex.Message);
|
||||
}
|
||||
}
|
||||
if (connection == null)
|
||||
{
|
||||
_ = Monitor.Wait(this._pool);
|
||||
}
|
||||
}
|
||||
while (connection == null);
|
||||
}
|
||||
|
||||
public void ReleaseConnection (UnixConnection entry)
|
||||
{
|
||||
lock (_pool)
|
||||
{
|
||||
entry.ControlTime = DateTime.UtcNow; // Initialize timeout
|
||||
_pool.Add (entry);
|
||||
Monitor.Pulse (_pool);
|
||||
}
|
||||
}
|
||||
if (connection == null) {
|
||||
return this.CreateConnection ();
|
||||
} else {
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
|
||||
private void CancelConnection(UnixConnection entry)
|
||||
{
|
||||
try
|
||||
{
|
||||
entry.Stream.Close();
|
||||
_activeConnections--;
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
private UnixConnection CreateConnection()
|
||||
{
|
||||
try
|
||||
{
|
||||
ReusableUnixClient client = new ReusableUnixClient (this._path);
|
||||
UnixConnection entry = new UnixConnection(this, client);
|
||||
this._activeConnections++;
|
||||
return entry;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new RemotingException (ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public void PurgeConnections()
|
||||
{
|
||||
lock (_pool)
|
||||
{
|
||||
for (int n=0; n < _pool.Count; n++)
|
||||
{
|
||||
UnixConnection entry = (UnixConnection)_pool[n];
|
||||
if ( (DateTime.UtcNow - entry.ControlTime).TotalSeconds > UnixConnectionPool.KeepAliveSeconds)
|
||||
{
|
||||
CancelConnection (entry);
|
||||
_pool.RemoveAt(n);
|
||||
n--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public void ReleaseConnection (UnixConnection entry)
|
||||
{
|
||||
lock (this._pool)
|
||||
{
|
||||
entry.ControlTime = DateTime.UtcNow; // Initialize timeout
|
||||
_ = this._pool.Add(entry);
|
||||
Monitor.Pulse (this._pool);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
private void CancelConnection(UnixConnection entry)
|
||||
{
|
||||
try
|
||||
{
|
||||
entry.Stream.Close();
|
||||
this._activeConnections--;
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public void PurgeConnections()
|
||||
{
|
||||
lock (this._pool)
|
||||
{
|
||||
for (Int32 n =0; n < this._pool.Count; n++)
|
||||
{
|
||||
UnixConnection entry = (UnixConnection)this._pool[n];
|
||||
if ( (DateTime.UtcNow - entry.ControlTime).TotalSeconds > UnixConnectionPool.KeepAliveSeconds)
|
||||
{
|
||||
this.CancelConnection (entry);
|
||||
this._pool.RemoveAt(n);
|
||||
n--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -38,246 +38,265 @@ using System.Runtime.Remoting;
|
||||
|
||||
namespace Mono.Remoting.Channels.Unix
|
||||
{
|
||||
enum MessageStatus { MethodMessage = 0, CancelSignal = 1, Unknown = 10}
|
||||
enum MessageStatus { MethodMessage = 0, CancelSignal = 1, Unknown = 10}
|
||||
|
||||
internal class UnixMessageIO
|
||||
{
|
||||
static byte[][] _msgHeaders =
|
||||
{
|
||||
new byte[] { (byte)'.', (byte)'N', (byte)'E', (byte)'T', 1, 0 },
|
||||
new byte[] { 255, 255, 255, 255, 255, 255 }
|
||||
};
|
||||
|
||||
public static int DefaultStreamBufferSize = 1000;
|
||||
internal class UnixMessageIO
|
||||
{
|
||||
static Byte[][] _msgHeaders =
|
||||
{
|
||||
new Byte[] { (Byte)'.', (Byte)'N', (Byte)'E', (Byte)'T', 1, 0 },
|
||||
new Byte[] { 255, 255, 255, 255, 255, 255 }
|
||||
};
|
||||
|
||||
public static Int32 DefaultStreamBufferSize = 1000;
|
||||
|
||||
// Identifies an incoming message
|
||||
public static MessageStatus ReceiveMessageStatus (Stream networkStream, byte[] buffer)
|
||||
{
|
||||
try {
|
||||
StreamRead (networkStream, buffer, 6);
|
||||
} catch (Exception ex) {
|
||||
throw new RemotingException ("Unix transport error.", ex);
|
||||
}
|
||||
// Identifies an incoming message
|
||||
public static MessageStatus ReceiveMessageStatus (Stream networkStream, Byte[] buffer)
|
||||
{
|
||||
try {
|
||||
_ = StreamRead(networkStream, buffer, 6);
|
||||
} catch (Exception ex) {
|
||||
throw new RemotingException ("Unix transport error.", ex);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
bool[] isOnTrack = new bool[_msgHeaders.Length];
|
||||
bool atLeastOneOnTrack = true;
|
||||
int i = 0;
|
||||
try
|
||||
{
|
||||
Boolean[] isOnTrack = new Boolean[_msgHeaders.Length];
|
||||
Boolean atLeastOneOnTrack = true;
|
||||
Int32 i = 0;
|
||||
|
||||
while (atLeastOneOnTrack)
|
||||
{
|
||||
atLeastOneOnTrack = false;
|
||||
byte c = buffer [i];
|
||||
for (int n = 0; n<_msgHeaders.Length; n++)
|
||||
{
|
||||
if (i > 0 && !isOnTrack[n]) continue;
|
||||
while (atLeastOneOnTrack)
|
||||
{
|
||||
atLeastOneOnTrack = false;
|
||||
Byte c = buffer [i];
|
||||
for (Int32 n = 0; n<_msgHeaders.Length; n++)
|
||||
{
|
||||
if (i > 0 && !isOnTrack[n]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
isOnTrack[n] = c == _msgHeaders[n][i];
|
||||
if (isOnTrack[n] && i == _msgHeaders[n].Length-1) {
|
||||
return (MessageStatus) n;
|
||||
}
|
||||
|
||||
atLeastOneOnTrack = atLeastOneOnTrack || isOnTrack[n];
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return MessageStatus.Unknown;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new RemotingException ("Unix transport error.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
static Boolean StreamRead (Stream networkStream, Byte[] buffer, Int32 count)
|
||||
{
|
||||
Int32 nr = 0;
|
||||
do {
|
||||
Int32 pr = networkStream.Read (buffer, nr, count - nr);
|
||||
if (pr == 0) {
|
||||
throw new RemotingException ("Connection closed");
|
||||
}
|
||||
|
||||
nr += pr;
|
||||
} while (nr < count);
|
||||
return true;
|
||||
}
|
||||
|
||||
isOnTrack[n] = (c == _msgHeaders[n][i]);
|
||||
if (isOnTrack[n] && (i == _msgHeaders[n].Length-1)) return (MessageStatus) n;
|
||||
atLeastOneOnTrack = atLeastOneOnTrack || isOnTrack[n];
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return MessageStatus.Unknown;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new RemotingException ("Unix transport error.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
static bool StreamRead (Stream networkStream, byte[] buffer, int count)
|
||||
{
|
||||
int nr = 0;
|
||||
do {
|
||||
int pr = networkStream.Read (buffer, nr, count - nr);
|
||||
if (pr == 0)
|
||||
throw new RemotingException ("Connection closed");
|
||||
nr += pr;
|
||||
} while (nr < count);
|
||||
return true;
|
||||
}
|
||||
public static void SendMessageStream (Stream networkStream, Stream data, ITransportHeaders requestHeaders, Byte[] buffer)
|
||||
{
|
||||
if (buffer == null) {
|
||||
buffer = new Byte[DefaultStreamBufferSize];
|
||||
}
|
||||
|
||||
// Writes the message start header
|
||||
Byte[] dotnetHeader = _msgHeaders[(Int32) MessageStatus.MethodMessage];
|
||||
networkStream.Write(dotnetHeader, 0, dotnetHeader.Length);
|
||||
|
||||
public static void SendMessageStream (Stream networkStream, Stream data, ITransportHeaders requestHeaders, byte[] buffer)
|
||||
{
|
||||
if (buffer == null) buffer = new byte[DefaultStreamBufferSize];
|
||||
// Writes header tag (0x0000 if request stream, 0x0002 if response stream)
|
||||
if(requestHeaders["__RequestUri"]!=null) {
|
||||
buffer [0] = (Byte) 0;
|
||||
} else {
|
||||
buffer[0] = (Byte) 2;
|
||||
}
|
||||
|
||||
buffer [1] = (Byte) 0 ;
|
||||
|
||||
// Writes the message start header
|
||||
byte[] dotnetHeader = _msgHeaders[(int) MessageStatus.MethodMessage];
|
||||
networkStream.Write(dotnetHeader, 0, dotnetHeader.Length);
|
||||
// Writes ID
|
||||
buffer [2] = (Byte) 0;
|
||||
|
||||
// Writes header tag (0x0000 if request stream, 0x0002 if response stream)
|
||||
if(requestHeaders["__RequestUri"]!=null) buffer [0] = (byte) 0;
|
||||
else buffer[0] = (byte) 2;
|
||||
buffer [1] = (byte) 0 ;
|
||||
// Writes assemblyID????
|
||||
buffer [3] = (Byte) 0;
|
||||
|
||||
// Writes the length of the stream being sent (not including the headers)
|
||||
Int32 num = (Int32)data.Length;
|
||||
buffer [4] = (Byte) num;
|
||||
buffer [5] = (Byte) (num >> 8);
|
||||
buffer [6] = (Byte) (num >> 16);
|
||||
buffer [7] = (Byte) (num >> 24);
|
||||
networkStream.Write(buffer, 0, 8);
|
||||
|
||||
// Writes the message headers
|
||||
SendHeaders (networkStream, requestHeaders, buffer);
|
||||
|
||||
// Writes ID
|
||||
buffer [2] = (byte) 0;
|
||||
// Writes the stream
|
||||
if (data is MemoryStream)
|
||||
{
|
||||
// The copy of the stream can be optimized. The internal
|
||||
// buffer of MemoryStream can be used.
|
||||
MemoryStream memStream = (MemoryStream)data;
|
||||
networkStream.Write (memStream.GetBuffer(), 0, (Int32)memStream.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
Int32 nread = data.Read (buffer, 0, buffer.Length);
|
||||
while (nread > 0)
|
||||
{
|
||||
networkStream.Write (buffer, 0, nread);
|
||||
nread = data.Read (buffer, 0, buffer.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Byte[] msgUriTransportKey = new Byte[] { 4, 0, 1, 1 };
|
||||
static Byte[] msgContentTypeTransportKey = new Byte[] { 6, 0, 1, 1 };
|
||||
static Byte[] msgDefaultTransportKey = new Byte[] { 1, 0, 1 };
|
||||
static Byte[] msgHeaderTerminator = new Byte[] { 0, 0 };
|
||||
|
||||
// Writes assemblyID????
|
||||
buffer [3] = (byte) 0;
|
||||
private static void SendHeaders(Stream networkStream, ITransportHeaders requestHeaders, Byte[] buffer)
|
||||
{
|
||||
// Writes the headers as a sequence of strings
|
||||
if (networkStream != null)
|
||||
{
|
||||
IEnumerator e = requestHeaders.GetEnumerator();
|
||||
while (e.MoveNext())
|
||||
{
|
||||
DictionaryEntry hdr = (DictionaryEntry)e.Current;
|
||||
switch (hdr.Key.ToString())
|
||||
{
|
||||
case "__RequestUri":
|
||||
networkStream.Write (msgUriTransportKey, 0, 4);
|
||||
break;
|
||||
case "Content-Type":
|
||||
networkStream.Write (msgContentTypeTransportKey, 0, 4);
|
||||
break;
|
||||
default:
|
||||
networkStream.Write (msgDefaultTransportKey, 0, 3);
|
||||
SendString (networkStream, hdr.Key.ToString(), buffer);
|
||||
networkStream.WriteByte (1);
|
||||
break;
|
||||
}
|
||||
SendString (networkStream, hdr.Value.ToString(), buffer);
|
||||
}
|
||||
}
|
||||
networkStream.Write (msgHeaderTerminator, 0, 2); // End of headers
|
||||
}
|
||||
|
||||
public static ITransportHeaders ReceiveHeaders (Stream networkStream, Byte[] buffer)
|
||||
{
|
||||
_ = StreamRead(networkStream, buffer, 2);
|
||||
|
||||
Byte headerType = buffer [0];
|
||||
TransportHeaders headers = new TransportHeaders ();
|
||||
|
||||
// Writes the length of the stream being sent (not including the headers)
|
||||
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
|
||||
SendHeaders (networkStream, requestHeaders, buffer);
|
||||
while (headerType != 0)
|
||||
{
|
||||
String key;
|
||||
_ = StreamRead(networkStream, buffer, 1); // byte 1
|
||||
switch (headerType)
|
||||
{
|
||||
case 4: key = "__RequestUri"; break;
|
||||
case 6: key = "Content-Type"; break;
|
||||
case 1: key = ReceiveString (networkStream, buffer); break;
|
||||
default: throw new NotSupportedException ("Unknown header code: " + headerType);
|
||||
}
|
||||
_ = StreamRead(networkStream, buffer, 1); // byte 1
|
||||
headers[key] = ReceiveString (networkStream, buffer);
|
||||
|
||||
_ = StreamRead(networkStream, buffer, 2);
|
||||
headerType = buffer [0];
|
||||
}
|
||||
|
||||
// Writes the stream
|
||||
if (data is MemoryStream)
|
||||
{
|
||||
// The copy of the stream can be optimized. The internal
|
||||
// buffer of MemoryStream can be used.
|
||||
MemoryStream memStream = (MemoryStream)data;
|
||||
networkStream.Write (memStream.GetBuffer(), 0, (int)memStream.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
int nread = data.Read (buffer, 0, buffer.Length);
|
||||
while (nread > 0)
|
||||
{
|
||||
networkStream.Write (buffer, 0, nread);
|
||||
nread = data.Read (buffer, 0, buffer.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static byte[] msgUriTransportKey = new byte[] { 4, 0, 1, 1 };
|
||||
static byte[] msgContentTypeTransportKey = new byte[] { 6, 0, 1, 1 };
|
||||
static byte[] msgDefaultTransportKey = new byte[] { 1, 0, 1 };
|
||||
static byte[] msgHeaderTerminator = new byte[] { 0, 0 };
|
||||
return headers;
|
||||
}
|
||||
|
||||
public static Stream ReceiveMessageStream (Stream networkStream, out ITransportHeaders headers, Byte[] buffer)
|
||||
{
|
||||
headers = null;
|
||||
|
||||
private static void SendHeaders(Stream networkStream, ITransportHeaders requestHeaders, byte[] buffer)
|
||||
{
|
||||
// Writes the headers as a sequence of strings
|
||||
if (networkStream != null)
|
||||
{
|
||||
IEnumerator e = requestHeaders.GetEnumerator();
|
||||
while (e.MoveNext())
|
||||
{
|
||||
DictionaryEntry hdr = (DictionaryEntry)e.Current;
|
||||
switch (hdr.Key.ToString())
|
||||
{
|
||||
case "__RequestUri":
|
||||
networkStream.Write (msgUriTransportKey, 0, 4);
|
||||
break;
|
||||
case "Content-Type":
|
||||
networkStream.Write (msgContentTypeTransportKey, 0, 4);
|
||||
break;
|
||||
default:
|
||||
networkStream.Write (msgDefaultTransportKey, 0, 3);
|
||||
SendString (networkStream, hdr.Key.ToString(), buffer);
|
||||
networkStream.WriteByte (1);
|
||||
break;
|
||||
}
|
||||
SendString (networkStream, hdr.Value.ToString(), buffer);
|
||||
}
|
||||
}
|
||||
networkStream.Write (msgHeaderTerminator, 0, 2); // End of headers
|
||||
}
|
||||
|
||||
public static ITransportHeaders ReceiveHeaders (Stream networkStream, byte[] buffer)
|
||||
{
|
||||
StreamRead (networkStream, buffer, 2);
|
||||
|
||||
byte headerType = buffer [0];
|
||||
TransportHeaders headers = new TransportHeaders ();
|
||||
if (buffer == null) {
|
||||
buffer = new Byte[DefaultStreamBufferSize];
|
||||
}
|
||||
|
||||
// Reads header tag: 0 -> Stream with headers or 2 -> Response Stream
|
||||
// +
|
||||
// Gets the length of the data stream
|
||||
_ = StreamRead(networkStream, buffer, 8);
|
||||
|
||||
Int32 byteCount = buffer [4] | (buffer [5] << 8) |
|
||||
(buffer [6] << 16) | (buffer [7] << 24);
|
||||
|
||||
while (headerType != 0)
|
||||
{
|
||||
string key;
|
||||
StreamRead (networkStream, buffer, 1); // byte 1
|
||||
switch (headerType)
|
||||
{
|
||||
case 4: key = "__RequestUri"; break;
|
||||
case 6: key = "Content-Type"; break;
|
||||
case 1: key = ReceiveString (networkStream, buffer); break;
|
||||
default: throw new NotSupportedException ("Unknown header code: " + headerType);
|
||||
}
|
||||
StreamRead (networkStream, buffer, 1); // byte 1
|
||||
headers[key] = ReceiveString (networkStream, buffer);
|
||||
// Reads the headers
|
||||
headers = ReceiveHeaders (networkStream, buffer);
|
||||
|
||||
Byte[] resultBuffer = new Byte[byteCount];
|
||||
_ = StreamRead(networkStream, resultBuffer, byteCount);
|
||||
|
||||
StreamRead (networkStream, buffer, 2);
|
||||
headerType = buffer [0];
|
||||
}
|
||||
return new MemoryStream (resultBuffer);
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
public static Stream ReceiveMessageStream (Stream networkStream, out ITransportHeaders headers, byte[] buffer)
|
||||
{
|
||||
headers = null;
|
||||
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.
|
||||
|
||||
Int32 maxBytes = Encoding.UTF8.GetMaxByteCount(str.Length)+4; //+4 bytes for storing the string length
|
||||
if (maxBytes > buffer.Length) {
|
||||
buffer = new Byte[maxBytes];
|
||||
}
|
||||
|
||||
Int32 num = Encoding.UTF8.GetBytes (str, 0, str.Length, buffer, 4);
|
||||
|
||||
if (buffer == null) buffer = new byte[DefaultStreamBufferSize];
|
||||
// store number of bytes (not number of chars!)
|
||||
|
||||
// Reads header tag: 0 -> Stream with headers or 2 -> Response Stream
|
||||
// +
|
||||
// Gets the length of the data stream
|
||||
StreamRead (networkStream, buffer, 8);
|
||||
buffer [0] = (Byte) num;
|
||||
buffer [1] = (Byte) (num >> 8);
|
||||
buffer [2] = (Byte) (num >> 16);
|
||||
buffer [3] = (Byte) (num >> 24);
|
||||
|
||||
int byteCount = (buffer [4] | (buffer [5] << 8) |
|
||||
(buffer [6] << 16) | (buffer [7] << 24));
|
||||
// Write the string bytes
|
||||
networkStream.Write (buffer, 0, num + 4);
|
||||
}
|
||||
|
||||
// Reads the headers
|
||||
headers = ReceiveHeaders (networkStream, buffer);
|
||||
private static String ReceiveString (Stream networkStream, Byte[] buffer)
|
||||
{
|
||||
_ = StreamRead(networkStream, buffer, 4);
|
||||
|
||||
// Reads the number of bytes (not chars!)
|
||||
|
||||
Int32 byteCount = buffer [0] | (buffer [1] << 8) |
|
||||
(buffer [2] << 16) | (buffer [3] << 24);
|
||||
|
||||
byte[] resultBuffer = new byte[byteCount];
|
||||
StreamRead (networkStream, resultBuffer, byteCount);
|
||||
|
||||
return new MemoryStream (resultBuffer);
|
||||
}
|
||||
|
||||
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.
|
||||
|
||||
int maxBytes = Encoding.UTF8.GetMaxByteCount(str.Length)+4; //+4 bytes for storing the string length
|
||||
if (maxBytes > buffer.Length)
|
||||
buffer = new byte[maxBytes];
|
||||
|
||||
int num = Encoding.UTF8.GetBytes (str, 0, str.Length, buffer, 4);
|
||||
|
||||
// store number of bytes (not number of chars!)
|
||||
|
||||
buffer [0] = (byte) num;
|
||||
buffer [1] = (byte) (num >> 8);
|
||||
buffer [2] = (byte) (num >> 16);
|
||||
buffer [3] = (byte) (num >> 24);
|
||||
|
||||
// Write the string bytes
|
||||
networkStream.Write (buffer, 0, num + 4);
|
||||
}
|
||||
|
||||
private static string ReceiveString (Stream networkStream, byte[] buffer)
|
||||
{
|
||||
StreamRead (networkStream, buffer, 4);
|
||||
|
||||
// Reads the number of bytes (not chars!)
|
||||
|
||||
int byteCount = (buffer [0] | (buffer [1] << 8) |
|
||||
(buffer [2] << 16) | (buffer [3] << 24));
|
||||
|
||||
if (byteCount == 0) return string.Empty;
|
||||
|
||||
// Allocates a buffer of the correct size. Use the
|
||||
// internal buffer if it is big enough
|
||||
|
||||
if (byteCount > buffer.Length)
|
||||
buffer = new byte[byteCount];
|
||||
|
||||
// Reads the string
|
||||
|
||||
StreamRead (networkStream, buffer, byteCount);
|
||||
char[] chars = Encoding.UTF8.GetChars (buffer, 0, byteCount);
|
||||
|
||||
return new string (chars);
|
||||
}
|
||||
|
||||
}
|
||||
if (byteCount == 0) {
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
// Allocates a buffer of the correct size. Use the
|
||||
// internal buffer if it is big enough
|
||||
|
||||
if (byteCount > buffer.Length) {
|
||||
buffer = new Byte[byteCount];
|
||||
}
|
||||
|
||||
// Reads the string
|
||||
|
||||
_ = StreamRead(networkStream, buffer, byteCount);
|
||||
Char[] chars = Encoding.UTF8.GetChars (buffer, 0, byteCount);
|
||||
|
||||
return new String(chars);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -42,18 +42,18 @@ using Mono.Unix;
|
||||
namespace Mono.Remoting.Channels.Unix
|
||||
{
|
||||
public class UnixServerChannel : IChannelReceiver, IChannel
|
||||
{
|
||||
string path = null;
|
||||
string name = "unix";
|
||||
|
||||
int priority = 1;
|
||||
bool supressChannelData = false;
|
||||
{
|
||||
String path = null;
|
||||
String name = "unix";
|
||||
|
||||
Int32 priority = 1;
|
||||
Boolean supressChannelData = false;
|
||||
|
||||
Thread server_thread = null;
|
||||
UnixListener listener;
|
||||
UnixServerTransportSink sink;
|
||||
ChannelDataStore channel_data;
|
||||
int _maxConcurrentConnections = 100;
|
||||
ChannelDataStore channel_data;
|
||||
Int32 _maxConcurrentConnections = 100;
|
||||
ArrayList _activeConnections = new ArrayList();
|
||||
|
||||
|
||||
@ -62,30 +62,30 @@ namespace Mono.Remoting.Channels.Unix
|
||||
if (serverSinkProvider == null)
|
||||
{
|
||||
serverSinkProvider = new UnixBinaryServerFormatterSinkProvider ();
|
||||
}
|
||||
|
||||
// Gets channel data from the chain of channel providers
|
||||
|
||||
channel_data = new ChannelDataStore (null);
|
||||
}
|
||||
|
||||
// Gets channel data from the chain of channel providers
|
||||
|
||||
this.channel_data = new ChannelDataStore (null);
|
||||
IServerChannelSinkProvider provider = serverSinkProvider;
|
||||
while (provider != null)
|
||||
{
|
||||
provider.GetChannelData(channel_data);
|
||||
provider.GetChannelData(this.channel_data);
|
||||
provider = provider.Next;
|
||||
}
|
||||
|
||||
// Creates the sink chain that will process all incoming messages
|
||||
|
||||
IServerChannelSink next_sink = ChannelServices.CreateServerChannelSinkChain (serverSinkProvider, this);
|
||||
sink = new UnixServerTransportSink (next_sink);
|
||||
|
||||
StartListening (null);
|
||||
IServerChannelSink next_sink = ChannelServices.CreateServerChannelSinkChain (serverSinkProvider, this);
|
||||
this.sink = new UnixServerTransportSink (next_sink);
|
||||
|
||||
this.StartListening (null);
|
||||
}
|
||||
|
||||
public UnixServerChannel (string path)
|
||||
public UnixServerChannel (String path)
|
||||
{
|
||||
this.path = path;
|
||||
Init (null);
|
||||
this.path = path;
|
||||
this.Init (null);
|
||||
}
|
||||
|
||||
public UnixServerChannel (IDictionary properties,
|
||||
@ -93,90 +93,80 @@ namespace Mono.Remoting.Channels.Unix
|
||||
{
|
||||
foreach(DictionaryEntry property in properties)
|
||||
{
|
||||
switch((string)property.Key)
|
||||
switch((String)property.Key)
|
||||
{
|
||||
case "path":
|
||||
path = property.Value as string;
|
||||
case "path":
|
||||
this.path = property.Value as String;
|
||||
break;
|
||||
case "priority":
|
||||
priority = Convert.ToInt32(property.Value);
|
||||
case "priority":
|
||||
this.priority = Convert.ToInt32(property.Value);
|
||||
break;
|
||||
case "supressChannelData":
|
||||
supressChannelData = Convert.ToBoolean (property.Value);
|
||||
case "supressChannelData":
|
||||
this.supressChannelData = Convert.ToBoolean (property.Value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Init (serverSinkProvider);
|
||||
}
|
||||
this.Init (serverSinkProvider);
|
||||
}
|
||||
|
||||
public UnixServerChannel (string name, string path,
|
||||
public UnixServerChannel (String name, String path,
|
||||
IServerChannelSinkProvider serverSinkProvider)
|
||||
{
|
||||
this.name = name;
|
||||
this.path = path;
|
||||
Init (serverSinkProvider);
|
||||
this.path = path;
|
||||
this.Init (serverSinkProvider);
|
||||
}
|
||||
|
||||
public UnixServerChannel (string name, string path)
|
||||
public UnixServerChannel (String name, String path)
|
||||
{
|
||||
this.name = name;
|
||||
this.path = path;
|
||||
Init (null);
|
||||
this.path = path;
|
||||
this.Init (null);
|
||||
}
|
||||
|
||||
public object ChannelData
|
||||
public Object ChannelData
|
||||
{
|
||||
get {
|
||||
if (supressChannelData) return null;
|
||||
else return channel_data;
|
||||
}
|
||||
}
|
||||
|
||||
public string ChannelName
|
||||
if (this.supressChannelData) {
|
||||
return null;
|
||||
} else {
|
||||
return this.channel_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String ChannelName => this.name;
|
||||
|
||||
public Int32 ChannelPriority => this.priority;
|
||||
|
||||
public String GetChannelUri() => "unix://" + this.path;
|
||||
|
||||
public String[] GetUrlsForUri (String uri)
|
||||
{
|
||||
get {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
if (!uri.StartsWith ("/")) {
|
||||
uri = "/" + uri;
|
||||
}
|
||||
|
||||
String[] chnl_uris = this.channel_data.ChannelUris;
|
||||
String[] result = new String [chnl_uris.Length];
|
||||
|
||||
public int ChannelPriority
|
||||
{
|
||||
get {
|
||||
return priority;
|
||||
}
|
||||
}
|
||||
|
||||
public string GetChannelUri ()
|
||||
{
|
||||
return "unix://" + path;
|
||||
}
|
||||
|
||||
public string[] GetUrlsForUri (string uri)
|
||||
{
|
||||
if (!uri.StartsWith ("/")) uri = "/" + uri;
|
||||
|
||||
string [] chnl_uris = channel_data.ChannelUris;
|
||||
string [] result = new String [chnl_uris.Length];
|
||||
|
||||
for (int i = 0; i < chnl_uris.Length; i++)
|
||||
result [i] = chnl_uris [i] + "?" + uri;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public string Parse (string url, out string objectURI)
|
||||
{
|
||||
return UnixChannel.ParseUnixURL (url, out objectURI);
|
||||
}
|
||||
|
||||
void WaitForConnections ()
|
||||
for (Int32 i = 0; i < chnl_uris.Length; i++) {
|
||||
result [i] = chnl_uris [i] + "?" + uri;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public String Parse(String url, out String objectURI) => UnixChannel.ParseUnixURL(url, out objectURI);
|
||||
|
||||
void WaitForConnections ()
|
||||
{
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
Socket client = listener.AcceptSocket ();
|
||||
CreateListenerConnection (client);
|
||||
Socket client = this.listener.AcceptSocket ();
|
||||
this.CreateListenerConnection (client);
|
||||
}
|
||||
}
|
||||
catch
|
||||
@ -185,71 +175,77 @@ namespace Mono.Remoting.Channels.Unix
|
||||
|
||||
internal void CreateListenerConnection (Socket client)
|
||||
{
|
||||
lock (_activeConnections)
|
||||
lock (this._activeConnections)
|
||||
{
|
||||
if (_activeConnections.Count >= _maxConcurrentConnections)
|
||||
Monitor.Wait (_activeConnections);
|
||||
|
||||
if (server_thread == null) return; // Server was stopped while waiting
|
||||
|
||||
ClientConnection reader = new ClientConnection (this, client, sink);
|
||||
if (this._activeConnections.Count >= this._maxConcurrentConnections) {
|
||||
_ = Monitor.Wait(this._activeConnections);
|
||||
}
|
||||
|
||||
if (this.server_thread == null) {
|
||||
return; // Server was stopped while waiting
|
||||
}
|
||||
|
||||
ClientConnection reader = new ClientConnection (this, client, this.sink);
|
||||
Thread thread = new Thread (new ThreadStart (reader.ProcessMessages));
|
||||
thread.Start();
|
||||
thread.IsBackground = true;
|
||||
_activeConnections.Add (thread);
|
||||
thread.IsBackground = true;
|
||||
_ = this._activeConnections.Add(thread);
|
||||
}
|
||||
}
|
||||
|
||||
internal void ReleaseConnection (Thread thread)
|
||||
{
|
||||
lock (_activeConnections)
|
||||
{
|
||||
_activeConnections.Remove (thread);
|
||||
Monitor.Pulse (_activeConnections);
|
||||
lock (this._activeConnections)
|
||||
{
|
||||
this._activeConnections.Remove (thread);
|
||||
Monitor.Pulse (this._activeConnections);
|
||||
}
|
||||
}
|
||||
|
||||
public void StartListening (object data)
|
||||
{
|
||||
listener = new UnixListener (path);
|
||||
Mono.Unix.Native.Syscall.chmod (path,
|
||||
Mono.Unix.Native.FilePermissions.S_IRUSR |
|
||||
Mono.Unix.Native.FilePermissions.S_IWUSR |
|
||||
Mono.Unix.Native.FilePermissions.S_IRGRP |
|
||||
Mono.Unix.Native.FilePermissions.S_IWGRP |
|
||||
Mono.Unix.Native.FilePermissions.S_IROTH |
|
||||
Mono.Unix.Native.FilePermissions.S_IWOTH);
|
||||
public void StartListening (Object data)
|
||||
{
|
||||
this.listener = new UnixListener (this.path);
|
||||
_ = Mono.Unix.Native.Syscall.chmod(this.path,
|
||||
Mono.Unix.Native.FilePermissions.S_IRUSR |
|
||||
Mono.Unix.Native.FilePermissions.S_IWUSR |
|
||||
Mono.Unix.Native.FilePermissions.S_IRGRP |
|
||||
Mono.Unix.Native.FilePermissions.S_IWGRP |
|
||||
Mono.Unix.Native.FilePermissions.S_IROTH |
|
||||
Mono.Unix.Native.FilePermissions.S_IWOTH);
|
||||
|
||||
if (server_thread == null)
|
||||
{
|
||||
listener.Start ();
|
||||
|
||||
string[] uris = new String [1];
|
||||
if (this.server_thread == null)
|
||||
{
|
||||
this.listener.Start ();
|
||||
|
||||
String[] uris = new String [1];
|
||||
uris = new String [1];
|
||||
uris [0] = GetChannelUri ();
|
||||
channel_data.ChannelUris = uris;
|
||||
|
||||
server_thread = new Thread (new ThreadStart (WaitForConnections));
|
||||
server_thread.IsBackground = true;
|
||||
server_thread.Start ();
|
||||
uris [0] = this.GetChannelUri ();
|
||||
this.channel_data.ChannelUris = uris;
|
||||
|
||||
this.server_thread = new Thread (new ThreadStart (this.WaitForConnections));
|
||||
this.server_thread.IsBackground = true;
|
||||
this.server_thread.Start ();
|
||||
}
|
||||
}
|
||||
|
||||
public void StopListening (object data)
|
||||
public void StopListening (Object data)
|
||||
{
|
||||
if (server_thread == null) return;
|
||||
if (this.server_thread == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
lock (this._activeConnections)
|
||||
{
|
||||
this.server_thread.Abort ();
|
||||
this.server_thread = null;
|
||||
this.listener.Stop ();
|
||||
|
||||
lock (_activeConnections)
|
||||
{
|
||||
server_thread.Abort ();
|
||||
server_thread = null;
|
||||
listener.Stop ();
|
||||
|
||||
foreach (Thread thread in _activeConnections)
|
||||
thread.Abort();
|
||||
|
||||
_activeConnections.Clear();
|
||||
Monitor.PulseAll (_activeConnections);
|
||||
foreach (Thread thread in this._activeConnections) {
|
||||
thread.Abort();
|
||||
}
|
||||
|
||||
this._activeConnections.Clear();
|
||||
Monitor.PulseAll (this._activeConnections);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -259,48 +255,43 @@ namespace Mono.Remoting.Channels.Unix
|
||||
Socket _client;
|
||||
UnixServerTransportSink _sink;
|
||||
Stream _stream;
|
||||
UnixServerChannel _serverChannel;
|
||||
|
||||
byte[] _buffer = new byte[UnixMessageIO.DefaultStreamBufferSize];
|
||||
UnixServerChannel _serverChannel;
|
||||
|
||||
Byte[] _buffer = new Byte[UnixMessageIO.DefaultStreamBufferSize];
|
||||
|
||||
public ClientConnection (UnixServerChannel serverChannel, Socket client, UnixServerTransportSink sink)
|
||||
{
|
||||
_serverChannel = serverChannel;
|
||||
_client = client;
|
||||
_sink = sink;
|
||||
}
|
||||
|
||||
public Socket Client {
|
||||
get { return _client; }
|
||||
}
|
||||
|
||||
public byte[] Buffer
|
||||
{
|
||||
get { return _buffer; }
|
||||
}
|
||||
|
||||
public void ProcessMessages()
|
||||
{
|
||||
byte[] buffer = new byte[256];
|
||||
_stream = new BufferedStream (new NetworkStream (_client));
|
||||
{
|
||||
this._serverChannel = serverChannel;
|
||||
this._client = client;
|
||||
this._sink = sink;
|
||||
}
|
||||
|
||||
public Socket Client => this._client;
|
||||
|
||||
public Byte[] Buffer => this._buffer;
|
||||
|
||||
public void ProcessMessages()
|
||||
{
|
||||
Byte[] buffer = new Byte[256];
|
||||
this._stream = new BufferedStream (new NetworkStream (this._client));
|
||||
|
||||
try
|
||||
{
|
||||
bool end = false;
|
||||
{
|
||||
Boolean end = false;
|
||||
while (!end)
|
||||
{
|
||||
MessageStatus type = UnixMessageIO.ReceiveMessageStatus (_stream, buffer);
|
||||
MessageStatus type = UnixMessageIO.ReceiveMessageStatus (this._stream, buffer);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case MessageStatus.MethodMessage:
|
||||
_sink.InternalProcessMessage (this, _stream);
|
||||
break;
|
||||
case MessageStatus.MethodMessage:
|
||||
this._sink.InternalProcessMessage (this, this._stream);
|
||||
break;
|
||||
|
||||
case MessageStatus.Unknown:
|
||||
case MessageStatus.CancelSignal:
|
||||
end = true;
|
||||
break;
|
||||
case MessageStatus.Unknown:
|
||||
case MessageStatus.CancelSignal:
|
||||
end = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -310,21 +301,15 @@ namespace Mono.Remoting.Channels.Unix
|
||||
}
|
||||
finally
|
||||
{
|
||||
try {
|
||||
_serverChannel.ReleaseConnection (Thread.CurrentThread);
|
||||
_stream.Close();
|
||||
_client.Close ();
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
try {
|
||||
this._serverChannel.ReleaseConnection (Thread.CurrentThread);
|
||||
this._stream.Close();
|
||||
this._client.Close ();
|
||||
} catch {
|
||||
}
|
||||
|
||||
public bool IsLocal
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Boolean IsLocal => true;
|
||||
}
|
||||
}
|
||||
|
@ -35,102 +35,80 @@ using System.Runtime.Remoting.Messaging;
|
||||
using System.IO;
|
||||
using System.Runtime.Remoting.Channels;
|
||||
|
||||
namespace Mono.Remoting.Channels.Unix
|
||||
{
|
||||
internal class UnixServerTransportSink : IServerChannelSink, IChannelSinkBase
|
||||
{
|
||||
IServerChannelSink next_sink;
|
||||
|
||||
public UnixServerTransportSink (IServerChannelSink next)
|
||||
{
|
||||
next_sink = next;
|
||||
}
|
||||
|
||||
public IServerChannelSink NextChannelSink
|
||||
{
|
||||
get
|
||||
{
|
||||
return next_sink;
|
||||
}
|
||||
}
|
||||
|
||||
public IDictionary Properties
|
||||
{
|
||||
get
|
||||
{
|
||||
if (next_sink != null) return next_sink.Properties;
|
||||
else return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void AsyncProcessResponse (IServerResponseChannelSinkStack sinkStack, object state,
|
||||
IMessage msg, ITransportHeaders headers, Stream responseStream)
|
||||
{
|
||||
ClientConnection connection = (ClientConnection)state;
|
||||
NetworkStream stream = new NetworkStream (connection.Client);
|
||||
UnixMessageIO.SendMessageStream (stream, responseStream, headers, connection.Buffer);
|
||||
stream.Flush ();
|
||||
stream.Close ();
|
||||
}
|
||||
|
||||
public Stream GetResponseStream (IServerResponseChannelSinkStack sinkStack, object state,
|
||||
IMessage msg, ITransportHeaders headers)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public ServerProcessing ProcessMessage (IServerChannelSinkStack sinkStack,
|
||||
IMessage requestMsg,
|
||||
ITransportHeaders requestHeaders,
|
||||
Stream requestStream,
|
||||
out IMessage responseMsg,
|
||||
out ITransportHeaders responseHeaders,
|
||||
out Stream responseStream)
|
||||
{
|
||||
// this is the first sink, and UnixServerChannel does not call it.
|
||||
throw new NotSupportedException ();
|
||||
}
|
||||
|
||||
internal void InternalProcessMessage (ClientConnection connection, Stream stream)
|
||||
{
|
||||
// Reads the headers and the request stream
|
||||
|
||||
Stream requestStream;
|
||||
ITransportHeaders requestHeaders;
|
||||
|
||||
requestStream = UnixMessageIO.ReceiveMessageStream (stream, out requestHeaders, connection.Buffer);
|
||||
|
||||
/* try {
|
||||
PeerCred cred = connection.Client.PeerCredential;
|
||||
requestHeaders["__uid"] = cred.UserID;
|
||||
} catch (Exception e) {
|
||||
Console.WriteLine ("Couldn't get the peer cred: " + e);
|
||||
}
|
||||
*/
|
||||
// Pushes the connection object together with the sink. This information
|
||||
// will be used for sending the response in an async call.
|
||||
|
||||
ServerChannelSinkStack sinkStack = new ServerChannelSinkStack();
|
||||
sinkStack.Push(this, connection);
|
||||
|
||||
ITransportHeaders responseHeaders;
|
||||
Stream responseStream;
|
||||
IMessage responseMsg;
|
||||
|
||||
ServerProcessing proc = next_sink.ProcessMessage(sinkStack, null, requestHeaders, requestStream, out responseMsg, out responseHeaders, out responseStream);
|
||||
|
||||
switch (proc)
|
||||
{
|
||||
case ServerProcessing.Complete:
|
||||
UnixMessageIO.SendMessageStream (stream, responseStream, responseHeaders, connection.Buffer);
|
||||
stream.Flush ();
|
||||
break;
|
||||
|
||||
case ServerProcessing.Async:
|
||||
case ServerProcessing.OneWay:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
namespace Mono.Remoting.Channels.Unix {
|
||||
internal class UnixServerTransportSink : IServerChannelSink, IChannelSinkBase {
|
||||
IServerChannelSink next_sink;
|
||||
|
||||
public UnixServerTransportSink(IServerChannelSink next) => this.next_sink = next;
|
||||
|
||||
public IServerChannelSink NextChannelSink => this.next_sink;
|
||||
|
||||
public IDictionary Properties {
|
||||
get {
|
||||
if(this.next_sink != null) {
|
||||
return this.next_sink.Properties;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AsyncProcessResponse(IServerResponseChannelSinkStack sinkStack, Object state,
|
||||
IMessage msg, ITransportHeaders headers, Stream responseStream) {
|
||||
ClientConnection connection = (ClientConnection)state;
|
||||
NetworkStream stream = new NetworkStream(connection.Client);
|
||||
UnixMessageIO.SendMessageStream(stream, responseStream, headers, connection.Buffer);
|
||||
stream.Flush();
|
||||
stream.Close();
|
||||
}
|
||||
|
||||
public Stream GetResponseStream(IServerResponseChannelSinkStack sinkStack, Object state,
|
||||
IMessage msg, ITransportHeaders headers) => null;
|
||||
|
||||
public ServerProcessing ProcessMessage(IServerChannelSinkStack sinkStack,
|
||||
IMessage requestMsg,
|
||||
ITransportHeaders requestHeaders,
|
||||
Stream requestStream,
|
||||
out IMessage responseMsg,
|
||||
out ITransportHeaders responseHeaders,
|
||||
out Stream responseStream) =>
|
||||
// this is the first sink, and UnixServerChannel does not call it.
|
||||
throw new NotSupportedException();
|
||||
|
||||
internal void InternalProcessMessage(ClientConnection connection, Stream stream) {
|
||||
// Reads the headers and the request stream
|
||||
|
||||
Stream requestStream;
|
||||
|
||||
requestStream = UnixMessageIO.ReceiveMessageStream(stream, out ITransportHeaders requestHeaders, connection.Buffer);
|
||||
|
||||
/* try {
|
||||
PeerCred cred = connection.Client.PeerCredential;
|
||||
requestHeaders["__uid"] = cred.UserID;
|
||||
} catch (Exception e) {
|
||||
Console.WriteLine ("Couldn't get the peer cred: " + e);
|
||||
}
|
||||
*/
|
||||
// Pushes the connection object together with the sink. This information
|
||||
// will be used for sending the response in an async call.
|
||||
|
||||
ServerChannelSinkStack sinkStack = new ServerChannelSinkStack();
|
||||
sinkStack.Push(this, connection);
|
||||
|
||||
|
||||
ServerProcessing proc = this.next_sink.ProcessMessage(sinkStack, null, requestHeaders, requestStream, out IMessage responseMsg, out ITransportHeaders responseHeaders, out Stream responseStream);
|
||||
|
||||
switch(proc) {
|
||||
case ServerProcessing.Complete:
|
||||
UnixMessageIO.SendMessageStream(stream, responseStream, responseHeaders, connection.Buffer);
|
||||
stream.Flush();
|
||||
break;
|
||||
|
||||
case ServerProcessing.Async:
|
||||
case ServerProcessing.OneWay:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,154 +35,158 @@ using System.Text;
|
||||
|
||||
namespace Mono.Unix.Native {
|
||||
|
||||
// This class represents a single unmanaged function with "cdecl" calling
|
||||
// convention -- that is, it can accept a variable number of arguments which
|
||||
// are passed on the runtime stack.
|
||||
//
|
||||
// To use, create an instance:
|
||||
//
|
||||
// CdeclFunction printf = new CdeclFunction ("the library",
|
||||
// "the function name", /* optional */ typeof (ReturnType));
|
||||
//
|
||||
// Then call the Invoke method with the appropriate number of arguments:
|
||||
//
|
||||
// printf.Invoke (new object[]{"hello, %s\n", "world!"});
|
||||
//
|
||||
// In the background a P/Invoke definition for the method with the
|
||||
// requested argument types will be generated and invoked, invoking the
|
||||
// unmanaged function. The generated methods are cached, so that subsequent
|
||||
// calls with the same argument list do not generate new code, speeding up
|
||||
// the call sequence.
|
||||
//
|
||||
// Invoking Cdecl functions is not guaranteed to be portable across all
|
||||
// platforms. For example, AMD64 requires that the caller set EAX to the
|
||||
// number of floating point arguments passed in the SSE registers. This
|
||||
// is only required for variable argument/cdecl functions; consequently,
|
||||
// the overload technique used by this class wouldn't normally work.
|
||||
// Mono's AMD64 JIT works around this by always setting EAX on P/Invoke
|
||||
// invocations, allowing CdeclFunction to work properly, but it will not
|
||||
// necessarily always work. See also:
|
||||
//
|
||||
// http://lwn.net/Articles/5201/?format=printable
|
||||
//
|
||||
// Due to potential portability issues, cdecl functions should be avoided
|
||||
// on most platforms.
|
||||
//
|
||||
// This class is intended to be thread-safe.
|
||||
public sealed class CdeclFunction
|
||||
{
|
||||
// The readonly fields (1) shouldn't be modified, and (2) should only be
|
||||
// used when `overloads' is locked.
|
||||
private readonly string library;
|
||||
private readonly string method;
|
||||
private readonly Type returnType;
|
||||
private readonly AssemblyName assemblyName;
|
||||
private readonly AssemblyBuilder assemblyBuilder;
|
||||
private readonly ModuleBuilder moduleBuilder;
|
||||
// This class represents a single unmanaged function with "cdecl" calling
|
||||
// convention -- that is, it can accept a variable number of arguments which
|
||||
// are passed on the runtime stack.
|
||||
//
|
||||
// To use, create an instance:
|
||||
//
|
||||
// CdeclFunction printf = new CdeclFunction ("the library",
|
||||
// "the function name", /* optional */ typeof (ReturnType));
|
||||
//
|
||||
// Then call the Invoke method with the appropriate number of arguments:
|
||||
//
|
||||
// printf.Invoke (new object[]{"hello, %s\n", "world!"});
|
||||
//
|
||||
// In the background a P/Invoke definition for the method with the
|
||||
// requested argument types will be generated and invoked, invoking the
|
||||
// unmanaged function. The generated methods are cached, so that subsequent
|
||||
// calls with the same argument list do not generate new code, speeding up
|
||||
// the call sequence.
|
||||
//
|
||||
// Invoking Cdecl functions is not guaranteed to be portable across all
|
||||
// platforms. For example, AMD64 requires that the caller set EAX to the
|
||||
// number of floating point arguments passed in the SSE registers. This
|
||||
// is only required for variable argument/cdecl functions; consequently,
|
||||
// the overload technique used by this class wouldn't normally work.
|
||||
// Mono's AMD64 JIT works around this by always setting EAX on P/Invoke
|
||||
// invocations, allowing CdeclFunction to work properly, but it will not
|
||||
// necessarily always work. See also:
|
||||
//
|
||||
// http://lwn.net/Articles/5201/?format=printable
|
||||
//
|
||||
// Due to potential portability issues, cdecl functions should be avoided
|
||||
// on most platforms.
|
||||
//
|
||||
// This class is intended to be thread-safe.
|
||||
public sealed class CdeclFunction
|
||||
{
|
||||
// The readonly fields (1) shouldn't be modified, and (2) should only be
|
||||
// used when `overloads' is locked.
|
||||
private readonly String library;
|
||||
private readonly String method;
|
||||
private readonly Type returnType;
|
||||
private readonly AssemblyName assemblyName;
|
||||
private readonly AssemblyBuilder assemblyBuilder;
|
||||
private readonly ModuleBuilder moduleBuilder;
|
||||
|
||||
private Hashtable overloads;
|
||||
private readonly Hashtable overloads;
|
||||
|
||||
public CdeclFunction (string library, string method)
|
||||
: this (library, method, typeof(void))
|
||||
{
|
||||
}
|
||||
public CdeclFunction (String library, String method)
|
||||
: this (library, method, typeof(void))
|
||||
{
|
||||
}
|
||||
|
||||
public CdeclFunction (string library, string method, Type returnType)
|
||||
{
|
||||
this.library = library;
|
||||
this.method = method;
|
||||
this.returnType = returnType;
|
||||
this.overloads = new Hashtable ();
|
||||
this.assemblyName = new AssemblyName ();
|
||||
this.assemblyName.Name = "Mono.Posix.Imports." + library;
|
||||
this.assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly (
|
||||
assemblyName, AssemblyBuilderAccess.Run);
|
||||
this.moduleBuilder = assemblyBuilder.DefineDynamicModule (assemblyName.Name);
|
||||
}
|
||||
public CdeclFunction (String library, String method, Type returnType)
|
||||
{
|
||||
this.library = library;
|
||||
this.method = method;
|
||||
this.returnType = returnType;
|
||||
this.overloads = new Hashtable ();
|
||||
this.assemblyName = new AssemblyName {
|
||||
Name = "Mono.Posix.Imports." + library
|
||||
};
|
||||
this.assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly (
|
||||
this.assemblyName, AssemblyBuilderAccess.Run);
|
||||
this.moduleBuilder = this.assemblyBuilder.DefineDynamicModule (this.assemblyName.Name);
|
||||
}
|
||||
|
||||
public object Invoke (object[] parameters)
|
||||
{
|
||||
Type[] parameterTypes = GetParameterTypes (parameters);
|
||||
MethodInfo m = CreateMethod (parameterTypes);
|
||||
return m.Invoke (null, parameters);
|
||||
}
|
||||
public Object Invoke (Object[] parameters)
|
||||
{
|
||||
Type[] parameterTypes = GetParameterTypes (parameters);
|
||||
MethodInfo m = this.CreateMethod (parameterTypes);
|
||||
return m.Invoke (null, parameters);
|
||||
}
|
||||
|
||||
private MethodInfo CreateMethod (Type[] parameterTypes)
|
||||
{
|
||||
string typeName = GetTypeName (parameterTypes);
|
||||
private MethodInfo CreateMethod (Type[] parameterTypes)
|
||||
{
|
||||
String typeName = this.GetTypeName (parameterTypes);
|
||||
|
||||
lock (overloads) {
|
||||
MethodInfo mi = (MethodInfo) overloads [typeName];
|
||||
lock (this.overloads) {
|
||||
MethodInfo mi = (MethodInfo)this.overloads [typeName];
|
||||
|
||||
if (mi != null) {
|
||||
return mi;
|
||||
}
|
||||
if (mi != null) {
|
||||
return mi;
|
||||
}
|
||||
|
||||
TypeBuilder tb = CreateType (typeName);
|
||||
/* MethodBuilder mb = */ tb.DefinePInvokeMethod (
|
||||
method,
|
||||
library,
|
||||
MethodAttributes.PinvokeImpl | MethodAttributes.Static | MethodAttributes.Public,
|
||||
CallingConventions.Standard,
|
||||
returnType,
|
||||
parameterTypes,
|
||||
CallingConvention.Cdecl,
|
||||
CharSet.Ansi);
|
||||
mi = tb.CreateType ().GetMethod (method);
|
||||
overloads.Add (typeName, mi);
|
||||
return mi;
|
||||
}
|
||||
}
|
||||
TypeBuilder tb = this.CreateType (typeName);
|
||||
/* MethodBuilder mb = */
|
||||
_ = tb.DefinePInvokeMethod(
|
||||
this.method,
|
||||
this.library,
|
||||
MethodAttributes.PinvokeImpl | MethodAttributes.Static | MethodAttributes.Public,
|
||||
CallingConventions.Standard,
|
||||
this.returnType,
|
||||
parameterTypes,
|
||||
CallingConvention.Cdecl,
|
||||
CharSet.Ansi);
|
||||
mi = tb.CreateType ().GetMethod (this.method);
|
||||
this.overloads.Add (typeName, mi);
|
||||
return mi;
|
||||
}
|
||||
}
|
||||
|
||||
private TypeBuilder CreateType(String typeName) => this.moduleBuilder.DefineType(typeName, TypeAttributes.Public);
|
||||
|
||||
private static Type GetMarshalType (Type t)
|
||||
{
|
||||
switch (Type.GetTypeCode (t)) {
|
||||
// types < sizeof(int) are marshaled as ints
|
||||
case TypeCode.Boolean: case TypeCode.Char: case TypeCode.SByte:
|
||||
case TypeCode.Int16: case TypeCode.Int32:
|
||||
return typeof(Int32);
|
||||
case TypeCode.Byte: case TypeCode.UInt16: case TypeCode.UInt32:
|
||||
return typeof(UInt32);
|
||||
case TypeCode.Int64:
|
||||
return typeof(Int64);
|
||||
case TypeCode.UInt64:
|
||||
return typeof(UInt64);
|
||||
case TypeCode.Single: case TypeCode.Double:
|
||||
return typeof(Double);
|
||||
default:
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
private TypeBuilder CreateType (string typeName)
|
||||
{
|
||||
return moduleBuilder.DefineType (typeName, TypeAttributes.Public);
|
||||
}
|
||||
private String GetTypeName (Type[] parameterTypes)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder ();
|
||||
|
||||
_ = sb.Append("[").Append(this.library).Append("] ").Append(this.method);
|
||||
_ = sb.Append("(");
|
||||
|
||||
private static Type GetMarshalType (Type t)
|
||||
{
|
||||
switch (Type.GetTypeCode (t)) {
|
||||
// types < sizeof(int) are marshaled as ints
|
||||
case TypeCode.Boolean: case TypeCode.Char: case TypeCode.SByte:
|
||||
case TypeCode.Int16: case TypeCode.Int32:
|
||||
return typeof(int);
|
||||
case TypeCode.Byte: case TypeCode.UInt16: case TypeCode.UInt32:
|
||||
return typeof(uint);
|
||||
case TypeCode.Int64:
|
||||
return typeof(long);
|
||||
case TypeCode.UInt64:
|
||||
return typeof(ulong);
|
||||
case TypeCode.Single: case TypeCode.Double:
|
||||
return typeof(double);
|
||||
default:
|
||||
return t;
|
||||
}
|
||||
}
|
||||
if (parameterTypes.Length > 0) {
|
||||
_ = sb.Append(parameterTypes[0]);
|
||||
}
|
||||
|
||||
for (Int32 i = 1; i < parameterTypes.Length; ++i) {
|
||||
_ = sb.Append(",").Append(parameterTypes[i]);
|
||||
}
|
||||
|
||||
_ = sb.Append(") : ").Append(this.returnType.FullName);
|
||||
|
||||
private string GetTypeName (Type[] parameterTypes)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder ();
|
||||
return sb.ToString ();
|
||||
}
|
||||
|
||||
sb.Append ("[").Append (library).Append ("] ").Append (method);
|
||||
sb.Append ("(");
|
||||
|
||||
if (parameterTypes.Length > 0)
|
||||
sb.Append (parameterTypes [0]);
|
||||
for (int i = 1; i < parameterTypes.Length; ++i)
|
||||
sb.Append (",").Append (parameterTypes [i]);
|
||||
|
||||
sb.Append (") : ").Append (returnType.FullName);
|
||||
|
||||
return sb.ToString ();
|
||||
}
|
||||
|
||||
private static Type[] GetParameterTypes (object[] parameters)
|
||||
{
|
||||
Type[] parameterTypes = new Type [parameters.Length];
|
||||
for (int i = 0; i < parameters.Length; ++i)
|
||||
parameterTypes [i] = GetMarshalType (parameters [i].GetType ());
|
||||
return parameterTypes;
|
||||
}
|
||||
}
|
||||
private static Type[] GetParameterTypes (Object[] parameters)
|
||||
{
|
||||
Type[] parameterTypes = new Type [parameters.Length];
|
||||
for (Int32 i = 0; i < parameters.Length; ++i) {
|
||||
parameterTypes [i] = GetMarshalType (parameters [i].GetType ());
|
||||
}
|
||||
|
||||
return parameterTypes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,48 +32,42 @@ using Mono.Unix;
|
||||
|
||||
namespace Mono.Unix.Native {
|
||||
|
||||
class FileNameMarshaler : ICustomMarshaler {
|
||||
class FileNameMarshaler : ICustomMarshaler {
|
||||
|
||||
private static FileNameMarshaler Instance = new FileNameMarshaler ();
|
||||
private static readonly FileNameMarshaler Instance = new FileNameMarshaler ();
|
||||
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Stil", "IDE0060:Nicht verwendete Parameter entfernen", Justification = "<Ausstehend>")]
|
||||
public static ICustomMarshaler GetInstance(String s) => Instance;
|
||||
|
||||
public void CleanUpManagedData (Object o)
|
||||
{
|
||||
}
|
||||
|
||||
public void CleanUpNativeData(IntPtr pNativeData) =>
|
||||
// Console.WriteLine ("# FileNameMarshaler.CleanUpManagedData ({0:x})", pNativeData);
|
||||
UnixMarshal.FreeHeap(pNativeData);
|
||||
|
||||
public Int32 GetNativeDataSize() => IntPtr.Size;
|
||||
|
||||
public IntPtr MarshalManagedToNative (Object obj)
|
||||
{
|
||||
if(!(obj is String s)) {
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
IntPtr p = UnixMarshal.StringToHeap (s, UnixEncoding.Instance);
|
||||
// Console.WriteLine ("# FileNameMarshaler.MarshalNativeToManaged for `{0}'={1:x}", s, p);
|
||||
return p;
|
||||
}
|
||||
|
||||
public static ICustomMarshaler GetInstance (string s)
|
||||
{
|
||||
return Instance;
|
||||
}
|
||||
|
||||
public void CleanUpManagedData (object o)
|
||||
{
|
||||
}
|
||||
|
||||
public void CleanUpNativeData (IntPtr pNativeData)
|
||||
{
|
||||
// Console.WriteLine ("# FileNameMarshaler.CleanUpManagedData ({0:x})", pNativeData);
|
||||
UnixMarshal.FreeHeap (pNativeData);
|
||||
}
|
||||
|
||||
public int GetNativeDataSize ()
|
||||
{
|
||||
return IntPtr.Size;
|
||||
}
|
||||
|
||||
public IntPtr MarshalManagedToNative (object obj)
|
||||
{
|
||||
string s = obj as string;
|
||||
if (s == null)
|
||||
return IntPtr.Zero;
|
||||
IntPtr p = UnixMarshal.StringToHeap (s, UnixEncoding.Instance);
|
||||
// Console.WriteLine ("# FileNameMarshaler.MarshalNativeToManaged for `{0}'={1:x}", s, p);
|
||||
return p;
|
||||
}
|
||||
|
||||
public object MarshalNativeToManaged (IntPtr pNativeData)
|
||||
{
|
||||
string s = UnixMarshal.PtrToString (pNativeData, UnixEncoding.Instance);
|
||||
// Console.WriteLine ("# FileNameMarshaler.MarshalNativeToManaged ({0:x})=`{1}'",
|
||||
// pNativeData, s);
|
||||
return s;
|
||||
}
|
||||
}
|
||||
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
|
||||
|
@ -30,31 +30,23 @@
|
||||
using System;
|
||||
|
||||
[AttributeUsage (
|
||||
AttributeTargets.Class |
|
||||
AttributeTargets.Delegate |
|
||||
AttributeTargets.Enum |
|
||||
AttributeTargets.Field |
|
||||
AttributeTargets.Struct)]
|
||||
internal class MapAttribute : Attribute {
|
||||
private string nativeType;
|
||||
private string suppressFlags;
|
||||
AttributeTargets.Class |
|
||||
AttributeTargets.Delegate |
|
||||
AttributeTargets.Enum |
|
||||
AttributeTargets.Field |
|
||||
AttributeTargets.Struct)]
|
||||
internal class MapAttribute : Attribute {
|
||||
public MapAttribute ()
|
||||
{
|
||||
}
|
||||
|
||||
public MapAttribute ()
|
||||
{
|
||||
}
|
||||
|
||||
public MapAttribute (string nativeType)
|
||||
{
|
||||
this.nativeType = nativeType;
|
||||
}
|
||||
|
||||
public string NativeType {
|
||||
get {return nativeType;}
|
||||
}
|
||||
|
||||
public string SuppressFlags {
|
||||
get {return suppressFlags;}
|
||||
set {suppressFlags = value;}
|
||||
}
|
||||
public MapAttribute(String nativeType) => this.NativeType = nativeType;
|
||||
|
||||
public String NativeType {
|
||||
get;
|
||||
}
|
||||
|
||||
public String SuppressFlags { get;
|
||||
set; }
|
||||
}
|
||||
|
||||
|
@ -14,470 +14,458 @@ using Mono.Unix.Android;
|
||||
|
||||
namespace Mono.Unix.Native {
|
||||
|
||||
[CLSCompliant (false)]
|
||||
public sealed /* static */ partial class NativeConvert
|
||||
{
|
||||
//
|
||||
// Non-generated exports
|
||||
//
|
||||
//[CLSCompliant (false)]
|
||||
public sealed /* static */ partial class NativeConvert
|
||||
{
|
||||
//
|
||||
// Non-generated exports
|
||||
//
|
||||
#if MONODROID
|
||||
[DllImport (LIB, EntryPoint="Mono_Posix_FromRealTimeSignum")]
|
||||
static extern int HelperFromRealTimeSignum (Int32 offset, out Int32 rval);
|
||||
[DllImport (LIB, EntryPoint="Mono_Posix_FromRealTimeSignum")]
|
||||
static extern int HelperFromRealTimeSignum (Int32 offset, out Int32 rval);
|
||||
|
||||
static int FromRealTimeSignum (Int32 offset, out Int32 rval)
|
||||
{
|
||||
if (!AndroidUtils.AreRealTimeSignalsSafe ())
|
||||
throw new PlatformNotSupportedException ("Real-time signals are not supported on this Android architecture");
|
||||
return HelperFromRealTimeSignum (offset, out rval);
|
||||
}
|
||||
static int FromRealTimeSignum (Int32 offset, out Int32 rval)
|
||||
{
|
||||
if (!AndroidUtils.AreRealTimeSignalsSafe ())
|
||||
throw new PlatformNotSupportedException ("Real-time signals are not supported on this Android architecture");
|
||||
return HelperFromRealTimeSignum (offset, out rval);
|
||||
}
|
||||
#else
|
||||
[DllImport (LIB, EntryPoint="Mono_Posix_FromRealTimeSignum")]
|
||||
private static extern int FromRealTimeSignum (Int32 offset, out Int32 rval);
|
||||
[DllImport (LIB, EntryPoint="Mono_Posix_FromRealTimeSignum")]
|
||||
private static extern Int32 FromRealTimeSignum (Int32 offset, out Int32 rval);
|
||||
#endif
|
||||
// convert a realtime signal to os signal
|
||||
public static int FromRealTimeSignum (RealTimeSignum sig)
|
||||
{
|
||||
int sigNum;
|
||||
if (FromRealTimeSignum (sig.Offset, out sigNum) == -1)
|
||||
ThrowArgumentException (sig.Offset);
|
||||
return sigNum;
|
||||
}
|
||||
// convert a realtime signal to os signal
|
||||
public static Int32 FromRealTimeSignum (RealTimeSignum sig)
|
||||
{
|
||||
if(FromRealTimeSignum(sig.Offset, out Int32 sigNum) == -1) {
|
||||
ThrowArgumentException(sig.Offset);
|
||||
}
|
||||
|
||||
return sigNum;
|
||||
}
|
||||
|
||||
// convert an offset to an rt signum
|
||||
public static RealTimeSignum ToRealTimeSignum(Int32 offset) => new RealTimeSignum(offset);
|
||||
|
||||
// convert from octal representation.
|
||||
public static FilePermissions FromOctalPermissionString (String value)
|
||||
{
|
||||
UInt32 n = Convert.ToUInt32 (value, 8);
|
||||
return ToFilePermissions (n);
|
||||
}
|
||||
|
||||
// convert an offset to an rt signum
|
||||
public static RealTimeSignum ToRealTimeSignum (int offset)
|
||||
{
|
||||
return new RealTimeSignum (offset);
|
||||
}
|
||||
public static String ToOctalPermissionString (FilePermissions value)
|
||||
{
|
||||
String s = Convert.ToString ((Int32) (value & ~FilePermissions.S_IFMT), 8);
|
||||
return new String('0', 4-s.Length) + s;
|
||||
}
|
||||
|
||||
// convert from octal representation.
|
||||
public static FilePermissions FromOctalPermissionString (string value)
|
||||
{
|
||||
uint n = Convert.ToUInt32 (value, 8);
|
||||
return ToFilePermissions (n);
|
||||
}
|
||||
public static FilePermissions FromUnixPermissionString (String value)
|
||||
{
|
||||
if (value == null) {
|
||||
throw new ArgumentNullException ("value");
|
||||
}
|
||||
|
||||
if (value.Length != 9 && value.Length != 10) {
|
||||
throw new ArgumentException ("value", "must contain 9 or 10 characters");
|
||||
}
|
||||
|
||||
Int32 i = 0;
|
||||
FilePermissions perms = new FilePermissions ();
|
||||
|
||||
public static string ToOctalPermissionString (FilePermissions value)
|
||||
{
|
||||
string s = Convert.ToString ((int) (value & ~FilePermissions.S_IFMT), 8);
|
||||
return new string ('0', 4-s.Length) + s;
|
||||
}
|
||||
if (value.Length == 10) {
|
||||
perms |= GetUnixPermissionDevice (value [i]);
|
||||
++i;
|
||||
}
|
||||
|
||||
public static FilePermissions FromUnixPermissionString (string value)
|
||||
{
|
||||
if (value == null)
|
||||
throw new ArgumentNullException ("value");
|
||||
if (value.Length != 9 && value.Length != 10)
|
||||
throw new ArgumentException ("value", "must contain 9 or 10 characters");
|
||||
perms |= GetUnixPermissionGroup (
|
||||
value [i++], FilePermissions.S_IRUSR,
|
||||
value [i++], FilePermissions.S_IWUSR,
|
||||
value [i++], FilePermissions.S_IXUSR,
|
||||
's', 'S', FilePermissions.S_ISUID);
|
||||
|
||||
int i = 0;
|
||||
FilePermissions perms = new FilePermissions ();
|
||||
perms |= GetUnixPermissionGroup (
|
||||
value [i++], FilePermissions.S_IRGRP,
|
||||
value [i++], FilePermissions.S_IWGRP,
|
||||
value [i++], FilePermissions.S_IXGRP,
|
||||
's', 'S', FilePermissions.S_ISGID);
|
||||
|
||||
if (value.Length == 10) {
|
||||
perms |= GetUnixPermissionDevice (value [i]);
|
||||
++i;
|
||||
}
|
||||
perms |= GetUnixPermissionGroup (
|
||||
value [i++], FilePermissions.S_IROTH,
|
||||
value [i++], FilePermissions.S_IWOTH,
|
||||
value [i++], FilePermissions.S_IXOTH,
|
||||
't', 'T', FilePermissions.S_ISVTX);
|
||||
|
||||
perms |= GetUnixPermissionGroup (
|
||||
value [i++], FilePermissions.S_IRUSR,
|
||||
value [i++], FilePermissions.S_IWUSR,
|
||||
value [i++], FilePermissions.S_IXUSR,
|
||||
's', 'S', FilePermissions.S_ISUID);
|
||||
return perms;
|
||||
}
|
||||
|
||||
perms |= GetUnixPermissionGroup (
|
||||
value [i++], FilePermissions.S_IRGRP,
|
||||
value [i++], FilePermissions.S_IWGRP,
|
||||
value [i++], FilePermissions.S_IXGRP,
|
||||
's', 'S', FilePermissions.S_ISGID);
|
||||
private static FilePermissions GetUnixPermissionDevice (Char value)
|
||||
{
|
||||
switch (value) {
|
||||
case 'd': return FilePermissions.S_IFDIR;
|
||||
case 'c': return FilePermissions.S_IFCHR;
|
||||
case 'b': return FilePermissions.S_IFBLK;
|
||||
case '-': return FilePermissions.S_IFREG;
|
||||
case 'p': return FilePermissions.S_IFIFO;
|
||||
case 'l': return FilePermissions.S_IFLNK;
|
||||
case 's': return FilePermissions.S_IFSOCK;
|
||||
}
|
||||
throw new ArgumentException ("value", "invalid device specification: " +
|
||||
value);
|
||||
}
|
||||
|
||||
perms |= GetUnixPermissionGroup (
|
||||
value [i++], FilePermissions.S_IROTH,
|
||||
value [i++], FilePermissions.S_IWOTH,
|
||||
value [i++], FilePermissions.S_IXOTH,
|
||||
't', 'T', FilePermissions.S_ISVTX);
|
||||
private static FilePermissions GetUnixPermissionGroup (
|
||||
Char read, FilePermissions readb,
|
||||
Char write, FilePermissions writeb,
|
||||
Char exec, FilePermissions execb,
|
||||
Char xboth, Char xbitonly, FilePermissions xbit)
|
||||
{
|
||||
FilePermissions perms = new FilePermissions ();
|
||||
if (read == 'r') {
|
||||
perms |= readb;
|
||||
}
|
||||
|
||||
if (write == 'w') {
|
||||
perms |= writeb;
|
||||
}
|
||||
|
||||
if (exec == 'x') {
|
||||
perms |= execb;
|
||||
} else if (exec == xbitonly) {
|
||||
perms |= xbit;
|
||||
} else if (exec == xboth) {
|
||||
perms |= execb | xbit;
|
||||
}
|
||||
|
||||
return perms;
|
||||
}
|
||||
|
||||
return perms;
|
||||
}
|
||||
// Create ls(1) drwxrwxrwx permissions display
|
||||
public static String ToUnixPermissionString (FilePermissions value)
|
||||
{
|
||||
Char[] access = new Char[] {
|
||||
'-', // device
|
||||
'-', '-', '-', // owner
|
||||
'-', '-', '-', // group
|
||||
'-', '-', '-', // other
|
||||
};
|
||||
Boolean have_device = true;
|
||||
switch (value & FilePermissions.S_IFMT) {
|
||||
case FilePermissions.S_IFDIR: access [0] = 'd'; break;
|
||||
case FilePermissions.S_IFCHR: access [0] = 'c'; break;
|
||||
case FilePermissions.S_IFBLK: access [0] = 'b'; break;
|
||||
case FilePermissions.S_IFREG: access [0] = '-'; break;
|
||||
case FilePermissions.S_IFIFO: access [0] = 'p'; break;
|
||||
case FilePermissions.S_IFLNK: access [0] = 'l'; break;
|
||||
case FilePermissions.S_IFSOCK: access [0] = 's'; break;
|
||||
default: have_device = false; break;
|
||||
}
|
||||
SetUnixPermissionGroup (value, access, 1,
|
||||
FilePermissions.S_IRUSR, FilePermissions.S_IWUSR, FilePermissions.S_IXUSR,
|
||||
's', 'S', FilePermissions.S_ISUID);
|
||||
SetUnixPermissionGroup (value, access, 4,
|
||||
FilePermissions.S_IRGRP, FilePermissions.S_IWGRP, FilePermissions.S_IXGRP,
|
||||
's', 'S', FilePermissions.S_ISGID);
|
||||
SetUnixPermissionGroup (value, access, 7,
|
||||
FilePermissions.S_IROTH, FilePermissions.S_IWOTH, FilePermissions.S_IXOTH,
|
||||
't', 'T', FilePermissions.S_ISVTX);
|
||||
return have_device
|
||||
? new String(access)
|
||||
: new String(access, 1, 9);
|
||||
}
|
||||
|
||||
private static FilePermissions GetUnixPermissionDevice (char value)
|
||||
{
|
||||
switch (value) {
|
||||
case 'd': return FilePermissions.S_IFDIR;
|
||||
case 'c': return FilePermissions.S_IFCHR;
|
||||
case 'b': return FilePermissions.S_IFBLK;
|
||||
case '-': return FilePermissions.S_IFREG;
|
||||
case 'p': return FilePermissions.S_IFIFO;
|
||||
case 'l': return FilePermissions.S_IFLNK;
|
||||
case 's': return FilePermissions.S_IFSOCK;
|
||||
}
|
||||
throw new ArgumentException ("value", "invalid device specification: " +
|
||||
value);
|
||||
}
|
||||
private static void SetUnixPermissionGroup (FilePermissions value,
|
||||
Char[] access, Int32 index,
|
||||
FilePermissions read, FilePermissions write, FilePermissions exec,
|
||||
Char both, Char setonly, FilePermissions setxbit)
|
||||
{
|
||||
if (UnixFileSystemInfo.IsSet (value, read)) {
|
||||
access [index] = 'r';
|
||||
}
|
||||
|
||||
if (UnixFileSystemInfo.IsSet (value, write)) {
|
||||
access [index+1] = 'w';
|
||||
}
|
||||
|
||||
access [index+2] = GetSymbolicMode (value, exec, both, setonly, setxbit);
|
||||
}
|
||||
|
||||
private static FilePermissions GetUnixPermissionGroup (
|
||||
char read, FilePermissions readb,
|
||||
char write, FilePermissions writeb,
|
||||
char exec, FilePermissions execb,
|
||||
char xboth, char xbitonly, FilePermissions xbit)
|
||||
{
|
||||
FilePermissions perms = new FilePermissions ();
|
||||
if (read == 'r')
|
||||
perms |= readb;
|
||||
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;
|
||||
}
|
||||
// Implement the GNU ls(1) permissions spec; see `info coreutils ls`,
|
||||
// section 10.1.2, the `-l' argument information.
|
||||
private static Char GetSymbolicMode (FilePermissions value,
|
||||
FilePermissions xbit, Char both, Char setonly, FilePermissions setxbit)
|
||||
{
|
||||
Boolean is_x = UnixFileSystemInfo.IsSet (value, xbit);
|
||||
Boolean is_sx = UnixFileSystemInfo.IsSet (value, setxbit);
|
||||
|
||||
return is_x && is_sx ? both : is_sx ? setonly : is_x ? 'x' : '-';
|
||||
}
|
||||
|
||||
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 DateTime ToDateTime(Int64 time) => FromTimeT(time);
|
||||
|
||||
public static DateTime ToDateTime(Int64 time, Int64 nanoTime) => FromTimeT(time).AddMilliseconds(nanoTime / 1000);
|
||||
|
||||
public static Int64 FromDateTime(DateTime time) => ToTimeT(time);
|
||||
|
||||
public static DateTime FromTimeT(Int64 time) => UnixEpoch.AddSeconds(time).ToLocalTime();
|
||||
|
||||
public static Int64 ToTimeT (DateTime time)
|
||||
{
|
||||
if (time.Kind == DateTimeKind.Unspecified) {
|
||||
throw new ArgumentException ("DateTimeKind.Unspecified is not supported. Use Local or Utc times.", "time");
|
||||
}
|
||||
|
||||
if (time.Kind == DateTimeKind.Local) {
|
||||
time = time.ToUniversalTime ();
|
||||
}
|
||||
|
||||
return (Int64) (time - UnixEpoch).TotalSeconds;
|
||||
}
|
||||
|
||||
// Create ls(1) drwxrwxrwx permissions display
|
||||
public static string ToUnixPermissionString (FilePermissions value)
|
||||
{
|
||||
char [] access = new char[] {
|
||||
'-', // device
|
||||
'-', '-', '-', // owner
|
||||
'-', '-', '-', // group
|
||||
'-', '-', '-', // other
|
||||
};
|
||||
bool have_device = true;
|
||||
switch (value & FilePermissions.S_IFMT) {
|
||||
case FilePermissions.S_IFDIR: access [0] = 'd'; break;
|
||||
case FilePermissions.S_IFCHR: access [0] = 'c'; break;
|
||||
case FilePermissions.S_IFBLK: access [0] = 'b'; break;
|
||||
case FilePermissions.S_IFREG: access [0] = '-'; break;
|
||||
case FilePermissions.S_IFIFO: access [0] = 'p'; break;
|
||||
case FilePermissions.S_IFLNK: access [0] = 'l'; break;
|
||||
case FilePermissions.S_IFSOCK: access [0] = 's'; break;
|
||||
default: have_device = false; break;
|
||||
}
|
||||
SetUnixPermissionGroup (value, access, 1,
|
||||
FilePermissions.S_IRUSR, FilePermissions.S_IWUSR, FilePermissions.S_IXUSR,
|
||||
's', 'S', FilePermissions.S_ISUID);
|
||||
SetUnixPermissionGroup (value, access, 4,
|
||||
FilePermissions.S_IRGRP, FilePermissions.S_IWGRP, FilePermissions.S_IXGRP,
|
||||
's', 'S', FilePermissions.S_ISGID);
|
||||
SetUnixPermissionGroup (value, access, 7,
|
||||
FilePermissions.S_IROTH, FilePermissions.S_IWOTH, FilePermissions.S_IXOTH,
|
||||
't', 'T', FilePermissions.S_ISVTX);
|
||||
return have_device
|
||||
? new string (access)
|
||||
: new string (access, 1, 9);
|
||||
}
|
||||
public static OpenFlags ToOpenFlags (FileMode mode, FileAccess access)
|
||||
{
|
||||
OpenFlags flags = 0;
|
||||
switch (mode) {
|
||||
case FileMode.CreateNew:
|
||||
flags = OpenFlags.O_CREAT | OpenFlags.O_EXCL;
|
||||
break;
|
||||
case FileMode.Create:
|
||||
flags = OpenFlags.O_CREAT | OpenFlags.O_TRUNC;
|
||||
break;
|
||||
case FileMode.Open:
|
||||
// do nothing
|
||||
break;
|
||||
case FileMode.OpenOrCreate:
|
||||
flags = OpenFlags.O_CREAT;
|
||||
break;
|
||||
case FileMode.Truncate:
|
||||
flags = OpenFlags.O_TRUNC;
|
||||
break;
|
||||
case FileMode.Append:
|
||||
flags = OpenFlags.O_APPEND;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentException (Locale.GetText ("Unsupported mode value"), "mode");
|
||||
}
|
||||
|
||||
// Is O_LARGEFILE supported?
|
||||
if(TryFromOpenFlags(OpenFlags.O_LARGEFILE, out _)) {
|
||||
flags |= OpenFlags.O_LARGEFILE;
|
||||
}
|
||||
|
||||
switch (access) {
|
||||
case FileAccess.Read:
|
||||
flags |= OpenFlags.O_RDONLY;
|
||||
break;
|
||||
case FileAccess.Write:
|
||||
flags |= OpenFlags.O_WRONLY;
|
||||
break;
|
||||
case FileAccess.ReadWrite:
|
||||
flags |= OpenFlags.O_RDWR;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException (Locale.GetText ("Unsupported access value"), "access");
|
||||
}
|
||||
|
||||
private static void SetUnixPermissionGroup (FilePermissions value,
|
||||
char[] access, int index,
|
||||
FilePermissions read, FilePermissions write, FilePermissions exec,
|
||||
char both, char setonly, FilePermissions setxbit)
|
||||
{
|
||||
if (UnixFileSystemInfo.IsSet (value, read))
|
||||
access [index] = 'r';
|
||||
if (UnixFileSystemInfo.IsSet (value, write))
|
||||
access [index+1] = 'w';
|
||||
access [index+2] = GetSymbolicMode (value, exec, both, setonly, setxbit);
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
// Implement the GNU ls(1) permissions spec; see `info coreutils ls`,
|
||||
// section 10.1.2, the `-l' argument information.
|
||||
private static char GetSymbolicMode (FilePermissions value,
|
||||
FilePermissions xbit, char both, char setonly, FilePermissions setxbit)
|
||||
{
|
||||
bool is_x = UnixFileSystemInfo.IsSet (value, xbit);
|
||||
bool is_sx = UnixFileSystemInfo.IsSet (value, setxbit);
|
||||
|
||||
if (is_x && is_sx)
|
||||
return both;
|
||||
if (is_sx)
|
||||
return setonly;
|
||||
if (is_x)
|
||||
return 'x';
|
||||
return '-';
|
||||
}
|
||||
public static String ToFopenMode (FileAccess access)
|
||||
{
|
||||
switch (access) {
|
||||
case FileAccess.Read: return "rb";
|
||||
case FileAccess.Write: return "wb";
|
||||
case FileAccess.ReadWrite: return "r+b";
|
||||
default: throw new ArgumentOutOfRangeException ("access");
|
||||
}
|
||||
}
|
||||
|
||||
public static 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 String ToFopenMode (FileMode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case FileMode.CreateNew: case FileMode.Create: return "w+b";
|
||||
case FileMode.Open: case FileMode.OpenOrCreate: return "r+b";
|
||||
case FileMode.Truncate: return "w+b";
|
||||
case FileMode.Append: return "a+b";
|
||||
default: throw new ArgumentOutOfRangeException ("mode");
|
||||
}
|
||||
}
|
||||
|
||||
public static DateTime ToDateTime (long time)
|
||||
{
|
||||
return FromTimeT (time);
|
||||
}
|
||||
private static readonly String[][] fopen_modes = new String[][]{
|
||||
// Read Write ReadWrite
|
||||
/* FileMode.CreateNew: */ new String[]{"Can't Read+Create", "wb", "w+b"},
|
||||
/* FileMode.Create: */ new String[]{"Can't Read+Create", "wb", "w+b"},
|
||||
/* FileMode.Open: */ new String[]{"rb", "wb", "r+b"},
|
||||
/* FileMode.OpenOrCreate: */ new String[]{"rb", "wb", "r+b"},
|
||||
/* FileMode.Truncate: */ new String[]{"Cannot Truncate and Read","wb", "w+b"},
|
||||
/* FileMode.Append: */ new String[]{"Cannot Append and Read", "ab", "a+b"},
|
||||
};
|
||||
|
||||
public static DateTime ToDateTime (long time, long nanoTime)
|
||||
{
|
||||
return FromTimeT (time).AddMilliseconds (nanoTime / 1000);
|
||||
}
|
||||
public static String ToFopenMode (FileMode mode, FileAccess access)
|
||||
{
|
||||
Int32 fm = -1, fa = -1;
|
||||
switch (mode) {
|
||||
case FileMode.CreateNew: fm = 0; break;
|
||||
case FileMode.Create: fm = 1; break;
|
||||
case FileMode.Open: fm = 2; break;
|
||||
case FileMode.OpenOrCreate: fm = 3; break;
|
||||
case FileMode.Truncate: fm = 4; break;
|
||||
case FileMode.Append: fm = 5; break;
|
||||
}
|
||||
switch (access) {
|
||||
case FileAccess.Read: fa = 0; break;
|
||||
case FileAccess.Write: fa = 1; break;
|
||||
case FileAccess.ReadWrite: fa = 2; break;
|
||||
}
|
||||
|
||||
public static long FromDateTime (DateTime time)
|
||||
{
|
||||
return ToTimeT (time);
|
||||
}
|
||||
if (fm == -1) {
|
||||
throw new ArgumentOutOfRangeException ("mode");
|
||||
}
|
||||
|
||||
if (fa == -1) {
|
||||
throw new ArgumentOutOfRangeException ("access");
|
||||
}
|
||||
|
||||
String fopen_mode = fopen_modes [fm][fa];
|
||||
if (fopen_mode [0] != 'r' && fopen_mode [0] != 'w' && fopen_mode [0] != 'a') {
|
||||
throw new ArgumentException (fopen_mode);
|
||||
}
|
||||
|
||||
return fopen_mode;
|
||||
}
|
||||
|
||||
public static DateTime FromTimeT (long time)
|
||||
{
|
||||
return UnixEpoch.AddSeconds (time).ToLocalTime ();
|
||||
}
|
||||
[DllImport (LIB, EntryPoint="Mono_Posix_FromStat")]
|
||||
private static extern Int32 FromStat (ref Stat source, IntPtr destination);
|
||||
|
||||
public static Boolean TryCopy(ref Stat source, IntPtr destination) => FromStat(ref source, destination) == 0;
|
||||
|
||||
[DllImport (LIB, EntryPoint="Mono_Posix_ToStat")]
|
||||
private static extern Int32 ToStat (IntPtr source, out Stat destination);
|
||||
|
||||
public static Boolean TryCopy(IntPtr source, out Stat destination) => ToStat(source, out destination) == 0;
|
||||
|
||||
[DllImport (LIB, EntryPoint="Mono_Posix_FromStatvfs")]
|
||||
private static extern Int32 FromStatvfs (ref Statvfs source, IntPtr destination);
|
||||
|
||||
public static Boolean TryCopy(ref Statvfs source, IntPtr destination) => FromStatvfs(ref source, destination) == 0;
|
||||
|
||||
[DllImport (LIB, EntryPoint="Mono_Posix_ToStatvfs")]
|
||||
private static extern Int32 ToStatvfs (IntPtr source, out Statvfs destination);
|
||||
|
||||
public static Boolean TryCopy(IntPtr source, out Statvfs destination) => ToStatvfs(source, out destination) == 0;
|
||||
|
||||
[DllImport (LIB, EntryPoint="Mono_Posix_FromInAddr")]
|
||||
private static extern Int32 FromInAddr (ref InAddr source, IntPtr destination);
|
||||
|
||||
public static Boolean TryCopy(ref InAddr source, IntPtr destination) => FromInAddr(ref source, destination) == 0;
|
||||
|
||||
[DllImport (LIB, EntryPoint="Mono_Posix_ToInAddr")]
|
||||
private static extern Int32 ToInAddr (IntPtr source, out InAddr destination);
|
||||
|
||||
public static Boolean TryCopy(IntPtr source, out InAddr destination) => ToInAddr(source, out destination) == 0;
|
||||
|
||||
[DllImport (LIB, EntryPoint="Mono_Posix_FromIn6Addr")]
|
||||
private static extern Int32 FromIn6Addr (ref In6Addr source, IntPtr destination);
|
||||
|
||||
public static Boolean TryCopy(ref In6Addr source, IntPtr destination) => FromIn6Addr(ref source, destination) == 0;
|
||||
|
||||
[DllImport (LIB, EntryPoint="Mono_Posix_ToIn6Addr")]
|
||||
private static extern Int32 ToIn6Addr (IntPtr source, out In6Addr destination);
|
||||
|
||||
public static Boolean TryCopy(IntPtr source, out In6Addr destination) => ToIn6Addr(source, out destination) == 0;
|
||||
|
||||
public static InAddr ToInAddr (System.Net.IPAddress address)
|
||||
{
|
||||
if (address == null) {
|
||||
throw new ArgumentNullException ("address");
|
||||
}
|
||||
|
||||
if (address.AddressFamily != System.Net.Sockets.AddressFamily.InterNetwork) {
|
||||
throw new ArgumentException ("address", "address.AddressFamily != System.Net.Sockets.AddressFamily.InterNetwork");
|
||||
}
|
||||
|
||||
return new InAddr (address.GetAddressBytes ());
|
||||
}
|
||||
|
||||
public static long ToTimeT (DateTime time)
|
||||
{
|
||||
if (time.Kind == DateTimeKind.Unspecified)
|
||||
throw new ArgumentException ("DateTimeKind.Unspecified is not supported. Use Local or Utc times.", "time");
|
||||
public static System.Net.IPAddress ToIPAddress (InAddr address)
|
||||
{
|
||||
Byte[] bytes = new Byte[4];
|
||||
address.CopyTo (bytes, 0);
|
||||
return new System.Net.IPAddress (bytes);
|
||||
}
|
||||
|
||||
if (time.Kind == DateTimeKind.Local)
|
||||
time = time.ToUniversalTime ();
|
||||
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 ());
|
||||
}
|
||||
|
||||
return (long) (time - UnixEpoch).TotalSeconds;
|
||||
}
|
||||
public static System.Net.IPAddress ToIPAddress (In6Addr address)
|
||||
{
|
||||
Byte[] bytes = new Byte[16];
|
||||
address.CopyTo (bytes, 0);
|
||||
return new System.Net.IPAddress (bytes);
|
||||
}
|
||||
|
||||
public static OpenFlags ToOpenFlags (FileMode mode, FileAccess access)
|
||||
{
|
||||
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");
|
||||
}
|
||||
[DllImport (LIB, EntryPoint="Mono_Posix_FromSockaddr")]
|
||||
private static extern unsafe Int32 FromSockaddr (_SockaddrHeader* source, IntPtr destination);
|
||||
|
||||
// Is O_LARGEFILE supported?
|
||||
int _v;
|
||||
if (TryFromOpenFlags (OpenFlags.O_LARGEFILE, out _v))
|
||||
flags |= OpenFlags.O_LARGEFILE;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
switch (access) {
|
||||
case FileAccess.Read:
|
||||
flags |= OpenFlags.O_RDONLY;
|
||||
break;
|
||||
case FileAccess.Write:
|
||||
flags |= OpenFlags.O_WRONLY;
|
||||
break;
|
||||
case FileAccess.ReadWrite:
|
||||
flags |= OpenFlags.O_RDWR;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException (Locale.GetText ("Unsupported access value"), "access");
|
||||
}
|
||||
[DllImport (LIB, EntryPoint="Mono_Posix_ToSockaddr")]
|
||||
private static extern unsafe Int32 ToSockaddr (IntPtr source, Int64 size, _SockaddrHeader* destination);
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
public static string ToFopenMode (FileAccess access)
|
||||
{
|
||||
switch (access) {
|
||||
case FileAccess.Read: return "rb";
|
||||
case FileAccess.Write: return "wb";
|
||||
case FileAccess.ReadWrite: return "r+b";
|
||||
default: throw new ArgumentOutOfRangeException ("access");
|
||||
}
|
||||
}
|
||||
|
||||
public static string ToFopenMode (FileMode mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case FileMode.CreateNew: case FileMode.Create: return "w+b";
|
||||
case FileMode.Open: case FileMode.OpenOrCreate: return "r+b";
|
||||
case FileMode.Truncate: return "w+b";
|
||||
case FileMode.Append: return "a+b";
|
||||
default: throw new ArgumentOutOfRangeException ("mode");
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly string[][] fopen_modes = new string[][]{
|
||||
// Read Write ReadWrite
|
||||
/* FileMode.CreateNew: */ new string[]{"Can't Read+Create", "wb", "w+b"},
|
||||
/* FileMode.Create: */ new string[]{"Can't Read+Create", "wb", "w+b"},
|
||||
/* FileMode.Open: */ new string[]{"rb", "wb", "r+b"},
|
||||
/* FileMode.OpenOrCreate: */ new string[]{"rb", "wb", "r+b"},
|
||||
/* FileMode.Truncate: */ new string[]{"Cannot Truncate and Read","wb", "w+b"},
|
||||
/* FileMode.Append: */ new string[]{"Cannot Append and Read", "ab", "a+b"},
|
||||
};
|
||||
|
||||
public static string ToFopenMode (FileMode mode, FileAccess access)
|
||||
{
|
||||
int fm = -1, fa = -1;
|
||||
switch (mode) {
|
||||
case FileMode.CreateNew: fm = 0; break;
|
||||
case FileMode.Create: fm = 1; break;
|
||||
case FileMode.Open: fm = 2; break;
|
||||
case FileMode.OpenOrCreate: fm = 3; break;
|
||||
case FileMode.Truncate: fm = 4; break;
|
||||
case FileMode.Append: fm = 5; break;
|
||||
}
|
||||
switch (access) {
|
||||
case FileAccess.Read: fa = 0; break;
|
||||
case FileAccess.Write: fa = 1; break;
|
||||
case FileAccess.ReadWrite: fa = 2; break;
|
||||
}
|
||||
|
||||
if (fm == -1)
|
||||
throw new ArgumentOutOfRangeException ("mode");
|
||||
if (fa == -1)
|
||||
throw new ArgumentOutOfRangeException ("access");
|
||||
|
||||
string fopen_mode = fopen_modes [fm][fa];
|
||||
if (fopen_mode [0] != 'r' && fopen_mode [0] != 'w' && fopen_mode [0] != 'a')
|
||||
throw new ArgumentException (fopen_mode);
|
||||
return fopen_mode;
|
||||
}
|
||||
|
||||
[DllImport (LIB, EntryPoint="Mono_Posix_FromStat")]
|
||||
private static extern int FromStat (ref Stat source, IntPtr destination);
|
||||
|
||||
public static bool TryCopy (ref Stat source, IntPtr destination)
|
||||
{
|
||||
return FromStat (ref source, destination) == 0;
|
||||
}
|
||||
|
||||
[DllImport (LIB, EntryPoint="Mono_Posix_ToStat")]
|
||||
private static extern int ToStat (IntPtr source, out Stat destination);
|
||||
|
||||
public static bool TryCopy (IntPtr source, out Stat destination)
|
||||
{
|
||||
return ToStat (source, out destination) == 0;
|
||||
}
|
||||
|
||||
[DllImport (LIB, EntryPoint="Mono_Posix_FromStatvfs")]
|
||||
private static extern int FromStatvfs (ref Statvfs source, IntPtr destination);
|
||||
|
||||
public static bool TryCopy (ref Statvfs source, IntPtr destination)
|
||||
{
|
||||
return FromStatvfs (ref source, destination) == 0;
|
||||
}
|
||||
|
||||
[DllImport (LIB, EntryPoint="Mono_Posix_ToStatvfs")]
|
||||
private static extern int ToStatvfs (IntPtr source, out Statvfs destination);
|
||||
|
||||
public static bool TryCopy (IntPtr source, out Statvfs destination)
|
||||
{
|
||||
return ToStatvfs (source, out destination) == 0;
|
||||
}
|
||||
|
||||
[DllImport (LIB, EntryPoint="Mono_Posix_FromInAddr")]
|
||||
private static extern int FromInAddr (ref InAddr source, IntPtr destination);
|
||||
|
||||
public static bool TryCopy (ref InAddr source, IntPtr destination)
|
||||
{
|
||||
return FromInAddr (ref source, destination) == 0;
|
||||
}
|
||||
|
||||
[DllImport (LIB, EntryPoint="Mono_Posix_ToInAddr")]
|
||||
private static extern int ToInAddr (IntPtr source, out InAddr destination);
|
||||
|
||||
public static bool TryCopy (IntPtr source, out InAddr destination)
|
||||
{
|
||||
return ToInAddr (source, out destination) == 0;
|
||||
}
|
||||
|
||||
[DllImport (LIB, EntryPoint="Mono_Posix_FromIn6Addr")]
|
||||
private static extern int FromIn6Addr (ref In6Addr source, IntPtr destination);
|
||||
|
||||
public static bool TryCopy (ref In6Addr source, IntPtr destination)
|
||||
{
|
||||
return FromIn6Addr (ref source, destination) == 0;
|
||||
}
|
||||
|
||||
[DllImport (LIB, EntryPoint="Mono_Posix_ToIn6Addr")]
|
||||
private static extern int ToIn6Addr (IntPtr source, out In6Addr destination);
|
||||
|
||||
public static bool TryCopy (IntPtr source, out In6Addr destination)
|
||||
{
|
||||
return ToIn6Addr (source, out destination) == 0;
|
||||
}
|
||||
|
||||
public static InAddr ToInAddr (System.Net.IPAddress address)
|
||||
{
|
||||
if (address == null)
|
||||
throw new ArgumentNullException ("address");
|
||||
if (address.AddressFamily != System.Net.Sockets.AddressFamily.InterNetwork)
|
||||
throw new ArgumentException ("address", "address.AddressFamily != System.Net.Sockets.AddressFamily.InterNetwork");
|
||||
return new InAddr (address.GetAddressBytes ());
|
||||
}
|
||||
|
||||
public static System.Net.IPAddress ToIPAddress (InAddr address)
|
||||
{
|
||||
var bytes = new byte[4];
|
||||
address.CopyTo (bytes, 0);
|
||||
return new System.Net.IPAddress (bytes);
|
||||
}
|
||||
|
||||
public static In6Addr ToIn6Addr (System.Net.IPAddress address)
|
||||
{
|
||||
if (address == null)
|
||||
throw new ArgumentNullException ("address");
|
||||
if (address.AddressFamily != System.Net.Sockets.AddressFamily.InterNetworkV6)
|
||||
throw new ArgumentException ("address", "address.AddressFamily != System.Net.Sockets.AddressFamily.InterNetworkV6");
|
||||
return new In6Addr (address.GetAddressBytes ());
|
||||
}
|
||||
|
||||
public static System.Net.IPAddress ToIPAddress (In6Addr address)
|
||||
{
|
||||
var bytes = new byte[16];
|
||||
address.CopyTo (bytes, 0);
|
||||
return new System.Net.IPAddress (bytes);
|
||||
}
|
||||
|
||||
[DllImport (LIB, EntryPoint="Mono_Posix_FromSockaddr")]
|
||||
private static extern unsafe int FromSockaddr (_SockaddrHeader* source, IntPtr destination);
|
||||
|
||||
public static unsafe bool TryCopy (Sockaddr source, IntPtr destination)
|
||||
{
|
||||
if (source == null)
|
||||
throw new ArgumentNullException ("source");
|
||||
byte[] array = Sockaddr.GetDynamicData (source);
|
||||
// SockaddrStorage has to be handled extra because the native code assumes that SockaddrStorage input is used in-place
|
||||
if (source.type == (SockaddrType.SockaddrStorage | SockaddrType.MustBeWrapped)) {
|
||||
Marshal.Copy (array, 0, destination, (int) source.GetDynamicLength ());
|
||||
return true;
|
||||
}
|
||||
fixed (SockaddrType* addr = &Sockaddr.GetAddress (source).type)
|
||||
fixed (byte* data = array) {
|
||||
var dyn = new _SockaddrDynamic (source, data, useMaxLength: false);
|
||||
return FromSockaddr (Sockaddr.GetNative (&dyn, addr), destination) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport (LIB, EntryPoint="Mono_Posix_ToSockaddr")]
|
||||
private static extern unsafe int ToSockaddr (IntPtr source, long size, _SockaddrHeader* destination);
|
||||
|
||||
public static unsafe bool TryCopy (IntPtr source, long size, Sockaddr destination)
|
||||
{
|
||||
if (destination == null)
|
||||
throw new ArgumentNullException ("destination");
|
||||
byte[] array = Sockaddr.GetDynamicData (destination);
|
||||
fixed (SockaddrType* addr = &Sockaddr.GetAddress (destination).type)
|
||||
fixed (byte* data = Sockaddr.GetDynamicData (destination)) {
|
||||
var dyn = new _SockaddrDynamic (destination, data, useMaxLength: true);
|
||||
var r = ToSockaddr (source, size, Sockaddr.GetNative (&dyn, addr));
|
||||
dyn.Update (destination);
|
||||
// SockaddrStorage has to be handled extra because the native code assumes that SockaddrStorage input is used in-place
|
||||
if (r == 0 && destination.type == (SockaddrType.SockaddrStorage | SockaddrType.MustBeWrapped)) {
|
||||
Marshal.Copy (source, array, 0, (int) destination.GetDynamicLength ());
|
||||
}
|
||||
return r == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
public static unsafe Boolean TryCopy (IntPtr source, Int64 size, Sockaddr destination)
|
||||
{
|
||||
if (destination == null) {
|
||||
throw new ArgumentNullException ("destination");
|
||||
}
|
||||
|
||||
Byte[] array = Sockaddr.GetDynamicData (destination);
|
||||
fixed (SockaddrType* addr = &Sockaddr.GetAddress (destination).type)
|
||||
fixed (Byte* data = Sockaddr.GetDynamicData (destination)) {
|
||||
_SockaddrDynamic dyn = new _SockaddrDynamic (destination, data, useMaxLength: true);
|
||||
Int32 r = ToSockaddr (source, size, Sockaddr.GetNative (&dyn, addr));
|
||||
dyn.Update (destination);
|
||||
// SockaddrStorage has to be handled extra because the native code assumes that SockaddrStorage input is used in-place
|
||||
if (r == 0 && destination.type == (SockaddrType.SockaddrStorage | SockaddrType.MustBeWrapped)) {
|
||||
Marshal.Copy (source, array, 0, (Int32) destination.GetDynamicLength ());
|
||||
}
|
||||
return r == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// vim: noexpandtab
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -25,57 +25,39 @@
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace Mono.Unix.Native {
|
||||
|
||||
public struct RealTimeSignum
|
||||
: IEquatable <RealTimeSignum>
|
||||
{
|
||||
private int rt_offset;
|
||||
private static readonly int MaxOffset = UnixSignal.GetSIGRTMAX () - UnixSignal.GetSIGRTMIN () - 1;
|
||||
public static readonly RealTimeSignum MinValue = new RealTimeSignum (0);
|
||||
public static readonly RealTimeSignum MaxValue = new RealTimeSignum (MaxOffset);
|
||||
public struct RealTimeSignum
|
||||
: IEquatable <RealTimeSignum>
|
||||
{
|
||||
private static readonly Int32 MaxOffset = UnixSignal.GetSIGRTMAX () - UnixSignal.GetSIGRTMIN () - 1;
|
||||
public static readonly RealTimeSignum MinValue = new RealTimeSignum (0);
|
||||
public static readonly RealTimeSignum MaxValue = new RealTimeSignum (MaxOffset);
|
||||
|
||||
public RealTimeSignum (int offset)
|
||||
{
|
||||
if (offset < 0)
|
||||
throw new ArgumentOutOfRangeException ("Offset cannot be negative");
|
||||
if (offset > MaxOffset)
|
||||
throw new ArgumentOutOfRangeException ("Offset greater than maximum supported SIGRT");
|
||||
rt_offset = offset;
|
||||
}
|
||||
public RealTimeSignum (Int32 offset)
|
||||
{
|
||||
if (offset < 0) {
|
||||
throw new ArgumentOutOfRangeException ("Offset cannot be negative");
|
||||
}
|
||||
|
||||
if (offset > MaxOffset) {
|
||||
throw new ArgumentOutOfRangeException ("Offset greater than maximum supported SIGRT");
|
||||
}
|
||||
|
||||
this.Offset = offset;
|
||||
}
|
||||
|
||||
public int Offset {
|
||||
get { return rt_offset; }
|
||||
}
|
||||
public Int32 Offset { get; }
|
||||
|
||||
public override int GetHashCode ()
|
||||
{
|
||||
return rt_offset.GetHashCode ();
|
||||
}
|
||||
public override Int32 GetHashCode() => this.Offset.GetHashCode();
|
||||
|
||||
public override bool Equals (object obj)
|
||||
{
|
||||
if ((obj == null) || (obj.GetType () != GetType ()))
|
||||
return false;
|
||||
return Equals ((RealTimeSignum)obj);
|
||||
}
|
||||
public override Boolean Equals(Object obj) => obj == null || obj.GetType() != this.GetType() ? false : this.Equals((RealTimeSignum)obj);
|
||||
|
||||
public bool Equals (RealTimeSignum value)
|
||||
{
|
||||
return Offset == value.Offset;
|
||||
}
|
||||
public Boolean Equals(RealTimeSignum value) => this.Offset == value.Offset;
|
||||
|
||||
public static bool operator== (RealTimeSignum lhs, RealTimeSignum rhs)
|
||||
{
|
||||
return lhs.Equals (rhs);
|
||||
}
|
||||
public static Boolean operator ==(RealTimeSignum lhs, RealTimeSignum rhs) => lhs.Equals(rhs);
|
||||
|
||||
public static bool operator!= (RealTimeSignum lhs, RealTimeSignum rhs)
|
||||
{
|
||||
return !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
@ -1,138 +1,152 @@
|
||||
//
|
||||
// TypeAttributes.cs
|
||||
//
|
||||
// Author:
|
||||
// Jonathan Pryor (jonpryor@vt.edu)
|
||||
//
|
||||
// (C) 2006 Jonathan Pryor
|
||||
//
|
||||
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
using System;
|
||||
|
||||
namespace Mono.Unix.Native {
|
||||
|
||||
[AttributeUsage (AttributeTargets.Field)]
|
||||
internal class blkcnt_tAttribute : MapAttribute {
|
||||
|
||||
public blkcnt_tAttribute () : base ("blkcnt_t")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage (AttributeTargets.Field)]
|
||||
internal class blksize_tAttribute : MapAttribute {
|
||||
|
||||
public blksize_tAttribute () : base ("blksize_t")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage (AttributeTargets.Field)]
|
||||
internal class dev_tAttribute : MapAttribute {
|
||||
|
||||
public dev_tAttribute () : base ("dev_t")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage (AttributeTargets.Field)]
|
||||
internal class gid_tAttribute : MapAttribute {
|
||||
|
||||
public gid_tAttribute () : base ("gid_t")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage (AttributeTargets.Field)]
|
||||
internal class fsblkcnt_tAttribute : MapAttribute {
|
||||
|
||||
public fsblkcnt_tAttribute () : base ("fsblkcnt_t")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage (AttributeTargets.Field)]
|
||||
internal class fsfilcnt_tAttribute : MapAttribute {
|
||||
|
||||
public fsfilcnt_tAttribute () : base ("fsfilcnt_t")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage (AttributeTargets.Field)]
|
||||
internal class ino_tAttribute : MapAttribute {
|
||||
|
||||
public ino_tAttribute () : base ("ino_t")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage (AttributeTargets.Field)]
|
||||
internal class nlink_tAttribute : MapAttribute {
|
||||
|
||||
public nlink_tAttribute () : base ("nlink_t")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage (AttributeTargets.Field)]
|
||||
internal class off_tAttribute : MapAttribute {
|
||||
|
||||
public off_tAttribute () : base ("off_t")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage (AttributeTargets.Field)]
|
||||
internal class pid_tAttribute : MapAttribute {
|
||||
|
||||
public pid_tAttribute () : base ("pid_t")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage (AttributeTargets.Field)]
|
||||
internal class suseconds_tAttribute : MapAttribute {
|
||||
|
||||
public suseconds_tAttribute () : base ("suseconds_t")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage (AttributeTargets.Field)]
|
||||
internal class uid_tAttribute : MapAttribute {
|
||||
|
||||
public uid_tAttribute () : base ("uid_t")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage (AttributeTargets.Field)]
|
||||
internal class time_tAttribute : MapAttribute {
|
||||
|
||||
public time_tAttribute () : base ("time_t")
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// TypeAttributes.cs
|
||||
//
|
||||
// Author:
|
||||
// Jonathan Pryor (jonpryor@vt.edu)
|
||||
//
|
||||
// (C) 2006 Jonathan Pryor
|
||||
//
|
||||
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining
|
||||
// a copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to
|
||||
// permit persons to whom the Software is furnished to do so, subject to
|
||||
// the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be
|
||||
// included in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Mono.Unix.Native {
|
||||
|
||||
[AttributeUsage (AttributeTargets.Field)]
|
||||
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||
internal class blkcnt_tAttribute : MapAttribute {
|
||||
|
||||
public blkcnt_tAttribute () : base ("blkcnt_t")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage (AttributeTargets.Field)]
|
||||
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||
internal class blksize_tAttribute : MapAttribute {
|
||||
|
||||
public blksize_tAttribute () : base ("blksize_t")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage (AttributeTargets.Field)]
|
||||
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||
internal class dev_tAttribute : MapAttribute {
|
||||
|
||||
public dev_tAttribute () : base ("dev_t")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage (AttributeTargets.Field)]
|
||||
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||
internal class gid_tAttribute : MapAttribute {
|
||||
|
||||
public gid_tAttribute () : base ("gid_t")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage (AttributeTargets.Field)]
|
||||
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||
internal class fsblkcnt_tAttribute : MapAttribute {
|
||||
|
||||
public fsblkcnt_tAttribute () : base ("fsblkcnt_t")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage (AttributeTargets.Field)]
|
||||
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||
internal class fsfilcnt_tAttribute : MapAttribute {
|
||||
|
||||
public fsfilcnt_tAttribute () : base ("fsfilcnt_t")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage (AttributeTargets.Field)]
|
||||
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||
internal class ino_tAttribute : MapAttribute {
|
||||
|
||||
public ino_tAttribute () : base ("ino_t")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage (AttributeTargets.Field)]
|
||||
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||
internal class nlink_tAttribute : MapAttribute {
|
||||
|
||||
public nlink_tAttribute () : base ("nlink_t")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage (AttributeTargets.Field)]
|
||||
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||
internal class off_tAttribute : MapAttribute {
|
||||
|
||||
public off_tAttribute () : base ("off_t")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage (AttributeTargets.Field)]
|
||||
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||
internal class pid_tAttribute : MapAttribute {
|
||||
|
||||
public pid_tAttribute () : base ("pid_t")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage (AttributeTargets.Field)]
|
||||
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||
internal class suseconds_tAttribute : MapAttribute {
|
||||
|
||||
public suseconds_tAttribute () : base ("suseconds_t")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage (AttributeTargets.Field)]
|
||||
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||
internal class uid_tAttribute : MapAttribute {
|
||||
|
||||
public uid_tAttribute () : base ("uid_t")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage (AttributeTargets.Field)]
|
||||
[SuppressMessage("Microsoft.Design","IDE1006", Justification = "Can not change name!")]
|
||||
internal class time_tAttribute : MapAttribute {
|
||||
|
||||
public time_tAttribute () : base ("time_t")
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,88 +36,82 @@ using System.Text;
|
||||
|
||||
namespace Mono.Unix
|
||||
{
|
||||
[Serializable]
|
||||
public class AbstractUnixEndPoint : EndPoint
|
||||
{
|
||||
string path;
|
||||
[Serializable]
|
||||
public class AbstractUnixEndPoint : EndPoint
|
||||
{
|
||||
String path;
|
||||
|
||||
public AbstractUnixEndPoint (string path)
|
||||
{
|
||||
if (path == null)
|
||||
throw new ArgumentNullException ("path");
|
||||
public AbstractUnixEndPoint (String path)
|
||||
{
|
||||
if (path == null) {
|
||||
throw new ArgumentNullException ("path");
|
||||
}
|
||||
|
||||
if (path == "") {
|
||||
throw new ArgumentException ("Cannot be empty.", "path");
|
||||
}
|
||||
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
if (path == "")
|
||||
throw new ArgumentException ("Cannot be empty.", "path");
|
||||
this.path = path;
|
||||
}
|
||||
public String Path {
|
||||
get => this.path;
|
||||
set => this.path = value;
|
||||
}
|
||||
|
||||
public override AddressFamily AddressFamily => AddressFamily.Unix;
|
||||
|
||||
public override EndPoint Create (SocketAddress socketAddress)
|
||||
{
|
||||
/*
|
||||
* Should also check this
|
||||
*
|
||||
int addr = (int) AddressFamily.Unix;
|
||||
if (socketAddress [0] != (addr & 0xFF))
|
||||
throw new ArgumentException ("socketAddress is not a unix socket address.");
|
||||
|
||||
public string Path {
|
||||
get {
|
||||
return(path);
|
||||
}
|
||||
set {
|
||||
path=value;
|
||||
}
|
||||
}
|
||||
if (socketAddress [1] != ((addr & 0xFF00) >> 8))
|
||||
throw new ArgumentException ("socketAddress is not a unix socket address.");
|
||||
*/
|
||||
|
||||
Byte[] bytes = new Byte[socketAddress.Size - 2 - 1];
|
||||
for (Int32 i = 0; i < bytes.Length; i++) {
|
||||
bytes [i] = socketAddress [2 + 1 + i];
|
||||
}
|
||||
|
||||
String name = Encoding.Default.GetString (bytes);
|
||||
return new AbstractUnixEndPoint (name);
|
||||
}
|
||||
|
||||
public override AddressFamily AddressFamily {
|
||||
get { return AddressFamily.Unix; }
|
||||
}
|
||||
public override SocketAddress Serialize ()
|
||||
{
|
||||
Byte[] bytes = Encoding.Default.GetBytes (this.path);
|
||||
SocketAddress sa = new SocketAddress (this.AddressFamily, 2 + 1 + bytes.Length);
|
||||
//NULL prefix denotes the abstract namespace, see unix(7)
|
||||
//in this case, there is no NULL suffix
|
||||
sa [2] = 0;
|
||||
|
||||
public override EndPoint Create (SocketAddress socketAddress)
|
||||
{
|
||||
/*
|
||||
* Should also check this
|
||||
*
|
||||
int addr = (int) AddressFamily.Unix;
|
||||
if (socketAddress [0] != (addr & 0xFF))
|
||||
throw new ArgumentException ("socketAddress is not a unix socket address.");
|
||||
|
||||
if (socketAddress [1] != ((addr & 0xFF00) >> 8))
|
||||
throw new ArgumentException ("socketAddress is not a unix socket address.");
|
||||
*/
|
||||
|
||||
byte [] bytes = new byte [socketAddress.Size - 2 - 1];
|
||||
for (int i = 0; i < bytes.Length; i++) {
|
||||
bytes [i] = socketAddress [2 + 1 + i];
|
||||
}
|
||||
|
||||
string name = Encoding.Default.GetString (bytes);
|
||||
return new AbstractUnixEndPoint (name);
|
||||
}
|
||||
|
||||
public override SocketAddress Serialize ()
|
||||
{
|
||||
byte [] bytes = Encoding.Default.GetBytes (path);
|
||||
SocketAddress sa = new SocketAddress (AddressFamily, 2 + 1 + bytes.Length);
|
||||
//NULL prefix denotes the abstract namespace, see unix(7)
|
||||
//in this case, there is no NULL suffix
|
||||
sa [2] = 0;
|
||||
|
||||
// sa [0] -> family low byte, sa [1] -> family high byte
|
||||
for (int i = 0; i < bytes.Length; i++)
|
||||
sa [i + 2 + 1] = bytes [i];
|
||||
|
||||
return sa;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return(path);
|
||||
}
|
||||
|
||||
public override int GetHashCode ()
|
||||
{
|
||||
return path.GetHashCode ();
|
||||
}
|
||||
|
||||
public override bool Equals (object o)
|
||||
{
|
||||
AbstractUnixEndPoint other = o as AbstractUnixEndPoint;
|
||||
if (other == null)
|
||||
return false;
|
||||
|
||||
return (other.path == path);
|
||||
}
|
||||
}
|
||||
// sa [0] -> family low byte, sa [1] -> family high byte
|
||||
for (Int32 i = 0; i < bytes.Length; i++) {
|
||||
sa [i + 2 + 1] = bytes [i];
|
||||
}
|
||||
|
||||
return sa;
|
||||
}
|
||||
|
||||
public override String ToString() => this.path;
|
||||
|
||||
public override Int32 GetHashCode() => this.path.GetHashCode();
|
||||
|
||||
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.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Mono.Unix {
|
||||
|
||||
public class Catalog {
|
||||
private Catalog () {}
|
||||
public class Catalog {
|
||||
private Catalog () {}
|
||||
|
||||
[DllImport("intl", CallingConvention=CallingConvention.Cdecl)]
|
||||
static extern IntPtr bindtextdomain (IntPtr domainname, IntPtr dirname);
|
||||
[DllImport("intl", CallingConvention=CallingConvention.Cdecl)]
|
||||
static extern IntPtr bind_textdomain_codeset (IntPtr domainname,
|
||||
IntPtr codeset);
|
||||
[DllImport("intl", CallingConvention=CallingConvention.Cdecl)]
|
||||
static extern IntPtr textdomain (IntPtr domainname);
|
||||
|
||||
public static void Init (String package, String localedir)
|
||||
{
|
||||
IntPtr ipackage, ilocaledir, iutf8;
|
||||
MarshalStrings (package, out ipackage, localedir, out ilocaledir,
|
||||
"UTF-8", out iutf8);
|
||||
try {
|
||||
if (bindtextdomain (ipackage, ilocaledir) == IntPtr.Zero)
|
||||
throw new UnixIOException (Native.Errno.ENOMEM);
|
||||
if (bind_textdomain_codeset (ipackage, iutf8) == IntPtr.Zero)
|
||||
throw new UnixIOException (Native.Errno.ENOMEM);
|
||||
if (textdomain (ipackage) == IntPtr.Zero)
|
||||
throw new UnixIOException (Native.Errno.ENOMEM);
|
||||
}
|
||||
finally {
|
||||
UnixMarshal.FreeHeap (ipackage);
|
||||
UnixMarshal.FreeHeap (ilocaledir);
|
||||
UnixMarshal.FreeHeap (iutf8);
|
||||
}
|
||||
}
|
||||
[DllImport("intl", CallingConvention=CallingConvention.Cdecl)]
|
||||
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||
static extern IntPtr bindtextdomain (IntPtr domainname, IntPtr dirname);
|
||||
[DllImport("intl", CallingConvention=CallingConvention.Cdecl)]
|
||||
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||
static extern IntPtr bind_textdomain_codeset (IntPtr domainname,
|
||||
IntPtr codeset);
|
||||
[DllImport("intl", CallingConvention=CallingConvention.Cdecl)]
|
||||
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||
static extern IntPtr textdomain (IntPtr domainname);
|
||||
|
||||
public static void Init (String package, String localedir)
|
||||
{
|
||||
MarshalStrings(package, out IntPtr ipackage, localedir, out IntPtr ilocaledir,
|
||||
"UTF-8", out IntPtr iutf8);
|
||||
try {
|
||||
if (bindtextdomain (ipackage, ilocaledir) == IntPtr.Zero) {
|
||||
throw new UnixIOException (Native.Errno.ENOMEM);
|
||||
}
|
||||
|
||||
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,
|
||||
string s2, out IntPtr p2, string s3, out IntPtr p3)
|
||||
{
|
||||
p1 = p2 = p3 = IntPtr.Zero;
|
||||
private static void MarshalStrings (String s1, out IntPtr p1,
|
||||
String s2, out IntPtr p2, String s3, out IntPtr p3)
|
||||
{
|
||||
p1 = p2 = p3 = IntPtr.Zero;
|
||||
|
||||
Boolean cleanup = true;
|
||||
|
||||
bool cleanup = true;
|
||||
|
||||
try {
|
||||
p1 = UnixMarshal.StringToHeap (s1);
|
||||
p2 = UnixMarshal.StringToHeap (s2);
|
||||
if (s3 != null)
|
||||
p3 = UnixMarshal.StringToHeap (s3);
|
||||
cleanup = false;
|
||||
}
|
||||
finally {
|
||||
if (cleanup) {
|
||||
UnixMarshal.FreeHeap (p1);
|
||||
UnixMarshal.FreeHeap (p2);
|
||||
UnixMarshal.FreeHeap (p3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport("intl", CallingConvention=CallingConvention.Cdecl)]
|
||||
static extern IntPtr gettext (IntPtr instring);
|
||||
|
||||
public static String GetString (String s)
|
||||
{
|
||||
IntPtr ints = UnixMarshal.StringToHeap (s);
|
||||
try {
|
||||
// gettext(3) returns the input pointer if no translation is found
|
||||
IntPtr r = gettext (ints);
|
||||
if (r != ints)
|
||||
return UnixMarshal.PtrToStringUnix (r);
|
||||
return s;
|
||||
}
|
||||
finally {
|
||||
UnixMarshal.FreeHeap (ints);
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport("intl", CallingConvention=CallingConvention.Cdecl)]
|
||||
static extern IntPtr ngettext (IntPtr singular, IntPtr plural, Int32 n);
|
||||
|
||||
public static String GetPluralString (String s, String p, Int32 n)
|
||||
{
|
||||
IntPtr ints, intp, _ignore;
|
||||
MarshalStrings (s, out ints, p, out intp, null, out _ignore);
|
||||
|
||||
try {
|
||||
// ngettext(3) returns an input pointer if no translation is found
|
||||
IntPtr r = ngettext (ints, intp, n);
|
||||
if (r == ints)
|
||||
return s;
|
||||
if (r == intp)
|
||||
return p;
|
||||
return UnixMarshal.PtrToStringUnix (r);
|
||||
}
|
||||
finally {
|
||||
UnixMarshal.FreeHeap (ints);
|
||||
UnixMarshal.FreeHeap (intp);
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
p1 = UnixMarshal.StringToHeap (s1);
|
||||
p2 = UnixMarshal.StringToHeap (s2);
|
||||
if (s3 != null) {
|
||||
p3 = UnixMarshal.StringToHeap (s3);
|
||||
}
|
||||
|
||||
cleanup = false;
|
||||
}
|
||||
finally {
|
||||
if (cleanup) {
|
||||
UnixMarshal.FreeHeap (p1);
|
||||
UnixMarshal.FreeHeap (p2);
|
||||
UnixMarshal.FreeHeap (p3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport("intl", CallingConvention=CallingConvention.Cdecl)]
|
||||
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||
static extern IntPtr gettext (IntPtr instring);
|
||||
|
||||
public static String GetString (String s)
|
||||
{
|
||||
IntPtr ints = UnixMarshal.StringToHeap (s);
|
||||
try {
|
||||
// gettext(3) returns the input pointer if no translation is found
|
||||
IntPtr r = gettext (ints);
|
||||
if (r != ints) {
|
||||
return UnixMarshal.PtrToStringUnix (r);
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
finally {
|
||||
UnixMarshal.FreeHeap (ints);
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport("intl", CallingConvention=CallingConvention.Cdecl)]
|
||||
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||
static extern IntPtr ngettext (IntPtr singular, IntPtr plural, Int32 n);
|
||||
|
||||
public static String GetPluralString (String s, String p, Int32 n)
|
||||
{
|
||||
MarshalStrings(s, out IntPtr ints, p, out IntPtr intp, null, out IntPtr _ignore);
|
||||
|
||||
try {
|
||||
// ngettext(3) returns an input pointer if no translation is found
|
||||
IntPtr r = ngettext (ints, intp, n);
|
||||
return r == ints ? s : r == intp ? p : UnixMarshal.PtrToStringUnix (r);
|
||||
} finally {
|
||||
UnixMarshal.FreeHeap (ints);
|
||||
UnixMarshal.FreeHeap (intp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,13 +31,13 @@ using Mono.Unix;
|
||||
|
||||
namespace Mono.Unix {
|
||||
|
||||
public enum FileAccessPattern {
|
||||
Normal = Native.PosixFadviseAdvice.POSIX_FADV_NORMAL,
|
||||
Sequential = Native.PosixFadviseAdvice.POSIX_FADV_SEQUENTIAL,
|
||||
Random = Native.PosixFadviseAdvice.POSIX_FADV_RANDOM,
|
||||
NoReuse = Native.PosixFadviseAdvice.POSIX_FADV_NOREUSE,
|
||||
PreLoad = Native.PosixFadviseAdvice.POSIX_FADV_WILLNEED,
|
||||
FlushCache = Native.PosixFadviseAdvice.POSIX_FADV_DONTNEED,
|
||||
}
|
||||
public enum FileAccessPattern {
|
||||
Normal = Native.PosixFadviseAdvice.POSIX_FADV_NORMAL,
|
||||
Sequential = Native.PosixFadviseAdvice.POSIX_FADV_SEQUENTIAL,
|
||||
Random = Native.PosixFadviseAdvice.POSIX_FADV_RANDOM,
|
||||
NoReuse = Native.PosixFadviseAdvice.POSIX_FADV_NOREUSE,
|
||||
PreLoad = Native.PosixFadviseAdvice.POSIX_FADV_WILLNEED,
|
||||
FlushCache = Native.PosixFadviseAdvice.POSIX_FADV_DONTNEED,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,23 +31,23 @@ using Mono.Unix;
|
||||
|
||||
namespace Mono.Unix {
|
||||
|
||||
[Flags]
|
||||
public enum FileAccessPermissions {
|
||||
UserReadWriteExecute = (int) Native.FilePermissions.S_IRWXU,
|
||||
UserRead = (int) Native.FilePermissions.S_IRUSR,
|
||||
UserWrite = (int) Native.FilePermissions.S_IWUSR,
|
||||
UserExecute = (int) Native.FilePermissions.S_IXUSR,
|
||||
GroupReadWriteExecute = (int) Native.FilePermissions.S_IRWXG,
|
||||
GroupRead = (int) Native.FilePermissions.S_IRGRP,
|
||||
GroupWrite = (int) Native.FilePermissions.S_IWGRP,
|
||||
GroupExecute = (int) Native.FilePermissions.S_IXGRP,
|
||||
OtherReadWriteExecute = (int) Native.FilePermissions.S_IRWXO,
|
||||
OtherRead = (int) Native.FilePermissions.S_IROTH,
|
||||
OtherWrite = (int) Native.FilePermissions.S_IWOTH,
|
||||
OtherExecute = (int) Native.FilePermissions.S_IXOTH,
|
||||
[Flags]
|
||||
public enum FileAccessPermissions {
|
||||
UserReadWriteExecute = (Int32) Native.FilePermissions.S_IRWXU,
|
||||
UserRead = (Int32) Native.FilePermissions.S_IRUSR,
|
||||
UserWrite = (Int32) Native.FilePermissions.S_IWUSR,
|
||||
UserExecute = (Int32) Native.FilePermissions.S_IXUSR,
|
||||
GroupReadWriteExecute = (Int32) Native.FilePermissions.S_IRWXG,
|
||||
GroupRead = (Int32) Native.FilePermissions.S_IRGRP,
|
||||
GroupWrite = (Int32) Native.FilePermissions.S_IWGRP,
|
||||
GroupExecute = (Int32) Native.FilePermissions.S_IXGRP,
|
||||
OtherReadWriteExecute = (Int32) Native.FilePermissions.S_IRWXO,
|
||||
OtherRead = (Int32) Native.FilePermissions.S_IROTH,
|
||||
OtherWrite = (Int32) Native.FilePermissions.S_IWOTH,
|
||||
OtherExecute = (Int32) Native.FilePermissions.S_IXOTH,
|
||||
|
||||
DefaultPermissions = (int) Native.FilePermissions.DEFFILEMODE,
|
||||
AllPermissions = (int) Native.FilePermissions.ACCESSPERMS,
|
||||
}
|
||||
DefaultPermissions = (Int32) Native.FilePermissions.DEFFILEMODE,
|
||||
AllPermissions = (Int32) Native.FilePermissions.ACCESSPERMS,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,56 +27,53 @@
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Mono.Unix;
|
||||
|
||||
namespace Mono.Unix {
|
||||
|
||||
public sealed /* static */ class FileHandleOperations
|
||||
{
|
||||
private FileHandleOperations () {}
|
||||
public sealed /* static */ class FileHandleOperations
|
||||
{
|
||||
private FileHandleOperations () {}
|
||||
|
||||
public static void AdviseFileAccessPattern (int fd, FileAccessPattern pattern, long offset, long len)
|
||||
{
|
||||
int r = Native.Syscall.posix_fadvise (fd, offset, len,
|
||||
(Native.PosixFadviseAdvice) pattern);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
|
||||
public static void AdviseFileAccessPattern (int fd, FileAccessPattern pattern)
|
||||
{
|
||||
AdviseFileAccessPattern (fd, pattern, 0, 0);
|
||||
}
|
||||
|
||||
public static void AdviseFileAccessPattern (FileStream file, FileAccessPattern pattern, long offset, long len)
|
||||
{
|
||||
if (file == null)
|
||||
throw new ArgumentNullException ("file");
|
||||
int r = Native.Syscall.posix_fadvise (file.Handle.ToInt32(), offset, len,
|
||||
(Native.PosixFadviseAdvice) pattern);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
|
||||
public static void AdviseFileAccessPattern (FileStream file, FileAccessPattern pattern)
|
||||
{
|
||||
AdviseFileAccessPattern (file, pattern, 0, 0);
|
||||
}
|
||||
|
||||
public static void AdviseFileAccessPattern (UnixStream stream, FileAccessPattern pattern, long offset, long len)
|
||||
{
|
||||
if (stream == null)
|
||||
throw new ArgumentNullException ("stream");
|
||||
int r = Native.Syscall.posix_fadvise (stream.Handle, offset, len,
|
||||
(Native.PosixFadviseAdvice) pattern);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
|
||||
public static void AdviseFileAccessPattern (UnixStream stream, FileAccessPattern pattern)
|
||||
{
|
||||
AdviseFileAccessPattern (stream, pattern, 0, 0);
|
||||
}
|
||||
}
|
||||
public static void AdviseFileAccessPattern (Int32 fd, FileAccessPattern pattern, Int64 offset, Int64 len)
|
||||
{
|
||||
Int32 r = Native.Syscall.posix_fadvise (fd, offset, len,
|
||||
(Native.PosixFadviseAdvice) pattern);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
|
||||
public static void AdviseFileAccessPattern(Int32 fd, FileAccessPattern pattern) => AdviseFileAccessPattern(fd, pattern, 0, 0);
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CS0618", Justification = "Someone do shit")]
|
||||
public static void AdviseFileAccessPattern (FileStream file, FileAccessPattern pattern, Int64 offset, Int64 len)
|
||||
{
|
||||
if (file == null) {
|
||||
throw new ArgumentNullException ("file");
|
||||
}
|
||||
|
||||
Int32 r = Native.Syscall.posix_fadvise (file.Handle.ToInt32(), offset, len,
|
||||
(Native.PosixFadviseAdvice) pattern);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
|
||||
public static void AdviseFileAccessPattern(FileStream file, FileAccessPattern pattern) => AdviseFileAccessPattern(file, pattern, 0, 0);
|
||||
|
||||
public static void AdviseFileAccessPattern (UnixStream stream, FileAccessPattern pattern, Int64 offset, Int64 len)
|
||||
{
|
||||
if (stream == null) {
|
||||
throw new ArgumentNullException ("stream");
|
||||
}
|
||||
|
||||
Int32 r = Native.Syscall.posix_fadvise (stream.Handle, offset, len,
|
||||
(Native.PosixFadviseAdvice) pattern);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
|
||||
public static void AdviseFileAccessPattern(UnixStream stream, FileAccessPattern pattern) => AdviseFileAccessPattern(stream, pattern, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// vim: noexpandtab
|
||||
|
@ -31,11 +31,11 @@ using Mono.Unix;
|
||||
|
||||
namespace Mono.Unix {
|
||||
|
||||
[Flags]
|
||||
public enum FileSpecialAttributes {
|
||||
SetUserId = (int) Native.FilePermissions.S_ISUID,
|
||||
SetGroupId = (int) Native.FilePermissions.S_ISGID,
|
||||
Sticky = (int) Native.FilePermissions.S_ISVTX,
|
||||
}
|
||||
[Flags]
|
||||
public enum FileSpecialAttributes {
|
||||
SetUserId = (Int32) Native.FilePermissions.S_ISUID,
|
||||
SetGroupId = (Int32) Native.FilePermissions.S_ISGID,
|
||||
Sticky = (Int32) Native.FilePermissions.S_ISVTX,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,14 +31,15 @@ using Mono.Unix;
|
||||
|
||||
namespace Mono.Unix {
|
||||
|
||||
public enum FileTypes {
|
||||
Directory = (int) Native.FilePermissions.S_IFDIR,
|
||||
CharacterDevice = (int) Native.FilePermissions.S_IFCHR,
|
||||
BlockDevice = (int) Native.FilePermissions.S_IFBLK,
|
||||
RegularFile = (int) Native.FilePermissions.S_IFREG,
|
||||
Fifo = (int) Native.FilePermissions.S_IFIFO,
|
||||
SymbolicLink = (int) Native.FilePermissions.S_IFLNK,
|
||||
Socket = (int) Native.FilePermissions.S_IFSOCK,
|
||||
}
|
||||
}
|
||||
public enum FileTypes {
|
||||
Directory = (Int32) Native.FilePermissions.S_IFDIR,
|
||||
CharacterDevice = (Int32) Native.FilePermissions.S_IFCHR,
|
||||
BlockDevice = (Int32) Native.FilePermissions.S_IFBLK,
|
||||
RegularFile = (Int32) Native.FilePermissions.S_IFREG,
|
||||
Fifo = (Int32) Native.FilePermissions.S_IFIFO,
|
||||
SymbolicLink = (Int32) Native.FilePermissions.S_IFLNK,
|
||||
Socket = (Int32) Native.FilePermissions.S_IFSOCK,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -34,48 +34,36 @@ using System.Net.Sockets;
|
||||
namespace Mono.Unix
|
||||
{
|
||||
#pragma warning disable 649
|
||||
internal struct PeerCredData {
|
||||
public int pid;
|
||||
public int uid;
|
||||
public int gid;
|
||||
}
|
||||
internal struct PeerCredData {
|
||||
public Int32 pid;
|
||||
public Int32 uid;
|
||||
public Int32 gid;
|
||||
}
|
||||
#pragma warning restore 649
|
||||
|
||||
public class PeerCred
|
||||
{
|
||||
/* Make sure this doesn't clash with anything in
|
||||
* SocketOptionName, and keep it synchronised with the
|
||||
* runtime
|
||||
*/
|
||||
private const int so_peercred=10001;
|
||||
private PeerCredData data;
|
||||
|
||||
public PeerCred (Socket sock) {
|
||||
if (sock.AddressFamily != AddressFamily.Unix) {
|
||||
throw new ArgumentException ("Only Unix sockets are supported", "sock");
|
||||
}
|
||||
|
||||
data = (PeerCredData)
|
||||
sock.GetSocketOption (SocketOptionLevel.Socket, (SocketOptionName)so_peercred);
|
||||
}
|
||||
|
||||
public int ProcessID {
|
||||
get {
|
||||
return(data.pid);
|
||||
}
|
||||
}
|
||||
|
||||
public int UserID {
|
||||
get {
|
||||
return(data.uid);
|
||||
}
|
||||
}
|
||||
|
||||
public int GroupID {
|
||||
get {
|
||||
return(data.gid);
|
||||
}
|
||||
}
|
||||
}
|
||||
public class PeerCred
|
||||
{
|
||||
/* Make sure this doesn't clash with anything in
|
||||
* SocketOptionName, and keep it synchronised with the
|
||||
* runtime
|
||||
*/
|
||||
private const Int32 so_peercred =10001;
|
||||
private PeerCredData data;
|
||||
|
||||
public PeerCred (Socket sock) {
|
||||
if (sock.AddressFamily != AddressFamily.Unix) {
|
||||
throw new ArgumentException ("Only Unix sockets are supported", "sock");
|
||||
}
|
||||
|
||||
this.data = (PeerCredData)
|
||||
sock.GetSocketOption (SocketOptionLevel.Socket, (SocketOptionName)so_peercred);
|
||||
}
|
||||
|
||||
public Int32 ProcessID => this.data.pid;
|
||||
|
||||
public Int32 UserID => this.data.uid;
|
||||
|
||||
public Int32 GroupID => this.data.gid;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,373 +34,424 @@ using Mono.Unix;
|
||||
|
||||
namespace Mono.Unix {
|
||||
|
||||
public class StdioFileStream : Stream
|
||||
{
|
||||
public static readonly IntPtr InvalidFileStream = IntPtr.Zero;
|
||||
public static readonly IntPtr StandardInput = Native.Stdlib.stdin;
|
||||
public static readonly IntPtr StandardOutput = Native.Stdlib.stdout;
|
||||
public static readonly IntPtr StandardError = Native.Stdlib.stderr;
|
||||
public class StdioFileStream : Stream
|
||||
{
|
||||
public static readonly IntPtr InvalidFileStream = IntPtr.Zero;
|
||||
public static readonly IntPtr StandardInput = Native.Stdlib.stdin;
|
||||
public static readonly IntPtr StandardOutput = Native.Stdlib.stdout;
|
||||
public static readonly IntPtr StandardError = Native.Stdlib.stderr;
|
||||
|
||||
public StdioFileStream (IntPtr fileStream)
|
||||
: this (fileStream, true) {}
|
||||
public StdioFileStream (IntPtr fileStream)
|
||||
: this (fileStream, true) {}
|
||||
|
||||
public StdioFileStream(IntPtr fileStream, Boolean ownsHandle) => this.InitStream(fileStream, ownsHandle);
|
||||
|
||||
public StdioFileStream (IntPtr fileStream, FileAccess access)
|
||||
: this (fileStream, access, true) {}
|
||||
|
||||
public StdioFileStream (IntPtr fileStream, bool ownsHandle)
|
||||
{
|
||||
InitStream (fileStream, ownsHandle);
|
||||
}
|
||||
public StdioFileStream (IntPtr fileStream, FileAccess access, Boolean ownsHandle)
|
||||
{
|
||||
this.InitStream (fileStream, ownsHandle);
|
||||
this.InitCanReadWrite (access);
|
||||
}
|
||||
|
||||
public StdioFileStream (IntPtr fileStream, FileAccess access)
|
||||
: this (fileStream, access, true) {}
|
||||
public StdioFileStream (String path)
|
||||
{
|
||||
if (path == null) {
|
||||
throw new ArgumentNullException ("path");
|
||||
}
|
||||
|
||||
this.InitStream (Fopen (path, "rb"), true);
|
||||
}
|
||||
|
||||
public StdioFileStream (IntPtr fileStream, FileAccess access, bool ownsHandle)
|
||||
{
|
||||
InitStream (fileStream, ownsHandle);
|
||||
InitCanReadWrite (access);
|
||||
}
|
||||
public StdioFileStream (String path, String mode)
|
||||
{
|
||||
if (path == null) {
|
||||
throw new ArgumentNullException ("path");
|
||||
}
|
||||
|
||||
this.InitStream (Fopen (path, mode), true);
|
||||
}
|
||||
|
||||
public StdioFileStream (string path)
|
||||
{
|
||||
if (path == null)
|
||||
throw new ArgumentNullException ("path");
|
||||
InitStream (Fopen (path, "rb"), true);
|
||||
}
|
||||
public StdioFileStream (String path, FileMode mode)
|
||||
{
|
||||
if (path == null) {
|
||||
throw new ArgumentNullException ("path");
|
||||
}
|
||||
|
||||
this.InitStream (Fopen (path, ToFopenMode (path, mode)), true);
|
||||
}
|
||||
|
||||
public StdioFileStream (string path, string mode)
|
||||
{
|
||||
if (path == null)
|
||||
throw new ArgumentNullException ("path");
|
||||
InitStream (Fopen (path, mode), true);
|
||||
}
|
||||
public StdioFileStream (String path, FileAccess access)
|
||||
{
|
||||
if (path == null) {
|
||||
throw new ArgumentNullException ("path");
|
||||
}
|
||||
|
||||
this.InitStream (Fopen (path, ToFopenMode (path, access)), true);
|
||||
this.InitCanReadWrite (access);
|
||||
}
|
||||
|
||||
public StdioFileStream (string path, FileMode mode)
|
||||
{
|
||||
if (path == null)
|
||||
throw new ArgumentNullException ("path");
|
||||
InitStream (Fopen (path, ToFopenMode (path, mode)), true);
|
||||
}
|
||||
public StdioFileStream (String path, FileMode mode, FileAccess access)
|
||||
{
|
||||
if (path == null) {
|
||||
throw new ArgumentNullException ("path");
|
||||
}
|
||||
|
||||
this.InitStream (Fopen (path, ToFopenMode (path, mode, access)), true);
|
||||
this.InitCanReadWrite (access);
|
||||
}
|
||||
|
||||
public StdioFileStream (string path, FileAccess access)
|
||||
{
|
||||
if (path == null)
|
||||
throw new ArgumentNullException ("path");
|
||||
InitStream (Fopen (path, ToFopenMode (path, access)), true);
|
||||
InitCanReadWrite (access);
|
||||
}
|
||||
private static IntPtr Fopen (String path, String mode)
|
||||
{
|
||||
if (path.Length == 0) {
|
||||
throw new ArgumentException ("path");
|
||||
}
|
||||
|
||||
if (mode == null) {
|
||||
throw new ArgumentNullException ("mode");
|
||||
}
|
||||
|
||||
IntPtr f = Native.Stdlib.fopen (path, mode);
|
||||
if (f == IntPtr.Zero) {
|
||||
throw new DirectoryNotFoundException ("path",
|
||||
UnixMarshal.CreateExceptionForLastError ());
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
public StdioFileStream (string path, FileMode mode, FileAccess access)
|
||||
{
|
||||
if (path == null)
|
||||
throw new ArgumentNullException ("path");
|
||||
InitStream (Fopen (path, ToFopenMode (path, mode, access)), true);
|
||||
InitCanReadWrite (access);
|
||||
}
|
||||
private void InitStream (IntPtr fileStream, Boolean ownsHandle)
|
||||
{
|
||||
if (InvalidFileStream == fileStream) {
|
||||
throw new ArgumentException (Locale.GetText ("Invalid file stream"), "fileStream");
|
||||
}
|
||||
|
||||
this.file = fileStream;
|
||||
this.owner = ownsHandle;
|
||||
|
||||
try {
|
||||
Int64 offset = Native.Stdlib.fseek (this.file, 0, Native.SeekFlags.SEEK_CUR);
|
||||
if (offset != -1) {
|
||||
this.canSeek = true;
|
||||
}
|
||||
|
||||
_ = Native.Stdlib.fread(IntPtr.Zero, 0, 0, this.file);
|
||||
if (Native.Stdlib.ferror (this.file) == 0) {
|
||||
this.canRead = true;
|
||||
}
|
||||
|
||||
_ = Native.Stdlib.fwrite(IntPtr.Zero, 0, 0, this.file);
|
||||
if (Native.Stdlib.ferror (this.file) == 0) {
|
||||
this.canWrite = true;
|
||||
}
|
||||
|
||||
_ = Native.Stdlib.clearerr(this.file);
|
||||
}
|
||||
catch (Exception) {
|
||||
throw new ArgumentException (Locale.GetText ("Invalid file stream"), "fileStream");
|
||||
}
|
||||
GC.KeepAlive (this);
|
||||
}
|
||||
|
||||
private static IntPtr Fopen (string path, string mode)
|
||||
{
|
||||
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 InitCanReadWrite (FileAccess access)
|
||||
{
|
||||
this.canRead = this.canRead &&
|
||||
(access == FileAccess.Read || access == FileAccess.ReadWrite);
|
||||
this.canWrite = this.canWrite &&
|
||||
(access == FileAccess.Write || access == FileAccess.ReadWrite);
|
||||
}
|
||||
|
||||
private void InitStream (IntPtr fileStream, bool ownsHandle)
|
||||
{
|
||||
if (InvalidFileStream == fileStream)
|
||||
throw new ArgumentException (Locale.GetText ("Invalid file stream"), "fileStream");
|
||||
|
||||
this.file = fileStream;
|
||||
this.owner = ownsHandle;
|
||||
|
||||
try {
|
||||
long offset = Native.Stdlib.fseek (file, 0, Native.SeekFlags.SEEK_CUR);
|
||||
if (offset != -1)
|
||||
canSeek = true;
|
||||
Native.Stdlib.fread (IntPtr.Zero, 0, 0, file);
|
||||
if (Native.Stdlib.ferror (file) == 0)
|
||||
canRead = true;
|
||||
Native.Stdlib.fwrite (IntPtr.Zero, 0, 0, file);
|
||||
if (Native.Stdlib.ferror (file) == 0)
|
||||
canWrite = true;
|
||||
Native.Stdlib.clearerr (file);
|
||||
}
|
||||
catch (Exception) {
|
||||
throw new ArgumentException (Locale.GetText ("Invalid file stream"), "fileStream");
|
||||
}
|
||||
GC.KeepAlive (this);
|
||||
}
|
||||
private static String ToFopenMode (String file, FileMode mode)
|
||||
{
|
||||
String cmode = Native.NativeConvert.ToFopenMode (mode);
|
||||
_ = AssertFileMode(file, mode);
|
||||
return cmode;
|
||||
}
|
||||
|
||||
private static String ToFopenMode(String file, FileAccess access) => Native.NativeConvert.ToFopenMode(access);
|
||||
|
||||
private static String ToFopenMode (String file, FileMode mode, FileAccess access)
|
||||
{
|
||||
String cmode = Native.NativeConvert.ToFopenMode (mode, access);
|
||||
Boolean exists = AssertFileMode (file, mode);
|
||||
// HACK: for open-or-create & read, mode is "rb", which doesn't create
|
||||
// files. If the file doesn't exist, we need to use "w+b" to ensure
|
||||
// file creation.
|
||||
if (mode == FileMode.OpenOrCreate && access == FileAccess.Read && !exists) {
|
||||
cmode = "w+b";
|
||||
}
|
||||
|
||||
return cmode;
|
||||
}
|
||||
|
||||
private void InitCanReadWrite (FileAccess access)
|
||||
{
|
||||
canRead = canRead &&
|
||||
(access == FileAccess.Read || access == FileAccess.ReadWrite);
|
||||
canWrite = canWrite &&
|
||||
(access == FileAccess.Write || access == FileAccess.ReadWrite);
|
||||
}
|
||||
private static Boolean AssertFileMode (String file, FileMode mode)
|
||||
{
|
||||
Boolean exists = FileExists (file);
|
||||
if (mode == FileMode.CreateNew && exists) {
|
||||
throw new IOException ("File exists and FileMode.CreateNew specified");
|
||||
}
|
||||
|
||||
if ((mode == FileMode.Open || mode == FileMode.Truncate) && !exists) {
|
||||
throw new FileNotFoundException ("File doesn't exist and FileMode.Open specified", file);
|
||||
}
|
||||
|
||||
return exists;
|
||||
}
|
||||
|
||||
private static string ToFopenMode (string file, FileMode mode)
|
||||
{
|
||||
string cmode = Native.NativeConvert.ToFopenMode (mode);
|
||||
AssertFileMode (file, mode);
|
||||
return cmode;
|
||||
}
|
||||
private static Boolean FileExists (String file)
|
||||
{
|
||||
Boolean found = false;
|
||||
IntPtr f = Native.Stdlib.fopen (file, "r");
|
||||
found = f != IntPtr.Zero;
|
||||
if (f != IntPtr.Zero) {
|
||||
_ = Native.Stdlib.fclose(f);
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
private static string ToFopenMode (string file, FileAccess access)
|
||||
{
|
||||
return Native.NativeConvert.ToFopenMode (access);
|
||||
}
|
||||
private void AssertNotDisposed ()
|
||||
{
|
||||
if (this.file == InvalidFileStream) {
|
||||
throw new ObjectDisposedException ("Invalid File Stream");
|
||||
}
|
||||
|
||||
GC.KeepAlive (this);
|
||||
}
|
||||
|
||||
private static string ToFopenMode (string file, FileMode mode, FileAccess access)
|
||||
{
|
||||
string cmode = Native.NativeConvert.ToFopenMode (mode, access);
|
||||
bool exists = AssertFileMode (file, mode);
|
||||
// HACK: for open-or-create & read, mode is "rb", which doesn't create
|
||||
// files. If the file doesn't exist, we need to use "w+b" to ensure
|
||||
// file creation.
|
||||
if (mode == FileMode.OpenOrCreate && access == FileAccess.Read && !exists)
|
||||
cmode = "w+b";
|
||||
return cmode;
|
||||
}
|
||||
public IntPtr Handle {
|
||||
get {
|
||||
this.AssertNotDisposed ();
|
||||
GC.KeepAlive (this);
|
||||
return this.file;
|
||||
}
|
||||
}
|
||||
|
||||
public override Boolean CanRead => this.canRead;
|
||||
|
||||
public override Boolean CanSeek => this.canSeek;
|
||||
|
||||
public override Boolean CanWrite => this.canWrite;
|
||||
|
||||
public override Int64 Length {
|
||||
get {
|
||||
this.AssertNotDisposed ();
|
||||
if (!this.CanSeek) {
|
||||
throw new NotSupportedException ("File Stream doesn't support seeking");
|
||||
}
|
||||
|
||||
Int64 curPos = Native.Stdlib.ftell (this.file);
|
||||
if (curPos == -1) {
|
||||
throw new NotSupportedException ("Unable to obtain current file position");
|
||||
}
|
||||
|
||||
Int32 r = Native.Stdlib.fseek (this.file, 0, Native.SeekFlags.SEEK_END);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
|
||||
Int64 endPos = Native.Stdlib.ftell (this.file);
|
||||
if (endPos == -1) {
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
}
|
||||
|
||||
r = Native.Stdlib.fseek (this.file, curPos, Native.SeekFlags.SEEK_SET);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
|
||||
private static bool AssertFileMode (string file, FileMode mode)
|
||||
{
|
||||
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;
|
||||
}
|
||||
GC.KeepAlive (this);
|
||||
return endPos;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool FileExists (string file)
|
||||
{
|
||||
bool found = false;
|
||||
IntPtr f = Native.Stdlib.fopen (file, "r");
|
||||
found = f != IntPtr.Zero;
|
||||
if (f != IntPtr.Zero)
|
||||
Native.Stdlib.fclose (f);
|
||||
return found;
|
||||
}
|
||||
public override Int64 Position {
|
||||
get {
|
||||
this.AssertNotDisposed ();
|
||||
if (!this.CanSeek) {
|
||||
throw new NotSupportedException ("The stream does not support seeking");
|
||||
}
|
||||
|
||||
Int64 pos = Native.Stdlib.ftell (this.file);
|
||||
if (pos == -1) {
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
}
|
||||
|
||||
GC.KeepAlive (this);
|
||||
return (Int64) pos;
|
||||
}
|
||||
set {
|
||||
this.AssertNotDisposed ();
|
||||
_ = this.Seek(value, SeekOrigin.Begin);
|
||||
}
|
||||
}
|
||||
|
||||
private void AssertNotDisposed ()
|
||||
{
|
||||
if (file == InvalidFileStream)
|
||||
throw new ObjectDisposedException ("Invalid File Stream");
|
||||
GC.KeepAlive (this);
|
||||
}
|
||||
public void SaveFilePosition (Native.FilePosition pos)
|
||||
{
|
||||
this.AssertNotDisposed ();
|
||||
Int32 r = Native.Stdlib.fgetpos (this.file, pos);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
GC.KeepAlive (this);
|
||||
}
|
||||
|
||||
public IntPtr Handle {
|
||||
get {
|
||||
AssertNotDisposed ();
|
||||
GC.KeepAlive (this);
|
||||
return file;
|
||||
}
|
||||
}
|
||||
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 bool CanRead {
|
||||
get {return canRead;}
|
||||
}
|
||||
public override void Flush ()
|
||||
{
|
||||
this.AssertNotDisposed ();
|
||||
Int32 r = Native.Stdlib.fflush (this.file);
|
||||
if (r != 0) {
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
}
|
||||
|
||||
GC.KeepAlive (this);
|
||||
}
|
||||
|
||||
public override bool CanSeek {
|
||||
get {return canSeek;}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
public override bool CanWrite {
|
||||
get {return canWrite;}
|
||||
}
|
||||
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 override long Length {
|
||||
get {
|
||||
AssertNotDisposed ();
|
||||
if (!CanSeek)
|
||||
throw new NotSupportedException ("File Stream doesn't support seeking");
|
||||
long curPos = Native.Stdlib.ftell (file);
|
||||
if (curPos == -1)
|
||||
throw new NotSupportedException ("Unable to obtain current file position");
|
||||
int r = Native.Stdlib.fseek (file, 0, Native.SeekFlags.SEEK_END);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
public void Rewind ()
|
||||
{
|
||||
this.AssertNotDisposed ();
|
||||
_ = Native.Stdlib.rewind(this.file);
|
||||
GC.KeepAlive (this);
|
||||
}
|
||||
|
||||
long endPos = Native.Stdlib.ftell (file);
|
||||
if (endPos == -1)
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
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 ();
|
||||
}
|
||||
|
||||
r = Native.Stdlib.fseek (file, curPos, Native.SeekFlags.SEEK_SET);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
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.KeepAlive (this);
|
||||
return endPos;
|
||||
}
|
||||
}
|
||||
|
||||
public override long Position {
|
||||
get {
|
||||
AssertNotDisposed ();
|
||||
if (!CanSeek)
|
||||
throw new NotSupportedException ("The stream does not support seeking");
|
||||
long pos = Native.Stdlib.ftell (file);
|
||||
if (pos == -1)
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
GC.KeepAlive (this);
|
||||
return (long) pos;
|
||||
}
|
||||
set {
|
||||
AssertNotDisposed ();
|
||||
Seek (value, SeekOrigin.Begin);
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveFilePosition (Native.FilePosition pos)
|
||||
{
|
||||
AssertNotDisposed ();
|
||||
int r = Native.Stdlib.fgetpos (file, pos);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
GC.KeepAlive (this);
|
||||
}
|
||||
|
||||
public void RestoreFilePosition (Native.FilePosition pos)
|
||||
{
|
||||
AssertNotDisposed ();
|
||||
if (pos == null)
|
||||
throw new ArgumentNullException ("value");
|
||||
int r = Native.Stdlib.fsetpos (file, pos);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
GC.KeepAlive (this);
|
||||
}
|
||||
|
||||
public override void Flush ()
|
||||
{
|
||||
AssertNotDisposed ();
|
||||
int r = Native.Stdlib.fflush (file);
|
||||
if (r != 0)
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
GC.KeepAlive (this);
|
||||
}
|
||||
|
||||
public override unsafe int Read ([In, Out] byte[] buffer, int offset, int count)
|
||||
{
|
||||
AssertNotDisposed ();
|
||||
AssertValidBuffer (buffer, offset, count);
|
||||
if (!CanRead)
|
||||
throw new NotSupportedException ("Stream does not support reading");
|
||||
|
||||
ulong r = 0;
|
||||
fixed (byte* buf = &buffer[offset]) {
|
||||
r = Native.Stdlib.fread (buf, 1, (ulong) count, file);
|
||||
}
|
||||
if (r != (ulong) count) {
|
||||
if (Native.Stdlib.ferror (file) != 0)
|
||||
throw new IOException ();
|
||||
}
|
||||
GC.KeepAlive (this);
|
||||
return (int) r;
|
||||
}
|
||||
|
||||
private void AssertValidBuffer (byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (buffer == null)
|
||||
throw new ArgumentNullException ("buffer");
|
||||
if (offset < 0)
|
||||
throw new ArgumentOutOfRangeException ("offset", "< 0");
|
||||
if (count < 0)
|
||||
throw new ArgumentOutOfRangeException ("count", "< 0");
|
||||
if (offset > buffer.Length)
|
||||
throw new ArgumentException ("destination offset is beyond array size");
|
||||
if (offset > (buffer.Length - count))
|
||||
throw new ArgumentException ("would overrun buffer");
|
||||
}
|
||||
|
||||
public void Rewind ()
|
||||
{
|
||||
AssertNotDisposed ();
|
||||
Native.Stdlib.rewind (file);
|
||||
GC.KeepAlive (this);
|
||||
}
|
||||
|
||||
public override long Seek (long offset, SeekOrigin origin)
|
||||
{
|
||||
AssertNotDisposed ();
|
||||
if (!CanSeek)
|
||||
throw new NotSupportedException ("The File Stream does not support seeking");
|
||||
|
||||
Native.SeekFlags sf = Native.SeekFlags.SEEK_CUR;
|
||||
switch (origin) {
|
||||
case SeekOrigin.Begin: sf = Native.SeekFlags.SEEK_SET; break;
|
||||
case SeekOrigin.Current: sf = Native.SeekFlags.SEEK_CUR; break;
|
||||
case SeekOrigin.End: sf = Native.SeekFlags.SEEK_END; break;
|
||||
default: throw new ArgumentException ("origin");
|
||||
}
|
||||
|
||||
int r = Native.Stdlib.fseek (file, offset, sf);
|
||||
if (r != 0)
|
||||
throw new IOException ("Unable to seek",
|
||||
UnixMarshal.CreateExceptionForLastError ());
|
||||
|
||||
long pos = Native.Stdlib.ftell (file);
|
||||
if (pos == -1)
|
||||
throw new IOException ("Unable to get current file position",
|
||||
UnixMarshal.CreateExceptionForLastError ());
|
||||
|
||||
GC.KeepAlive (this);
|
||||
return pos;
|
||||
}
|
||||
|
||||
public override void SetLength (long value)
|
||||
{
|
||||
throw new NotSupportedException ("ANSI C doesn't provide a way to truncate a file");
|
||||
}
|
||||
|
||||
public override unsafe void Write (byte[] buffer, int offset, int count)
|
||||
{
|
||||
AssertNotDisposed ();
|
||||
AssertValidBuffer (buffer, offset, count);
|
||||
if (!CanWrite)
|
||||
throw new NotSupportedException ("File Stream does not support writing");
|
||||
|
||||
ulong r = 0;
|
||||
fixed (byte* buf = &buffer[offset]) {
|
||||
r = Native.Stdlib.fwrite (buf, (ulong) 1, (ulong) count, file);
|
||||
}
|
||||
if (r != (ulong) count)
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
GC.KeepAlive (this);
|
||||
}
|
||||
|
||||
~StdioFileStream ()
|
||||
{
|
||||
Close ();
|
||||
}
|
||||
|
||||
public override void Close ()
|
||||
{
|
||||
if (file == InvalidFileStream)
|
||||
return;
|
||||
|
||||
if (owner) {
|
||||
int r = Native.Stdlib.fclose (file);
|
||||
if (r != 0)
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
} else
|
||||
Flush ();
|
||||
|
||||
file = InvalidFileStream;
|
||||
canRead = false;
|
||||
canSeek = false;
|
||||
canWrite = false;
|
||||
|
||||
GC.SuppressFinalize (this);
|
||||
GC.KeepAlive (this);
|
||||
}
|
||||
|
||||
private bool canSeek = false;
|
||||
private bool canRead = false;
|
||||
private bool canWrite = false;
|
||||
private bool owner = true;
|
||||
private IntPtr file = InvalidFileStream;
|
||||
}
|
||||
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
|
||||
|
@ -35,196 +35,198 @@ using System.Runtime.InteropServices;
|
||||
|
||||
namespace Mono.Unix {
|
||||
|
||||
public class UnixClient : MarshalByRefObject, IDisposable {
|
||||
NetworkStream stream;
|
||||
Socket client;
|
||||
bool disposed;
|
||||
public class UnixClient : MarshalByRefObject, IDisposable {
|
||||
NetworkStream stream;
|
||||
Socket client;
|
||||
Boolean disposed;
|
||||
|
||||
public UnixClient ()
|
||||
{
|
||||
if (client != null) {
|
||||
client.Close ();
|
||||
client = null;
|
||||
}
|
||||
public UnixClient ()
|
||||
{
|
||||
if (this.client != null) {
|
||||
this.client.Close ();
|
||||
this.client = null;
|
||||
}
|
||||
|
||||
this.client = new Socket (AddressFamily.Unix, SocketType.Stream, 0);
|
||||
}
|
||||
|
||||
client = new Socket (AddressFamily.Unix, SocketType.Stream, 0);
|
||||
}
|
||||
public UnixClient (String path) : this ()
|
||||
{
|
||||
if (path == null) {
|
||||
throw new ArgumentNullException ("ep");
|
||||
}
|
||||
|
||||
this.Connect (path);
|
||||
}
|
||||
|
||||
public UnixClient (string path) : this ()
|
||||
{
|
||||
if (path == null)
|
||||
throw new ArgumentNullException ("ep");
|
||||
|
||||
Connect (path);
|
||||
}
|
||||
|
||||
public UnixClient (UnixEndPoint ep) : this ()
|
||||
{
|
||||
if (ep == null)
|
||||
throw new ArgumentNullException ("ep");
|
||||
|
||||
Connect (ep);
|
||||
}
|
||||
|
||||
// UnixListener uses this when accepting a connection.
|
||||
internal UnixClient (Socket sock)
|
||||
{
|
||||
Client = sock;
|
||||
}
|
||||
|
||||
public
|
||||
Socket Client {
|
||||
get { return client; }
|
||||
set {
|
||||
client = value;
|
||||
stream = null;
|
||||
}
|
||||
}
|
||||
|
||||
public PeerCred PeerCredential {
|
||||
get {
|
||||
CheckDisposed ();
|
||||
return new PeerCred (client);
|
||||
}
|
||||
}
|
||||
public UnixClient (UnixEndPoint ep) : this ()
|
||||
{
|
||||
if (ep == null) {
|
||||
throw new ArgumentNullException ("ep");
|
||||
}
|
||||
|
||||
this.Connect (ep);
|
||||
}
|
||||
|
||||
// UnixListener uses this when accepting a connection.
|
||||
internal UnixClient(Socket sock) => this.Client = sock;
|
||||
|
||||
public
|
||||
Socket Client {
|
||||
get => this.client;
|
||||
set {
|
||||
this.client = value;
|
||||
this.stream = null;
|
||||
}
|
||||
}
|
||||
|
||||
public PeerCred PeerCredential {
|
||||
get {
|
||||
this.CheckDisposed ();
|
||||
return new PeerCred (this.client);
|
||||
}
|
||||
}
|
||||
|
||||
public LingerOption LingerState {
|
||||
get {
|
||||
CheckDisposed ();
|
||||
return (LingerOption) client.GetSocketOption (SocketOptionLevel.Socket,
|
||||
SocketOptionName.Linger);
|
||||
}
|
||||
public LingerOption LingerState {
|
||||
get {
|
||||
this.CheckDisposed ();
|
||||
return (LingerOption)this.client.GetSocketOption (SocketOptionLevel.Socket,
|
||||
SocketOptionName.Linger);
|
||||
}
|
||||
|
||||
set {
|
||||
CheckDisposed ();
|
||||
client.SetSocketOption (SocketOptionLevel.Socket,
|
||||
SocketOptionName.Linger, value);
|
||||
}
|
||||
}
|
||||
set {
|
||||
this.CheckDisposed ();
|
||||
this.client.SetSocketOption (SocketOptionLevel.Socket,
|
||||
SocketOptionName.Linger, value);
|
||||
}
|
||||
}
|
||||
|
||||
public int ReceiveBufferSize {
|
||||
get {
|
||||
CheckDisposed ();
|
||||
return (int) client.GetSocketOption (SocketOptionLevel.Socket,
|
||||
SocketOptionName.ReceiveBuffer);
|
||||
}
|
||||
public Int32 ReceiveBufferSize {
|
||||
get {
|
||||
this.CheckDisposed ();
|
||||
return (Int32)this.client.GetSocketOption (SocketOptionLevel.Socket,
|
||||
SocketOptionName.ReceiveBuffer);
|
||||
}
|
||||
|
||||
set {
|
||||
CheckDisposed ();
|
||||
client.SetSocketOption (SocketOptionLevel.Socket,
|
||||
SocketOptionName.ReceiveBuffer, value);
|
||||
}
|
||||
}
|
||||
set {
|
||||
this.CheckDisposed ();
|
||||
this.client.SetSocketOption (SocketOptionLevel.Socket,
|
||||
SocketOptionName.ReceiveBuffer, value);
|
||||
}
|
||||
}
|
||||
|
||||
public int ReceiveTimeout {
|
||||
get {
|
||||
CheckDisposed ();
|
||||
return (int) client.GetSocketOption (SocketOptionLevel.Socket,
|
||||
SocketOptionName.ReceiveTimeout);
|
||||
}
|
||||
public Int32 ReceiveTimeout {
|
||||
get {
|
||||
this.CheckDisposed ();
|
||||
return (Int32)this.client.GetSocketOption (SocketOptionLevel.Socket,
|
||||
SocketOptionName.ReceiveTimeout);
|
||||
}
|
||||
|
||||
set {
|
||||
CheckDisposed ();
|
||||
client.SetSocketOption (SocketOptionLevel.Socket,
|
||||
SocketOptionName.ReceiveTimeout, value);
|
||||
}
|
||||
}
|
||||
set {
|
||||
this.CheckDisposed ();
|
||||
this.client.SetSocketOption (SocketOptionLevel.Socket,
|
||||
SocketOptionName.ReceiveTimeout, value);
|
||||
}
|
||||
}
|
||||
|
||||
public int SendBufferSize {
|
||||
get {
|
||||
CheckDisposed ();
|
||||
return (int) client.GetSocketOption (SocketOptionLevel.Socket,
|
||||
SocketOptionName.SendBuffer);
|
||||
}
|
||||
public Int32 SendBufferSize {
|
||||
get {
|
||||
this.CheckDisposed ();
|
||||
return (Int32)this.client.GetSocketOption (SocketOptionLevel.Socket,
|
||||
SocketOptionName.SendBuffer);
|
||||
}
|
||||
|
||||
set {
|
||||
CheckDisposed ();
|
||||
client.SetSocketOption (SocketOptionLevel.Socket,
|
||||
SocketOptionName.SendBuffer, value);
|
||||
}
|
||||
}
|
||||
set {
|
||||
this.CheckDisposed ();
|
||||
this.client.SetSocketOption (SocketOptionLevel.Socket,
|
||||
SocketOptionName.SendBuffer, value);
|
||||
}
|
||||
}
|
||||
|
||||
public int SendTimeout {
|
||||
get {
|
||||
CheckDisposed ();
|
||||
return (int) client.GetSocketOption (SocketOptionLevel.Socket,
|
||||
SocketOptionName.SendTimeout);
|
||||
}
|
||||
public Int32 SendTimeout {
|
||||
get {
|
||||
this.CheckDisposed ();
|
||||
return (Int32)this.client.GetSocketOption (SocketOptionLevel.Socket,
|
||||
SocketOptionName.SendTimeout);
|
||||
}
|
||||
|
||||
set {
|
||||
CheckDisposed ();
|
||||
client.SetSocketOption (SocketOptionLevel.Socket,
|
||||
SocketOptionName.SendTimeout, value);
|
||||
}
|
||||
}
|
||||
set {
|
||||
this.CheckDisposed ();
|
||||
this.client.SetSocketOption (SocketOptionLevel.Socket,
|
||||
SocketOptionName.SendTimeout, value);
|
||||
}
|
||||
}
|
||||
|
||||
public void Close ()
|
||||
{
|
||||
CheckDisposed ();
|
||||
Dispose ();
|
||||
}
|
||||
public void Close ()
|
||||
{
|
||||
this.CheckDisposed ();
|
||||
this.Dispose ();
|
||||
}
|
||||
|
||||
public void Connect (UnixEndPoint remoteEndPoint)
|
||||
{
|
||||
CheckDisposed ();
|
||||
client.Connect (remoteEndPoint);
|
||||
stream = new NetworkStream (client, true);
|
||||
}
|
||||
public void Connect (UnixEndPoint remoteEndPoint)
|
||||
{
|
||||
this.CheckDisposed ();
|
||||
this.client.Connect (remoteEndPoint);
|
||||
this.stream = new NetworkStream (this.client, true);
|
||||
}
|
||||
|
||||
public void Connect (string path)
|
||||
{
|
||||
CheckDisposed ();
|
||||
Connect (new UnixEndPoint (path));
|
||||
}
|
||||
public void Connect (String path)
|
||||
{
|
||||
this.CheckDisposed ();
|
||||
this.Connect (new UnixEndPoint (path));
|
||||
}
|
||||
|
||||
public void Dispose ()
|
||||
{
|
||||
Dispose (true);
|
||||
GC.SuppressFinalize (this);
|
||||
}
|
||||
public void Dispose ()
|
||||
{
|
||||
this.Dispose (true);
|
||||
GC.SuppressFinalize (this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose (bool disposing)
|
||||
{
|
||||
if (disposed)
|
||||
return;
|
||||
protected virtual void Dispose (Boolean disposing)
|
||||
{
|
||||
if (this.disposed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (disposing) {
|
||||
// release managed resources
|
||||
NetworkStream s = this.stream;
|
||||
this.stream = null;
|
||||
if (s != null) {
|
||||
// This closes the socket as well, as the NetworkStream
|
||||
// owns the socket.
|
||||
s.Close();
|
||||
s = null;
|
||||
} else if (this.client != null){
|
||||
this.client.Close ();
|
||||
}
|
||||
this.client = null;
|
||||
}
|
||||
|
||||
this.disposed = true;
|
||||
}
|
||||
|
||||
if (disposing) {
|
||||
// release managed resources
|
||||
NetworkStream s = stream;
|
||||
stream = null;
|
||||
if (s != null) {
|
||||
// This closes the socket as well, as the NetworkStream
|
||||
// owns the socket.
|
||||
s.Close();
|
||||
s = null;
|
||||
} else if (client != null){
|
||||
client.Close ();
|
||||
}
|
||||
client = null;
|
||||
}
|
||||
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
public NetworkStream GetStream ()
|
||||
{
|
||||
CheckDisposed ();
|
||||
if (stream == null)
|
||||
stream = new NetworkStream (client, true);
|
||||
|
||||
return stream;
|
||||
}
|
||||
public NetworkStream GetStream ()
|
||||
{
|
||||
this.CheckDisposed ();
|
||||
if (this.stream == null) {
|
||||
this.stream = new NetworkStream (this.client, true);
|
||||
}
|
||||
|
||||
return this.stream;
|
||||
}
|
||||
|
||||
void CheckDisposed ()
|
||||
{
|
||||
if (disposed)
|
||||
throw new ObjectDisposedException (GetType().FullName);
|
||||
}
|
||||
void CheckDisposed ()
|
||||
{
|
||||
if (this.disposed) {
|
||||
throw new ObjectDisposedException (this.GetType().FullName);
|
||||
}
|
||||
}
|
||||
|
||||
~UnixClient ()
|
||||
{
|
||||
Dispose (false);
|
||||
}
|
||||
}
|
||||
~UnixClient ()
|
||||
{
|
||||
this.Dispose (false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,216 +35,223 @@ using Mono.Unix;
|
||||
|
||||
namespace Mono.Unix {
|
||||
|
||||
public sealed class UnixDirectoryInfo : UnixFileSystemInfo
|
||||
{
|
||||
public UnixDirectoryInfo (string path)
|
||||
: base (path)
|
||||
{
|
||||
}
|
||||
public sealed class UnixDirectoryInfo : UnixFileSystemInfo
|
||||
{
|
||||
public UnixDirectoryInfo (String path)
|
||||
: base (path)
|
||||
{
|
||||
}
|
||||
|
||||
internal UnixDirectoryInfo (string path, Native.Stat stat)
|
||||
: base (path, stat)
|
||||
{
|
||||
}
|
||||
internal UnixDirectoryInfo (String path, Native.Stat stat)
|
||||
: base (path, stat)
|
||||
{
|
||||
}
|
||||
|
||||
public override string Name {
|
||||
get {
|
||||
string r = UnixPath.GetFileName (FullPath);
|
||||
if (r == null || r.Length == 0)
|
||||
return FullPath;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
public override String Name {
|
||||
get {
|
||||
String r = UnixPath.GetFileName (this.FullPath);
|
||||
return r == null || r.Length == 0 ? this.FullPath : r;
|
||||
}
|
||||
}
|
||||
|
||||
public UnixDirectoryInfo Parent {
|
||||
get {
|
||||
if (FullPath == "/")
|
||||
return this;
|
||||
string dirname = UnixPath.GetDirectoryName (FullPath);
|
||||
if (dirname == "")
|
||||
throw new InvalidOperationException ("Do not know parent directory for path `" + FullPath + "'");
|
||||
return new UnixDirectoryInfo (dirname);
|
||||
}
|
||||
}
|
||||
public UnixDirectoryInfo Parent {
|
||||
get {
|
||||
if (this.FullPath == "/") {
|
||||
return this;
|
||||
}
|
||||
|
||||
String dirname = UnixPath.GetDirectoryName (this.FullPath);
|
||||
if (dirname == "") {
|
||||
throw new InvalidOperationException ("Do not know parent directory for path `" + this.FullPath + "'");
|
||||
}
|
||||
|
||||
return new UnixDirectoryInfo (dirname);
|
||||
}
|
||||
}
|
||||
|
||||
public UnixDirectoryInfo Root {
|
||||
get {
|
||||
string root = UnixPath.GetPathRoot (FullPath);
|
||||
if (root == null)
|
||||
return null;
|
||||
return new UnixDirectoryInfo (root);
|
||||
}
|
||||
}
|
||||
public UnixDirectoryInfo Root {
|
||||
get {
|
||||
String root = UnixPath.GetPathRoot (this.FullPath);
|
||||
return root == null ? null : new UnixDirectoryInfo (root);
|
||||
}
|
||||
}
|
||||
|
||||
[CLSCompliant (false)]
|
||||
public void Create (Mono.Unix.Native.FilePermissions mode)
|
||||
{
|
||||
int r = Mono.Unix.Native.Syscall.mkdir (FullPath, mode);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
base.Refresh ();
|
||||
}
|
||||
//[CLSCompliant (false)]
|
||||
public void Create (Mono.Unix.Native.FilePermissions mode)
|
||||
{
|
||||
Int32 r = Mono.Unix.Native.Syscall.mkdir (this.FullPath, mode);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
base.Refresh ();
|
||||
}
|
||||
|
||||
public void Create(FileAccessPermissions mode) => this.Create((Native.FilePermissions)mode);
|
||||
|
||||
public void Create ()
|
||||
{
|
||||
Mono.Unix.Native.FilePermissions mode =
|
||||
Mono.Unix.Native.FilePermissions.ACCESSPERMS;
|
||||
this.Create (mode);
|
||||
}
|
||||
|
||||
public override void Delete() => this.Delete(false);
|
||||
|
||||
public void Delete (Boolean recursive)
|
||||
{
|
||||
if (recursive) {
|
||||
foreach (UnixFileSystemInfo e in this.GetFileSystemEntries ()) {
|
||||
UnixDirectoryInfo d = e as UnixDirectoryInfo;
|
||||
if (d != null) {
|
||||
d.Delete (true);
|
||||
} else {
|
||||
e.Delete ();
|
||||
}
|
||||
}
|
||||
}
|
||||
Int32 r = Native.Syscall.rmdir (this.FullPath);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
base.Refresh ();
|
||||
}
|
||||
|
||||
public void Create (FileAccessPermissions mode)
|
||||
{
|
||||
Create ((Native.FilePermissions) mode);
|
||||
}
|
||||
public Native.Dirent[] GetEntries ()
|
||||
{
|
||||
IntPtr dirp = Native.Syscall.opendir (this.FullPath);
|
||||
if (dirp == IntPtr.Zero) {
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
}
|
||||
|
||||
Boolean complete = false;
|
||||
try {
|
||||
Native.Dirent[] entries = GetEntries (dirp);
|
||||
complete = true;
|
||||
return entries;
|
||||
}
|
||||
finally {
|
||||
Int32 r = Native.Syscall.closedir (dirp);
|
||||
// don't throw an exception if an exception is in progress
|
||||
if (complete) {
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Create ()
|
||||
{
|
||||
Mono.Unix.Native.FilePermissions mode =
|
||||
Mono.Unix.Native.FilePermissions.ACCESSPERMS;
|
||||
Create (mode);
|
||||
}
|
||||
private static Native.Dirent[] GetEntries (IntPtr dirp)
|
||||
{
|
||||
ArrayList entries = new ArrayList ();
|
||||
|
||||
Int32 r;
|
||||
IntPtr result;
|
||||
do {
|
||||
Native.Dirent d = new Native.Dirent ();
|
||||
r = Native.Syscall.readdir_r (dirp, d, out result);
|
||||
if (r == 0 && result != IntPtr.Zero) {
|
||||
// don't include current & parent dirs
|
||||
if (d.d_name != "." && d.d_name != "..") {
|
||||
_ = entries.Add(d);
|
||||
}
|
||||
}
|
||||
} while (r == 0 && result != IntPtr.Zero);
|
||||
if (r != 0) {
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
|
||||
return (Native.Dirent[]) entries.ToArray (typeof(Native.Dirent));
|
||||
}
|
||||
|
||||
public override void Delete ()
|
||||
{
|
||||
Delete (false);
|
||||
}
|
||||
public Native.Dirent[] GetEntries (Regex regex)
|
||||
{
|
||||
IntPtr dirp = Native.Syscall.opendir (this.FullPath);
|
||||
if (dirp == IntPtr.Zero) {
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
}
|
||||
|
||||
try {
|
||||
return GetEntries (dirp, regex);
|
||||
}
|
||||
finally {
|
||||
Int32 r = Native.Syscall.closedir (dirp);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
}
|
||||
|
||||
public void Delete (bool recursive)
|
||||
{
|
||||
if (recursive) {
|
||||
foreach (UnixFileSystemInfo e in GetFileSystemEntries ()) {
|
||||
UnixDirectoryInfo d = e as UnixDirectoryInfo;
|
||||
if (d != null)
|
||||
d.Delete (true);
|
||||
else
|
||||
e.Delete ();
|
||||
}
|
||||
}
|
||||
int r = Native.Syscall.rmdir (FullPath);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
base.Refresh ();
|
||||
}
|
||||
private static Native.Dirent[] GetEntries (IntPtr dirp, Regex regex)
|
||||
{
|
||||
ArrayList entries = new ArrayList ();
|
||||
|
||||
Int32 r;
|
||||
IntPtr result;
|
||||
do {
|
||||
Native.Dirent d = new Native.Dirent ();
|
||||
r = Native.Syscall.readdir_r (dirp, d, out result);
|
||||
if (r == 0 && result != IntPtr.Zero && regex.Match (d.d_name).Success) {
|
||||
// don't include current & parent dirs
|
||||
if (d.d_name != "." && d.d_name != "..") {
|
||||
_ = entries.Add(d);
|
||||
}
|
||||
}
|
||||
} while (r == 0 && result != IntPtr.Zero);
|
||||
if (r != 0) {
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
}
|
||||
|
||||
return (Native.Dirent[]) entries.ToArray (typeof(Native.Dirent));
|
||||
}
|
||||
|
||||
public Native.Dirent[] GetEntries ()
|
||||
{
|
||||
IntPtr dirp = Native.Syscall.opendir (FullPath);
|
||||
if (dirp == IntPtr.Zero)
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
public Native.Dirent[] GetEntries (String regex)
|
||||
{
|
||||
Regex re = new Regex (regex);
|
||||
return this.GetEntries (re);
|
||||
}
|
||||
|
||||
bool complete = false;
|
||||
try {
|
||||
Native.Dirent[] entries = GetEntries (dirp);
|
||||
complete = true;
|
||||
return entries;
|
||||
}
|
||||
finally {
|
||||
int r = Native.Syscall.closedir (dirp);
|
||||
// don't throw an exception if an exception is in progress
|
||||
if (complete)
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
}
|
||||
public UnixFileSystemInfo[] GetFileSystemEntries ()
|
||||
{
|
||||
Native.Dirent[] dentries = this.GetEntries ();
|
||||
return this.GetFileSystemEntries (dentries);
|
||||
}
|
||||
|
||||
private static Native.Dirent[] GetEntries (IntPtr dirp)
|
||||
{
|
||||
ArrayList entries = new ArrayList ();
|
||||
private UnixFileSystemInfo[] GetFileSystemEntries (Native.Dirent[] dentries)
|
||||
{
|
||||
UnixFileSystemInfo[] entries = new UnixFileSystemInfo[dentries.Length];
|
||||
for (Int32 i = 0; i != entries.Length; ++i) {
|
||||
entries [i] = UnixFileSystemInfo.GetFileSystemEntry (
|
||||
UnixPath.Combine (this.FullPath, dentries[i].d_name));
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
int r;
|
||||
IntPtr result;
|
||||
do {
|
||||
Native.Dirent d = new Native.Dirent ();
|
||||
r = Native.Syscall.readdir_r (dirp, d, out result);
|
||||
if (r == 0 && result != IntPtr.Zero)
|
||||
// don't include current & parent dirs
|
||||
if (d.d_name != "." && d.d_name != "..")
|
||||
entries.Add (d);
|
||||
} while (r == 0 && result != IntPtr.Zero);
|
||||
if (r != 0)
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
public UnixFileSystemInfo[] GetFileSystemEntries (Regex regex)
|
||||
{
|
||||
Native.Dirent[] dentries = this.GetEntries (regex);
|
||||
return this.GetFileSystemEntries (dentries);
|
||||
}
|
||||
|
||||
return (Native.Dirent[]) entries.ToArray (typeof(Native.Dirent));
|
||||
}
|
||||
public UnixFileSystemInfo[] GetFileSystemEntries (String regex)
|
||||
{
|
||||
Regex re = new Regex (regex);
|
||||
return this.GetFileSystemEntries (re);
|
||||
}
|
||||
|
||||
public Native.Dirent[] GetEntries (Regex regex)
|
||||
{
|
||||
IntPtr dirp = Native.Syscall.opendir (FullPath);
|
||||
if (dirp == IntPtr.Zero)
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
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 ();
|
||||
}
|
||||
|
||||
try {
|
||||
return GetEntries (dirp, regex);
|
||||
}
|
||||
finally {
|
||||
int r = Native.Syscall.closedir (dirp);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
}
|
||||
|
||||
private static Native.Dirent[] GetEntries (IntPtr dirp, Regex regex)
|
||||
{
|
||||
ArrayList entries = new ArrayList ();
|
||||
|
||||
int r;
|
||||
IntPtr result;
|
||||
do {
|
||||
Native.Dirent d = new Native.Dirent ();
|
||||
r = Native.Syscall.readdir_r (dirp, d, out result);
|
||||
if (r == 0 && result != IntPtr.Zero && regex.Match (d.d_name).Success) {
|
||||
// don't include current & parent dirs
|
||||
if (d.d_name != "." && d.d_name != "..")
|
||||
entries.Add (d);
|
||||
}
|
||||
} while (r == 0 && result != IntPtr.Zero);
|
||||
if (r != 0)
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
|
||||
return (Native.Dirent[]) entries.ToArray (typeof(Native.Dirent));
|
||||
}
|
||||
|
||||
public Native.Dirent[] GetEntries (string regex)
|
||||
{
|
||||
Regex re = new Regex (regex);
|
||||
return GetEntries (re);
|
||||
}
|
||||
|
||||
public UnixFileSystemInfo[] GetFileSystemEntries ()
|
||||
{
|
||||
Native.Dirent[] dentries = GetEntries ();
|
||||
return GetFileSystemEntries (dentries);
|
||||
}
|
||||
|
||||
private UnixFileSystemInfo[] GetFileSystemEntries (Native.Dirent[] dentries)
|
||||
{
|
||||
UnixFileSystemInfo[] entries = new UnixFileSystemInfo[dentries.Length];
|
||||
for (int i = 0; i != entries.Length; ++i)
|
||||
entries [i] = UnixFileSystemInfo.GetFileSystemEntry (
|
||||
UnixPath.Combine (FullPath, dentries[i].d_name));
|
||||
return entries;
|
||||
}
|
||||
|
||||
public UnixFileSystemInfo[] GetFileSystemEntries (Regex regex)
|
||||
{
|
||||
Native.Dirent[] dentries = GetEntries (regex);
|
||||
return GetFileSystemEntries (dentries);
|
||||
}
|
||||
|
||||
public UnixFileSystemInfo[] GetFileSystemEntries (string regex)
|
||||
{
|
||||
Regex re = new Regex (regex);
|
||||
return GetFileSystemEntries (re);
|
||||
}
|
||||
|
||||
public static string GetCurrentDirectory ()
|
||||
{
|
||||
StringBuilder buf = new StringBuilder (16);
|
||||
IntPtr r = IntPtr.Zero;
|
||||
do {
|
||||
buf.Capacity *= 2;
|
||||
r = Native.Syscall.getcwd (buf, (ulong) buf.Capacity);
|
||||
} while (r == IntPtr.Zero && Native.Syscall.GetLastError() == Native.Errno.ERANGE);
|
||||
if (r == IntPtr.Zero)
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
return buf.ToString ();
|
||||
}
|
||||
|
||||
public static void SetCurrentDirectory (string path)
|
||||
{
|
||||
int r = Native.Syscall.chdir (path);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
}
|
||||
public static void SetCurrentDirectory (String path)
|
||||
{
|
||||
Int32 r = Native.Syscall.chdir (path);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// vim: noexpandtab
|
||||
|
@ -33,163 +33,157 @@ using Mono.Unix;
|
||||
|
||||
namespace Mono.Unix {
|
||||
|
||||
public enum UnixDriveType {
|
||||
Unknown,
|
||||
NoRootDirectory,
|
||||
Removable,
|
||||
Fixed,
|
||||
Network,
|
||||
CDRom,
|
||||
Ram
|
||||
}
|
||||
public enum UnixDriveType {
|
||||
Unknown,
|
||||
NoRootDirectory,
|
||||
Removable,
|
||||
Fixed,
|
||||
Network,
|
||||
CDRom,
|
||||
Ram
|
||||
}
|
||||
|
||||
// All methods & properties can throw IOException
|
||||
public sealed class UnixDriveInfo
|
||||
{
|
||||
private Native.Statvfs stat;
|
||||
private string fstype, mount_point, block_device;
|
||||
// All methods & properties can throw IOException
|
||||
public sealed class UnixDriveInfo
|
||||
{
|
||||
private Native.Statvfs stat;
|
||||
private String fstype, mount_point, block_device;
|
||||
|
||||
public UnixDriveInfo (string mountPoint)
|
||||
{
|
||||
if (mountPoint == null)
|
||||
throw new ArgumentNullException ("mountPoint");
|
||||
Native.Fstab fstab = Native.Syscall.getfsfile (mountPoint);
|
||||
if (fstab != null) {
|
||||
FromFstab (fstab);
|
||||
}
|
||||
else {
|
||||
this.mount_point = mountPoint;
|
||||
this.block_device = "";
|
||||
this.fstype = "Unknown";
|
||||
}
|
||||
}
|
||||
public UnixDriveInfo (String mountPoint)
|
||||
{
|
||||
if (mountPoint == null) {
|
||||
throw new ArgumentNullException ("mountPoint");
|
||||
}
|
||||
|
||||
Native.Fstab fstab = Native.Syscall.getfsfile (mountPoint);
|
||||
if (fstab != null) {
|
||||
this.FromFstab (fstab);
|
||||
}
|
||||
else {
|
||||
this.mount_point = mountPoint;
|
||||
this.block_device = "";
|
||||
this.fstype = "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
private void FromFstab (Native.Fstab fstab)
|
||||
{
|
||||
this.fstype = fstab.fs_vfstype;
|
||||
this.mount_point = fstab.fs_file;
|
||||
this.block_device = fstab.fs_spec;
|
||||
}
|
||||
private void FromFstab (Native.Fstab fstab)
|
||||
{
|
||||
this.fstype = fstab.fs_vfstype;
|
||||
this.mount_point = fstab.fs_file;
|
||||
this.block_device = fstab.fs_spec;
|
||||
}
|
||||
|
||||
public static UnixDriveInfo GetForSpecialFile (string specialFile)
|
||||
{
|
||||
if (specialFile == null)
|
||||
throw new ArgumentNullException ("specialFile");
|
||||
Native.Fstab f = Native.Syscall.getfsspec (specialFile);
|
||||
if (f == null)
|
||||
throw new ArgumentException ("specialFile isn't valid: " + specialFile);
|
||||
return new UnixDriveInfo (f);
|
||||
}
|
||||
public static UnixDriveInfo GetForSpecialFile (String specialFile)
|
||||
{
|
||||
if (specialFile == null) {
|
||||
throw new ArgumentNullException ("specialFile");
|
||||
}
|
||||
|
||||
Native.Fstab f = Native.Syscall.getfsspec (specialFile);
|
||||
if (f == null) {
|
||||
throw new ArgumentException ("specialFile isn't valid: " + specialFile);
|
||||
}
|
||||
|
||||
return new UnixDriveInfo (f);
|
||||
}
|
||||
|
||||
private UnixDriveInfo(Native.Fstab fstab) => this.FromFstab(fstab);
|
||||
|
||||
public Int64 AvailableFreeSpace {
|
||||
get {
|
||||
this.Refresh (); return Convert.ToInt64 (this.stat.f_bavail * this.stat.f_frsize);}
|
||||
}
|
||||
|
||||
public String DriveFormat => this.fstype;
|
||||
|
||||
public UnixDriveType DriveType => UnixDriveType.Unknown;
|
||||
|
||||
// this throws no exceptions
|
||||
public Boolean IsReady {
|
||||
get {
|
||||
Boolean ready = this.Refresh (false);
|
||||
if (this.mount_point == "/" || !ready) {
|
||||
return ready;
|
||||
}
|
||||
|
||||
Int32 r = Native.Syscall.statvfs(this.RootDirectory.Parent.FullName,
|
||||
out Native.Statvfs parent);
|
||||
return r != 0 ? false : parent.f_fsid != this.stat.f_fsid;
|
||||
}
|
||||
}
|
||||
|
||||
public String Name => this.mount_point;
|
||||
|
||||
public UnixDirectoryInfo RootDirectory => new UnixDirectoryInfo(this.mount_point);
|
||||
|
||||
public Int64 TotalFreeSpace {
|
||||
get {
|
||||
this.Refresh (); return (Int64) (this.stat.f_bfree * this.stat.f_frsize);}
|
||||
}
|
||||
|
||||
private UnixDriveInfo (Native.Fstab fstab)
|
||||
{
|
||||
FromFstab (fstab);
|
||||
}
|
||||
public Int64 TotalSize {
|
||||
get {
|
||||
this.Refresh (); return (Int64) (this.stat.f_frsize * this.stat.f_blocks);}
|
||||
}
|
||||
|
||||
// also throws SecurityException if caller lacks perms
|
||||
public String VolumeLabel => this.block_device;
|
||||
|
||||
public Int64 MaximumFilenameLength {
|
||||
get {
|
||||
this.Refresh (); return Convert.ToInt64 (this.stat.f_namemax);}
|
||||
}
|
||||
|
||||
public long AvailableFreeSpace {
|
||||
get {Refresh (); return Convert.ToInt64 (stat.f_bavail * stat.f_frsize);}
|
||||
}
|
||||
public static UnixDriveInfo[] GetDrives ()
|
||||
{
|
||||
// TODO: Return any drives mentioned by getmntent(3) once getmntent(3)
|
||||
// is exported by Syscall.
|
||||
|
||||
public string DriveFormat {
|
||||
get {return fstype;}
|
||||
}
|
||||
// throws IOException, UnauthorizedAccessException (no permission)
|
||||
ArrayList entries = new ArrayList ();
|
||||
|
||||
public UnixDriveType DriveType {
|
||||
get {return UnixDriveType.Unknown;}
|
||||
}
|
||||
|
||||
// this throws no exceptions
|
||||
public bool IsReady {
|
||||
get {
|
||||
bool ready = Refresh (false);
|
||||
if (mount_point == "/" || !ready)
|
||||
return ready;
|
||||
Native.Statvfs parent;
|
||||
int r = Native.Syscall.statvfs (RootDirectory.Parent.FullName,
|
||||
out parent);
|
||||
if (r != 0)
|
||||
return false;
|
||||
return parent.f_fsid != stat.f_fsid;
|
||||
}
|
||||
}
|
||||
|
||||
public string Name {
|
||||
get {return mount_point;}
|
||||
}
|
||||
|
||||
public UnixDirectoryInfo RootDirectory {
|
||||
get {return new UnixDirectoryInfo (mount_point);}
|
||||
}
|
||||
|
||||
public long TotalFreeSpace {
|
||||
get {Refresh (); return (long) (stat.f_bfree * stat.f_frsize);}
|
||||
}
|
||||
|
||||
public long TotalSize {
|
||||
get {Refresh (); return (long) (stat.f_frsize * stat.f_blocks);}
|
||||
}
|
||||
|
||||
// also throws SecurityException if caller lacks perms
|
||||
public string VolumeLabel {
|
||||
get {return block_device;}
|
||||
// set {}
|
||||
}
|
||||
|
||||
public long MaximumFilenameLength {
|
||||
get {Refresh (); return Convert.ToInt64 (stat.f_namemax);}
|
||||
}
|
||||
|
||||
public static UnixDriveInfo[] GetDrives ()
|
||||
{
|
||||
// TODO: Return any drives mentioned by getmntent(3) once getmntent(3)
|
||||
// is exported by Syscall.
|
||||
|
||||
// throws IOException, UnauthorizedAccessException (no permission)
|
||||
ArrayList entries = new ArrayList ();
|
||||
|
||||
lock (Native.Syscall.fstab_lock) {
|
||||
int r = Native.Syscall.setfsent ();
|
||||
if (r != 1)
|
||||
throw new IOException ("Error calling setfsent(3)", new UnixIOException ());
|
||||
try {
|
||||
Native.Fstab fs;
|
||||
while ((fs = Native.Syscall.getfsent()) != null) {
|
||||
// avoid virtual entries, such as "swap"
|
||||
if (fs.fs_file != null && fs.fs_file.StartsWith ("/"))
|
||||
entries.Add (new UnixDriveInfo (fs));
|
||||
}
|
||||
}
|
||||
finally {
|
||||
Native.Syscall.endfsent ();
|
||||
}
|
||||
}
|
||||
return (UnixDriveInfo[]) entries.ToArray (typeof(UnixDriveInfo));
|
||||
}
|
||||
|
||||
public override string ToString ()
|
||||
{
|
||||
return VolumeLabel;
|
||||
}
|
||||
|
||||
private void Refresh ()
|
||||
{
|
||||
Refresh (true);
|
||||
}
|
||||
|
||||
private bool Refresh (bool throwException)
|
||||
{
|
||||
int r = Native.Syscall.statvfs (mount_point, out stat);
|
||||
if (r == -1 && throwException) {
|
||||
Native.Errno e = Native.Syscall.GetLastError ();
|
||||
throw new InvalidOperationException (
|
||||
UnixMarshal.GetErrorDescription (e),
|
||||
new UnixIOException (e));
|
||||
}
|
||||
else if (r == -1)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
lock (Native.Syscall.fstab_lock) {
|
||||
Int32 r = Native.Syscall.setfsent ();
|
||||
if (r != 1) {
|
||||
throw new IOException ("Error calling setfsent(3)", new UnixIOException ());
|
||||
}
|
||||
|
||||
try {
|
||||
Native.Fstab fs;
|
||||
while ((fs = Native.Syscall.getfsent()) != null) {
|
||||
// avoid virtual entries, such as "swap"
|
||||
if (fs.fs_file != null && fs.fs_file.StartsWith ("/")) {
|
||||
_ = entries.Add(new UnixDriveInfo(fs));
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
_ = Native.Syscall.endfsent();
|
||||
}
|
||||
}
|
||||
return (UnixDriveInfo[]) entries.ToArray (typeof(UnixDriveInfo));
|
||||
}
|
||||
|
||||
public override String ToString() => this.VolumeLabel;
|
||||
|
||||
private void Refresh() => this.Refresh(true);
|
||||
|
||||
private Boolean Refresh (Boolean throwException)
|
||||
{
|
||||
Int32 r = Native.Syscall.statvfs (this.mount_point, out this.stat);
|
||||
if (r == -1 && throwException) {
|
||||
Native.Errno e = Native.Syscall.GetLastError ();
|
||||
throw new InvalidOperationException (
|
||||
UnixMarshal.GetErrorDescription (e),
|
||||
new UnixIOException (e));
|
||||
}
|
||||
else if (r == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// vim: noexpandtab
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -34,100 +34,95 @@ using System.Text;
|
||||
|
||||
namespace Mono.Unix
|
||||
{
|
||||
[Serializable]
|
||||
public class UnixEndPoint : EndPoint
|
||||
{
|
||||
string filename;
|
||||
|
||||
public UnixEndPoint (string filename)
|
||||
{
|
||||
if (filename == null)
|
||||
throw new ArgumentNullException ("filename");
|
||||
[Serializable]
|
||||
public class UnixEndPoint : EndPoint
|
||||
{
|
||||
String filename;
|
||||
|
||||
public UnixEndPoint (String filename)
|
||||
{
|
||||
if (filename == null) {
|
||||
throw new ArgumentNullException ("filename");
|
||||
}
|
||||
|
||||
if (filename == "") {
|
||||
throw new ArgumentException ("Cannot be empty.", "filename");
|
||||
}
|
||||
|
||||
this.filename = filename;
|
||||
}
|
||||
|
||||
public String Filename {
|
||||
get => this.filename;
|
||||
set => this.filename = value;
|
||||
}
|
||||
|
||||
public override AddressFamily AddressFamily => AddressFamily.Unix;
|
||||
|
||||
public override EndPoint Create (SocketAddress socketAddress)
|
||||
{
|
||||
/*
|
||||
* Should also check this
|
||||
*
|
||||
int addr = (int) AddressFamily.Unix;
|
||||
if (socketAddress [0] != (addr & 0xFF))
|
||||
throw new ArgumentException ("socketAddress is not a unix socket address.");
|
||||
|
||||
if (filename == "")
|
||||
throw new ArgumentException ("Cannot be empty.", "filename");
|
||||
this.filename = filename;
|
||||
}
|
||||
|
||||
public string Filename {
|
||||
get {
|
||||
return(filename);
|
||||
}
|
||||
set {
|
||||
filename=value;
|
||||
}
|
||||
}
|
||||
if (socketAddress [1] != ((addr & 0xFF00) >> 8))
|
||||
throw new ArgumentException ("socketAddress is not a unix socket address.");
|
||||
*/
|
||||
|
||||
public override AddressFamily AddressFamily {
|
||||
get { return AddressFamily.Unix; }
|
||||
}
|
||||
if (socketAddress.Size == 2) {
|
||||
// Empty filename.
|
||||
// Probably from RemoteEndPoint which on linux does not return the file name.
|
||||
UnixEndPoint uep = new UnixEndPoint("a") {
|
||||
filename = ""
|
||||
};
|
||||
return uep;
|
||||
}
|
||||
Int32 size = socketAddress.Size - 2;
|
||||
Byte[] bytes = new Byte[size];
|
||||
for (Int32 i = 0; i < bytes.Length; i++) {
|
||||
bytes [i] = socketAddress [i + 2];
|
||||
// There may be junk after the null terminator, so ignore it all.
|
||||
if (bytes [i] == 0) {
|
||||
size = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
String name = Encoding.Default.GetString (bytes, 0, size);
|
||||
return new UnixEndPoint (name);
|
||||
}
|
||||
|
||||
public override EndPoint Create (SocketAddress socketAddress)
|
||||
{
|
||||
/*
|
||||
* Should also check this
|
||||
*
|
||||
int addr = (int) AddressFamily.Unix;
|
||||
if (socketAddress [0] != (addr & 0xFF))
|
||||
throw new ArgumentException ("socketAddress is not a unix socket address.");
|
||||
public override SocketAddress Serialize ()
|
||||
{
|
||||
Byte[] bytes = Encoding.Default.GetBytes (this.filename);
|
||||
SocketAddress sa = new SocketAddress (this.AddressFamily, 2 + bytes.Length + 1);
|
||||
// sa [0] -> family low byte, sa [1] -> family high byte
|
||||
for (Int32 i = 0; i < bytes.Length; i++) {
|
||||
sa [2 + i] = bytes [i];
|
||||
}
|
||||
|
||||
//NULL suffix for non-abstract path
|
||||
sa[2 + bytes.Length] = 0;
|
||||
|
||||
if (socketAddress [1] != ((addr & 0xFF00) >> 8))
|
||||
throw new ArgumentException ("socketAddress is not a unix socket address.");
|
||||
*/
|
||||
|
||||
if (socketAddress.Size == 2) {
|
||||
// Empty filename.
|
||||
// Probably from RemoteEndPoint which on linux does not return the file name.
|
||||
UnixEndPoint uep = new UnixEndPoint ("a");
|
||||
uep.filename = "";
|
||||
return uep;
|
||||
}
|
||||
int size = socketAddress.Size - 2;
|
||||
byte [] bytes = new byte [size];
|
||||
for (int i = 0; i < bytes.Length; i++) {
|
||||
bytes [i] = socketAddress [i + 2];
|
||||
// There may be junk after the null terminator, so ignore it all.
|
||||
if (bytes [i] == 0) {
|
||||
size = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
string name = Encoding.Default.GetString (bytes, 0, size);
|
||||
return new UnixEndPoint (name);
|
||||
}
|
||||
|
||||
public override SocketAddress Serialize ()
|
||||
{
|
||||
byte [] bytes = Encoding.Default.GetBytes (filename);
|
||||
SocketAddress sa = new SocketAddress (AddressFamily, 2 + bytes.Length + 1);
|
||||
// sa [0] -> family low byte, sa [1] -> family high byte
|
||||
for (int i = 0; i < bytes.Length; i++)
|
||||
sa [2 + i] = bytes [i];
|
||||
|
||||
//NULL suffix for non-abstract path
|
||||
sa[2 + bytes.Length] = 0;
|
||||
|
||||
return sa;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return(filename);
|
||||
}
|
||||
|
||||
public override int GetHashCode ()
|
||||
{
|
||||
return filename.GetHashCode ();
|
||||
}
|
||||
|
||||
public override bool Equals (object o)
|
||||
{
|
||||
UnixEndPoint other = o as UnixEndPoint;
|
||||
if (other == null)
|
||||
return false;
|
||||
|
||||
return (other.filename == filename);
|
||||
}
|
||||
}
|
||||
return sa;
|
||||
}
|
||||
|
||||
public override String ToString() => this.filename;
|
||||
|
||||
public override Int32 GetHashCode() => this.filename.GetHashCode();
|
||||
|
||||
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.Collections;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text;
|
||||
using Mono.Unix;
|
||||
|
||||
namespace Mono.Unix {
|
||||
|
||||
public sealed /* static */ class UnixEnvironment
|
||||
{
|
||||
private UnixEnvironment () {}
|
||||
public sealed /* static */ class UnixEnvironment
|
||||
{
|
||||
private UnixEnvironment () {}
|
||||
|
||||
public static string CurrentDirectory {
|
||||
get {
|
||||
return UnixDirectoryInfo.GetCurrentDirectory ();
|
||||
}
|
||||
set {
|
||||
UnixDirectoryInfo.SetCurrentDirectory (value);
|
||||
}
|
||||
}
|
||||
public static String CurrentDirectory {
|
||||
get => UnixDirectoryInfo.GetCurrentDirectory();
|
||||
set => UnixDirectoryInfo.SetCurrentDirectory(value);
|
||||
}
|
||||
|
||||
public static String MachineName {
|
||||
get {
|
||||
if(Native.Syscall.uname(out Native.Utsname buf) != 0) {
|
||||
throw UnixMarshal.CreateExceptionForLastError();
|
||||
}
|
||||
|
||||
return buf.nodename;
|
||||
}
|
||||
set {
|
||||
Int32 r = Native.Syscall.sethostname (value);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
}
|
||||
|
||||
public static String UserName => UnixUserInfo.GetRealUser().UserName;
|
||||
|
||||
public static UnixGroupInfo RealGroup => new UnixGroupInfo(RealGroupId);
|
||||
|
||||
public static Int64 RealGroupId => Native.Syscall.getgid();
|
||||
|
||||
public static UnixUserInfo RealUser => new UnixUserInfo(RealUserId);
|
||||
|
||||
public static Int64 RealUserId => Native.Syscall.getuid();
|
||||
|
||||
public static UnixGroupInfo EffectiveGroup {
|
||||
get => new UnixGroupInfo(EffectiveGroupId);
|
||||
set => EffectiveGroupId = value.GroupId;
|
||||
}
|
||||
|
||||
public static Int64 EffectiveGroupId {
|
||||
get => Native.Syscall.getegid();
|
||||
set => _ = Native.Syscall.setegid(Convert.ToUInt32(value));
|
||||
}
|
||||
|
||||
public static UnixUserInfo EffectiveUser {
|
||||
get => new UnixUserInfo(EffectiveUserId);
|
||||
set => EffectiveUserId = value.UserId;
|
||||
}
|
||||
|
||||
public static Int64 EffectiveUserId {
|
||||
get => Native.Syscall.geteuid();
|
||||
set => _ = Native.Syscall.seteuid(Convert.ToUInt32(value));
|
||||
}
|
||||
|
||||
public static String Login => UnixUserInfo.GetRealUser().UserName;
|
||||
|
||||
//[CLSCompliant (false)]
|
||||
public static Int64 GetConfigurationValue (Native.SysconfName name)
|
||||
{
|
||||
Int64 r = Native.Syscall.sysconf (name);
|
||||
if (r == -1 && Native.Stdlib.GetLastError() != (Native.Errno) 0) {
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
public static string MachineName {
|
||||
get {
|
||||
Native.Utsname buf;
|
||||
if (Native.Syscall.uname (out buf) != 0)
|
||||
throw UnixMarshal.CreateExceptionForLastError ();
|
||||
return buf.nodename;
|
||||
}
|
||||
set {
|
||||
int r = Native.Syscall.sethostname (value);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
}
|
||||
//[CLSCompliant (false)]
|
||||
public static String GetConfigurationString (Native.ConfstrName name)
|
||||
{
|
||||
UInt64 len = Native.Syscall.confstr (name, null, 0);
|
||||
if (len == unchecked ((UInt64) (-1))) {
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
StringBuilder buf = new StringBuilder ((Int32) len+1);
|
||||
len = Native.Syscall.confstr (name, buf, len);
|
||||
if (len == unchecked ((UInt64) (-1))) {
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
}
|
||||
|
||||
return buf.ToString ();
|
||||
}
|
||||
|
||||
public static string UserName {
|
||||
get {return UnixUserInfo.GetRealUser ().UserName;}
|
||||
}
|
||||
public static void SetNiceValue (Int32 inc)
|
||||
{
|
||||
Int32 r = Native.Syscall.nice (inc);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
|
||||
public static UnixGroupInfo RealGroup {
|
||||
get {return new UnixGroupInfo (RealGroupId);}
|
||||
// set can't be done as setgid(2) modifies effective gid as well
|
||||
}
|
||||
public static Int32 CreateSession ()
|
||||
{
|
||||
Int32 s = Native.Syscall.setsid ();
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (s);
|
||||
return s;
|
||||
}
|
||||
|
||||
public static long RealGroupId {
|
||||
get {return Native.Syscall.getgid ();}
|
||||
// set can't be done as setgid(2) modifies effective gid as well
|
||||
}
|
||||
public static void SetProcessGroup ()
|
||||
{
|
||||
Int32 r = Native.Syscall.setpgrp ();
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
|
||||
public static Int32 GetProcessGroup() => Native.Syscall.getpgrp();
|
||||
|
||||
public static UnixGroupInfo[] GetSupplementaryGroups ()
|
||||
{
|
||||
UInt32[] ids = _GetSupplementaryGroupIds ();
|
||||
UnixGroupInfo[] groups = new UnixGroupInfo [ids.Length];
|
||||
for (Int32 i = 0; i < groups.Length; ++i) {
|
||||
groups [i] = new UnixGroupInfo (ids [i]);
|
||||
}
|
||||
|
||||
return groups;
|
||||
}
|
||||
|
||||
public static UnixUserInfo RealUser {
|
||||
get {return new UnixUserInfo (RealUserId);}
|
||||
// set can't be done as setuid(2) modifies effective uid as well
|
||||
}
|
||||
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||
private static UInt32[] _GetSupplementaryGroupIds ()
|
||||
{
|
||||
Int32 ngroups = Native.Syscall.getgroups (0, new UInt32[]{});
|
||||
if (ngroups == -1) {
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
}
|
||||
|
||||
UInt32[] groups = new UInt32[ngroups];
|
||||
Int32 r = Native.Syscall.getgroups (groups);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
return groups;
|
||||
}
|
||||
|
||||
public static long RealUserId {
|
||||
get {return Native.Syscall.getuid ();}
|
||||
// set can't be done as setuid(2) modifies effective uid as well
|
||||
}
|
||||
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 UnixGroupInfo EffectiveGroup {
|
||||
get {return new UnixGroupInfo (EffectiveGroupId);}
|
||||
set {EffectiveGroupId = value.GroupId;}
|
||||
}
|
||||
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 long EffectiveGroupId {
|
||||
get {return Native.Syscall.getegid ();}
|
||||
set {Native.Syscall.setegid (Convert.ToUInt32 (value));}
|
||||
}
|
||||
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 ();
|
||||
|
||||
public static UnixUserInfo EffectiveUser {
|
||||
get {return new UnixUserInfo (EffectiveUserId);}
|
||||
set {EffectiveUserId = value.UserId;}
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
public static long EffectiveUserId {
|
||||
get {return Native.Syscall.geteuid ();}
|
||||
set {Native.Syscall.seteuid (Convert.ToUInt32 (value));}
|
||||
}
|
||||
|
||||
public static string Login {
|
||||
get {return UnixUserInfo.GetRealUser ().UserName;}
|
||||
}
|
||||
|
||||
[CLSCompliant (false)]
|
||||
public static long GetConfigurationValue (Native.SysconfName name)
|
||||
{
|
||||
long r = Native.Syscall.sysconf (name);
|
||||
if (r == -1 && Native.Stdlib.GetLastError() != (Native.Errno) 0)
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
return r;
|
||||
}
|
||||
|
||||
[CLSCompliant (false)]
|
||||
public static string GetConfigurationString (Native.ConfstrName name)
|
||||
{
|
||||
ulong len = Native.Syscall.confstr (name, null, 0);
|
||||
if (len == unchecked ((ulong) (-1)))
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
if (len == 0)
|
||||
return "";
|
||||
StringBuilder buf = new StringBuilder ((int) len+1);
|
||||
len = Native.Syscall.confstr (name, buf, len);
|
||||
if (len == unchecked ((ulong) (-1)))
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
return buf.ToString ();
|
||||
}
|
||||
|
||||
public static void SetNiceValue (int inc)
|
||||
{
|
||||
int r = Native.Syscall.nice (inc);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
|
||||
public static int CreateSession ()
|
||||
{
|
||||
int s = Native.Syscall.setsid ();
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (s);
|
||||
return s;
|
||||
}
|
||||
|
||||
public static void SetProcessGroup ()
|
||||
{
|
||||
int r = Native.Syscall.setpgrp ();
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
|
||||
public static int GetProcessGroup ()
|
||||
{
|
||||
return Native.Syscall.getpgrp ();
|
||||
}
|
||||
|
||||
public static UnixGroupInfo[] GetSupplementaryGroups ()
|
||||
{
|
||||
uint[] ids = _GetSupplementaryGroupIds ();
|
||||
UnixGroupInfo[] groups = new UnixGroupInfo [ids.Length];
|
||||
for (int i = 0; i < groups.Length; ++i)
|
||||
groups [i] = new UnixGroupInfo (ids [i]);
|
||||
return groups;
|
||||
}
|
||||
|
||||
private static uint[] _GetSupplementaryGroupIds ()
|
||||
{
|
||||
int ngroups = Native.Syscall.getgroups (0, new uint[]{});
|
||||
if (ngroups == -1)
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
uint[] groups = new uint[ngroups];
|
||||
int r = Native.Syscall.getgroups (groups);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
return groups;
|
||||
}
|
||||
|
||||
public static void SetSupplementaryGroups (UnixGroupInfo[] groups)
|
||||
{
|
||||
uint[] list = new uint [groups.Length];
|
||||
for (int i = 0; i < list.Length; ++i) {
|
||||
list [i] = Convert.ToUInt32 (groups [i].GroupId);
|
||||
}
|
||||
int r = Native.Syscall.setgroups (list);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
|
||||
public static long[] GetSupplementaryGroupIds ()
|
||||
{
|
||||
uint[] _groups = _GetSupplementaryGroupIds ();
|
||||
long[] groups = new long [_groups.Length];
|
||||
for (int i = 0; i < groups.Length; ++i)
|
||||
groups [i] = _groups [i];
|
||||
return groups;
|
||||
}
|
||||
|
||||
public static void SetSupplementaryGroupIds (long[] list)
|
||||
{
|
||||
uint[] _list = new uint [list.Length];
|
||||
for (int i = 0; i < _list.Length; ++i)
|
||||
_list [i] = Convert.ToUInt32 (list [i]);
|
||||
int r = Native.Syscall.setgroups (_list);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
|
||||
public static int GetParentProcessId ()
|
||||
{
|
||||
return Native.Syscall.getppid ();
|
||||
}
|
||||
|
||||
public static UnixProcess GetParentProcess ()
|
||||
{
|
||||
return new UnixProcess (GetParentProcessId ());
|
||||
}
|
||||
|
||||
public static string[] GetUserShells ()
|
||||
{
|
||||
ArrayList shells = new ArrayList ();
|
||||
|
||||
lock (Native.Syscall.usershell_lock) {
|
||||
try {
|
||||
if (Native.Syscall.setusershell () != 0)
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
string shell;
|
||||
while ((shell = Native.Syscall.getusershell ()) != null)
|
||||
shells.Add (shell);
|
||||
}
|
||||
finally {
|
||||
Native.Syscall.endusershell ();
|
||||
}
|
||||
}
|
||||
|
||||
return (string[]) shells.ToArray (typeof(string));
|
||||
}
|
||||
}
|
||||
return (String[]) shells.ToArray (typeof(String));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// vim: noexpandtab
|
||||
|
@ -33,115 +33,110 @@ using Mono.Unix;
|
||||
|
||||
namespace Mono.Unix {
|
||||
|
||||
public sealed class UnixFileInfo : UnixFileSystemInfo
|
||||
{
|
||||
public UnixFileInfo (string path)
|
||||
: base (path)
|
||||
{
|
||||
}
|
||||
public sealed class UnixFileInfo : UnixFileSystemInfo
|
||||
{
|
||||
public UnixFileInfo (String path)
|
||||
: base (path)
|
||||
{
|
||||
}
|
||||
|
||||
internal UnixFileInfo (string path, Native.Stat stat)
|
||||
: base (path, stat)
|
||||
{
|
||||
}
|
||||
internal UnixFileInfo (String path, Native.Stat stat)
|
||||
: base (path, stat)
|
||||
{
|
||||
}
|
||||
|
||||
public override String Name => UnixPath.GetFileName(this.FullPath);
|
||||
|
||||
public String DirectoryName => UnixPath.GetDirectoryName(this.FullPath);
|
||||
|
||||
public UnixDirectoryInfo Directory => new UnixDirectoryInfo(this.DirectoryName);
|
||||
|
||||
public override void Delete ()
|
||||
{
|
||||
Int32 r = Native.Syscall.unlink (this.FullPath);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
base.Refresh ();
|
||||
}
|
||||
|
||||
public override string Name {
|
||||
get {return UnixPath.GetFileName (FullPath);}
|
||||
}
|
||||
public UnixStream Create ()
|
||||
{
|
||||
Native.FilePermissions mode = // 0644
|
||||
Native.FilePermissions.S_IRUSR | Native.FilePermissions.S_IWUSR |
|
||||
Native.FilePermissions.S_IRGRP | Native.FilePermissions.S_IROTH;
|
||||
return this.Create (mode);
|
||||
}
|
||||
|
||||
public string DirectoryName {
|
||||
get {return UnixPath.GetDirectoryName (FullPath);}
|
||||
}
|
||||
//[CLSCompliant (false)]
|
||||
public UnixStream Create (Native.FilePermissions mode)
|
||||
{
|
||||
Int32 fd = Native.Syscall.creat (this.FullPath, mode);
|
||||
if (fd < 0) {
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
}
|
||||
|
||||
base.Refresh ();
|
||||
return new UnixStream (fd);
|
||||
}
|
||||
|
||||
public UnixStream Create(FileAccessPermissions mode) => this.Create((Native.FilePermissions)mode);
|
||||
|
||||
//[CLSCompliant (false)]
|
||||
public UnixStream Open (Native.OpenFlags flags)
|
||||
{
|
||||
if ((flags & Native.OpenFlags.O_CREAT) != 0) {
|
||||
throw new ArgumentException (
|
||||
"Cannot specify OpenFlags.O_CREAT without providing " +
|
||||
"FilePermissions. Use the Open(OpenFlags, FilePermissions) " +
|
||||
"method instead");
|
||||
}
|
||||
|
||||
Int32 fd = Native.Syscall.open (this.FullPath, flags);
|
||||
if (fd < 0) {
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
}
|
||||
|
||||
return new UnixStream (fd);
|
||||
}
|
||||
|
||||
public UnixDirectoryInfo Directory {
|
||||
get {return new UnixDirectoryInfo (DirectoryName);}
|
||||
}
|
||||
//[CLSCompliant (false)]
|
||||
public UnixStream Open (Native.OpenFlags flags, Native.FilePermissions mode)
|
||||
{
|
||||
Int32 fd = Native.Syscall.open (this.FullPath, flags, mode);
|
||||
if (fd < 0) {
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
}
|
||||
|
||||
return new UnixStream (fd);
|
||||
}
|
||||
|
||||
public override void Delete ()
|
||||
{
|
||||
int r = Native.Syscall.unlink (FullPath);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
base.Refresh ();
|
||||
}
|
||||
public UnixStream Open (FileMode mode)
|
||||
{
|
||||
Native.OpenFlags flags = Native.NativeConvert.ToOpenFlags (mode, FileAccess.ReadWrite);
|
||||
return this.Open (flags);
|
||||
}
|
||||
|
||||
public UnixStream Create ()
|
||||
{
|
||||
Native.FilePermissions mode = // 0644
|
||||
Native.FilePermissions.S_IRUSR | Native.FilePermissions.S_IWUSR |
|
||||
Native.FilePermissions.S_IRGRP | Native.FilePermissions.S_IROTH;
|
||||
return Create (mode);
|
||||
}
|
||||
public UnixStream Open (FileMode mode, FileAccess access)
|
||||
{
|
||||
Native.OpenFlags flags = Native.NativeConvert.ToOpenFlags (mode, access);
|
||||
return this.Open (flags);
|
||||
}
|
||||
|
||||
[CLSCompliant (false)]
|
||||
public UnixStream Create (Native.FilePermissions mode)
|
||||
{
|
||||
int fd = Native.Syscall.creat (FullPath, mode);
|
||||
if (fd < 0)
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
base.Refresh ();
|
||||
return new UnixStream (fd);
|
||||
}
|
||||
|
||||
public UnixStream Create (FileAccessPermissions mode)
|
||||
{
|
||||
return Create ((Native.FilePermissions) mode);
|
||||
}
|
||||
|
||||
[CLSCompliant (false)]
|
||||
public UnixStream Open (Native.OpenFlags flags)
|
||||
{
|
||||
if ((flags & Native.OpenFlags.O_CREAT) != 0)
|
||||
throw new ArgumentException (
|
||||
"Cannot specify OpenFlags.O_CREAT without providing " +
|
||||
"FilePermissions. Use the Open(OpenFlags, FilePermissions) " +
|
||||
"method instead");
|
||||
int fd = Native.Syscall.open (FullPath, flags);
|
||||
if (fd < 0)
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
return new UnixStream (fd);
|
||||
}
|
||||
|
||||
[CLSCompliant (false)]
|
||||
public UnixStream Open (Native.OpenFlags flags, Native.FilePermissions mode)
|
||||
{
|
||||
int fd = Native.Syscall.open (FullPath, flags, mode);
|
||||
if (fd < 0)
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
return new UnixStream (fd);
|
||||
}
|
||||
|
||||
public UnixStream Open (FileMode mode)
|
||||
{
|
||||
Native.OpenFlags flags = Native.NativeConvert.ToOpenFlags (mode, FileAccess.ReadWrite);
|
||||
return Open (flags);
|
||||
}
|
||||
|
||||
public UnixStream Open (FileMode mode, FileAccess access)
|
||||
{
|
||||
Native.OpenFlags flags = Native.NativeConvert.ToOpenFlags (mode, access);
|
||||
return Open (flags);
|
||||
}
|
||||
|
||||
[CLSCompliant (false)]
|
||||
public UnixStream Open (FileMode mode, FileAccess access, Native.FilePermissions perms)
|
||||
{
|
||||
Native.OpenFlags flags = Native.NativeConvert.ToOpenFlags (mode, access);
|
||||
int fd = Native.Syscall.open (FullPath, flags, perms);
|
||||
if (fd < 0)
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
return new UnixStream (fd);
|
||||
}
|
||||
|
||||
public UnixStream OpenRead ()
|
||||
{
|
||||
return Open (FileMode.Open, FileAccess.Read);
|
||||
}
|
||||
|
||||
public UnixStream OpenWrite ()
|
||||
{
|
||||
return Open (FileMode.OpenOrCreate, FileAccess.Write);
|
||||
}
|
||||
}
|
||||
//[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
|
||||
|
@ -33,396 +33,409 @@ using Mono.Unix;
|
||||
|
||||
namespace Mono.Unix {
|
||||
|
||||
public abstract class UnixFileSystemInfo
|
||||
{
|
||||
private Native.Stat stat;
|
||||
private string fullPath;
|
||||
private string originalPath;
|
||||
private bool valid = false;
|
||||
|
||||
internal const FileSpecialAttributes AllSpecialAttributes =
|
||||
FileSpecialAttributes.SetUserId | FileSpecialAttributes.SetGroupId |
|
||||
FileSpecialAttributes.Sticky;
|
||||
internal const FileTypes AllFileTypes =
|
||||
FileTypes.Directory | FileTypes.CharacterDevice | FileTypes.BlockDevice |
|
||||
FileTypes.RegularFile | FileTypes.Fifo | FileTypes.SymbolicLink |
|
||||
FileTypes.Socket;
|
||||
|
||||
protected UnixFileSystemInfo (string path)
|
||||
{
|
||||
UnixPath.CheckPath (path);
|
||||
this.originalPath = path;
|
||||
this.fullPath = UnixPath.GetFullPath (path);
|
||||
Refresh (true);
|
||||
}
|
||||
|
||||
internal UnixFileSystemInfo (String path, Native.Stat stat)
|
||||
{
|
||||
this.originalPath = path;
|
||||
this.fullPath = UnixPath.GetFullPath (path);
|
||||
this.stat = stat;
|
||||
this.valid = true;
|
||||
}
|
||||
|
||||
protected string FullPath {
|
||||
get {return fullPath;}
|
||||
set {
|
||||
if (fullPath != value) {
|
||||
UnixPath.CheckPath (value);
|
||||
valid = false;
|
||||
fullPath = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected string OriginalPath {
|
||||
get {return originalPath;}
|
||||
set {originalPath = value;}
|
||||
}
|
||||
|
||||
private void AssertValid ()
|
||||
{
|
||||
Refresh (false);
|
||||
if (!valid)
|
||||
throw new InvalidOperationException ("Path doesn't exist!");
|
||||
}
|
||||
|
||||
public virtual string FullName {
|
||||
get {return FullPath;}
|
||||
}
|
||||
|
||||
public abstract string Name {get;}
|
||||
|
||||
public bool Exists {
|
||||
get {
|
||||
Refresh (true);
|
||||
return valid;
|
||||
}
|
||||
}
|
||||
|
||||
public long Device {
|
||||
get {AssertValid (); return Convert.ToInt64 (stat.st_dev);}
|
||||
}
|
||||
|
||||
public long Inode {
|
||||
get {AssertValid (); return Convert.ToInt64 (stat.st_ino);}
|
||||
}
|
||||
|
||||
[CLSCompliant (false)]
|
||||
public Native.FilePermissions Protection {
|
||||
get {AssertValid (); return (Native.FilePermissions) stat.st_mode;}
|
||||
set {
|
||||
int r = Native.Syscall.chmod (FullPath, value);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
}
|
||||
|
||||
public FileTypes FileType {
|
||||
get {
|
||||
AssertValid ();
|
||||
return (FileTypes) (stat.st_mode & Native.FilePermissions.S_IFMT);
|
||||
}
|
||||
// no set as chmod(2) won't accept changing the file type.
|
||||
}
|
||||
|
||||
public FileAccessPermissions FileAccessPermissions {
|
||||
get {
|
||||
AssertValid ();
|
||||
int perms = (int) stat.st_mode;
|
||||
return (FileAccessPermissions) (perms & (int) FileAccessPermissions.AllPermissions);
|
||||
}
|
||||
set {
|
||||
AssertValid ();
|
||||
int perms = (int) stat.st_mode;
|
||||
perms &= (int) ~FileAccessPermissions.AllPermissions;
|
||||
perms |= (int) value;
|
||||
Protection = (Native.FilePermissions) perms;
|
||||
}
|
||||
}
|
||||
|
||||
public FileSpecialAttributes FileSpecialAttributes {
|
||||
get {
|
||||
AssertValid ();
|
||||
int attrs = (int) stat.st_mode;
|
||||
return (FileSpecialAttributes) (attrs & (int) AllSpecialAttributes);
|
||||
}
|
||||
set {
|
||||
AssertValid ();
|
||||
int perms = (int) stat.st_mode;
|
||||
perms &= (int) ~AllSpecialAttributes;
|
||||
perms |= (int) value;
|
||||
Protection = (Native.FilePermissions) perms;
|
||||
}
|
||||
}
|
||||
|
||||
public long LinkCount {
|
||||
get {AssertValid (); return Convert.ToInt64 (stat.st_nlink);}
|
||||
}
|
||||
|
||||
public UnixUserInfo OwnerUser {
|
||||
get {AssertValid (); return new UnixUserInfo (stat.st_uid);}
|
||||
}
|
||||
|
||||
public long OwnerUserId {
|
||||
get {AssertValid (); return stat.st_uid;}
|
||||
}
|
||||
|
||||
public UnixGroupInfo OwnerGroup {
|
||||
get {AssertValid (); return new UnixGroupInfo (stat.st_gid);}
|
||||
}
|
||||
|
||||
public long OwnerGroupId {
|
||||
get {AssertValid (); return stat.st_gid;}
|
||||
}
|
||||
|
||||
public long DeviceType {
|
||||
get {AssertValid (); return Convert.ToInt64 (stat.st_rdev);}
|
||||
}
|
||||
|
||||
public long Length {
|
||||
get {AssertValid (); return (long) stat.st_size;}
|
||||
}
|
||||
|
||||
public long BlockSize {
|
||||
get {AssertValid (); return (long) stat.st_blksize;}
|
||||
}
|
||||
|
||||
public long BlocksAllocated {
|
||||
get {AssertValid (); return (long) stat.st_blocks;}
|
||||
}
|
||||
|
||||
public DateTime LastAccessTime {
|
||||
get {AssertValid (); return Native.NativeConvert.ToDateTime (stat.st_atime, stat.st_atime_nsec);}
|
||||
}
|
||||
|
||||
public DateTime LastAccessTimeUtc {
|
||||
get {return LastAccessTime.ToUniversalTime ();}
|
||||
}
|
||||
|
||||
public DateTime LastWriteTime {
|
||||
get {AssertValid (); return Native.NativeConvert.ToDateTime (stat.st_mtime, stat.st_mtime_nsec);}
|
||||
}
|
||||
|
||||
public DateTime LastWriteTimeUtc {
|
||||
get {return LastWriteTime.ToUniversalTime ();}
|
||||
}
|
||||
|
||||
public DateTime LastStatusChangeTime {
|
||||
get {AssertValid (); return Native.NativeConvert.ToDateTime (stat.st_ctime, stat.st_ctime_nsec);}
|
||||
}
|
||||
|
||||
public DateTime LastStatusChangeTimeUtc {
|
||||
get {return LastStatusChangeTime.ToUniversalTime ();}
|
||||
}
|
||||
|
||||
public bool IsDirectory {
|
||||
get {AssertValid (); return IsFileType (stat.st_mode, Native.FilePermissions.S_IFDIR);}
|
||||
}
|
||||
|
||||
public bool IsCharacterDevice {
|
||||
get {AssertValid (); return IsFileType (stat.st_mode, Native.FilePermissions.S_IFCHR);}
|
||||
}
|
||||
|
||||
public bool IsBlockDevice {
|
||||
get {AssertValid (); return IsFileType (stat.st_mode, Native.FilePermissions.S_IFBLK);}
|
||||
}
|
||||
|
||||
public bool IsRegularFile {
|
||||
get {AssertValid (); return IsFileType (stat.st_mode, Native.FilePermissions.S_IFREG);}
|
||||
}
|
||||
|
||||
public bool IsFifo {
|
||||
get {AssertValid (); return IsFileType (stat.st_mode, Native.FilePermissions.S_IFIFO);}
|
||||
}
|
||||
|
||||
public bool IsSymbolicLink {
|
||||
get {AssertValid (); return IsFileType (stat.st_mode, Native.FilePermissions.S_IFLNK);}
|
||||
}
|
||||
|
||||
public bool IsSocket {
|
||||
get {AssertValid (); return IsFileType (stat.st_mode, Native.FilePermissions.S_IFSOCK);}
|
||||
}
|
||||
|
||||
public bool IsSetUser {
|
||||
get {AssertValid (); return IsSet (stat.st_mode, Native.FilePermissions.S_ISUID);}
|
||||
}
|
||||
|
||||
public bool IsSetGroup {
|
||||
get {AssertValid (); return IsSet (stat.st_mode, Native.FilePermissions.S_ISGID);}
|
||||
}
|
||||
|
||||
public bool IsSticky {
|
||||
get {AssertValid (); return IsSet (stat.st_mode, Native.FilePermissions.S_ISVTX);}
|
||||
}
|
||||
|
||||
internal static bool IsFileType (Native.FilePermissions mode, Native.FilePermissions type)
|
||||
{
|
||||
return (mode & Native.FilePermissions.S_IFMT) == type;
|
||||
}
|
||||
|
||||
internal static bool IsSet (Native.FilePermissions mode, Native.FilePermissions type)
|
||||
{
|
||||
return (mode & type) == type;
|
||||
}
|
||||
|
||||
[CLSCompliant (false)]
|
||||
public bool CanAccess (Native.AccessModes mode)
|
||||
{
|
||||
int r = Native.Syscall.access (FullPath, mode);
|
||||
return r == 0;
|
||||
}
|
||||
|
||||
public UnixFileSystemInfo CreateLink (string path)
|
||||
{
|
||||
int r = Native.Syscall.link (FullName, path);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
return GetFileSystemEntry (path);
|
||||
}
|
||||
|
||||
public UnixSymbolicLinkInfo CreateSymbolicLink (string path)
|
||||
{
|
||||
int r = Native.Syscall.symlink (FullName, path);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
return new UnixSymbolicLinkInfo (path);
|
||||
}
|
||||
|
||||
public abstract void Delete ();
|
||||
|
||||
[CLSCompliant (false)]
|
||||
public long GetConfigurationValue (Native.PathconfName name)
|
||||
{
|
||||
long r = Native.Syscall.pathconf (FullPath, name);
|
||||
if (r == -1 && Native.Stdlib.GetLastError() != (Native.Errno) 0)
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
return r;
|
||||
}
|
||||
|
||||
public void Refresh ()
|
||||
{
|
||||
Refresh (true);
|
||||
}
|
||||
|
||||
internal void Refresh (bool force)
|
||||
{
|
||||
if (valid && !force)
|
||||
return;
|
||||
valid = GetFileStatus (FullPath, out this.stat);
|
||||
}
|
||||
|
||||
protected virtual bool GetFileStatus (string path, out Native.Stat stat)
|
||||
{
|
||||
return Native.Syscall.stat (path, out stat) == 0;
|
||||
}
|
||||
|
||||
public void SetLength (long length)
|
||||
{
|
||||
int r;
|
||||
do {
|
||||
r = Native.Syscall.truncate (FullPath, length);
|
||||
} while (UnixMarshal.ShouldRetrySyscall (r));
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
|
||||
public virtual void SetOwner (long owner, long group)
|
||||
{
|
||||
uint _owner = Convert.ToUInt32 (owner);
|
||||
uint _group = Convert.ToUInt32 (group);
|
||||
int r = Native.Syscall.chown (FullPath, _owner, _group);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
|
||||
public void SetOwner (string owner)
|
||||
{
|
||||
Native.Passwd pw = Native.Syscall.getpwnam (owner);
|
||||
if (pw == null)
|
||||
throw new ArgumentException (Locale.GetText ("invalid username"), "owner");
|
||||
uint uid = pw.pw_uid;
|
||||
uint gid = pw.pw_gid;
|
||||
SetOwner ((long) uid, (long) gid);
|
||||
}
|
||||
|
||||
public void SetOwner (string owner, string group)
|
||||
{
|
||||
long uid = -1;
|
||||
if (owner != null)
|
||||
uid = new UnixUserInfo (owner).UserId;
|
||||
long gid = -1;
|
||||
if (group != null)
|
||||
gid = new UnixGroupInfo (group).GroupId;
|
||||
|
||||
SetOwner (uid, gid);
|
||||
}
|
||||
|
||||
public void SetOwner (UnixUserInfo owner)
|
||||
{
|
||||
long uid, gid;
|
||||
uid = gid = -1;
|
||||
if (owner != null) {
|
||||
uid = owner.UserId;
|
||||
gid = owner.GroupId;
|
||||
}
|
||||
SetOwner (uid, gid);
|
||||
}
|
||||
|
||||
public void SetOwner (UnixUserInfo owner, UnixGroupInfo group)
|
||||
{
|
||||
long uid, gid;
|
||||
uid = gid = -1;
|
||||
if (owner != null)
|
||||
uid = owner.UserId;
|
||||
if (group != null)
|
||||
gid = owner.GroupId;
|
||||
SetOwner (uid, gid);
|
||||
}
|
||||
|
||||
public override string ToString ()
|
||||
{
|
||||
return FullPath;
|
||||
}
|
||||
|
||||
public Native.Stat ToStat ()
|
||||
{
|
||||
AssertValid ();
|
||||
return stat;
|
||||
}
|
||||
|
||||
public static UnixFileSystemInfo GetFileSystemEntry (string path)
|
||||
{
|
||||
UnixFileSystemInfo info;
|
||||
if (TryGetFileSystemEntry (path, out info))
|
||||
return info;
|
||||
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
|
||||
// Throw DirectoryNotFoundException because lstat(2) probably failed
|
||||
// because of ENOTDIR (e.g. "/path/to/file/wtf"), so
|
||||
// DirectoryNotFoundException is what would have been thrown anyway.
|
||||
throw new DirectoryNotFoundException ("UnixMarshal.ThrowExceptionForLastError didn't throw?!");
|
||||
}
|
||||
|
||||
public static bool TryGetFileSystemEntry (string path, out UnixFileSystemInfo entry)
|
||||
{
|
||||
Native.Stat stat;
|
||||
int r = Native.Syscall.lstat (path, out stat);
|
||||
if (r == -1) {
|
||||
if (Native.Stdlib.GetLastError() == Native.Errno.ENOENT) {
|
||||
entry = new UnixFileInfo (path);
|
||||
return true;
|
||||
}
|
||||
entry = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsFileType (stat.st_mode, Native.FilePermissions.S_IFDIR))
|
||||
entry = new UnixDirectoryInfo (path, stat);
|
||||
else if (IsFileType (stat.st_mode, Native.FilePermissions.S_IFLNK))
|
||||
entry = new UnixSymbolicLinkInfo (path, stat);
|
||||
else
|
||||
entry = new UnixFileInfo (path, stat);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public abstract class UnixFileSystemInfo
|
||||
{
|
||||
private Native.Stat stat;
|
||||
private String fullPath;
|
||||
private String originalPath;
|
||||
private Boolean valid = false;
|
||||
|
||||
internal const FileSpecialAttributes AllSpecialAttributes =
|
||||
FileSpecialAttributes.SetUserId | FileSpecialAttributes.SetGroupId |
|
||||
FileSpecialAttributes.Sticky;
|
||||
internal const FileTypes AllFileTypes =
|
||||
FileTypes.Directory | FileTypes.CharacterDevice | FileTypes.BlockDevice |
|
||||
FileTypes.RegularFile | FileTypes.Fifo | FileTypes.SymbolicLink |
|
||||
FileTypes.Socket;
|
||||
|
||||
protected UnixFileSystemInfo (String path)
|
||||
{
|
||||
UnixPath.CheckPath (path);
|
||||
this.originalPath = path;
|
||||
this.fullPath = UnixPath.GetFullPath (path);
|
||||
this.Refresh (true);
|
||||
}
|
||||
|
||||
internal UnixFileSystemInfo (String path, Native.Stat stat)
|
||||
{
|
||||
this.originalPath = path;
|
||||
this.fullPath = UnixPath.GetFullPath (path);
|
||||
this.stat = stat;
|
||||
this.valid = true;
|
||||
}
|
||||
|
||||
protected String FullPath {
|
||||
get => this.fullPath;
|
||||
set {
|
||||
if(this.fullPath != value) {
|
||||
UnixPath.CheckPath(value);
|
||||
this.valid = false;
|
||||
this.fullPath = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected String OriginalPath {
|
||||
get => this.originalPath;
|
||||
set => this.originalPath = value;
|
||||
}
|
||||
|
||||
private void AssertValid ()
|
||||
{
|
||||
this.Refresh (false);
|
||||
if (!this.valid) {
|
||||
throw new InvalidOperationException ("Path doesn't exist!");
|
||||
}
|
||||
}
|
||||
|
||||
public virtual String FullName => this.FullPath;
|
||||
|
||||
public abstract String Name {get;}
|
||||
|
||||
public Boolean Exists {
|
||||
get {
|
||||
this.Refresh (true);
|
||||
return this.valid;
|
||||
}
|
||||
}
|
||||
|
||||
public Int64 Device {
|
||||
get {
|
||||
this.AssertValid (); return Convert.ToInt64 (this.stat.st_dev);}
|
||||
}
|
||||
|
||||
public Int64 Inode {
|
||||
get {
|
||||
this.AssertValid (); return Convert.ToInt64 (this.stat.st_ino);}
|
||||
}
|
||||
|
||||
//[CLSCompliant (false)]
|
||||
public Native.FilePermissions Protection {
|
||||
get {
|
||||
this.AssertValid (); return (Native.FilePermissions)this.stat.st_mode;}
|
||||
set {
|
||||
Int32 r = Native.Syscall.chmod (this.FullPath, value);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
}
|
||||
|
||||
public FileTypes FileType {
|
||||
get {
|
||||
this.AssertValid ();
|
||||
return (FileTypes) (this.stat.st_mode & Native.FilePermissions.S_IFMT);
|
||||
}
|
||||
// no set as chmod(2) won't accept changing the file type.
|
||||
}
|
||||
|
||||
public FileAccessPermissions FileAccessPermissions {
|
||||
get {
|
||||
this.AssertValid ();
|
||||
Int32 perms = (Int32)this.stat.st_mode;
|
||||
return (FileAccessPermissions) (perms & (Int32) FileAccessPermissions.AllPermissions);
|
||||
}
|
||||
set {
|
||||
this.AssertValid ();
|
||||
Int32 perms = (Int32)this.stat.st_mode;
|
||||
perms &= (Int32) ~FileAccessPermissions.AllPermissions;
|
||||
perms |= (Int32) value;
|
||||
this.Protection = (Native.FilePermissions) perms;
|
||||
}
|
||||
}
|
||||
|
||||
public FileSpecialAttributes FileSpecialAttributes {
|
||||
get {
|
||||
this.AssertValid ();
|
||||
Int32 attrs = (Int32)this.stat.st_mode;
|
||||
return (FileSpecialAttributes) (attrs & (Int32) AllSpecialAttributes);
|
||||
}
|
||||
set {
|
||||
this.AssertValid ();
|
||||
Int32 perms = (Int32)this.stat.st_mode;
|
||||
perms &= (Int32) ~AllSpecialAttributes;
|
||||
perms |= (Int32) value;
|
||||
this.Protection = (Native.FilePermissions) perms;
|
||||
}
|
||||
}
|
||||
|
||||
public Int64 LinkCount {
|
||||
get {
|
||||
this.AssertValid (); return Convert.ToInt64 (this.stat.st_nlink);}
|
||||
}
|
||||
|
||||
public UnixUserInfo OwnerUser {
|
||||
get {
|
||||
this.AssertValid (); return new UnixUserInfo (this.stat.st_uid);}
|
||||
}
|
||||
|
||||
public Int64 OwnerUserId {
|
||||
get {
|
||||
this.AssertValid (); return this.stat.st_uid;}
|
||||
}
|
||||
|
||||
public UnixGroupInfo OwnerGroup {
|
||||
get {
|
||||
this.AssertValid (); return new UnixGroupInfo (this.stat.st_gid);}
|
||||
}
|
||||
|
||||
public Int64 OwnerGroupId {
|
||||
get {
|
||||
this.AssertValid (); return this.stat.st_gid;}
|
||||
}
|
||||
|
||||
public Int64 DeviceType {
|
||||
get {
|
||||
this.AssertValid (); return Convert.ToInt64 (this.stat.st_rdev);}
|
||||
}
|
||||
|
||||
public Int64 Length {
|
||||
get {
|
||||
this.AssertValid (); return (Int64)this.stat.st_size;}
|
||||
}
|
||||
|
||||
public Int64 BlockSize {
|
||||
get {
|
||||
this.AssertValid (); return (Int64)this.stat.st_blksize;}
|
||||
}
|
||||
|
||||
public Int64 BlocksAllocated {
|
||||
get {
|
||||
this.AssertValid (); return (Int64)this.stat.st_blocks;}
|
||||
}
|
||||
|
||||
public DateTime LastAccessTime {
|
||||
get {
|
||||
this.AssertValid (); return Native.NativeConvert.ToDateTime (this.stat.st_atime, this.stat.st_atime_nsec);}
|
||||
}
|
||||
|
||||
public DateTime LastAccessTimeUtc => this.LastAccessTime.ToUniversalTime();
|
||||
|
||||
public DateTime LastWriteTime {
|
||||
get {
|
||||
this.AssertValid (); return Native.NativeConvert.ToDateTime (this.stat.st_mtime, this.stat.st_mtime_nsec);}
|
||||
}
|
||||
|
||||
public DateTime LastWriteTimeUtc => this.LastWriteTime.ToUniversalTime();
|
||||
|
||||
public DateTime LastStatusChangeTime {
|
||||
get {
|
||||
this.AssertValid (); return Native.NativeConvert.ToDateTime (this.stat.st_ctime, this.stat.st_ctime_nsec);}
|
||||
}
|
||||
|
||||
public DateTime LastStatusChangeTimeUtc => this.LastStatusChangeTime.ToUniversalTime();
|
||||
|
||||
public Boolean IsDirectory {
|
||||
get {
|
||||
this.AssertValid (); return IsFileType (this.stat.st_mode, Native.FilePermissions.S_IFDIR);}
|
||||
}
|
||||
|
||||
public Boolean IsCharacterDevice {
|
||||
get {
|
||||
this.AssertValid (); return IsFileType (this.stat.st_mode, Native.FilePermissions.S_IFCHR);}
|
||||
}
|
||||
|
||||
public Boolean IsBlockDevice {
|
||||
get {
|
||||
this.AssertValid (); return IsFileType (this.stat.st_mode, Native.FilePermissions.S_IFBLK);}
|
||||
}
|
||||
|
||||
public Boolean IsRegularFile {
|
||||
get {
|
||||
this.AssertValid (); return IsFileType (this.stat.st_mode, Native.FilePermissions.S_IFREG);}
|
||||
}
|
||||
|
||||
public Boolean IsFifo {
|
||||
get {
|
||||
this.AssertValid (); return IsFileType (this.stat.st_mode, Native.FilePermissions.S_IFIFO);}
|
||||
}
|
||||
|
||||
public Boolean IsSymbolicLink {
|
||||
get {
|
||||
this.AssertValid (); return IsFileType (this.stat.st_mode, Native.FilePermissions.S_IFLNK);}
|
||||
}
|
||||
|
||||
public Boolean IsSocket {
|
||||
get {
|
||||
this.AssertValid (); return IsFileType (this.stat.st_mode, Native.FilePermissions.S_IFSOCK);}
|
||||
}
|
||||
|
||||
public Boolean IsSetUser {
|
||||
get {
|
||||
this.AssertValid (); return IsSet (this.stat.st_mode, Native.FilePermissions.S_ISUID);}
|
||||
}
|
||||
|
||||
public Boolean IsSetGroup {
|
||||
get {
|
||||
this.AssertValid (); return IsSet (this.stat.st_mode, Native.FilePermissions.S_ISGID);}
|
||||
}
|
||||
|
||||
public Boolean IsSticky {
|
||||
get {
|
||||
this.AssertValid (); return IsSet (this.stat.st_mode, Native.FilePermissions.S_ISVTX);}
|
||||
}
|
||||
|
||||
internal static Boolean IsFileType(Native.FilePermissions mode, Native.FilePermissions type) => (mode & Native.FilePermissions.S_IFMT) == type;
|
||||
|
||||
internal static Boolean IsSet(Native.FilePermissions mode, Native.FilePermissions type) => (mode & type) == type;
|
||||
|
||||
//[CLSCompliant (false)]
|
||||
public Boolean CanAccess (Native.AccessModes mode)
|
||||
{
|
||||
Int32 r = Native.Syscall.access (this.FullPath, mode);
|
||||
return r == 0;
|
||||
}
|
||||
|
||||
public UnixFileSystemInfo CreateLink (String path)
|
||||
{
|
||||
Int32 r = Native.Syscall.link (this.FullName, path);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
return GetFileSystemEntry (path);
|
||||
}
|
||||
|
||||
public UnixSymbolicLinkInfo CreateSymbolicLink (String path)
|
||||
{
|
||||
Int32 r = Native.Syscall.symlink (this.FullName, path);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
return new UnixSymbolicLinkInfo (path);
|
||||
}
|
||||
|
||||
public abstract void Delete ();
|
||||
|
||||
//[CLSCompliant (false)]
|
||||
public Int64 GetConfigurationValue (Native.PathconfName name)
|
||||
{
|
||||
Int64 r = Native.Syscall.pathconf (this.FullPath, name);
|
||||
if (r == -1 && Native.Stdlib.GetLastError() != (Native.Errno) 0) {
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
public void Refresh() => this.Refresh(true);
|
||||
|
||||
internal void Refresh (Boolean force)
|
||||
{
|
||||
if (this.valid && !force) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.valid = this.GetFileStatus (this.FullPath, out this.stat);
|
||||
}
|
||||
|
||||
protected virtual Boolean GetFileStatus(String path, out Native.Stat stat) => Native.Syscall.stat(path, out stat) == 0;
|
||||
|
||||
public void SetLength (Int64 length)
|
||||
{
|
||||
Int32 r;
|
||||
do {
|
||||
r = Native.Syscall.truncate (this.FullPath, length);
|
||||
} while (UnixMarshal.ShouldRetrySyscall (r));
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
|
||||
public virtual void SetOwner (Int64 owner, Int64 group)
|
||||
{
|
||||
UInt32 _owner = Convert.ToUInt32 (owner);
|
||||
UInt32 _group = Convert.ToUInt32 (group);
|
||||
Int32 r = Native.Syscall.chown (this.FullPath, _owner, _group);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
|
||||
public void SetOwner (String owner)
|
||||
{
|
||||
Native.Passwd pw = Native.Syscall.getpwnam (owner);
|
||||
if (pw == null) {
|
||||
throw new ArgumentException (Locale.GetText ("invalid username"), "owner");
|
||||
}
|
||||
|
||||
UInt32 uid = pw.pw_uid;
|
||||
UInt32 gid = pw.pw_gid;
|
||||
this.SetOwner ((Int64) uid, (Int64) gid);
|
||||
}
|
||||
|
||||
public void SetOwner (String owner, String group)
|
||||
{
|
||||
Int64 uid = -1;
|
||||
if (owner != null) {
|
||||
uid = new UnixUserInfo (owner).UserId;
|
||||
}
|
||||
|
||||
Int64 gid = -1;
|
||||
if (group != null) {
|
||||
gid = new UnixGroupInfo (group).GroupId;
|
||||
}
|
||||
|
||||
this.SetOwner (uid, gid);
|
||||
}
|
||||
|
||||
public void SetOwner (UnixUserInfo owner)
|
||||
{
|
||||
Int64 uid, gid;
|
||||
uid = gid = -1;
|
||||
if (owner != null) {
|
||||
uid = owner.UserId;
|
||||
gid = owner.GroupId;
|
||||
}
|
||||
this.SetOwner (uid, gid);
|
||||
}
|
||||
|
||||
public void SetOwner (UnixUserInfo owner, UnixGroupInfo group)
|
||||
{
|
||||
Int64 uid, gid;
|
||||
uid = gid = -1;
|
||||
if (owner != null) {
|
||||
uid = owner.UserId;
|
||||
}
|
||||
|
||||
if (group != null) {
|
||||
gid = owner.GroupId;
|
||||
}
|
||||
|
||||
this.SetOwner (uid, gid);
|
||||
}
|
||||
|
||||
public override String ToString() => this.FullPath;
|
||||
|
||||
public Native.Stat ToStat ()
|
||||
{
|
||||
this.AssertValid ();
|
||||
return this.stat;
|
||||
}
|
||||
|
||||
public static UnixFileSystemInfo GetFileSystemEntry (String path)
|
||||
{
|
||||
if(TryGetFileSystemEntry(path, out UnixFileSystemInfo info)) {
|
||||
return info;
|
||||
}
|
||||
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
|
||||
// Throw DirectoryNotFoundException because lstat(2) probably failed
|
||||
// because of ENOTDIR (e.g. "/path/to/file/wtf"), so
|
||||
// DirectoryNotFoundException is what would have been thrown anyway.
|
||||
throw new DirectoryNotFoundException ("UnixMarshal.ThrowExceptionForLastError didn't throw?!");
|
||||
}
|
||||
|
||||
public static Boolean TryGetFileSystemEntry (String path, out UnixFileSystemInfo entry)
|
||||
{
|
||||
Int32 r = Native.Syscall.lstat(path, out Native.Stat stat);
|
||||
if (r == -1) {
|
||||
if (Native.Stdlib.GetLastError() == Native.Errno.ENOENT) {
|
||||
entry = new UnixFileInfo (path);
|
||||
return true;
|
||||
}
|
||||
entry = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
entry = IsFileType (stat.st_mode, Native.FilePermissions.S_IFDIR)
|
||||
? new UnixDirectoryInfo (path, stat)
|
||||
: IsFileType(stat.st_mode, Native.FilePermissions.S_IFLNK)
|
||||
? new UnixSymbolicLinkInfo(path, stat)
|
||||
: (UnixFileSystemInfo)new UnixFileInfo(path, stat);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// vim: noexpandtab
|
||||
|
@ -33,117 +33,91 @@ using Mono.Unix;
|
||||
|
||||
namespace Mono.Unix {
|
||||
|
||||
public sealed class UnixGroupInfo
|
||||
{
|
||||
private Native.Group group;
|
||||
public sealed class UnixGroupInfo
|
||||
{
|
||||
private readonly Native.Group group;
|
||||
|
||||
public UnixGroupInfo (string group)
|
||||
{
|
||||
this.group = new Native.Group ();
|
||||
Native.Group gr;
|
||||
int r = Native.Syscall.getgrnam_r (group, this.group, out gr);
|
||||
if (r != 0 || gr == null)
|
||||
throw new ArgumentException (Locale.GetText ("invalid group name"), "group");
|
||||
}
|
||||
public UnixGroupInfo (String group)
|
||||
{
|
||||
this.group = new Native.Group ();
|
||||
Int32 r = Native.Syscall.getgrnam_r(group, this.group, out Native.Group gr);
|
||||
if (r != 0 || gr == null) {
|
||||
throw new ArgumentException (Locale.GetText ("invalid group name"), "group");
|
||||
}
|
||||
}
|
||||
|
||||
public UnixGroupInfo (long group)
|
||||
{
|
||||
this.group = new Native.Group ();
|
||||
Native.Group gr;
|
||||
int r = Native.Syscall.getgrgid_r (Convert.ToUInt32 (group), this.group, out gr);
|
||||
if (r != 0 || gr == null)
|
||||
throw new ArgumentException (Locale.GetText ("invalid group id"), "group");
|
||||
}
|
||||
|
||||
public UnixGroupInfo (Native.Group group)
|
||||
{
|
||||
this.group = CopyGroup (group);
|
||||
}
|
||||
|
||||
private static Native.Group CopyGroup (Native.Group group)
|
||||
{
|
||||
Native.Group g = new Native.Group ();
|
||||
|
||||
g.gr_gid = group.gr_gid;
|
||||
g.gr_mem = group.gr_mem;
|
||||
g.gr_name = group.gr_name;
|
||||
g.gr_passwd = group.gr_passwd;
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
public string GroupName {
|
||||
get {return group.gr_name;}
|
||||
}
|
||||
|
||||
public string Password {
|
||||
get {return group.gr_passwd;}
|
||||
}
|
||||
|
||||
public long GroupId {
|
||||
get {return group.gr_gid;}
|
||||
}
|
||||
|
||||
public UnixUserInfo[] GetMembers ()
|
||||
{
|
||||
ArrayList members = new ArrayList (group.gr_mem.Length);
|
||||
for (int i = 0; i < group.gr_mem.Length; ++i) {
|
||||
try {
|
||||
members.Add (new UnixUserInfo (group.gr_mem [i]));
|
||||
} catch (ArgumentException) {
|
||||
// ignore invalid users
|
||||
}
|
||||
}
|
||||
return (UnixUserInfo[]) members.ToArray (typeof (UnixUserInfo));
|
||||
}
|
||||
|
||||
public string[] GetMemberNames ()
|
||||
{
|
||||
return (string[]) group.gr_mem.Clone ();
|
||||
}
|
||||
|
||||
public override int GetHashCode ()
|
||||
{
|
||||
return group.GetHashCode ();
|
||||
}
|
||||
|
||||
public override bool Equals (object obj)
|
||||
{
|
||||
if (obj == null || GetType () != obj.GetType())
|
||||
return false;
|
||||
return group.Equals (((UnixGroupInfo) obj).group);
|
||||
}
|
||||
|
||||
public override string ToString ()
|
||||
{
|
||||
return group.ToString();
|
||||
}
|
||||
|
||||
public Native.Group ToGroup ()
|
||||
{
|
||||
return CopyGroup (group);
|
||||
}
|
||||
|
||||
public static UnixGroupInfo[] GetLocalGroups ()
|
||||
{
|
||||
ArrayList entries = new ArrayList ();
|
||||
lock (Native.Syscall.grp_lock) {
|
||||
if (Native.Syscall.setgrent () != 0)
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
try {
|
||||
Native.Group g;
|
||||
while ((g = Native.Syscall.getgrent()) != null)
|
||||
entries.Add (new UnixGroupInfo (g));
|
||||
if (Native.Syscall.GetLastError() != (Native.Errno) 0)
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
}
|
||||
finally {
|
||||
Native.Syscall.endgrent ();
|
||||
}
|
||||
}
|
||||
return (UnixGroupInfo[]) entries.ToArray (typeof(UnixGroupInfo));
|
||||
}
|
||||
}
|
||||
public UnixGroupInfo (Int64 group)
|
||||
{
|
||||
this.group = new Native.Group ();
|
||||
Int32 r = Native.Syscall.getgrgid_r(Convert.ToUInt32(group), this.group, out Native.Group gr);
|
||||
if (r != 0 || gr == null) {
|
||||
throw new ArgumentException (Locale.GetText ("invalid group id"), "group");
|
||||
}
|
||||
}
|
||||
|
||||
public UnixGroupInfo(Native.Group group) => this.group = CopyGroup(group);
|
||||
|
||||
private static Native.Group CopyGroup(Native.Group group) => new Native.Group {
|
||||
gr_gid = group.gr_gid,
|
||||
gr_mem = group.gr_mem,
|
||||
gr_name = group.gr_name,
|
||||
gr_passwd = group.gr_passwd
|
||||
};
|
||||
|
||||
public String GroupName => this.group.gr_name;
|
||||
|
||||
public String Password => this.group.gr_passwd;
|
||||
|
||||
public Int64 GroupId => this.group.gr_gid;
|
||||
|
||||
public UnixUserInfo[] GetMembers ()
|
||||
{
|
||||
ArrayList members = new ArrayList (this.group.gr_mem.Length);
|
||||
for (Int32 i = 0; i < this.group.gr_mem.Length; ++i) {
|
||||
try {
|
||||
_ = members.Add(new UnixUserInfo(this.group.gr_mem[i]));
|
||||
} catch (ArgumentException) {
|
||||
// ignore invalid users
|
||||
}
|
||||
}
|
||||
return (UnixUserInfo[]) members.ToArray (typeof (UnixUserInfo));
|
||||
}
|
||||
|
||||
public String[] GetMemberNames() => (String[])this.group.gr_mem.Clone();
|
||||
|
||||
public override Int32 GetHashCode() => this.group.GetHashCode();
|
||||
|
||||
public override Boolean Equals(Object obj) => obj == null || this.GetType() != obj.GetType() ? false : this.group.Equals(((UnixGroupInfo)obj).group);
|
||||
|
||||
public override String ToString() => this.group.ToString();
|
||||
|
||||
public Native.Group ToGroup() => CopyGroup(this.group);
|
||||
|
||||
public static UnixGroupInfo[] GetLocalGroups ()
|
||||
{
|
||||
ArrayList entries = new ArrayList ();
|
||||
lock (Native.Syscall.grp_lock) {
|
||||
if (Native.Syscall.setgrent () != 0) {
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
}
|
||||
|
||||
try {
|
||||
Native.Group g;
|
||||
while ((g = Native.Syscall.getgrent()) != null) {
|
||||
_ = entries.Add(new UnixGroupInfo(g));
|
||||
}
|
||||
|
||||
if (Native.Syscall.GetLastError() != (Native.Errno) 0) {
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
_ = Native.Syscall.endgrent();
|
||||
}
|
||||
}
|
||||
return (UnixGroupInfo[]) entries.ToArray (typeof(UnixGroupInfo));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// vim: noexpandtab
|
||||
|
@ -30,75 +30,49 @@ using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Serialization;
|
||||
using Mono.Unix;
|
||||
|
||||
namespace Mono.Unix {
|
||||
|
||||
[Serializable]
|
||||
public class UnixIOException : IOException
|
||||
{
|
||||
private int errno;
|
||||
[Serializable]
|
||||
public class UnixIOException : IOException
|
||||
{
|
||||
private Int32 errno;
|
||||
|
||||
public UnixIOException ()
|
||||
: this (Marshal.GetLastWin32Error())
|
||||
{}
|
||||
|
||||
public UnixIOException (int errno)
|
||||
: base (GetMessage (Native.NativeConvert.ToErrno (errno)))
|
||||
{
|
||||
this.errno = errno;
|
||||
}
|
||||
|
||||
public UnixIOException (int errno, Exception inner)
|
||||
: base (GetMessage (Native.NativeConvert.ToErrno (errno)), inner)
|
||||
{
|
||||
this.errno = errno;
|
||||
}
|
||||
public UnixIOException ()
|
||||
: this (Marshal.GetLastWin32Error())
|
||||
{}
|
||||
|
||||
public UnixIOException(Int32 errno)
|
||||
: base(GetMessage(Native.NativeConvert.ToErrno(errno))) => this.errno = errno;
|
||||
|
||||
public UnixIOException(Int32 errno, Exception inner)
|
||||
: base(GetMessage(Native.NativeConvert.ToErrno(errno)), inner) => this.errno = errno;
|
||||
|
||||
public UnixIOException (Native.Errno errno)
|
||||
: base (GetMessage (errno))
|
||||
{
|
||||
this.errno = Native.NativeConvert.FromErrno (errno);
|
||||
}
|
||||
public UnixIOException(Native.Errno errno)
|
||||
: base(GetMessage(errno)) => this.errno = Native.NativeConvert.FromErrno(errno);
|
||||
|
||||
public UnixIOException (Native.Errno errno, Exception inner)
|
||||
: base (GetMessage (errno), inner)
|
||||
{
|
||||
this.errno = Native.NativeConvert.FromErrno (errno);
|
||||
}
|
||||
public UnixIOException(Native.Errno errno, Exception inner)
|
||||
: base(GetMessage(errno), inner) => this.errno = Native.NativeConvert.FromErrno(errno);
|
||||
|
||||
public UnixIOException (string message)
|
||||
: base (message)
|
||||
{
|
||||
this.errno = 0;
|
||||
}
|
||||
public UnixIOException(String message)
|
||||
: base(message) => this.errno = 0;
|
||||
|
||||
public UnixIOException (string message, Exception inner)
|
||||
: base (message, inner)
|
||||
{
|
||||
this.errno = 0;
|
||||
}
|
||||
public UnixIOException(String message, Exception inner)
|
||||
: base(message, inner) => this.errno = 0;
|
||||
|
||||
protected UnixIOException (SerializationInfo info, StreamingContext context)
|
||||
: base (info, context)
|
||||
{
|
||||
}
|
||||
|
||||
public int NativeErrorCode {
|
||||
get {return errno;}
|
||||
}
|
||||
|
||||
public Native.Errno ErrorCode {
|
||||
get {return Native.NativeConvert.ToErrno (errno);}
|
||||
}
|
||||
|
||||
private static string GetMessage (Native.Errno errno)
|
||||
{
|
||||
return string.Format ("{0} [{1}].",
|
||||
UnixMarshal.GetErrorDescription (errno),
|
||||
errno);
|
||||
}
|
||||
}
|
||||
protected UnixIOException (SerializationInfo info, StreamingContext context)
|
||||
: base (info, context)
|
||||
{
|
||||
}
|
||||
|
||||
public Int32 NativeErrorCode => this.errno;
|
||||
|
||||
public Native.Errno ErrorCode => Native.NativeConvert.ToErrno(this.errno);
|
||||
|
||||
private static String GetMessage(Native.Errno errno) => String.Format("{0} [{1}].",
|
||||
UnixMarshal.GetErrorDescription(errno),
|
||||
errno);
|
||||
}
|
||||
}
|
||||
|
||||
// vim: noexpandtab
|
||||
|
@ -35,139 +35,141 @@ using System.IO;
|
||||
|
||||
namespace Mono.Unix {
|
||||
|
||||
public class UnixListener : MarshalByRefObject, IDisposable {
|
||||
bool disposed;
|
||||
bool listening;
|
||||
Socket server;
|
||||
EndPoint savedEP;
|
||||
public class UnixListener : MarshalByRefObject, IDisposable {
|
||||
Boolean disposed;
|
||||
Boolean listening;
|
||||
Socket server;
|
||||
EndPoint savedEP;
|
||||
|
||||
void Init (UnixEndPoint ep)
|
||||
{
|
||||
listening = false;
|
||||
string filename = ep.Filename;
|
||||
if (File.Exists (filename)) {
|
||||
Socket conn = new Socket (AddressFamily.Unix, SocketType.Stream, 0);
|
||||
try {
|
||||
conn.Connect (ep);
|
||||
conn.Close ();
|
||||
throw new InvalidOperationException ("There's already a server listening on " + filename);
|
||||
} catch (SocketException) {
|
||||
}
|
||||
File.Delete (filename);
|
||||
}
|
||||
void Init (UnixEndPoint ep)
|
||||
{
|
||||
this.listening = false;
|
||||
String filename = ep.Filename;
|
||||
if (File.Exists (filename)) {
|
||||
Socket conn = new Socket (AddressFamily.Unix, SocketType.Stream, 0);
|
||||
try {
|
||||
conn.Connect (ep);
|
||||
conn.Close ();
|
||||
throw new InvalidOperationException ("There's already a server listening on " + filename);
|
||||
} catch (SocketException) {
|
||||
}
|
||||
File.Delete (filename);
|
||||
}
|
||||
|
||||
this.server = new Socket (AddressFamily.Unix, SocketType.Stream, 0);
|
||||
this.server.Bind (ep);
|
||||
this.savedEP = this.server.LocalEndPoint;
|
||||
}
|
||||
|
||||
public UnixListener (String path)
|
||||
{
|
||||
if (!Directory.Exists (Path.GetDirectoryName (path))) {
|
||||
_ = Directory.CreateDirectory(Path.GetDirectoryName(path));
|
||||
}
|
||||
|
||||
this.Init (new UnixEndPoint (path));
|
||||
}
|
||||
|
||||
server = new Socket (AddressFamily.Unix, SocketType.Stream, 0);
|
||||
server.Bind (ep);
|
||||
savedEP = server.LocalEndPoint;
|
||||
}
|
||||
public UnixListener (UnixEndPoint localEndPoint)
|
||||
{
|
||||
if (localEndPoint == null) {
|
||||
throw new ArgumentNullException ("localendPoint");
|
||||
}
|
||||
|
||||
this.Init (localEndPoint);
|
||||
}
|
||||
|
||||
public EndPoint LocalEndpoint => this.savedEP;
|
||||
|
||||
protected Socket Server => this.server;
|
||||
|
||||
public Socket AcceptSocket ()
|
||||
{
|
||||
this.CheckDisposed ();
|
||||
if (!this.listening) {
|
||||
throw new InvalidOperationException ("Socket is not listening");
|
||||
}
|
||||
|
||||
return this.server.Accept ();
|
||||
}
|
||||
|
||||
public UnixListener (string path)
|
||||
{
|
||||
if (!Directory.Exists (Path.GetDirectoryName (path)))
|
||||
Directory.CreateDirectory (Path.GetDirectoryName (path));
|
||||
|
||||
Init (new UnixEndPoint (path));
|
||||
}
|
||||
|
||||
public UnixListener (UnixEndPoint localEndPoint)
|
||||
{
|
||||
if (localEndPoint == null)
|
||||
throw new ArgumentNullException ("localendPoint");
|
||||
|
||||
Init (localEndPoint);
|
||||
}
|
||||
public UnixClient AcceptUnixClient ()
|
||||
{
|
||||
this.CheckDisposed ();
|
||||
if (!this.listening) {
|
||||
throw new InvalidOperationException ("Socket is not listening");
|
||||
}
|
||||
|
||||
return new UnixClient (this.AcceptSocket ());
|
||||
}
|
||||
|
||||
public EndPoint LocalEndpoint {
|
||||
get { return savedEP; }
|
||||
}
|
||||
|
||||
protected Socket Server {
|
||||
get { return server; }
|
||||
}
|
||||
|
||||
public Socket AcceptSocket ()
|
||||
{
|
||||
CheckDisposed ();
|
||||
if (!listening)
|
||||
throw new InvalidOperationException ("Socket is not listening");
|
||||
|
||||
return server.Accept ();
|
||||
}
|
||||
|
||||
public UnixClient AcceptUnixClient ()
|
||||
{
|
||||
CheckDisposed ();
|
||||
if (!listening)
|
||||
throw new InvalidOperationException ("Socket is not listening");
|
||||
|
||||
return new UnixClient (AcceptSocket ());
|
||||
}
|
||||
|
||||
~UnixListener ()
|
||||
{
|
||||
Dispose (false);
|
||||
}
|
||||
~UnixListener ()
|
||||
{
|
||||
this.Dispose (false);
|
||||
}
|
||||
|
||||
public bool Pending ()
|
||||
{
|
||||
CheckDisposed ();
|
||||
if (!listening)
|
||||
throw new InvalidOperationException ("Socket is not listening");
|
||||
public Boolean Pending ()
|
||||
{
|
||||
this.CheckDisposed ();
|
||||
if (!this.listening) {
|
||||
throw new InvalidOperationException ("Socket is not listening");
|
||||
}
|
||||
|
||||
return this.server.Poll (1000, SelectMode.SelectRead);
|
||||
}
|
||||
|
||||
public void Start() => this.Start(5);
|
||||
|
||||
public void Start (Int32 backlog)
|
||||
{
|
||||
this.CheckDisposed ();
|
||||
if (this.listening) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.server.Listen (backlog);
|
||||
this.listening = true;
|
||||
}
|
||||
|
||||
return server.Poll (1000, SelectMode.SelectRead);
|
||||
}
|
||||
public void Stop ()
|
||||
{
|
||||
this.CheckDisposed ();
|
||||
this.Dispose (true);
|
||||
}
|
||||
|
||||
public void Dispose ()
|
||||
{
|
||||
this.Dispose (true);
|
||||
GC.SuppressFinalize (this);
|
||||
}
|
||||
|
||||
protected void Dispose (Boolean disposing)
|
||||
{
|
||||
if (this.disposed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (disposing) {
|
||||
try {
|
||||
File.Delete (((UnixEndPoint)this.savedEP).Filename);
|
||||
} catch {
|
||||
}
|
||||
if (this.server != null) {
|
||||
this.server.Close ();
|
||||
}
|
||||
|
||||
this.server = null;
|
||||
}
|
||||
|
||||
this.disposed = true;
|
||||
}
|
||||
|
||||
public void Start ()
|
||||
{
|
||||
Start (5);
|
||||
}
|
||||
|
||||
public void Start (int backlog)
|
||||
{
|
||||
CheckDisposed ();
|
||||
if (listening)
|
||||
return;
|
||||
|
||||
server.Listen (backlog);
|
||||
listening = true;
|
||||
}
|
||||
|
||||
public void Stop ()
|
||||
{
|
||||
CheckDisposed ();
|
||||
Dispose (true);
|
||||
}
|
||||
|
||||
public void Dispose ()
|
||||
{
|
||||
Dispose (true);
|
||||
GC.SuppressFinalize (this);
|
||||
}
|
||||
|
||||
protected void Dispose (bool disposing)
|
||||
{
|
||||
if (disposed)
|
||||
return;
|
||||
|
||||
if (disposing) {
|
||||
try {
|
||||
File.Delete (((UnixEndPoint) savedEP).Filename);
|
||||
} catch {
|
||||
}
|
||||
if (server != null)
|
||||
server.Close ();
|
||||
|
||||
server = null;
|
||||
}
|
||||
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
void CheckDisposed ()
|
||||
{
|
||||
if (disposed)
|
||||
throw new ObjectDisposedException (GetType().FullName);
|
||||
}
|
||||
}
|
||||
void CheckDisposed ()
|
||||
{
|
||||
if (this.disposed) {
|
||||
throw new ObjectDisposedException (this.GetType().FullName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -27,6 +27,7 @@
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.InteropServices;
|
||||
@ -36,461 +37,434 @@ using Mono.Unix;
|
||||
|
||||
namespace Mono.Unix {
|
||||
|
||||
// Scenario: We want to be able to translate an Error to a string.
|
||||
// Problem: Thread-safety. Strerror(3) isn't thread safe (unless
|
||||
// thread-local-variables are used, which is probably only
|
||||
// true on Windows).
|
||||
// Solution: Use strerror_r().
|
||||
// Problem: strerror_r() isn't portable.
|
||||
// (Apparently Solaris doesn't provide it.)
|
||||
// Solution: Cry. Then introduce an intermediary, ErrorMarshal.
|
||||
// ErrorMarshal exposes a single public delegate, Translator,
|
||||
// which will convert an Error to a string. It's static
|
||||
// constructor first tries using strerror_r(). If it works,
|
||||
// great; use it in the future. If it doesn't work, fallback to
|
||||
// using strerror(3).
|
||||
// This should be thread safe, since the check is done within the
|
||||
// class constructor lock.
|
||||
// Strerror(3) will be thread-safe from managed code, but won't
|
||||
// be thread-safe between managed & unmanaged code.
|
||||
internal class ErrorMarshal
|
||||
{
|
||||
internal delegate string ErrorTranslator (Native.Errno errno);
|
||||
|
||||
internal static readonly ErrorTranslator Translate;
|
||||
|
||||
static ErrorMarshal ()
|
||||
{
|
||||
try {
|
||||
Translate = new ErrorTranslator (strerror_r);
|
||||
Translate (Native.Errno.ERANGE);
|
||||
}
|
||||
catch (EntryPointNotFoundException) {
|
||||
Translate = new ErrorTranslator (strerror);
|
||||
}
|
||||
}
|
||||
|
||||
private static string strerror (Native.Errno errno)
|
||||
{
|
||||
return Native.Stdlib.strerror (errno);
|
||||
}
|
||||
|
||||
private static string strerror_r (Native.Errno errno)
|
||||
{
|
||||
StringBuilder buf = new StringBuilder (16);
|
||||
int r = 0;
|
||||
do {
|
||||
buf.Capacity *= 2;
|
||||
r = Native.Syscall.strerror_r (errno, buf);
|
||||
} while (r == -1 && Native.Stdlib.GetLastError() == Native.Errno.ERANGE);
|
||||
|
||||
if (r == -1)
|
||||
return "** Unknown error code: " + ((int) errno) + "**";
|
||||
return buf.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed /* static */ class UnixMarshal
|
||||
{
|
||||
private UnixMarshal () {}
|
||||
|
||||
[CLSCompliant (false)]
|
||||
public static string GetErrorDescription (Native.Errno errno)
|
||||
{
|
||||
return ErrorMarshal.Translate (errno);
|
||||
}
|
||||
|
||||
public static IntPtr AllocHeap (long size)
|
||||
{
|
||||
if (size < 0)
|
||||
throw new ArgumentOutOfRangeException ("size", "< 0");
|
||||
return Native.Stdlib.malloc ((ulong) size);
|
||||
}
|
||||
|
||||
public static IntPtr ReAllocHeap (IntPtr ptr, long size)
|
||||
{
|
||||
if (size < 0)
|
||||
throw new ArgumentOutOfRangeException ("size", "< 0");
|
||||
return Native.Stdlib.realloc (ptr, (ulong) size);
|
||||
}
|
||||
|
||||
public static void FreeHeap (IntPtr ptr)
|
||||
{
|
||||
Native.Stdlib.free (ptr);
|
||||
}
|
||||
|
||||
public static unsafe string PtrToStringUnix (IntPtr p)
|
||||
{
|
||||
if (p == IntPtr.Zero)
|
||||
return null;
|
||||
|
||||
int len = checked ((int) Native.Stdlib.strlen (p));
|
||||
return new string ((sbyte*) p, 0, len, UnixEncoding.Instance);
|
||||
}
|
||||
|
||||
public static string PtrToString (IntPtr p)
|
||||
{
|
||||
if (p == IntPtr.Zero)
|
||||
return null;
|
||||
return PtrToString (p, UnixEncoding.Instance);
|
||||
}
|
||||
|
||||
public static unsafe string PtrToString (IntPtr p, Encoding encoding)
|
||||
{
|
||||
if (p == IntPtr.Zero)
|
||||
return null;
|
||||
|
||||
if (encoding == null)
|
||||
throw new ArgumentNullException ("encoding");
|
||||
|
||||
int len = GetStringByteLength (p, encoding);
|
||||
|
||||
// Due to variable-length encoding schemes, GetStringByteLength() may
|
||||
// have returned multiple "null" characters. (For example, when
|
||||
// encoding a string into UTF-8 there will be 4 terminating nulls.)
|
||||
// We don't want these null's to be in the returned string, so strip
|
||||
// them off.
|
||||
string s = new string ((sbyte*) p, 0, len, encoding);
|
||||
len = s.Length;
|
||||
while (len > 0 && s [len-1] == 0)
|
||||
--len;
|
||||
if (len == s.Length)
|
||||
return s;
|
||||
return s.Substring (0, len);
|
||||
}
|
||||
|
||||
private static int GetStringByteLength (IntPtr p, Encoding encoding)
|
||||
{
|
||||
Type encodingType = encoding.GetType ();
|
||||
|
||||
int len = -1;
|
||||
|
||||
// Encodings that will always end with a single null byte
|
||||
if (typeof(UTF8Encoding).IsAssignableFrom (encodingType) ||
|
||||
typeof(UTF7Encoding).IsAssignableFrom (encodingType) ||
|
||||
typeof(UnixEncoding).IsAssignableFrom (encodingType) ||
|
||||
typeof(ASCIIEncoding).IsAssignableFrom (encodingType)) {
|
||||
len = checked ((int) Native.Stdlib.strlen (p));
|
||||
}
|
||||
// Encodings that will always end with a 0x0000 16-bit word
|
||||
else if (typeof(UnicodeEncoding).IsAssignableFrom (encodingType)) {
|
||||
len = GetInt16BufferLength (p);
|
||||
}
|
||||
// Encodings that will always end with a 0x00000000 32-bit word
|
||||
else if (typeof(UTF32Encoding).IsAssignableFrom (encodingType)) {
|
||||
len = GetInt32BufferLength (p);
|
||||
}
|
||||
// Some non-public encoding, such as Latin1 or a DBCS charset.
|
||||
// Look for a sequence of encoding.GetMaxByteCount() bytes that are all
|
||||
// 0, which should be the terminating null.
|
||||
// This is "iffy", since it may fail for variable-width encodings; for
|
||||
// example, UTF8Encoding.GetMaxByteCount(1) = 4, so this would read 3
|
||||
// bytes past the end of the string, possibly into garbage memory
|
||||
// (which is why we special case UTF above).
|
||||
else {
|
||||
len = GetRandomBufferLength (p, encoding.GetMaxByteCount(1));
|
||||
}
|
||||
|
||||
if (len == -1)
|
||||
throw new NotSupportedException ("Unable to determine native string buffer length");
|
||||
return len;
|
||||
}
|
||||
|
||||
private static int GetInt16BufferLength (IntPtr p)
|
||||
{
|
||||
int len = 0;
|
||||
while (Marshal.ReadInt16 (p, len*2) != 0)
|
||||
checked {++len;}
|
||||
return checked(len*2);
|
||||
}
|
||||
|
||||
private static int GetInt32BufferLength (IntPtr p)
|
||||
{
|
||||
int len = 0;
|
||||
while (Marshal.ReadInt32 (p, len*4) != 0)
|
||||
checked {++len;}
|
||||
return checked(len*4);
|
||||
}
|
||||
|
||||
private static int GetRandomBufferLength (IntPtr p, int nullLength)
|
||||
{
|
||||
switch (nullLength) {
|
||||
case 1: return checked ((int) Native.Stdlib.strlen (p));
|
||||
case 2: return GetInt16BufferLength (p);
|
||||
case 4: return GetInt32BufferLength (p);
|
||||
}
|
||||
|
||||
int len = 0;
|
||||
int num_null_seen = 0;
|
||||
|
||||
do {
|
||||
byte b = Marshal.ReadByte (p, len++);
|
||||
if (b == 0)
|
||||
++num_null_seen;
|
||||
else
|
||||
num_null_seen = 0;
|
||||
} while (num_null_seen != nullLength);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Marshal a C `char **'. ANSI C `main' requirements are assumed:
|
||||
*
|
||||
* stringArray is an array of pointers to C strings
|
||||
* stringArray has a terminating NULL string.
|
||||
*
|
||||
* For example:
|
||||
* stringArray[0] = "string 1";
|
||||
* stringArray[1] = "string 2";
|
||||
* stringArray[2] = NULL
|
||||
*
|
||||
* The terminating NULL is required so that we know when to stop looking
|
||||
* for strings.
|
||||
*/
|
||||
public static string[] PtrToStringArray (IntPtr stringArray)
|
||||
{
|
||||
return PtrToStringArray (stringArray, UnixEncoding.Instance);
|
||||
}
|
||||
|
||||
public static string[] PtrToStringArray (IntPtr stringArray, Encoding encoding)
|
||||
{
|
||||
if (stringArray == IntPtr.Zero)
|
||||
return new string[]{};
|
||||
|
||||
int argc = CountStrings (stringArray);
|
||||
return PtrToStringArray (argc, stringArray, encoding);
|
||||
}
|
||||
|
||||
private static int CountStrings (IntPtr stringArray)
|
||||
{
|
||||
int count = 0;
|
||||
while (Marshal.ReadIntPtr (stringArray, count*IntPtr.Size) != IntPtr.Zero)
|
||||
++count;
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Like PtrToStringArray(IntPtr), but it allows the user to specify how
|
||||
* many strings to look for in the array. As such, the requirement for a
|
||||
* terminating NULL element is not required.
|
||||
*
|
||||
* Usage is similar to ANSI C `main': count is argc, stringArray is argv.
|
||||
* stringArray[count] is NOT accessed (though ANSI C requires that
|
||||
* argv[argc] = NULL, which PtrToStringArray(IntPtr) requires).
|
||||
*/
|
||||
public static string[] PtrToStringArray (int count, IntPtr stringArray)
|
||||
{
|
||||
return PtrToStringArray (count, stringArray, UnixEncoding.Instance);
|
||||
}
|
||||
|
||||
public static string[] PtrToStringArray (int count, IntPtr stringArray, Encoding encoding)
|
||||
{
|
||||
if (count < 0)
|
||||
throw new ArgumentOutOfRangeException ("count", "< 0");
|
||||
if (encoding == null)
|
||||
throw new ArgumentNullException ("encoding");
|
||||
if (stringArray == IntPtr.Zero)
|
||||
return new string[count];
|
||||
|
||||
string[] members = new string[count];
|
||||
for (int i = 0; i < count; ++i) {
|
||||
IntPtr s = Marshal.ReadIntPtr (stringArray, i * IntPtr.Size);
|
||||
members[i] = PtrToString (s, encoding);
|
||||
}
|
||||
|
||||
return members;
|
||||
}
|
||||
|
||||
public static IntPtr StringToHeap (string s)
|
||||
{
|
||||
return StringToHeap (s, UnixEncoding.Instance);
|
||||
}
|
||||
|
||||
public static IntPtr StringToHeap (string s, Encoding encoding)
|
||||
{
|
||||
if (s == null)
|
||||
return IntPtr.Zero;
|
||||
|
||||
return StringToHeap (s, 0, s.Length, encoding);
|
||||
}
|
||||
|
||||
public static IntPtr StringToHeap (string s, int index, int count)
|
||||
{
|
||||
return StringToHeap (s, index, count, UnixEncoding.Instance);
|
||||
}
|
||||
|
||||
public static IntPtr StringToHeap (string s, int index, int count, Encoding encoding)
|
||||
{
|
||||
if (s == null)
|
||||
return IntPtr.Zero;
|
||||
|
||||
if (encoding == null)
|
||||
throw new ArgumentNullException ("encoding");
|
||||
|
||||
if (index < 0 || count < 0)
|
||||
throw new ArgumentOutOfRangeException ((index < 0 ? "index" : "count"),
|
||||
"Non - negative number required.");
|
||||
|
||||
if (s.Length - index < count)
|
||||
throw new ArgumentOutOfRangeException ("s", "Index and count must refer to a location within the string.");
|
||||
|
||||
int null_terminator_count = encoding.GetMaxByteCount (1);
|
||||
int length_without_null = encoding.GetByteCount (s);
|
||||
int marshalLength = checked (length_without_null + null_terminator_count);
|
||||
|
||||
IntPtr mem = AllocHeap (marshalLength);
|
||||
if (mem == IntPtr.Zero)
|
||||
throw new UnixIOException (Native.Errno.ENOMEM);
|
||||
|
||||
unsafe {
|
||||
fixed (char* p = s) {
|
||||
byte* marshal = (byte*)mem;
|
||||
int bytes_copied;
|
||||
|
||||
try {
|
||||
bytes_copied = encoding.GetBytes (p + index, count, marshal, marshalLength);
|
||||
} catch {
|
||||
FreeHeap (mem);
|
||||
throw;
|
||||
}
|
||||
|
||||
if (bytes_copied != length_without_null) {
|
||||
FreeHeap (mem);
|
||||
throw new NotSupportedException ("encoding.GetBytes() doesn't equal encoding.GetByteCount()!");
|
||||
}
|
||||
|
||||
marshal += length_without_null;
|
||||
for (int i = 0; i < null_terminator_count; ++i)
|
||||
marshal[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
public static bool ShouldRetrySyscall (int r)
|
||||
{
|
||||
if (r == -1 && Native.Stdlib.GetLastError () == Native.Errno.EINTR)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
[CLSCompliant (false)]
|
||||
public static bool ShouldRetrySyscall (int r, out Native.Errno errno)
|
||||
{
|
||||
errno = (Native.Errno) 0;
|
||||
if (r == -1 && (errno = Native.Stdlib.GetLastError ()) == Native.Errno.EINTR)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// we can't permit any printf(3)-style formatting information, since that
|
||||
// would kill the stack. However, replacing %% is silly, and some %* are
|
||||
// permitted (such as %m in syslog to print strerror(errno)).
|
||||
internal static string EscapeFormatString (string message,
|
||||
char [] permitted)
|
||||
{
|
||||
if (message == null)
|
||||
return "";
|
||||
StringBuilder sb = new StringBuilder (message.Length);
|
||||
for (int i = 0; i < message.Length; ++i) {
|
||||
char c = message [i];
|
||||
sb.Append (c);
|
||||
if (c == '%' && (i+1) < message.Length) {
|
||||
char n = message [i+1];
|
||||
if (n == '%' || IsCharPresent (permitted, n))
|
||||
sb.Append (n);
|
||||
else
|
||||
sb.Append ('%').Append (n);
|
||||
++i;
|
||||
}
|
||||
// invalid format string: % at EOS.
|
||||
else if (c == '%')
|
||||
sb.Append ('%');
|
||||
}
|
||||
return sb.ToString ();
|
||||
}
|
||||
|
||||
private static bool IsCharPresent (char[] array, char c)
|
||||
{
|
||||
if (array == null)
|
||||
return false;
|
||||
for (int i = 0; i < array.Length; ++i)
|
||||
if (array [i] == c)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static Exception CreateExceptionForError (Native.Errno errno)
|
||||
{
|
||||
string message = GetErrorDescription (errno);
|
||||
UnixIOException p = new UnixIOException (errno);
|
||||
|
||||
// Ordering: Order alphabetically by exception first (right column),
|
||||
// then order alphabetically by Errno value (left column) for the given
|
||||
// exception.
|
||||
switch (errno) {
|
||||
case Native.Errno.EBADF:
|
||||
case Native.Errno.EINVAL: return new ArgumentException (message, p);
|
||||
|
||||
case Native.Errno.ERANGE: return new ArgumentOutOfRangeException (message);
|
||||
case Native.Errno.ENOTDIR: return new DirectoryNotFoundException (message, p);
|
||||
case Native.Errno.ENOENT: return new FileNotFoundException (message, p);
|
||||
|
||||
case Native.Errno.EOPNOTSUPP:
|
||||
case Native.Errno.EPERM: return new InvalidOperationException (message, p);
|
||||
|
||||
case Native.Errno.ENOEXEC: return new InvalidProgramException (message, p);
|
||||
|
||||
case Native.Errno.EIO:
|
||||
case Native.Errno.ENOSPC:
|
||||
case Native.Errno.ENOTEMPTY:
|
||||
case Native.Errno.ENXIO:
|
||||
case Native.Errno.EROFS:
|
||||
case Native.Errno.ESPIPE: return new IOException (message, p);
|
||||
|
||||
case Native.Errno.EFAULT: return new NullReferenceException (message, p);
|
||||
case Native.Errno.EOVERFLOW: return new OverflowException (message, p);
|
||||
case Native.Errno.ENAMETOOLONG: return new PathTooLongException (message, p);
|
||||
|
||||
case Native.Errno.EACCES:
|
||||
case Native.Errno.EISDIR: return new UnauthorizedAccessException (message, p);
|
||||
|
||||
default: /* ignore */ break;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
internal static Exception CreateExceptionForLastError ()
|
||||
{
|
||||
return CreateExceptionForError (Native.Stdlib.GetLastError());
|
||||
}
|
||||
|
||||
[CLSCompliant (false)]
|
||||
public static void ThrowExceptionForError (Native.Errno errno)
|
||||
{
|
||||
throw CreateExceptionForError (errno);
|
||||
}
|
||||
|
||||
public static void ThrowExceptionForLastError ()
|
||||
{
|
||||
throw CreateExceptionForLastError ();
|
||||
}
|
||||
|
||||
[CLSCompliant (false)]
|
||||
public static void ThrowExceptionForErrorIf (int retval, Native.Errno errno)
|
||||
{
|
||||
if (retval == -1)
|
||||
ThrowExceptionForError (errno);
|
||||
}
|
||||
|
||||
public static void ThrowExceptionForLastErrorIf (int retval)
|
||||
{
|
||||
if (retval == -1)
|
||||
ThrowExceptionForLastError ();
|
||||
}
|
||||
}
|
||||
// Scenario: We want to be able to translate an Error to a string.
|
||||
// Problem: Thread-safety. Strerror(3) isn't thread safe (unless
|
||||
// thread-local-variables are used, which is probably only
|
||||
// true on Windows).
|
||||
// Solution: Use strerror_r().
|
||||
// Problem: strerror_r() isn't portable.
|
||||
// (Apparently Solaris doesn't provide it.)
|
||||
// Solution: Cry. Then introduce an intermediary, ErrorMarshal.
|
||||
// ErrorMarshal exposes a single public delegate, Translator,
|
||||
// which will convert an Error to a string. It's static
|
||||
// constructor first tries using strerror_r(). If it works,
|
||||
// great; use it in the future. If it doesn't work, fallback to
|
||||
// using strerror(3).
|
||||
// This should be thread safe, since the check is done within the
|
||||
// class constructor lock.
|
||||
// Strerror(3) will be thread-safe from managed code, but won't
|
||||
// be thread-safe between managed & unmanaged code.
|
||||
internal class ErrorMarshal
|
||||
{
|
||||
internal delegate String ErrorTranslator (Native.Errno errno);
|
||||
|
||||
internal static readonly ErrorTranslator Translate;
|
||||
|
||||
static ErrorMarshal ()
|
||||
{
|
||||
try {
|
||||
Translate = new ErrorTranslator (strerror_r);
|
||||
_ = Translate(Native.Errno.ERANGE);
|
||||
}
|
||||
catch (EntryPointNotFoundException) {
|
||||
Translate = new ErrorTranslator (strerror);
|
||||
}
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||
private static String strerror(Native.Errno errno) => Native.Stdlib.strerror(errno);
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||
private static String strerror_r (Native.Errno errno)
|
||||
{
|
||||
StringBuilder buf = new StringBuilder (16);
|
||||
Int32 r;
|
||||
do {
|
||||
buf.Capacity *= 2;
|
||||
r = Native.Syscall.strerror_r (errno, buf);
|
||||
} while (r == -1 && Native.Stdlib.GetLastError() == Native.Errno.ERANGE);
|
||||
|
||||
return r == -1 ? "** Unknown error code: " + (Int32) errno + "**" : buf.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed /* static */ class UnixMarshal
|
||||
{
|
||||
private UnixMarshal () {}
|
||||
|
||||
//[CLSCompliant(false)]
|
||||
public static String GetErrorDescription(Native.Errno errno) => ErrorMarshal.Translate(errno);
|
||||
|
||||
public static IntPtr AllocHeap (Int64 size)
|
||||
{
|
||||
if (size < 0) {
|
||||
throw new ArgumentOutOfRangeException ("size", "< 0");
|
||||
}
|
||||
|
||||
return Native.Stdlib.malloc ((UInt64) size);
|
||||
}
|
||||
|
||||
public static IntPtr ReAllocHeap (IntPtr ptr, Int64 size)
|
||||
{
|
||||
if (size < 0) {
|
||||
throw new ArgumentOutOfRangeException ("size", "< 0");
|
||||
}
|
||||
|
||||
return Native.Stdlib.realloc (ptr, (UInt64) size);
|
||||
}
|
||||
|
||||
public static void FreeHeap(IntPtr ptr) => Native.Stdlib.free(ptr);
|
||||
|
||||
public static unsafe String PtrToStringUnix (IntPtr p)
|
||||
{
|
||||
if (p == IntPtr.Zero) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Int32 len = checked ((Int32) Native.Stdlib.strlen (p));
|
||||
return new String((SByte*) p, 0, len, UnixEncoding.Instance);
|
||||
}
|
||||
|
||||
public static String PtrToString(IntPtr p) => p == IntPtr.Zero ? null : PtrToString(p, UnixEncoding.Instance);
|
||||
|
||||
public static unsafe String PtrToString (IntPtr p, Encoding encoding)
|
||||
{
|
||||
if (p == IntPtr.Zero) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (encoding == null) {
|
||||
throw new ArgumentNullException ("encoding");
|
||||
}
|
||||
|
||||
Int32 len = GetStringByteLength (p, encoding);
|
||||
|
||||
// Due to variable-length encoding schemes, GetStringByteLength() may
|
||||
// have returned multiple "null" characters. (For example, when
|
||||
// encoding a string into UTF-8 there will be 4 terminating nulls.)
|
||||
// We don't want these null's to be in the returned string, so strip
|
||||
// them off.
|
||||
String s = new String((SByte*) p, 0, len, encoding);
|
||||
len = s.Length;
|
||||
while (len > 0 && s [len-1] == 0) {
|
||||
--len;
|
||||
}
|
||||
|
||||
return len == s.Length ? s : s.Substring (0, len);
|
||||
}
|
||||
|
||||
private static Int32 GetStringByteLength (IntPtr p, Encoding encoding)
|
||||
{
|
||||
Type encodingType = encoding.GetType ();
|
||||
|
||||
Int32 len = typeof(UTF8Encoding).IsAssignableFrom (encodingType) ||
|
||||
typeof(UTF7Encoding).IsAssignableFrom (encodingType) ||
|
||||
typeof(UnixEncoding).IsAssignableFrom (encodingType) ||
|
||||
typeof(ASCIIEncoding).IsAssignableFrom (encodingType)
|
||||
? (Int32) Native.Stdlib.strlen (p)
|
||||
: typeof(UnicodeEncoding).IsAssignableFrom(encodingType)
|
||||
? GetInt16BufferLength(p)
|
||||
: typeof(UTF32Encoding).IsAssignableFrom(encodingType)
|
||||
? GetInt32BufferLength(p)
|
||||
: GetRandomBufferLength(p, encoding.GetMaxByteCount(1));
|
||||
|
||||
// Encodings that will always end with a single null byte
|
||||
|
||||
if(len == -1) {
|
||||
throw new NotSupportedException ("Unable to determine native string buffer length");
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
private static Int32 GetInt16BufferLength (IntPtr p)
|
||||
{
|
||||
Int32 len = 0;
|
||||
while (Marshal.ReadInt16 (p, len*2) != 0) {
|
||||
checked {++len;}
|
||||
}
|
||||
|
||||
return checked(len*2);
|
||||
}
|
||||
|
||||
private static Int32 GetInt32BufferLength (IntPtr p)
|
||||
{
|
||||
Int32 len = 0;
|
||||
while (Marshal.ReadInt32 (p, len*4) != 0) {
|
||||
checked {++len;}
|
||||
}
|
||||
|
||||
return checked(len*4);
|
||||
}
|
||||
|
||||
private static Int32 GetRandomBufferLength (IntPtr p, Int32 nullLength)
|
||||
{
|
||||
switch (nullLength) {
|
||||
case 1: return checked ((Int32) Native.Stdlib.strlen (p));
|
||||
case 2: return GetInt16BufferLength (p);
|
||||
case 4: return GetInt32BufferLength (p);
|
||||
}
|
||||
|
||||
Int32 len = 0;
|
||||
Int32 num_null_seen = 0;
|
||||
|
||||
do {
|
||||
Byte b = Marshal.ReadByte (p, len++);
|
||||
if (b == 0) {
|
||||
++num_null_seen;
|
||||
} else {
|
||||
num_null_seen = 0;
|
||||
}
|
||||
} while (num_null_seen != nullLength);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Marshal a C `char **'. ANSI C `main' requirements are assumed:
|
||||
*
|
||||
* stringArray is an array of pointers to C strings
|
||||
* stringArray has a terminating NULL string.
|
||||
*
|
||||
* For example:
|
||||
* stringArray[0] = "string 1";
|
||||
* stringArray[1] = "string 2";
|
||||
* stringArray[2] = NULL
|
||||
*
|
||||
* The terminating NULL is required so that we know when to stop looking
|
||||
* for strings.
|
||||
*/
|
||||
public static String[] PtrToStringArray(IntPtr stringArray) => PtrToStringArray(stringArray, UnixEncoding.Instance);
|
||||
|
||||
public static String[] PtrToStringArray (IntPtr stringArray, Encoding encoding)
|
||||
{
|
||||
if (stringArray == IntPtr.Zero) {
|
||||
return new String[]{};
|
||||
}
|
||||
|
||||
Int32 argc = CountStrings (stringArray);
|
||||
return PtrToStringArray (argc, stringArray, encoding);
|
||||
}
|
||||
|
||||
private static Int32 CountStrings (IntPtr stringArray)
|
||||
{
|
||||
Int32 count = 0;
|
||||
while (Marshal.ReadIntPtr (stringArray, count*IntPtr.Size) != IntPtr.Zero) {
|
||||
++count;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Like PtrToStringArray(IntPtr), but it allows the user to specify how
|
||||
* many strings to look for in the array. As such, the requirement for a
|
||||
* terminating NULL element is not required.
|
||||
*
|
||||
* Usage is similar to ANSI C `main': count is argc, stringArray is argv.
|
||||
* stringArray[count] is NOT accessed (though ANSI C requires that
|
||||
* argv[argc] = NULL, which PtrToStringArray(IntPtr) requires).
|
||||
*/
|
||||
public static String[] PtrToStringArray(Int32 count, IntPtr stringArray) => PtrToStringArray(count, stringArray, UnixEncoding.Instance);
|
||||
|
||||
public static String[] PtrToStringArray (Int32 count, IntPtr stringArray, Encoding encoding)
|
||||
{
|
||||
if (count < 0) {
|
||||
throw new ArgumentOutOfRangeException ("count", "< 0");
|
||||
}
|
||||
|
||||
if (encoding == null) {
|
||||
throw new ArgumentNullException ("encoding");
|
||||
}
|
||||
|
||||
if (stringArray == IntPtr.Zero) {
|
||||
return new String[count];
|
||||
}
|
||||
|
||||
String[] members = new String[count];
|
||||
for (Int32 i = 0; i < count; ++i) {
|
||||
IntPtr s = Marshal.ReadIntPtr (stringArray, i * IntPtr.Size);
|
||||
members[i] = PtrToString (s, encoding);
|
||||
}
|
||||
|
||||
return members;
|
||||
}
|
||||
|
||||
public static IntPtr StringToHeap(String s) => StringToHeap(s, UnixEncoding.Instance);
|
||||
|
||||
public static IntPtr StringToHeap(String s, Encoding encoding) => s == null ? IntPtr.Zero : StringToHeap(s, 0, s.Length, encoding);
|
||||
|
||||
public static IntPtr StringToHeap(String s, Int32 index, Int32 count) => StringToHeap(s, index, count, UnixEncoding.Instance);
|
||||
|
||||
public static IntPtr StringToHeap (String s, Int32 index, Int32 count, Encoding encoding)
|
||||
{
|
||||
if (s == null) {
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
if (encoding == null) {
|
||||
throw new ArgumentNullException ("encoding");
|
||||
}
|
||||
|
||||
if (index < 0 || count < 0) {
|
||||
throw new ArgumentOutOfRangeException (index < 0 ? "index" : "count",
|
||||
"Non - negative number required.");
|
||||
}
|
||||
|
||||
if (s.Length - index < count) {
|
||||
throw new ArgumentOutOfRangeException ("s", "Index and count must refer to a location within the string.");
|
||||
}
|
||||
|
||||
Int32 null_terminator_count = encoding.GetMaxByteCount (1);
|
||||
Int32 length_without_null = encoding.GetByteCount (s);
|
||||
Int32 marshalLength = checked (length_without_null + null_terminator_count);
|
||||
|
||||
IntPtr mem = AllocHeap (marshalLength);
|
||||
if (mem == IntPtr.Zero) {
|
||||
throw new UnixIOException (Native.Errno.ENOMEM);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
fixed (Char* p = s) {
|
||||
Byte* marshal = (Byte*)mem;
|
||||
Int32 bytes_copied;
|
||||
|
||||
try {
|
||||
bytes_copied = encoding.GetBytes (p + index, count, marshal, marshalLength);
|
||||
} catch {
|
||||
FreeHeap (mem);
|
||||
throw;
|
||||
}
|
||||
|
||||
if (bytes_copied != length_without_null) {
|
||||
FreeHeap (mem);
|
||||
throw new NotSupportedException ("encoding.GetBytes() doesn't equal encoding.GetByteCount()!");
|
||||
}
|
||||
|
||||
marshal += length_without_null;
|
||||
for (Int32 i = 0; i < null_terminator_count; ++i) {
|
||||
marshal[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
public static Boolean ShouldRetrySyscall(Int32 r) => r == -1 && Native.Stdlib.GetLastError() == Native.Errno.EINTR;
|
||||
|
||||
//[CLSCompliant (false)]
|
||||
public static Boolean ShouldRetrySyscall (Int32 r, out Native.Errno errno)
|
||||
{
|
||||
errno = (Native.Errno) 0;
|
||||
return r == -1 && (errno = Native.Stdlib.GetLastError ()) == Native.Errno.EINTR;
|
||||
}
|
||||
|
||||
// we can't permit any printf(3)-style formatting information, since that
|
||||
// would kill the stack. However, replacing %% is silly, and some %* are
|
||||
// permitted (such as %m in syslog to print strerror(errno)).
|
||||
internal static String EscapeFormatString (String message,
|
||||
Char[] permitted)
|
||||
{
|
||||
if (message == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder (message.Length);
|
||||
for (Int32 i = 0; i < message.Length; ++i) {
|
||||
Char c = message [i];
|
||||
_ = sb.Append(c);
|
||||
if (c == '%' && i+1 < message.Length) {
|
||||
Char n = message [i+1];
|
||||
_ = n == '%' || IsCharPresent (permitted, n) ? sb.Append(n) : sb.Append('%').Append(n);
|
||||
|
||||
++i;
|
||||
}
|
||||
// invalid format string: % at EOS.
|
||||
else if (c == '%') {
|
||||
_ = sb.Append('%');
|
||||
}
|
||||
}
|
||||
return sb.ToString ();
|
||||
}
|
||||
|
||||
private static Boolean IsCharPresent (Char[] array, Char c)
|
||||
{
|
||||
if (array == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Int32 i = 0; i < array.Length; ++i) {
|
||||
if (array [i] == c) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static Exception CreateExceptionForError (Native.Errno errno)
|
||||
{
|
||||
String message = GetErrorDescription (errno);
|
||||
UnixIOException p = new UnixIOException (errno);
|
||||
|
||||
// Ordering: Order alphabetically by exception first (right column),
|
||||
// then order alphabetically by Errno value (left column) for the given
|
||||
// exception.
|
||||
switch (errno) {
|
||||
case Native.Errno.EBADF:
|
||||
case Native.Errno.EINVAL: return new ArgumentException (message, p);
|
||||
|
||||
case Native.Errno.ERANGE: return new ArgumentOutOfRangeException (message);
|
||||
case Native.Errno.ENOTDIR: return new DirectoryNotFoundException (message, p);
|
||||
case Native.Errno.ENOENT: return new FileNotFoundException (message, p);
|
||||
|
||||
case Native.Errno.EOPNOTSUPP:
|
||||
case Native.Errno.EPERM: return new InvalidOperationException (message, p);
|
||||
|
||||
case Native.Errno.ENOEXEC: return new InvalidProgramException (message, p);
|
||||
|
||||
case Native.Errno.EIO:
|
||||
case Native.Errno.ENOSPC:
|
||||
case Native.Errno.ENOTEMPTY:
|
||||
case Native.Errno.ENXIO:
|
||||
case Native.Errno.EROFS:
|
||||
case Native.Errno.ESPIPE: return new IOException (message, p);
|
||||
|
||||
case Native.Errno.EFAULT: return new NullReferenceException (message, p);
|
||||
case Native.Errno.EOVERFLOW: return new OverflowException (message, p);
|
||||
case Native.Errno.ENAMETOOLONG: return new PathTooLongException (message, p);
|
||||
|
||||
case Native.Errno.EACCES:
|
||||
case Native.Errno.EISDIR: return new UnauthorizedAccessException (message, p);
|
||||
|
||||
default: /* ignore */ break;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
internal static Exception CreateExceptionForLastError() => CreateExceptionForError(Native.Stdlib.GetLastError());
|
||||
|
||||
//[CLSCompliant(false)]
|
||||
public static void ThrowExceptionForError(Native.Errno errno) => throw CreateExceptionForError(errno);
|
||||
|
||||
public static void ThrowExceptionForLastError() => throw CreateExceptionForLastError();
|
||||
|
||||
//[CLSCompliant (false)]
|
||||
public static void ThrowExceptionForErrorIf (Int32 retval, Native.Errno errno)
|
||||
{
|
||||
if (retval == -1) {
|
||||
ThrowExceptionForError (errno);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ThrowExceptionForLastErrorIf (Int32 retval)
|
||||
{
|
||||
if (retval == -1) {
|
||||
ThrowExceptionForLastError ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// vim: noexpandtab
|
||||
|
@ -28,259 +28,272 @@
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text;
|
||||
using Mono.Unix;
|
||||
|
||||
namespace Mono.Unix {
|
||||
|
||||
public sealed class UnixPath
|
||||
{
|
||||
private UnixPath () {}
|
||||
public sealed class UnixPath
|
||||
{
|
||||
private UnixPath () {}
|
||||
|
||||
public static readonly char DirectorySeparatorChar = '/';
|
||||
public static readonly char AltDirectorySeparatorChar = '/';
|
||||
public static readonly char PathSeparator = ':';
|
||||
public static readonly char VolumeSeparatorChar = '/';
|
||||
public static readonly Char DirectorySeparatorChar = '/';
|
||||
public static readonly Char AltDirectorySeparatorChar = '/';
|
||||
public static readonly Char PathSeparator = ':';
|
||||
public static readonly Char VolumeSeparatorChar = '/';
|
||||
|
||||
private static readonly char[] _InvalidPathChars = new char[]{};
|
||||
private static readonly Char[] _InvalidPathChars = new Char[]{};
|
||||
|
||||
public static Char[] GetInvalidPathChars() => (Char[])_InvalidPathChars.Clone();
|
||||
|
||||
public static String Combine (String path1, params String[] paths)
|
||||
{
|
||||
if (path1 == null) {
|
||||
throw new ArgumentNullException ("path1");
|
||||
}
|
||||
|
||||
if (paths == null) {
|
||||
throw new ArgumentNullException ("paths");
|
||||
}
|
||||
|
||||
if (path1.IndexOfAny (_InvalidPathChars) != -1) {
|
||||
throw new ArgumentException ("Illegal characters in path", "path1");
|
||||
}
|
||||
|
||||
Int32 len = path1.Length;
|
||||
Int32 start = -1;
|
||||
for (Int32 i = 0; i < paths.Length; ++i) {
|
||||
if (paths [i] == null) {
|
||||
throw new ArgumentNullException ("paths[" + i + "]");
|
||||
}
|
||||
|
||||
if (paths [i].IndexOfAny (_InvalidPathChars) != -1) {
|
||||
throw new ArgumentException ("Illegal characters in path", "paths[" + i + "]");
|
||||
}
|
||||
|
||||
if (IsPathRooted (paths [i])) {
|
||||
len = 0;
|
||||
start = i;
|
||||
}
|
||||
len += paths [i].Length + 1;
|
||||
}
|
||||
|
||||
public static char[] GetInvalidPathChars ()
|
||||
{
|
||||
return (char[]) _InvalidPathChars.Clone ();
|
||||
}
|
||||
StringBuilder sb = new StringBuilder (len);
|
||||
if (start == -1) {
|
||||
_ = sb.Append(path1);
|
||||
start = 0;
|
||||
}
|
||||
for (Int32 i = start; i < paths.Length; ++i) {
|
||||
Combine (sb, paths [i]);
|
||||
}
|
||||
|
||||
return sb.ToString ();
|
||||
}
|
||||
|
||||
public static string Combine (string path1, params string[] paths)
|
||||
{
|
||||
if (path1 == null)
|
||||
throw new ArgumentNullException ("path1");
|
||||
if (paths == null)
|
||||
throw new ArgumentNullException ("paths");
|
||||
if (path1.IndexOfAny (_InvalidPathChars) != -1)
|
||||
throw new ArgumentException ("Illegal characters in path", "path1");
|
||||
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);
|
||||
}
|
||||
|
||||
int len = path1.Length;
|
||||
int start = -1;
|
||||
for (int i = 0; i < paths.Length; ++i) {
|
||||
if (paths [i] == null)
|
||||
throw new ArgumentNullException ("paths[" + i + "]");
|
||||
if (paths [i].IndexOfAny (_InvalidPathChars) != -1)
|
||||
throw new ArgumentException ("Illegal characters in path", "paths[" + i + "]");
|
||||
if (IsPathRooted (paths [i])) {
|
||||
len = 0;
|
||||
start = i;
|
||||
}
|
||||
len += paths [i].Length + 1;
|
||||
}
|
||||
public static String GetDirectoryName (String path)
|
||||
{
|
||||
CheckPath (path);
|
||||
|
||||
StringBuilder sb = new StringBuilder (len);
|
||||
if (start == -1) {
|
||||
sb.Append (path1);
|
||||
start = 0;
|
||||
}
|
||||
for (int i = start; i < paths.Length; ++i)
|
||||
Combine (sb, paths [i]);
|
||||
return sb.ToString ();
|
||||
}
|
||||
Int32 lastDir = path.LastIndexOf (DirectorySeparatorChar);
|
||||
return lastDir > 0 ? path.Substring (0, lastDir) : lastDir == 0 ? "/" : "";
|
||||
}
|
||||
|
||||
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 GetFileName (String path)
|
||||
{
|
||||
if (path == null || path.Length == 0) {
|
||||
return path;
|
||||
}
|
||||
|
||||
Int32 lastDir = path.LastIndexOf (DirectorySeparatorChar);
|
||||
return lastDir >= 0 ? path.Substring (lastDir+1) : path;
|
||||
}
|
||||
|
||||
public static string GetDirectoryName (string path)
|
||||
{
|
||||
CheckPath (path);
|
||||
public static String GetFullPath (String path)
|
||||
{
|
||||
path = _GetFullPath (path);
|
||||
return GetCanonicalPath (path);
|
||||
}
|
||||
|
||||
int lastDir = path.LastIndexOf (DirectorySeparatorChar);
|
||||
if (lastDir > 0)
|
||||
return path.Substring (0, lastDir);
|
||||
if (lastDir == 0)
|
||||
return "/";
|
||||
return "";
|
||||
}
|
||||
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||
private static String _GetFullPath (String path)
|
||||
{
|
||||
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)
|
||||
{
|
||||
GetPathComponents(path, out String[] dirs, out Int32 lastIndex);
|
||||
String end = String.Join ("/", dirs, 0, lastIndex);
|
||||
return IsPathRooted (path) ? "/" + end : end;
|
||||
}
|
||||
|
||||
int lastDir = path.LastIndexOf (DirectorySeparatorChar);
|
||||
if (lastDir >= 0)
|
||||
return path.Substring (lastDir+1);
|
||||
private static void GetPathComponents (String path,
|
||||
out String[] components, out Int32 lastIndex)
|
||||
{
|
||||
String[] dirs = path.Split (DirectorySeparatorChar);
|
||||
Int32 target = 0;
|
||||
for (Int32 i = 0; i < dirs.Length; ++i) {
|
||||
if (dirs [i] == "." || dirs [i] == String.Empty) {
|
||||
continue;
|
||||
} else if (dirs [i] == "..") {
|
||||
if (target != 0) {
|
||||
--target;
|
||||
} else {
|
||||
++target;
|
||||
}
|
||||
}
|
||||
else {
|
||||
dirs [target++] = dirs [i];
|
||||
}
|
||||
}
|
||||
components = dirs;
|
||||
lastIndex = target;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
public static String GetPathRoot(String path) => path == null ? null : !IsPathRooted(path) ? "" : "/";
|
||||
|
||||
public static string GetFullPath (string path)
|
||||
{
|
||||
path = _GetFullPath (path);
|
||||
return GetCanonicalPath (path);
|
||||
}
|
||||
public static String GetCompleteRealPath (String path)
|
||||
{
|
||||
if (path == null) {
|
||||
throw new ArgumentNullException ("path");
|
||||
}
|
||||
|
||||
GetPathComponents(path, out String[] dirs, out Int32 lastIndex);
|
||||
StringBuilder realPath = new StringBuilder ();
|
||||
if (dirs.Length > 0) {
|
||||
String dir = IsPathRooted (path) ? "/" : "";
|
||||
dir += dirs [0];
|
||||
_ = realPath.Append(GetRealPath(dir));
|
||||
}
|
||||
for (Int32 i = 1; i < lastIndex; ++i) {
|
||||
_ = realPath.Append("/").Append(dirs[i]);
|
||||
String p = GetRealPath (realPath.ToString());
|
||||
_ = realPath.Remove(0, realPath.Length);
|
||||
_ = realPath.Append(p);
|
||||
}
|
||||
return realPath.ToString ();
|
||||
}
|
||||
|
||||
private static string _GetFullPath (string path)
|
||||
{
|
||||
if (path == null)
|
||||
throw new ArgumentNullException ("path");
|
||||
if (!IsPathRooted (path))
|
||||
path = UnixDirectoryInfo.GetCurrentDirectory() + DirectorySeparatorChar + path;
|
||||
public static String GetRealPath (String path)
|
||||
{
|
||||
do {
|
||||
String name = ReadSymbolicLink (path);
|
||||
if (name == null) {
|
||||
return path;
|
||||
}
|
||||
|
||||
if (IsPathRooted (name)) {
|
||||
path = name;
|
||||
} else {
|
||||
path = GetDirectoryName (path) + DirectorySeparatorChar + name;
|
||||
path = GetCanonicalPath (path);
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
// Read the specified symbolic link. If the file isn't a symbolic link,
|
||||
// return null; otherwise, return the contents of the symbolic link.
|
||||
internal static String ReadSymbolicLink (String path)
|
||||
{
|
||||
String target = TryReadLink (path);
|
||||
if (target == null) {
|
||||
Native.Errno errno = Native.Stdlib.GetLastError ();
|
||||
if (errno != Native.Errno.EINVAL) {
|
||||
UnixMarshal.ThrowExceptionForError (errno);
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
public static string GetCanonicalPath (string path)
|
||||
{
|
||||
string [] dirs;
|
||||
int lastIndex;
|
||||
GetPathComponents (path, out dirs, out lastIndex);
|
||||
string end = string.Join ("/", dirs, 0, lastIndex);
|
||||
return IsPathRooted (path) ? "/" + end : end;
|
||||
}
|
||||
public static String TryReadLink (String path)
|
||||
{
|
||||
Byte[] buf = new Byte[256];
|
||||
do {
|
||||
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);
|
||||
}
|
||||
|
||||
private static void GetPathComponents (string path,
|
||||
out string[] components, out int lastIndex)
|
||||
{
|
||||
string [] dirs = path.Split (DirectorySeparatorChar);
|
||||
int target = 0;
|
||||
for (int i = 0; i < dirs.Length; ++i) {
|
||||
if (dirs [i] == "." || dirs [i] == string.Empty) continue;
|
||||
else if (dirs [i] == "..") {
|
||||
if (target != 0) --target;
|
||||
else ++target;
|
||||
}
|
||||
else
|
||||
dirs [target++] = dirs [i];
|
||||
}
|
||||
components = dirs;
|
||||
lastIndex = target;
|
||||
}
|
||||
public static String 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 GetPathRoot (string path)
|
||||
{
|
||||
if (path == null)
|
||||
return null;
|
||||
if (!IsPathRooted (path))
|
||||
return "";
|
||||
return "/";
|
||||
}
|
||||
public static String ReadLink (String path)
|
||||
{
|
||||
String target = TryReadLink (path);
|
||||
if (target == null) {
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
public static string GetCompleteRealPath (string path)
|
||||
{
|
||||
if (path == null)
|
||||
throw new ArgumentNullException ("path");
|
||||
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 ReadLinkAt (Int32 dirfd, String path)
|
||||
{
|
||||
String target = TryReadLinkAt (dirfd, path);
|
||||
if (target == null) {
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
public static string GetRealPath (string path)
|
||||
{
|
||||
do {
|
||||
string name = ReadSymbolicLink (path);
|
||||
if (name == null)
|
||||
return path;
|
||||
if (IsPathRooted (name))
|
||||
path = name;
|
||||
else {
|
||||
path = GetDirectoryName (path) + DirectorySeparatorChar + name;
|
||||
path = GetCanonicalPath (path);
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
public static Boolean IsPathRooted(String path) => path == null || path.Length == 0 ? false : path[0] == DirectorySeparatorChar;
|
||||
|
||||
// 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 {
|
||||
long r = Native.Syscall.readlink (path, buf);
|
||||
if (r < 0)
|
||||
return null;
|
||||
else if (r == buf.Length)
|
||||
buf = new byte[checked (buf.LongLength * 2)];
|
||||
else
|
||||
return UnixEncoding.Instance.GetString (buf, 0, checked ((int) r));
|
||||
} while (true);
|
||||
}
|
||||
|
||||
public static string TryReadLinkAt (int dirfd, string path)
|
||||
{
|
||||
byte[] buf = new byte[256];
|
||||
do {
|
||||
long r = Native.Syscall.readlinkat (dirfd, path, buf);
|
||||
if (r < 0)
|
||||
return null;
|
||||
else if (r == buf.Length)
|
||||
buf = new byte[checked (buf.LongLength * 2)];
|
||||
else
|
||||
return UnixEncoding.Instance.GetString (buf, 0, checked ((int) r));
|
||||
} while (true);
|
||||
}
|
||||
|
||||
public static string ReadLink (string path)
|
||||
{
|
||||
string target = TryReadLink (path);
|
||||
if (target == null)
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
return target;
|
||||
}
|
||||
|
||||
public static string ReadLinkAt (int dirfd, string path)
|
||||
{
|
||||
string target = TryReadLinkAt (dirfd, path);
|
||||
if (target == null)
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
return target;
|
||||
}
|
||||
|
||||
public static bool IsPathRooted (string path)
|
||||
{
|
||||
if (path == null || path.Length == 0)
|
||||
return false;
|
||||
return path [0] == DirectorySeparatorChar;
|
||||
}
|
||||
|
||||
internal static void CheckPath (string path)
|
||||
{
|
||||
if (path == null)
|
||||
throw new ArgumentNullException ();
|
||||
if (path.Length == 0)
|
||||
throw new ArgumentException ("Path cannot contain a zero-length string", "path");
|
||||
if (path.IndexOfAny (_InvalidPathChars) != -1)
|
||||
throw new ArgumentException ("Invalid characters in path.", "path");
|
||||
}
|
||||
}
|
||||
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
|
||||
|
@ -33,56 +33,45 @@ using Mono.Unix;
|
||||
|
||||
namespace Mono.Unix {
|
||||
|
||||
public struct UnixPipes
|
||||
: IEquatable <UnixPipes>
|
||||
{
|
||||
public UnixPipes (UnixStream reading, UnixStream writing)
|
||||
{
|
||||
Reading = reading;
|
||||
Writing = writing;
|
||||
}
|
||||
public struct UnixPipes
|
||||
: IEquatable <UnixPipes>
|
||||
{
|
||||
public UnixPipes (UnixStream reading, UnixStream writing)
|
||||
{
|
||||
this.Reading = reading;
|
||||
this.Writing = writing;
|
||||
}
|
||||
|
||||
public UnixStream Reading;
|
||||
public UnixStream Writing;
|
||||
public UnixStream Reading;
|
||||
public UnixStream Writing;
|
||||
|
||||
public static UnixPipes CreatePipes ()
|
||||
{
|
||||
int reading, writing;
|
||||
int r = Native.Syscall.pipe (out reading, out writing);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
return new UnixPipes (new UnixStream (reading), new UnixStream (writing));
|
||||
}
|
||||
public static UnixPipes CreatePipes ()
|
||||
{
|
||||
Int32 r = Native.Syscall.pipe(out Int32 reading, out Int32 writing);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
return new UnixPipes (new UnixStream (reading), new UnixStream (writing));
|
||||
}
|
||||
|
||||
public override bool Equals (object value)
|
||||
{
|
||||
if ((value == null) || (value.GetType () != GetType ()))
|
||||
return false;
|
||||
UnixPipes other = (UnixPipes) value;
|
||||
return Reading.Handle == other.Reading.Handle &&
|
||||
Writing.Handle == other.Writing.Handle;
|
||||
}
|
||||
public override Boolean Equals (Object value)
|
||||
{
|
||||
if (value == null || value.GetType () != this.GetType ()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
UnixPipes other = (UnixPipes) value;
|
||||
return this.Reading.Handle == other.Reading.Handle &&
|
||||
this.Writing.Handle == other.Writing.Handle;
|
||||
}
|
||||
|
||||
public bool Equals (UnixPipes value)
|
||||
{
|
||||
return Reading.Handle == value.Reading.Handle &&
|
||||
Writing.Handle == value.Writing.Handle;
|
||||
}
|
||||
public Boolean Equals(UnixPipes value) => this.Reading.Handle == value.Reading.Handle &&
|
||||
this.Writing.Handle == value.Writing.Handle;
|
||||
|
||||
public override int GetHashCode ()
|
||||
{
|
||||
return Reading.Handle.GetHashCode () ^ Writing.Handle.GetHashCode ();
|
||||
}
|
||||
public override Int32 GetHashCode() => this.Reading.Handle.GetHashCode() ^ this.Writing.Handle.GetHashCode();
|
||||
|
||||
public static bool operator== (UnixPipes lhs, UnixPipes rhs)
|
||||
{
|
||||
return lhs.Equals (rhs);
|
||||
}
|
||||
public static Boolean operator ==(UnixPipes lhs, UnixPipes rhs) => lhs.Equals(rhs);
|
||||
|
||||
public static bool operator!= (UnixPipes lhs, UnixPipes rhs)
|
||||
{
|
||||
return !lhs.Equals (rhs);
|
||||
}
|
||||
}
|
||||
public static Boolean operator !=(UnixPipes lhs, UnixPipes rhs) => !lhs.Equals(rhs);
|
||||
}
|
||||
}
|
||||
|
||||
// vim: noexpandtab
|
||||
|
@ -31,127 +31,117 @@ using Mono.Unix;
|
||||
|
||||
namespace Mono.Unix {
|
||||
|
||||
public sealed class UnixProcess
|
||||
{
|
||||
private int pid;
|
||||
public sealed class UnixProcess
|
||||
{
|
||||
private Int32 pid;
|
||||
|
||||
internal UnixProcess (int pid)
|
||||
{
|
||||
this.pid = pid;
|
||||
}
|
||||
internal UnixProcess(Int32 pid) => this.pid = pid;
|
||||
|
||||
public int Id {
|
||||
get {return pid;}
|
||||
}
|
||||
public Int32 Id => this.pid;
|
||||
|
||||
public bool HasExited {
|
||||
get {
|
||||
int status = GetProcessStatus ();
|
||||
return Native.Syscall.WIFEXITED (status);
|
||||
}
|
||||
}
|
||||
public Boolean HasExited {
|
||||
get {
|
||||
Int32 status = this.GetProcessStatus ();
|
||||
return Native.Syscall.WIFEXITED (status);
|
||||
}
|
||||
}
|
||||
|
||||
private int GetProcessStatus ()
|
||||
{
|
||||
int status;
|
||||
int r = Native.Syscall.waitpid (pid, out status,
|
||||
Native.WaitOptions.WNOHANG | Native.WaitOptions.WUNTRACED);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
return r;
|
||||
}
|
||||
private Int32 GetProcessStatus ()
|
||||
{
|
||||
Int32 r = Native.Syscall.waitpid(this.pid, out Int32 status,
|
||||
Native.WaitOptions.WNOHANG | Native.WaitOptions.WUNTRACED);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
return r;
|
||||
}
|
||||
|
||||
public int ExitCode {
|
||||
get {
|
||||
if (!HasExited)
|
||||
throw new InvalidOperationException (
|
||||
Locale.GetText ("Process hasn't exited"));
|
||||
int status = GetProcessStatus ();
|
||||
return Native.Syscall.WEXITSTATUS (status);
|
||||
}
|
||||
}
|
||||
public Int32 ExitCode {
|
||||
get {
|
||||
if (!this.HasExited) {
|
||||
throw new InvalidOperationException (
|
||||
Locale.GetText ("Process hasn't exited"));
|
||||
}
|
||||
|
||||
Int32 status = this.GetProcessStatus ();
|
||||
return Native.Syscall.WEXITSTATUS (status);
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasSignaled {
|
||||
get {
|
||||
int status = GetProcessStatus ();
|
||||
return Native.Syscall.WIFSIGNALED (status);
|
||||
}
|
||||
}
|
||||
public Boolean HasSignaled {
|
||||
get {
|
||||
Int32 status = this.GetProcessStatus ();
|
||||
return Native.Syscall.WIFSIGNALED (status);
|
||||
}
|
||||
}
|
||||
|
||||
public Native.Signum TerminationSignal {
|
||||
get {
|
||||
if (!HasSignaled)
|
||||
throw new InvalidOperationException (
|
||||
Locale.GetText ("Process wasn't terminated by a signal"));
|
||||
int status = GetProcessStatus ();
|
||||
return Native.Syscall.WTERMSIG (status);
|
||||
}
|
||||
}
|
||||
public Native.Signum TerminationSignal {
|
||||
get {
|
||||
if (!this.HasSignaled) {
|
||||
throw new InvalidOperationException (
|
||||
Locale.GetText ("Process wasn't terminated by a signal"));
|
||||
}
|
||||
|
||||
Int32 status = this.GetProcessStatus ();
|
||||
return Native.Syscall.WTERMSIG (status);
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasStopped {
|
||||
get {
|
||||
int status = GetProcessStatus ();
|
||||
return Native.Syscall.WIFSTOPPED (status);
|
||||
}
|
||||
}
|
||||
public Boolean HasStopped {
|
||||
get {
|
||||
Int32 status = this.GetProcessStatus ();
|
||||
return Native.Syscall.WIFSTOPPED (status);
|
||||
}
|
||||
}
|
||||
|
||||
public Native.Signum StopSignal {
|
||||
get {
|
||||
if (!HasStopped)
|
||||
throw new InvalidOperationException (
|
||||
Locale.GetText ("Process isn't stopped"));
|
||||
int status = GetProcessStatus ();
|
||||
return Native.Syscall.WSTOPSIG (status);
|
||||
}
|
||||
}
|
||||
public Native.Signum StopSignal {
|
||||
get {
|
||||
if (!this.HasStopped) {
|
||||
throw new InvalidOperationException (
|
||||
Locale.GetText ("Process isn't stopped"));
|
||||
}
|
||||
|
||||
Int32 status = this.GetProcessStatus ();
|
||||
return Native.Syscall.WSTOPSIG (status);
|
||||
}
|
||||
}
|
||||
|
||||
public int ProcessGroupId {
|
||||
get {return Native.Syscall.getpgid (pid);}
|
||||
set {
|
||||
int r = Native.Syscall.setpgid (pid, value);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
}
|
||||
public Int32 ProcessGroupId {
|
||||
get => Native.Syscall.getpgid(this.pid);
|
||||
set {
|
||||
Int32 r = Native.Syscall.setpgid(this.pid, value);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf(r);
|
||||
}
|
||||
}
|
||||
|
||||
public int SessionId {
|
||||
get {
|
||||
int r = Native.Syscall.getsid (pid);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
public Int32 SessionId {
|
||||
get {
|
||||
Int32 r = Native.Syscall.getsid (this.pid);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
public static UnixProcess GetCurrentProcess ()
|
||||
{
|
||||
return new UnixProcess (GetCurrentProcessId ());
|
||||
}
|
||||
public static UnixProcess GetCurrentProcess() => new UnixProcess(GetCurrentProcessId());
|
||||
|
||||
public static int GetCurrentProcessId ()
|
||||
{
|
||||
return Native.Syscall.getpid ();
|
||||
}
|
||||
public static Int32 GetCurrentProcessId() => Native.Syscall.getpid();
|
||||
|
||||
public void Kill ()
|
||||
{
|
||||
Signal (Native.Signum.SIGKILL);
|
||||
}
|
||||
public void Kill() => this.Signal(Native.Signum.SIGKILL);
|
||||
|
||||
[CLSCompliant (false)]
|
||||
public void Signal (Native.Signum signal)
|
||||
{
|
||||
int r = Native.Syscall.kill (pid, signal);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
//[CLSCompliant (false)]
|
||||
public void Signal (Native.Signum signal)
|
||||
{
|
||||
Int32 r = Native.Syscall.kill (this.pid, signal);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
|
||||
public void WaitForExit ()
|
||||
{
|
||||
int status;
|
||||
int r;
|
||||
do {
|
||||
r = Native.Syscall.waitpid (pid, out status, (Native.WaitOptions) 0);
|
||||
} while (UnixMarshal.ShouldRetrySyscall (r));
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
}
|
||||
public 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
|
||||
|
@ -28,6 +28,7 @@
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
@ -35,193 +36,195 @@ using Mono.Unix.Native;
|
||||
|
||||
namespace Mono.Unix {
|
||||
|
||||
public class UnixSignal : WaitHandle {
|
||||
private int signum;
|
||||
private IntPtr signal_info;
|
||||
public class UnixSignal : WaitHandle {
|
||||
private readonly Int32 signum;
|
||||
private IntPtr signal_info;
|
||||
|
||||
static UnixSignal ()
|
||||
{
|
||||
Stdlib.VersionCheck ();
|
||||
}
|
||||
static UnixSignal() => Stdlib.VersionCheck();
|
||||
|
||||
public UnixSignal (Signum signum)
|
||||
{
|
||||
this.signum = NativeConvert.FromSignum (signum);
|
||||
this.signal_info = install (this.signum);
|
||||
if (this.signal_info == IntPtr.Zero) {
|
||||
throw new ArgumentException ("Unable to handle signal", "signum");
|
||||
}
|
||||
}
|
||||
public UnixSignal (Signum signum)
|
||||
{
|
||||
this.signum = NativeConvert.FromSignum (signum);
|
||||
this.signal_info = install (this.signum);
|
||||
if (this.signal_info == IntPtr.Zero) {
|
||||
throw new ArgumentException ("Unable to handle signal", "signum");
|
||||
}
|
||||
}
|
||||
|
||||
public UnixSignal (Mono.Unix.Native.RealTimeSignum rtsig)
|
||||
{
|
||||
signum = NativeConvert.FromRealTimeSignum (rtsig);
|
||||
this.signal_info = install (this.signum);
|
||||
Native.Errno err = Native.Stdlib.GetLastError ();
|
||||
if (this.signal_info == IntPtr.Zero) {
|
||||
if (err == Native.Errno.EADDRINUSE)
|
||||
throw new ArgumentException ("Signal registered outside of Mono.Posix", "signum");
|
||||
throw new ArgumentException ("Unable to handle signal", "signum");
|
||||
}
|
||||
}
|
||||
public UnixSignal (RealTimeSignum rtsig)
|
||||
{
|
||||
this.signum = NativeConvert.FromRealTimeSignum (rtsig);
|
||||
this.signal_info = install (this.signum);
|
||||
Native.Errno err = Native.Stdlib.GetLastError ();
|
||||
if (this.signal_info == IntPtr.Zero) {
|
||||
if (err == Native.Errno.EADDRINUSE) {
|
||||
throw new ArgumentException ("Signal registered outside of Mono.Posix", "signum");
|
||||
}
|
||||
|
||||
throw new ArgumentException ("Unable to handle signal", "signum");
|
||||
}
|
||||
}
|
||||
|
||||
public Signum Signum {
|
||||
get {
|
||||
if (IsRealTimeSignal)
|
||||
throw new InvalidOperationException ("This signal is a RealTimeSignum");
|
||||
return NativeConvert.ToSignum (signum);
|
||||
}
|
||||
}
|
||||
public Signum Signum {
|
||||
get {
|
||||
if (this.IsRealTimeSignal) {
|
||||
throw new InvalidOperationException ("This signal is a RealTimeSignum");
|
||||
}
|
||||
|
||||
return NativeConvert.ToSignum (this.signum);
|
||||
}
|
||||
}
|
||||
|
||||
public RealTimeSignum RealTimeSignum {
|
||||
get {
|
||||
if (!IsRealTimeSignal)
|
||||
throw new InvalidOperationException ("This signal is not a RealTimeSignum");
|
||||
return NativeConvert.ToRealTimeSignum (signum-GetSIGRTMIN ());
|
||||
}
|
||||
}
|
||||
public RealTimeSignum RealTimeSignum {
|
||||
get {
|
||||
if (!this.IsRealTimeSignal) {
|
||||
throw new InvalidOperationException ("This signal is not a RealTimeSignum");
|
||||
}
|
||||
|
||||
return NativeConvert.ToRealTimeSignum (this.signum -GetSIGRTMIN ());
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsRealTimeSignal {
|
||||
get {
|
||||
AssertValid ();
|
||||
int sigrtmin = GetSIGRTMIN ();
|
||||
if (sigrtmin == -1)
|
||||
return false;
|
||||
return signum >= sigrtmin;
|
||||
}
|
||||
}
|
||||
public Boolean IsRealTimeSignal {
|
||||
get {
|
||||
this.AssertValid ();
|
||||
Int32 sigrtmin = GetSIGRTMIN ();
|
||||
return sigrtmin == -1 ? false : this.signum >= sigrtmin;
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl,
|
||||
EntryPoint="Mono_Unix_UnixSignal_install", SetLastError=true)]
|
||||
private static extern IntPtr install (int signum);
|
||||
[DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl,
|
||||
EntryPoint="Mono_Unix_UnixSignal_install", SetLastError=true)]
|
||||
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||
private static extern IntPtr install (Int32 signum);
|
||||
|
||||
[DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl,
|
||||
EntryPoint="Mono_Unix_UnixSignal_uninstall")]
|
||||
private static extern int uninstall (IntPtr info);
|
||||
[DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl,
|
||||
EntryPoint="Mono_Unix_UnixSignal_uninstall")]
|
||||
[SuppressMessage("Microsoft.Design", "IDE1006", Justification = "Can not change name!")]
|
||||
private static extern Int32 uninstall (IntPtr info);
|
||||
|
||||
[UnmanagedFunctionPointer (CallingConvention.Cdecl)]
|
||||
delegate int Mono_Posix_RuntimeIsShuttingDown ();
|
||||
static Mono_Posix_RuntimeIsShuttingDown ShuttingDown = RuntimeShuttingDownCallback;
|
||||
|
||||
static int RuntimeShuttingDownCallback ()
|
||||
{
|
||||
return Environment.HasShutdownStarted ? 1 : 0;
|
||||
}
|
||||
[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 int WaitAny (IntPtr[] infos, int count, int timeout, Mono_Posix_RuntimeIsShuttingDown shutting_down);
|
||||
[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,
|
||||
[DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl,
|
||||
EntryPoint="Mono_Posix_SIGRTMIN")]
|
||||
internal static extern int GetSIGRTMIN ();
|
||||
internal static extern Int32 GetSIGRTMIN ();
|
||||
|
||||
[DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl,
|
||||
[DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl,
|
||||
EntryPoint="Mono_Posix_SIGRTMAX")]
|
||||
internal static extern int GetSIGRTMAX ();
|
||||
internal static extern Int32 GetSIGRTMAX ();
|
||||
|
||||
private void AssertValid ()
|
||||
{
|
||||
if (signal_info == IntPtr.Zero)
|
||||
throw new ObjectDisposedException (GetType().FullName);
|
||||
}
|
||||
private void AssertValid ()
|
||||
{
|
||||
if (this.signal_info == IntPtr.Zero) {
|
||||
throw new ObjectDisposedException (this.GetType().FullName);
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe SignalInfo* Info {
|
||||
get {
|
||||
AssertValid ();
|
||||
return (SignalInfo*) signal_info;
|
||||
}
|
||||
}
|
||||
private unsafe SignalInfo* Info {
|
||||
get {
|
||||
this.AssertValid ();
|
||||
return (SignalInfo*)this.signal_info;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSet {
|
||||
get {
|
||||
return Count > 0;
|
||||
}
|
||||
}
|
||||
public Boolean IsSet => this.Count > 0;
|
||||
|
||||
public unsafe bool Reset ()
|
||||
{
|
||||
int n = Interlocked.Exchange (ref Info->count, 0);
|
||||
return n != 0;
|
||||
}
|
||||
public unsafe Boolean Reset ()
|
||||
{
|
||||
Int32 n = Interlocked.Exchange (ref this.Info->count, 0);
|
||||
return n != 0;
|
||||
}
|
||||
|
||||
public unsafe int Count {
|
||||
get {return Info->count;}
|
||||
set {Interlocked.Exchange (ref Info->count, value);}
|
||||
}
|
||||
public unsafe Int32 Count {
|
||||
get => this.Info->count;
|
||||
set => Interlocked.Exchange(ref this.Info->count, value);
|
||||
}
|
||||
|
||||
// signum, count, write_fd, pipecnt, and pipelock are read from a signal handler thread
|
||||
// count and pipelock are both read and written from the signal handler thread
|
||||
// signum, count, write_fd, pipecnt, and pipelock are read from a signal handler thread
|
||||
// count and pipelock are both read and written from the signal handler thread
|
||||
#pragma warning disable 649
|
||||
[Map]
|
||||
struct SignalInfo {
|
||||
public int signum, count, read_fd, write_fd, pipecnt, pipelock, have_handler;
|
||||
public IntPtr handler; // Backed-up handler to restore when signal unregistered
|
||||
}
|
||||
[Map]
|
||||
struct SignalInfo {
|
||||
public Int32 signum, count, read_fd, write_fd, pipecnt, pipelock, have_handler;
|
||||
public IntPtr handler; // Backed-up handler to restore when signal unregistered
|
||||
}
|
||||
#pragma warning restore 649
|
||||
|
||||
#region WaitHandle overrides
|
||||
protected unsafe override void Dispose (bool disposing)
|
||||
{
|
||||
base.Dispose (disposing);
|
||||
if (signal_info == IntPtr.Zero)
|
||||
return;
|
||||
uninstall (signal_info);
|
||||
signal_info = IntPtr.Zero;
|
||||
}
|
||||
#region WaitHandle overrides
|
||||
protected unsafe override void Dispose (Boolean disposing)
|
||||
{
|
||||
base.Dispose (disposing);
|
||||
if (this.signal_info == IntPtr.Zero) {
|
||||
return;
|
||||
}
|
||||
|
||||
_ = uninstall(this.signal_info);
|
||||
this.signal_info = IntPtr.Zero;
|
||||
}
|
||||
|
||||
public override bool WaitOne ()
|
||||
{
|
||||
return WaitOne (-1, false);
|
||||
}
|
||||
public override Boolean WaitOne() => this.WaitOne(-1, false);
|
||||
|
||||
public override bool WaitOne (TimeSpan timeout, bool exitContext)
|
||||
{
|
||||
long ms = (long) timeout.TotalMilliseconds;
|
||||
if (ms < -1 || ms > Int32.MaxValue)
|
||||
throw new ArgumentOutOfRangeException ("timeout");
|
||||
return WaitOne ((int) ms, exitContext);
|
||||
}
|
||||
public override Boolean WaitOne (TimeSpan timeout, Boolean exitContext)
|
||||
{
|
||||
Int64 ms = (Int64) timeout.TotalMilliseconds;
|
||||
if (ms < -1 || ms > Int32.MaxValue) {
|
||||
throw new ArgumentOutOfRangeException ("timeout");
|
||||
}
|
||||
|
||||
return this.WaitOne ((Int32) ms, exitContext);
|
||||
}
|
||||
|
||||
public override bool WaitOne (int millisecondsTimeout, bool exitContext)
|
||||
{
|
||||
AssertValid ();
|
||||
if (exitContext)
|
||||
throw new InvalidOperationException ("exitContext is not supported");
|
||||
if (millisecondsTimeout == 0)
|
||||
return IsSet;
|
||||
return WaitAny (new UnixSignal[]{this}, millisecondsTimeout) == 0;
|
||||
}
|
||||
#endregion
|
||||
public override Boolean WaitOne (Int32 millisecondsTimeout, Boolean exitContext)
|
||||
{
|
||||
this.AssertValid ();
|
||||
if (exitContext) {
|
||||
throw new InvalidOperationException ("exitContext is not supported");
|
||||
}
|
||||
|
||||
return millisecondsTimeout == 0 ? this.IsSet : WaitAny (new UnixSignal[]{this}, millisecondsTimeout) == 0;
|
||||
}
|
||||
#endregion
|
||||
|
||||
public static int WaitAny (UnixSignal[] signals)
|
||||
{
|
||||
return WaitAny (signals, -1);
|
||||
}
|
||||
public static Int32 WaitAny(UnixSignal[] signals) => WaitAny(signals, -1);
|
||||
|
||||
public static int WaitAny (UnixSignal[] signals, TimeSpan timeout)
|
||||
{
|
||||
long ms = (long) timeout.TotalMilliseconds;
|
||||
if (ms < -1 || ms > Int32.MaxValue)
|
||||
throw new ArgumentOutOfRangeException ("timeout");
|
||||
return WaitAny (signals, (int) ms);
|
||||
}
|
||||
public static Int32 WaitAny (UnixSignal[] signals, TimeSpan timeout)
|
||||
{
|
||||
Int64 ms = (Int64) timeout.TotalMilliseconds;
|
||||
if (ms < -1 || ms > Int32.MaxValue) {
|
||||
throw new ArgumentOutOfRangeException ("timeout");
|
||||
}
|
||||
|
||||
return WaitAny (signals, (Int32) ms);
|
||||
}
|
||||
|
||||
|
||||
public static unsafe int WaitAny (UnixSignal[] signals, int millisecondsTimeout)
|
||||
{
|
||||
if (signals == null)
|
||||
throw new ArgumentNullException ("signals");
|
||||
if (millisecondsTimeout < -1)
|
||||
throw new ArgumentOutOfRangeException ("millisecondsTimeout");
|
||||
IntPtr[] infos = new IntPtr [signals.Length];
|
||||
for (int i = 0; i < signals.Length; ++i) {
|
||||
infos [i] = signals [i].signal_info;
|
||||
if (infos [i] == IntPtr.Zero)
|
||||
throw new InvalidOperationException ("Disposed UnixSignal");
|
||||
}
|
||||
return WaitAny (infos, infos.Length, millisecondsTimeout, ShuttingDown);
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe Int32 WaitAny (UnixSignal[] signals, Int32 millisecondsTimeout)
|
||||
{
|
||||
if (signals == null) {
|
||||
throw new ArgumentNullException ("signals");
|
||||
}
|
||||
|
||||
if (millisecondsTimeout < -1) {
|
||||
throw new ArgumentOutOfRangeException ("millisecondsTimeout");
|
||||
}
|
||||
|
||||
IntPtr[] infos = new IntPtr [signals.Length];
|
||||
for (Int32 i = 0; i < signals.Length; ++i) {
|
||||
infos [i] = signals [i].signal_info;
|
||||
if (infos [i] == IntPtr.Zero) {
|
||||
throw new InvalidOperationException ("Disposed UnixSignal");
|
||||
}
|
||||
}
|
||||
return WaitAny (infos, infos.Length, millisecondsTimeout, ShuttingDown);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,400 +36,427 @@ using Mono.Unix;
|
||||
|
||||
namespace Mono.Unix {
|
||||
|
||||
public sealed class UnixStream : Stream, IDisposable
|
||||
{
|
||||
public const int InvalidFileDescriptor = -1;
|
||||
public const int StandardInputFileDescriptor = 0;
|
||||
public const int StandardOutputFileDescriptor = 1;
|
||||
public const int StandardErrorFileDescriptor = 2;
|
||||
public sealed class UnixStream : Stream, IDisposable {
|
||||
public const Int32 InvalidFileDescriptor = -1;
|
||||
public const Int32 StandardInputFileDescriptor = 0;
|
||||
public const Int32 StandardOutputFileDescriptor = 1;
|
||||
public const Int32 StandardErrorFileDescriptor = 2;
|
||||
|
||||
public UnixStream (int fileDescriptor)
|
||||
: this (fileDescriptor, true) {}
|
||||
public UnixStream(Int32 fileDescriptor)
|
||||
: this(fileDescriptor, true) { }
|
||||
|
||||
public UnixStream (int fileDescriptor, bool ownsHandle)
|
||||
{
|
||||
if (InvalidFileDescriptor == fileDescriptor)
|
||||
throw new ArgumentException (Locale.GetText ("Invalid file descriptor"), "fileDescriptor");
|
||||
|
||||
this.fileDescriptor = fileDescriptor;
|
||||
this.owner = ownsHandle;
|
||||
|
||||
long offset = Native.Syscall.lseek (fileDescriptor, 0, Native.SeekFlags.SEEK_CUR);
|
||||
if (offset != -1)
|
||||
canSeek = true;
|
||||
long read = Native.Syscall.read (fileDescriptor, IntPtr.Zero, 0);
|
||||
if (read != -1)
|
||||
canRead = true;
|
||||
long write = Native.Syscall.write (fileDescriptor, IntPtr.Zero, 0);
|
||||
if (write != -1)
|
||||
canWrite = true;
|
||||
}
|
||||
public UnixStream(Int32 fileDescriptor, Boolean ownsHandle) {
|
||||
if(InvalidFileDescriptor == fileDescriptor) {
|
||||
throw new ArgumentException(Locale.GetText("Invalid file descriptor"), "fileDescriptor");
|
||||
}
|
||||
|
||||
this.fileDescriptor = fileDescriptor;
|
||||
this.owner = ownsHandle;
|
||||
|
||||
Int64 offset = Native.Syscall.lseek(fileDescriptor, 0, Native.SeekFlags.SEEK_CUR);
|
||||
if(offset != -1) {
|
||||
this.canSeek = true;
|
||||
}
|
||||
|
||||
Int64 read = Native.Syscall.read(fileDescriptor, IntPtr.Zero, 0);
|
||||
if(read != -1) {
|
||||
this.canRead = true;
|
||||
}
|
||||
|
||||
Int64 write = Native.Syscall.write(fileDescriptor, IntPtr.Zero, 0);
|
||||
if(write != -1) {
|
||||
this.canWrite = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void AssertNotDisposed ()
|
||||
{
|
||||
if (fileDescriptor == InvalidFileDescriptor)
|
||||
throw new ObjectDisposedException ("Invalid File Descriptor");
|
||||
}
|
||||
private void AssertNotDisposed() {
|
||||
if(this.fileDescriptor == InvalidFileDescriptor) {
|
||||
throw new ObjectDisposedException("Invalid File Descriptor");
|
||||
}
|
||||
}
|
||||
|
||||
public int Handle {
|
||||
get {return fileDescriptor;}
|
||||
}
|
||||
public Int32 Handle => this.fileDescriptor;
|
||||
|
||||
public override bool CanRead {
|
||||
get {return canRead;}
|
||||
}
|
||||
public override Boolean CanRead => this.canRead;
|
||||
|
||||
public override bool CanSeek {
|
||||
get {return canSeek;}
|
||||
}
|
||||
public override Boolean CanSeek => this.canSeek;
|
||||
|
||||
public override bool CanWrite {
|
||||
get {return canWrite;}
|
||||
}
|
||||
public override Boolean CanWrite => this.canWrite;
|
||||
|
||||
public override long Length {
|
||||
get {
|
||||
AssertNotDisposed ();
|
||||
if (!CanSeek)
|
||||
throw new NotSupportedException ("File descriptor doesn't support seeking");
|
||||
RefreshStat ();
|
||||
return stat.st_size;
|
||||
}
|
||||
}
|
||||
public override Int64 Length {
|
||||
get {
|
||||
this.AssertNotDisposed();
|
||||
if(!this.CanSeek) {
|
||||
throw new NotSupportedException("File descriptor doesn't support seeking");
|
||||
}
|
||||
|
||||
this.RefreshStat();
|
||||
return this.stat.st_size;
|
||||
}
|
||||
}
|
||||
|
||||
public override long Position {
|
||||
get {
|
||||
AssertNotDisposed ();
|
||||
if (!CanSeek)
|
||||
throw new NotSupportedException ("The stream does not support seeking");
|
||||
long pos = Native.Syscall.lseek (fileDescriptor, 0, Native.SeekFlags.SEEK_CUR);
|
||||
if (pos == -1)
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
return (long) pos;
|
||||
}
|
||||
set {
|
||||
Seek (value, SeekOrigin.Begin);
|
||||
}
|
||||
}
|
||||
public override Int64 Position {
|
||||
get {
|
||||
this.AssertNotDisposed();
|
||||
if(!this.CanSeek) {
|
||||
throw new NotSupportedException("The stream does not support seeking");
|
||||
}
|
||||
|
||||
Int64 pos = Native.Syscall.lseek(this.fileDescriptor, 0, Native.SeekFlags.SEEK_CUR);
|
||||
if(pos == -1) {
|
||||
UnixMarshal.ThrowExceptionForLastError();
|
||||
}
|
||||
|
||||
return (Int64)pos;
|
||||
}
|
||||
set => _ = this.Seek(value, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
[CLSCompliant (false)]
|
||||
public Native.FilePermissions Protection {
|
||||
get {
|
||||
RefreshStat ();
|
||||
return stat.st_mode;
|
||||
}
|
||||
set {
|
||||
// we can't change file type with fchmod, so clear out that portion
|
||||
value &= ~Native.FilePermissions.S_IFMT;
|
||||
int r = Native.Syscall.fchmod (fileDescriptor, value);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
}
|
||||
//[CLSCompliant(false)]
|
||||
public Native.FilePermissions Protection {
|
||||
get {
|
||||
this.RefreshStat();
|
||||
return this.stat.st_mode;
|
||||
}
|
||||
set {
|
||||
// we can't change file type with fchmod, so clear out that portion
|
||||
value &= ~Native.FilePermissions.S_IFMT;
|
||||
Int32 r = Native.Syscall.fchmod(this.fileDescriptor, value);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf(r);
|
||||
}
|
||||
}
|
||||
|
||||
public FileTypes FileType {
|
||||
get {
|
||||
int type = (int) Protection;
|
||||
return (FileTypes) (type & (int) UnixFileSystemInfo.AllFileTypes);
|
||||
}
|
||||
// no set as fchmod(2) won't accept changing the file type.
|
||||
}
|
||||
public FileTypes FileType {
|
||||
get {
|
||||
Int32 type = (Int32)this.Protection;
|
||||
return (FileTypes)(type & (Int32)UnixFileSystemInfo.AllFileTypes);
|
||||
}
|
||||
// no set as fchmod(2) won't accept changing the file type.
|
||||
}
|
||||
|
||||
public FileAccessPermissions FileAccessPermissions {
|
||||
get {
|
||||
int perms = (int) Protection;
|
||||
return (FileAccessPermissions) (perms & (int) FileAccessPermissions.AllPermissions);
|
||||
}
|
||||
set {
|
||||
int perms = (int) Protection;
|
||||
perms &= (int) ~FileAccessPermissions.AllPermissions;
|
||||
perms |= (int) value;
|
||||
Protection = (Native.FilePermissions) perms;
|
||||
}
|
||||
}
|
||||
public FileAccessPermissions FileAccessPermissions {
|
||||
get {
|
||||
Int32 perms = (Int32)this.Protection;
|
||||
return (FileAccessPermissions)(perms & (Int32)FileAccessPermissions.AllPermissions);
|
||||
}
|
||||
set {
|
||||
Int32 perms = (Int32)this.Protection;
|
||||
perms &= (Int32)~FileAccessPermissions.AllPermissions;
|
||||
perms |= (Int32)value;
|
||||
this.Protection = (Native.FilePermissions)perms;
|
||||
}
|
||||
}
|
||||
|
||||
public FileSpecialAttributes FileSpecialAttributes {
|
||||
get {
|
||||
int attrs = (int) Protection;
|
||||
return (FileSpecialAttributes) (attrs & (int) UnixFileSystemInfo.AllSpecialAttributes);
|
||||
}
|
||||
set {
|
||||
int perms = (int) Protection;
|
||||
perms &= (int) ~UnixFileSystemInfo.AllSpecialAttributes;
|
||||
perms |= (int) value;
|
||||
Protection = (Native.FilePermissions) perms;
|
||||
}
|
||||
}
|
||||
public FileSpecialAttributes FileSpecialAttributes {
|
||||
get {
|
||||
Int32 attrs = (Int32)this.Protection;
|
||||
return (FileSpecialAttributes)(attrs & (Int32)UnixFileSystemInfo.AllSpecialAttributes);
|
||||
}
|
||||
set {
|
||||
Int32 perms = (Int32)this.Protection;
|
||||
perms &= (Int32)~UnixFileSystemInfo.AllSpecialAttributes;
|
||||
perms |= (Int32)value;
|
||||
this.Protection = (Native.FilePermissions)perms;
|
||||
}
|
||||
}
|
||||
|
||||
public UnixUserInfo OwnerUser {
|
||||
get {RefreshStat (); return new UnixUserInfo (stat.st_uid);}
|
||||
}
|
||||
|
||||
public long OwnerUserId {
|
||||
get {RefreshStat (); return stat.st_uid;}
|
||||
}
|
||||
|
||||
public UnixGroupInfo OwnerGroup {
|
||||
get {RefreshStat (); return new UnixGroupInfo (stat.st_gid);}
|
||||
}
|
||||
|
||||
public long OwnerGroupId {
|
||||
get {RefreshStat (); return stat.st_gid;}
|
||||
}
|
||||
public UnixUserInfo OwnerUser {
|
||||
get {
|
||||
this.RefreshStat();
|
||||
return new UnixUserInfo(this.stat.st_uid);
|
||||
}
|
||||
}
|
||||
|
||||
public Int64 OwnerUserId {
|
||||
get {
|
||||
this.RefreshStat();
|
||||
return this.stat.st_uid;
|
||||
}
|
||||
}
|
||||
|
||||
public UnixGroupInfo OwnerGroup {
|
||||
get {
|
||||
this.RefreshStat();
|
||||
return new UnixGroupInfo(this.stat.st_gid);
|
||||
}
|
||||
}
|
||||
|
||||
public Int64 OwnerGroupId {
|
||||
get {
|
||||
this.RefreshStat();
|
||||
return this.stat.st_gid;
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshStat ()
|
||||
{
|
||||
AssertNotDisposed ();
|
||||
int r = Native.Syscall.fstat (fileDescriptor, out stat);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
private void RefreshStat() {
|
||||
this.AssertNotDisposed();
|
||||
Int32 r = Native.Syscall.fstat(this.fileDescriptor, out this.stat);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf(r);
|
||||
}
|
||||
|
||||
public void AdviseFileAccessPattern (FileAccessPattern pattern, long offset, long len)
|
||||
{
|
||||
FileHandleOperations.AdviseFileAccessPattern (fileDescriptor, pattern, offset, len);
|
||||
}
|
||||
public void AdviseFileAccessPattern(FileAccessPattern pattern, Int64 offset, Int64 len) => FileHandleOperations.AdviseFileAccessPattern(this.fileDescriptor, pattern, offset, len);
|
||||
|
||||
public void AdviseFileAccessPattern (FileAccessPattern pattern)
|
||||
{
|
||||
AdviseFileAccessPattern (pattern, 0, 0);
|
||||
}
|
||||
public void AdviseFileAccessPattern(FileAccessPattern pattern) => this.AdviseFileAccessPattern(pattern, 0, 0);
|
||||
|
||||
public override void Flush ()
|
||||
{
|
||||
}
|
||||
public override void Flush() {
|
||||
}
|
||||
|
||||
public override unsafe int Read ([In, Out] byte[] buffer, int offset, int count)
|
||||
{
|
||||
AssertNotDisposed ();
|
||||
AssertValidBuffer (buffer, offset, count);
|
||||
if (!CanRead)
|
||||
throw new NotSupportedException ("Stream does not support reading");
|
||||
|
||||
if (buffer.Length == 0)
|
||||
return 0;
|
||||
public override unsafe Int32 Read([In, Out] Byte[] buffer, Int32 offset, Int32 count) {
|
||||
this.AssertNotDisposed();
|
||||
this.AssertValidBuffer(buffer, offset, count);
|
||||
if(!this.CanRead) {
|
||||
throw new NotSupportedException("Stream does not support reading");
|
||||
}
|
||||
|
||||
if(buffer.Length == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Int64 r = 0;
|
||||
fixed(Byte* buf = &buffer[offset]) {
|
||||
do {
|
||||
r = Native.Syscall.read(this.fileDescriptor, buf, (UInt64)count);
|
||||
} while(UnixMarshal.ShouldRetrySyscall((Int32)r));
|
||||
}
|
||||
if(r == -1) {
|
||||
UnixMarshal.ThrowExceptionForLastError();
|
||||
}
|
||||
|
||||
return (Int32)r;
|
||||
}
|
||||
|
||||
long r = 0;
|
||||
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, 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");
|
||||
}
|
||||
}
|
||||
|
||||
private void AssertValidBuffer (byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (buffer == null)
|
||||
throw new ArgumentNullException ("buffer");
|
||||
if (offset < 0)
|
||||
throw new ArgumentOutOfRangeException ("offset", "< 0");
|
||||
if (count < 0)
|
||||
throw new ArgumentOutOfRangeException ("count", "< 0");
|
||||
if (offset > buffer.Length)
|
||||
throw new ArgumentException ("destination offset is beyond array size");
|
||||
if (offset > (buffer.Length - count))
|
||||
throw new ArgumentException ("would overrun buffer");
|
||||
}
|
||||
public unsafe Int32 ReadAtOffset([In, Out] Byte[] buffer,
|
||||
Int32 offset, Int32 count, Int64 fileOffset) {
|
||||
this.AssertNotDisposed();
|
||||
this.AssertValidBuffer(buffer, offset, count);
|
||||
if(!this.CanRead) {
|
||||
throw new NotSupportedException("Stream does not support reading");
|
||||
}
|
||||
|
||||
if(buffer.Length == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Int64 r = 0;
|
||||
fixed(Byte* buf = &buffer[offset]) {
|
||||
do {
|
||||
r = Native.Syscall.pread(this.fileDescriptor, buf, (UInt64)count, fileOffset);
|
||||
} while(UnixMarshal.ShouldRetrySyscall((Int32)r));
|
||||
}
|
||||
if(r == -1) {
|
||||
UnixMarshal.ThrowExceptionForLastError();
|
||||
}
|
||||
|
||||
return (Int32)r;
|
||||
}
|
||||
|
||||
public unsafe int ReadAtOffset ([In, Out] byte[] buffer,
|
||||
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)
|
||||
return 0;
|
||||
public override Int64 Seek(Int64 offset, SeekOrigin origin) {
|
||||
this.AssertNotDisposed();
|
||||
if(!this.CanSeek) {
|
||||
throw new NotSupportedException("The File Descriptor 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;
|
||||
}
|
||||
|
||||
long r = 0;
|
||||
fixed (byte* buf = &buffer[offset]) {
|
||||
do {
|
||||
r = Native.Syscall.pread (fileDescriptor, buf, (ulong) count, fileOffset);
|
||||
} while (UnixMarshal.ShouldRetrySyscall ((int) r));
|
||||
}
|
||||
if (r == -1)
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
return (int) r;
|
||||
}
|
||||
Int64 pos = Native.Syscall.lseek(this.fileDescriptor, offset, sf);
|
||||
if(pos == -1) {
|
||||
UnixMarshal.ThrowExceptionForLastError();
|
||||
}
|
||||
|
||||
return (Int64)pos;
|
||||
}
|
||||
|
||||
public override long Seek (long offset, SeekOrigin origin)
|
||||
{
|
||||
AssertNotDisposed ();
|
||||
if (!CanSeek)
|
||||
throw new NotSupportedException ("The File Descriptor 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;
|
||||
}
|
||||
public override void SetLength(Int64 value) {
|
||||
this.AssertNotDisposed();
|
||||
if(value < 0) {
|
||||
throw new ArgumentOutOfRangeException("value", "< 0");
|
||||
}
|
||||
|
||||
if(!this.CanSeek && !this.CanWrite) {
|
||||
throw new NotSupportedException("You can't truncating the current file descriptor");
|
||||
}
|
||||
|
||||
Int32 r;
|
||||
do {
|
||||
r = Native.Syscall.ftruncate(this.fileDescriptor, value);
|
||||
} while(UnixMarshal.ShouldRetrySyscall(r));
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf(r);
|
||||
}
|
||||
|
||||
long pos = Native.Syscall.lseek (fileDescriptor, offset, sf);
|
||||
if (pos == -1)
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
return (long) pos;
|
||||
}
|
||||
public override unsafe void Write(Byte[] buffer, Int32 offset, Int32 count) {
|
||||
this.AssertNotDisposed();
|
||||
this.AssertValidBuffer(buffer, offset, count);
|
||||
if(!this.CanWrite) {
|
||||
throw new NotSupportedException("File Descriptor does not support writing");
|
||||
}
|
||||
|
||||
if(buffer.Length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Int64 r = 0;
|
||||
fixed(Byte* buf = &buffer[offset]) {
|
||||
do {
|
||||
r = Native.Syscall.write(this.fileDescriptor, buf, (UInt64)count);
|
||||
} while(UnixMarshal.ShouldRetrySyscall((Int32)r));
|
||||
}
|
||||
if(r == -1) {
|
||||
UnixMarshal.ThrowExceptionForLastError();
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe void WriteAtOffset(Byte[] buffer,
|
||||
Int32 offset, Int32 count, Int64 fileOffset) {
|
||||
this.AssertNotDisposed();
|
||||
this.AssertValidBuffer(buffer, offset, count);
|
||||
if(!this.CanWrite) {
|
||||
throw new NotSupportedException("File Descriptor does not support writing");
|
||||
}
|
||||
|
||||
if(buffer.Length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Int64 r = 0;
|
||||
fixed(Byte* buf = &buffer[offset]) {
|
||||
do {
|
||||
r = Native.Syscall.pwrite(this.fileDescriptor, buf, (UInt64)count, fileOffset);
|
||||
} while(UnixMarshal.ShouldRetrySyscall((Int32)r));
|
||||
}
|
||||
if(r == -1) {
|
||||
UnixMarshal.ThrowExceptionForLastError();
|
||||
}
|
||||
}
|
||||
|
||||
public override void SetLength (long value)
|
||||
{
|
||||
AssertNotDisposed ();
|
||||
if (value < 0)
|
||||
throw new ArgumentOutOfRangeException ("value", "< 0");
|
||||
if (!CanSeek && !CanWrite)
|
||||
throw new NotSupportedException ("You can't truncating the current file descriptor");
|
||||
|
||||
int r;
|
||||
do {
|
||||
r = Native.Syscall.ftruncate (fileDescriptor, value);
|
||||
} while (UnixMarshal.ShouldRetrySyscall (r));
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
public void SendTo(UnixStream output) => this.SendTo(output, (UInt64)output.Length);
|
||||
|
||||
public override unsafe void Write (byte[] buffer, int offset, int count)
|
||||
{
|
||||
AssertNotDisposed ();
|
||||
AssertValidBuffer (buffer, offset, count);
|
||||
if (!CanWrite)
|
||||
throw new NotSupportedException ("File Descriptor does not support writing");
|
||||
//[CLSCompliant(false)]
|
||||
public void SendTo(UnixStream output, UInt64 count) => this.SendTo(output.Handle, count);
|
||||
|
||||
if (buffer.Length == 0)
|
||||
return;
|
||||
//[CLSCompliant(false)]
|
||||
public void SendTo(Int32 out_fd, UInt64 count) {
|
||||
if(!this.CanWrite) {
|
||||
throw new NotSupportedException("Unable to write to the current file descriptor");
|
||||
}
|
||||
|
||||
Int64 offset = this.Position;
|
||||
Int64 r = Native.Syscall.sendfile(out_fd, this.fileDescriptor, ref offset, count);
|
||||
if(r == -1) {
|
||||
UnixMarshal.ThrowExceptionForLastError();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetOwner(Int64 user, Int64 group) {
|
||||
this.AssertNotDisposed();
|
||||
|
||||
long r = 0;
|
||||
fixed (byte* buf = &buffer[offset]) {
|
||||
do {
|
||||
r = Native.Syscall.write (fileDescriptor, buf, (ulong) count);
|
||||
} while (UnixMarshal.ShouldRetrySyscall ((int) r));
|
||||
}
|
||||
if (r == -1)
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
}
|
||||
|
||||
public unsafe void WriteAtOffset (byte[] buffer,
|
||||
int offset, int count, long fileOffset)
|
||||
{
|
||||
AssertNotDisposed ();
|
||||
AssertValidBuffer (buffer, offset, count);
|
||||
if (!CanWrite)
|
||||
throw new NotSupportedException ("File Descriptor does not support writing");
|
||||
Int32 r = Native.Syscall.fchown(this.fileDescriptor,
|
||||
Convert.ToUInt32(user), Convert.ToUInt32(group));
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf(r);
|
||||
}
|
||||
|
||||
if (buffer.Length == 0)
|
||||
return;
|
||||
public void SetOwner(String user, String group) {
|
||||
this.AssertNotDisposed();
|
||||
|
||||
long r = 0;
|
||||
fixed (byte* buf = &buffer[offset]) {
|
||||
do {
|
||||
r = Native.Syscall.pwrite (fileDescriptor, buf, (ulong) count, fileOffset);
|
||||
} while (UnixMarshal.ShouldRetrySyscall ((int) r));
|
||||
}
|
||||
if (r == -1)
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
}
|
||||
Int64 uid = new UnixUserInfo(user).UserId;
|
||||
Int64 gid = new UnixGroupInfo(group).GroupId;
|
||||
this.SetOwner(uid, gid);
|
||||
}
|
||||
|
||||
public void SendTo (UnixStream output)
|
||||
{
|
||||
SendTo (output, (ulong) output.Length);
|
||||
}
|
||||
public void SetOwner(String user) {
|
||||
this.AssertNotDisposed();
|
||||
|
||||
[CLSCompliant (false)]
|
||||
public void SendTo (UnixStream output, ulong count)
|
||||
{
|
||||
SendTo (output.Handle, count);
|
||||
}
|
||||
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 void SendTo (int out_fd, ulong count)
|
||||
{
|
||||
if (!CanWrite)
|
||||
throw new NotSupportedException ("Unable to write to the current file descriptor");
|
||||
long offset = Position;
|
||||
long r = Native.Syscall.sendfile (out_fd, fileDescriptor, ref offset, count);
|
||||
if (r == -1)
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
}
|
||||
|
||||
public void SetOwner (long user, long group)
|
||||
{
|
||||
AssertNotDisposed ();
|
||||
//[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;
|
||||
}
|
||||
|
||||
int r = Native.Syscall.fchown (fileDescriptor,
|
||||
Convert.ToUInt32 (user), Convert.ToUInt32 (group));
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
~UnixStream() {
|
||||
this.Close();
|
||||
}
|
||||
|
||||
public void SetOwner (string user, string group)
|
||||
{
|
||||
AssertNotDisposed ();
|
||||
public override void Close() {
|
||||
if(this.fileDescriptor == InvalidFileDescriptor) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.Flush();
|
||||
|
||||
long uid = new UnixUserInfo (user).UserId;
|
||||
long gid = new UnixGroupInfo (group).GroupId;
|
||||
SetOwner (uid, gid);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
public void SetOwner (string user)
|
||||
{
|
||||
AssertNotDisposed ();
|
||||
|
||||
Native.Passwd pw = Native.Syscall.getpwnam (user);
|
||||
if (pw == null)
|
||||
throw new ArgumentException (Locale.GetText ("invalid username"), "user");
|
||||
long uid = pw.pw_uid;
|
||||
long gid = pw.pw_gid;
|
||||
SetOwner (uid, gid);
|
||||
}
|
||||
|
||||
[CLSCompliant (false)]
|
||||
public long GetConfigurationValue (Native.PathconfName name)
|
||||
{
|
||||
AssertNotDisposed ();
|
||||
long r = Native.Syscall.fpathconf (fileDescriptor, name);
|
||||
if (r == -1 && Native.Syscall.GetLastError() != (Native.Errno) 0)
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
return r;
|
||||
}
|
||||
|
||||
~UnixStream ()
|
||||
{
|
||||
Close ();
|
||||
}
|
||||
|
||||
public override void Close ()
|
||||
{
|
||||
if (fileDescriptor == InvalidFileDescriptor)
|
||||
return;
|
||||
|
||||
Flush ();
|
||||
|
||||
if (!owner)
|
||||
return;
|
||||
|
||||
int r;
|
||||
do {
|
||||
r = Native.Syscall.close (fileDescriptor);
|
||||
} while (UnixMarshal.ShouldRetrySyscall (r));
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
fileDescriptor = InvalidFileDescriptor;
|
||||
GC.SuppressFinalize (this);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose ()
|
||||
{
|
||||
if (fileDescriptor != InvalidFileDescriptor && owner) {
|
||||
Close ();
|
||||
}
|
||||
GC.SuppressFinalize (this);
|
||||
}
|
||||
|
||||
private bool canSeek = false;
|
||||
private bool canRead = false;
|
||||
private bool canWrite = false;
|
||||
private bool owner = true;
|
||||
private int fileDescriptor = InvalidFileDescriptor;
|
||||
private Native.Stat stat;
|
||||
}
|
||||
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
|
||||
|
@ -27,82 +27,61 @@
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Mono.Unix;
|
||||
|
||||
namespace Mono.Unix {
|
||||
|
||||
public sealed class UnixSymbolicLinkInfo : UnixFileSystemInfo
|
||||
{
|
||||
public UnixSymbolicLinkInfo (string path)
|
||||
: base (path)
|
||||
{
|
||||
}
|
||||
public sealed class UnixSymbolicLinkInfo : UnixFileSystemInfo
|
||||
{
|
||||
public UnixSymbolicLinkInfo (String path)
|
||||
: base (path)
|
||||
{
|
||||
}
|
||||
|
||||
internal UnixSymbolicLinkInfo (string path, Native.Stat stat)
|
||||
: base (path, stat)
|
||||
{
|
||||
}
|
||||
internal UnixSymbolicLinkInfo (String path, Native.Stat stat)
|
||||
: base (path, stat)
|
||||
{
|
||||
}
|
||||
|
||||
public override string Name {
|
||||
get {return UnixPath.GetFileName (FullPath);}
|
||||
}
|
||||
public override String Name => UnixPath.GetFileName(this.FullPath);
|
||||
|
||||
[Obsolete ("Use GetContents()")]
|
||||
public UnixFileSystemInfo Contents {
|
||||
get {return GetContents ();}
|
||||
}
|
||||
[Obsolete("Use GetContents()")]
|
||||
public UnixFileSystemInfo Contents => this.GetContents();
|
||||
|
||||
public string ContentsPath {
|
||||
get {
|
||||
return UnixPath.ReadLink (FullPath);
|
||||
}
|
||||
}
|
||||
public String ContentsPath => UnixPath.ReadLink(this.FullPath);
|
||||
|
||||
public bool HasContents {
|
||||
get {
|
||||
return UnixPath.TryReadLink (FullPath) != null;
|
||||
}
|
||||
}
|
||||
public Boolean HasContents => UnixPath.TryReadLink(this.FullPath) != null;
|
||||
|
||||
public UnixFileSystemInfo GetContents ()
|
||||
{
|
||||
return UnixFileSystemInfo.GetFileSystemEntry (
|
||||
UnixPath.Combine (UnixPath.GetDirectoryName (FullPath),
|
||||
ContentsPath));
|
||||
}
|
||||
public UnixFileSystemInfo GetContents() => UnixFileSystemInfo.GetFileSystemEntry(
|
||||
UnixPath.Combine(UnixPath.GetDirectoryName(this.FullPath),
|
||||
this.ContentsPath));
|
||||
|
||||
public void CreateSymbolicLinkTo (string path)
|
||||
{
|
||||
int r = Native.Syscall.symlink (path, FullName);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
public void CreateSymbolicLinkTo (String path)
|
||||
{
|
||||
Int32 r = Native.Syscall.symlink (path, this.FullName);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
|
||||
public void CreateSymbolicLinkTo (UnixFileSystemInfo path)
|
||||
{
|
||||
int r = Native.Syscall.symlink (path.FullName, FullName);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
public void CreateSymbolicLinkTo (UnixFileSystemInfo path)
|
||||
{
|
||||
Int32 r = Native.Syscall.symlink (path.FullName, this.FullName);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
|
||||
public override void Delete ()
|
||||
{
|
||||
int r = Native.Syscall.unlink (FullPath);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
base.Refresh ();
|
||||
}
|
||||
public override void Delete ()
|
||||
{
|
||||
Int32 r = Native.Syscall.unlink (this.FullPath);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
this.Refresh();
|
||||
}
|
||||
|
||||
public override void SetOwner (long owner, long group)
|
||||
{
|
||||
int r = Native.Syscall.lchown (FullPath, Convert.ToUInt32 (owner), Convert.ToUInt32 (group));
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
public override void SetOwner (Int64 owner, Int64 group)
|
||||
{
|
||||
Int32 r = Native.Syscall.lchown (this.FullPath, Convert.ToUInt32 (owner), Convert.ToUInt32 (group));
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
}
|
||||
|
||||
protected override bool GetFileStatus (string path, out Native.Stat stat)
|
||||
{
|
||||
return Native.Syscall.lstat (path, out stat) == 0;
|
||||
}
|
||||
}
|
||||
protected override Boolean GetFileStatus(String path, out Native.Stat stat) => Native.Syscall.lstat(path, out stat) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
// vim: noexpandtab
|
||||
|
@ -29,165 +29,121 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Text;
|
||||
using Mono.Unix;
|
||||
|
||||
namespace Mono.Unix {
|
||||
|
||||
public sealed class UnixUserInfo
|
||||
{
|
||||
private Native.Passwd passwd;
|
||||
public sealed class UnixUserInfo
|
||||
{
|
||||
private readonly Native.Passwd passwd;
|
||||
|
||||
public UnixUserInfo (string user)
|
||||
{
|
||||
passwd = new Native.Passwd ();
|
||||
Native.Passwd pw;
|
||||
int r = Native.Syscall.getpwnam_r (user, passwd, out pw);
|
||||
if (r != 0 || pw == null)
|
||||
throw new ArgumentException (Locale.GetText ("invalid username"), "user");
|
||||
}
|
||||
public UnixUserInfo (String user)
|
||||
{
|
||||
this.passwd = new Native.Passwd ();
|
||||
Int32 r = Native.Syscall.getpwnam_r(user, this.passwd, out Native.Passwd pw);
|
||||
if (r != 0 || pw == null) {
|
||||
throw new ArgumentException (Locale.GetText ("invalid username"), "user");
|
||||
}
|
||||
}
|
||||
|
||||
[CLSCompliant (false)]
|
||||
public UnixUserInfo (uint user)
|
||||
{
|
||||
passwd = new Native.Passwd ();
|
||||
Native.Passwd pw;
|
||||
int r = Native.Syscall.getpwuid_r (user, passwd, out pw);
|
||||
if (r != 0 || pw == null)
|
||||
throw new ArgumentException (Locale.GetText ("invalid user id"), "user");
|
||||
}
|
||||
//[CLSCompliant (false)]
|
||||
public UnixUserInfo (UInt32 user)
|
||||
{
|
||||
this.passwd = new Native.Passwd ();
|
||||
Int32 r = Native.Syscall.getpwuid_r(user, this.passwd, out Native.Passwd pw);
|
||||
if (r != 0 || pw == null) {
|
||||
throw new ArgumentException (Locale.GetText ("invalid user id"), "user");
|
||||
}
|
||||
}
|
||||
|
||||
public UnixUserInfo (long user)
|
||||
{
|
||||
passwd = new Native.Passwd ();
|
||||
Native.Passwd pw;
|
||||
int r = Native.Syscall.getpwuid_r (Convert.ToUInt32 (user), passwd, out pw);
|
||||
if (r != 0 || pw == null)
|
||||
throw new ArgumentException (Locale.GetText ("invalid user id"), "user");
|
||||
}
|
||||
public UnixUserInfo (Int64 user)
|
||||
{
|
||||
this.passwd = new Native.Passwd ();
|
||||
Int32 r = Native.Syscall.getpwuid_r(Convert.ToUInt32(user), this.passwd, out Native.Passwd pw);
|
||||
if (r != 0 || pw == null) {
|
||||
throw new ArgumentException (Locale.GetText ("invalid user id"), "user");
|
||||
}
|
||||
}
|
||||
|
||||
public UnixUserInfo (Native.Passwd passwd)
|
||||
{
|
||||
this.passwd = CopyPasswd (passwd);
|
||||
}
|
||||
public UnixUserInfo(Native.Passwd passwd) => this.passwd = CopyPasswd(passwd);
|
||||
|
||||
private static Native.Passwd CopyPasswd (Native.Passwd pw)
|
||||
{
|
||||
Native.Passwd p = new Native.Passwd ();
|
||||
private static Native.Passwd CopyPasswd(Native.Passwd pw) => new Native.Passwd {
|
||||
pw_name = pw.pw_name,
|
||||
pw_passwd = pw.pw_passwd,
|
||||
pw_uid = pw.pw_uid,
|
||||
pw_gid = pw.pw_gid,
|
||||
pw_gecos = pw.pw_gecos,
|
||||
pw_dir = pw.pw_dir,
|
||||
pw_shell = pw.pw_shell
|
||||
};
|
||||
|
||||
p.pw_name = pw.pw_name;
|
||||
p.pw_passwd = pw.pw_passwd;
|
||||
p.pw_uid = pw.pw_uid;
|
||||
p.pw_gid = pw.pw_gid;
|
||||
p.pw_gecos = pw.pw_gecos;
|
||||
p.pw_dir = pw.pw_dir;
|
||||
p.pw_shell = pw.pw_shell;
|
||||
public String UserName => this.passwd.pw_name;
|
||||
|
||||
return p;
|
||||
}
|
||||
public String Password => this.passwd.pw_passwd;
|
||||
|
||||
public string UserName {
|
||||
get {return passwd.pw_name;}
|
||||
}
|
||||
public Int64 UserId => this.passwd.pw_uid;
|
||||
|
||||
public string Password {
|
||||
get {return passwd.pw_passwd;}
|
||||
}
|
||||
public UnixGroupInfo Group => new UnixGroupInfo(this.passwd.pw_gid);
|
||||
|
||||
public long UserId {
|
||||
get {return passwd.pw_uid;}
|
||||
}
|
||||
public Int64 GroupId => this.passwd.pw_gid;
|
||||
|
||||
public UnixGroupInfo Group {
|
||||
get {return new UnixGroupInfo (passwd.pw_gid);}
|
||||
}
|
||||
public String GroupName => this.Group.GroupName;
|
||||
|
||||
public long GroupId {
|
||||
get {return passwd.pw_gid;}
|
||||
}
|
||||
public String RealName => this.passwd.pw_gecos;
|
||||
|
||||
public string GroupName {
|
||||
get {return Group.GroupName;}
|
||||
}
|
||||
public String HomeDirectory => this.passwd.pw_dir;
|
||||
|
||||
public string RealName {
|
||||
get {return passwd.pw_gecos;}
|
||||
}
|
||||
public String ShellProgram => this.passwd.pw_shell;
|
||||
|
||||
public string HomeDirectory {
|
||||
get {return passwd.pw_dir;}
|
||||
}
|
||||
public override Int32 GetHashCode() => this.passwd.GetHashCode();
|
||||
|
||||
public string ShellProgram {
|
||||
get {return passwd.pw_shell;}
|
||||
}
|
||||
public override Boolean Equals(Object obj) => obj == null || this.GetType() != obj.GetType() ? false : this.passwd.Equals(((UnixUserInfo)obj).passwd);
|
||||
|
||||
public override int GetHashCode ()
|
||||
{
|
||||
return passwd.GetHashCode ();
|
||||
}
|
||||
public override String ToString() => this.passwd.ToString();
|
||||
|
||||
public override bool Equals (object obj)
|
||||
{
|
||||
if (obj == null || GetType () != obj.GetType())
|
||||
return false;
|
||||
return passwd.Equals (((UnixUserInfo) obj).passwd);
|
||||
}
|
||||
public static UnixUserInfo GetRealUser() => new UnixUserInfo(GetRealUserId());
|
||||
|
||||
public override string ToString ()
|
||||
{
|
||||
return passwd.ToString ();
|
||||
}
|
||||
public static Int64 GetRealUserId() => Native.Syscall.getuid();
|
||||
|
||||
public static UnixUserInfo GetRealUser ()
|
||||
{
|
||||
return new UnixUserInfo (GetRealUserId ());
|
||||
}
|
||||
// I would hope that this is the same as GetCurrentUserName, but it is a
|
||||
// different syscall, so who knows.
|
||||
public static String GetLoginName ()
|
||||
{
|
||||
StringBuilder buf = new StringBuilder (4);
|
||||
Int32 r;
|
||||
do {
|
||||
buf.Capacity *= 2;
|
||||
r = Native.Syscall.getlogin_r (buf, (UInt64) buf.Capacity);
|
||||
} while (r == -1 && Native.Stdlib.GetLastError() == Native.Errno.ERANGE);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
return buf.ToString ();
|
||||
}
|
||||
|
||||
public static long GetRealUserId ()
|
||||
{
|
||||
return Native.Syscall.getuid ();
|
||||
}
|
||||
public Native.Passwd ToPasswd() => CopyPasswd(this.passwd);
|
||||
|
||||
// I would hope that this is the same as GetCurrentUserName, but it is a
|
||||
// different syscall, so who knows.
|
||||
public static string GetLoginName ()
|
||||
{
|
||||
StringBuilder buf = new StringBuilder (4);
|
||||
int r;
|
||||
do {
|
||||
buf.Capacity *= 2;
|
||||
r = Native.Syscall.getlogin_r (buf, (ulong) buf.Capacity);
|
||||
} while (r == (-1) && Native.Stdlib.GetLastError() == Native.Errno.ERANGE);
|
||||
UnixMarshal.ThrowExceptionForLastErrorIf (r);
|
||||
return buf.ToString ();
|
||||
}
|
||||
|
||||
public Native.Passwd ToPasswd ()
|
||||
{
|
||||
return CopyPasswd (passwd);
|
||||
}
|
||||
|
||||
public static UnixUserInfo[] GetLocalUsers ()
|
||||
{
|
||||
ArrayList entries = new ArrayList ();
|
||||
lock (Native.Syscall.pwd_lock) {
|
||||
if (Native.Syscall.setpwent () != 0) {
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
}
|
||||
try {
|
||||
Native.Passwd p;
|
||||
while ((p = Native.Syscall.getpwent()) != null)
|
||||
entries.Add (new UnixUserInfo (p));
|
||||
if (Native.Syscall.GetLastError () != (Native.Errno) 0)
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
}
|
||||
finally {
|
||||
Native.Syscall.endpwent ();
|
||||
}
|
||||
}
|
||||
return (UnixUserInfo[]) entries.ToArray (typeof(UnixUserInfo));
|
||||
}
|
||||
}
|
||||
public static UnixUserInfo[] GetLocalUsers ()
|
||||
{
|
||||
ArrayList entries = new ArrayList ();
|
||||
lock (Native.Syscall.pwd_lock) {
|
||||
if (Native.Syscall.setpwent () != 0) {
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
}
|
||||
try {
|
||||
Native.Passwd p;
|
||||
while ((p = Native.Syscall.getpwent()) != null) {
|
||||
_ = entries.Add(new UnixUserInfo(p));
|
||||
}
|
||||
|
||||
if (Native.Syscall.GetLastError () != (Native.Errno) 0) {
|
||||
UnixMarshal.ThrowExceptionForLastError ();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
_ = Native.Syscall.endpwent();
|
||||
}
|
||||
}
|
||||
return (UnixUserInfo[]) entries.ToArray (typeof(UnixUserInfo));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// vim: noexpandtab
|
||||
|
Loading…
Reference in New Issue
Block a user