From 749da0d8db24cd037bdfb93761d31282f361923c Mon Sep 17 00:00:00 2001 From: BlubbFish Date: Sun, 17 Feb 2019 15:51:09 +0100 Subject: [PATCH] Create Mono.Posix library --- .gitignore | 3 + Mono.Posix.sln | 25 + Mono.Posix/Consts.cs | 136 + Mono.Posix/Locale.cs | 51 + Mono.Posix/Mono.Posix.csproj | 107 + Mono.Posix/Mono.Posix/Catalog.cs | 86 + Mono.Posix/Mono.Posix/PeerCred.cs | 81 + Mono.Posix/Mono.Posix/Syscall.cs | 641 ++ Mono.Posix/Mono.Posix/UnixEndPoint.cs | 118 + .../.gitattributes | 1 + .../UnixBinaryClientFormatterSink.cs | 167 + .../UnixBinaryClientFormatterSinkProvider.cs | 80 + .../UnixBinaryCore.cs | 148 + .../UnixBinaryServerFormatterSink.cs | 163 + .../UnixBinaryServerFormatterSinkProvider.cs | 85 + .../UnixChannel.cs | 143 + .../UnixClientChannel.cs | 134 + .../UnixClientTransportSink.cs | 193 + .../UnixClientTransportSinkProvider.cs | 62 + .../UnixConnectionPool.cs | 311 + .../UnixMessageIO.cs | 283 + .../UnixServerChannel.cs | 330 + .../UnixServerTransportSink.cs | 136 + Mono.Posix/Mono.Unix.Native/CdeclFunction.cs | 188 + .../Mono.Unix.Native/FileNameMarshaler.cs | 79 + Mono.Posix/Mono.Unix.Native/MapAttribute.cs | 60 + Mono.Posix/Mono.Unix.Native/NativeConvert.cs | 488 ++ .../NativeConvert.generated.cs | 1451 ++++ Mono.Posix/Mono.Unix.Native/RealTimeSignum.cs | 81 + Mono.Posix/Mono.Unix.Native/Stdlib.cs | 1171 ++++ Mono.Posix/Mono.Unix.Native/Syscall.cs | 5881 +++++++++++++++++ Mono.Posix/Mono.Unix.Native/TypeAttributes.cs | 138 + Mono.Posix/Mono.Unix/AbstractUnixEndPoint.cs | 123 + Mono.Posix/Mono.Unix/Catalog.cs | 136 + Mono.Posix/Mono.Unix/FileAccessPattern.cs | 43 + Mono.Posix/Mono.Unix/FileAccessPermissions.cs | 53 + Mono.Posix/Mono.Unix/FileHandleOperations.cs | 82 + Mono.Posix/Mono.Unix/FileSpecialAttributes.cs | 41 + Mono.Posix/Mono.Unix/FileTypes.cs | 44 + Mono.Posix/Mono.Unix/PeerCred.cs | 81 + Mono.Posix/Mono.Unix/StdioFileStream.cs | 406 ++ Mono.Posix/Mono.Unix/UnixClient.cs | 230 + Mono.Posix/Mono.Unix/UnixDirectoryInfo.cs | 250 + Mono.Posix/Mono.Unix/UnixDriveInfo.cs | 195 + Mono.Posix/Mono.Unix/UnixEncoding.cs | 856 +++ Mono.Posix/Mono.Unix/UnixEndPoint.cs | 133 + Mono.Posix/Mono.Unix/UnixEnvironment.cs | 238 + Mono.Posix/Mono.Unix/UnixFileInfo.cs | 147 + Mono.Posix/Mono.Unix/UnixFileSystemInfo.cs | 428 ++ Mono.Posix/Mono.Unix/UnixGroupInfo.cs | 149 + Mono.Posix/Mono.Unix/UnixIOException.cs | 104 + Mono.Posix/Mono.Unix/UnixListener.cs | 173 + Mono.Posix/Mono.Unix/UnixMarshal.cs | 496 ++ Mono.Posix/Mono.Unix/UnixPath.cs | 286 + Mono.Posix/Mono.Unix/UnixPipes.cs | 88 + Mono.Posix/Mono.Unix/UnixProcess.cs | 157 + Mono.Posix/Mono.Unix/UnixSignal.cs | 227 + Mono.Posix/Mono.Unix/UnixStream.cs | 435 ++ Mono.Posix/Mono.Unix/UnixSymbolicLinkInfo.cs | 108 + Mono.Posix/Mono.Unix/UnixUserInfo.cs | 193 + Mono.Posix/Properties/AssemblyInfo.cs | 36 + 61 files changed, 18959 insertions(+) create mode 100644 .gitignore create mode 100644 Mono.Posix.sln create mode 100644 Mono.Posix/Consts.cs create mode 100644 Mono.Posix/Locale.cs create mode 100644 Mono.Posix/Mono.Posix.csproj create mode 100644 Mono.Posix/Mono.Posix/Catalog.cs create mode 100644 Mono.Posix/Mono.Posix/PeerCred.cs create mode 100644 Mono.Posix/Mono.Posix/Syscall.cs create mode 100644 Mono.Posix/Mono.Posix/UnixEndPoint.cs create mode 100644 Mono.Posix/Mono.Remoting.Channels.Unix/.gitattributes create mode 100644 Mono.Posix/Mono.Remoting.Channels.Unix/UnixBinaryClientFormatterSink.cs create mode 100644 Mono.Posix/Mono.Remoting.Channels.Unix/UnixBinaryClientFormatterSinkProvider.cs create mode 100644 Mono.Posix/Mono.Remoting.Channels.Unix/UnixBinaryCore.cs create mode 100644 Mono.Posix/Mono.Remoting.Channels.Unix/UnixBinaryServerFormatterSink.cs create mode 100644 Mono.Posix/Mono.Remoting.Channels.Unix/UnixBinaryServerFormatterSinkProvider.cs create mode 100644 Mono.Posix/Mono.Remoting.Channels.Unix/UnixChannel.cs create mode 100644 Mono.Posix/Mono.Remoting.Channels.Unix/UnixClientChannel.cs create mode 100644 Mono.Posix/Mono.Remoting.Channels.Unix/UnixClientTransportSink.cs create mode 100644 Mono.Posix/Mono.Remoting.Channels.Unix/UnixClientTransportSinkProvider.cs create mode 100644 Mono.Posix/Mono.Remoting.Channels.Unix/UnixConnectionPool.cs create mode 100644 Mono.Posix/Mono.Remoting.Channels.Unix/UnixMessageIO.cs create mode 100644 Mono.Posix/Mono.Remoting.Channels.Unix/UnixServerChannel.cs create mode 100644 Mono.Posix/Mono.Remoting.Channels.Unix/UnixServerTransportSink.cs create mode 100644 Mono.Posix/Mono.Unix.Native/CdeclFunction.cs create mode 100644 Mono.Posix/Mono.Unix.Native/FileNameMarshaler.cs create mode 100644 Mono.Posix/Mono.Unix.Native/MapAttribute.cs create mode 100644 Mono.Posix/Mono.Unix.Native/NativeConvert.cs create mode 100644 Mono.Posix/Mono.Unix.Native/NativeConvert.generated.cs create mode 100644 Mono.Posix/Mono.Unix.Native/RealTimeSignum.cs create mode 100644 Mono.Posix/Mono.Unix.Native/Stdlib.cs create mode 100644 Mono.Posix/Mono.Unix.Native/Syscall.cs create mode 100644 Mono.Posix/Mono.Unix.Native/TypeAttributes.cs create mode 100644 Mono.Posix/Mono.Unix/AbstractUnixEndPoint.cs create mode 100644 Mono.Posix/Mono.Unix/Catalog.cs create mode 100644 Mono.Posix/Mono.Unix/FileAccessPattern.cs create mode 100644 Mono.Posix/Mono.Unix/FileAccessPermissions.cs create mode 100644 Mono.Posix/Mono.Unix/FileHandleOperations.cs create mode 100644 Mono.Posix/Mono.Unix/FileSpecialAttributes.cs create mode 100644 Mono.Posix/Mono.Unix/FileTypes.cs create mode 100644 Mono.Posix/Mono.Unix/PeerCred.cs create mode 100644 Mono.Posix/Mono.Unix/StdioFileStream.cs create mode 100644 Mono.Posix/Mono.Unix/UnixClient.cs create mode 100644 Mono.Posix/Mono.Unix/UnixDirectoryInfo.cs create mode 100644 Mono.Posix/Mono.Unix/UnixDriveInfo.cs create mode 100644 Mono.Posix/Mono.Unix/UnixEncoding.cs create mode 100644 Mono.Posix/Mono.Unix/UnixEndPoint.cs create mode 100644 Mono.Posix/Mono.Unix/UnixEnvironment.cs create mode 100644 Mono.Posix/Mono.Unix/UnixFileInfo.cs create mode 100644 Mono.Posix/Mono.Unix/UnixFileSystemInfo.cs create mode 100644 Mono.Posix/Mono.Unix/UnixGroupInfo.cs create mode 100644 Mono.Posix/Mono.Unix/UnixIOException.cs create mode 100644 Mono.Posix/Mono.Unix/UnixListener.cs create mode 100644 Mono.Posix/Mono.Unix/UnixMarshal.cs create mode 100644 Mono.Posix/Mono.Unix/UnixPath.cs create mode 100644 Mono.Posix/Mono.Unix/UnixPipes.cs create mode 100644 Mono.Posix/Mono.Unix/UnixProcess.cs create mode 100644 Mono.Posix/Mono.Unix/UnixSignal.cs create mode 100644 Mono.Posix/Mono.Unix/UnixStream.cs create mode 100644 Mono.Posix/Mono.Unix/UnixSymbolicLinkInfo.cs create mode 100644 Mono.Posix/Mono.Unix/UnixUserInfo.cs create mode 100644 Mono.Posix/Properties/AssemblyInfo.cs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dd97c96 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/.vs +/Mono.Posix/obj +/Mono.Posix/bin diff --git a/Mono.Posix.sln b/Mono.Posix.sln new file mode 100644 index 0000000..2218ea2 --- /dev/null +++ b/Mono.Posix.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27703.2026 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Posix", "Mono.Posix\Mono.Posix.csproj", "{E2CA132E-E85C-40AD-BE94-B138AA68772B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E2CA132E-E85C-40AD-BE94-B138AA68772B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E2CA132E-E85C-40AD-BE94-B138AA68772B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E2CA132E-E85C-40AD-BE94-B138AA68772B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E2CA132E-E85C-40AD-BE94-B138AA68772B}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {08A4AB48-4CF1-446D-9B29-6055D7993819} + EndGlobalSection +EndGlobal diff --git a/Mono.Posix/Consts.cs b/Mono.Posix/Consts.cs new file mode 100644 index 0000000..cedbdaa --- /dev/null +++ b/Mono.Posix/Consts.cs @@ -0,0 +1,136 @@ +// +// Consts.cs.in +// +// Author: +// Kornél Pál +// +// 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 \ No newline at end of file diff --git a/Mono.Posix/Locale.cs b/Mono.Posix/Locale.cs new file mode 100644 index 0000000..7293ab2 --- /dev/null +++ b/Mono.Posix/Locale.cs @@ -0,0 +1,51 @@ +// +// Locale.cs +// +// Author: +// Miguel de Icaza (miguel@ximian.com) +// Andreas Nahr (ClassDevelopment@A-SoftTech.com) +// +// (C) 2001 - 2003 Ximian, Inc (http://www.ximian.com) +// + +// +// Copyright (C) 2004 Novell, Inc (http://www.novell.com) +// +// 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; + +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); + } +} diff --git a/Mono.Posix/Mono.Posix.csproj b/Mono.Posix/Mono.Posix.csproj new file mode 100644 index 0000000..438ab47 --- /dev/null +++ b/Mono.Posix/Mono.Posix.csproj @@ -0,0 +1,107 @@ + + + + + Debug + AnyCPU + {E2CA132E-E85C-40AD-BE94-B138AA68772B} + Library + Properties + Mono.Posix + Mono.Posix + v4.7.1 + 512 + + + true + full + false + bin\Debug\ + TRACE;DEBUG;NET_4_6 + prompt + 4 + true + + + pdbonly + true + bin\Release\ + TRACE;NET_4_6 + prompt + 4 + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Mono.Posix/Mono.Posix/Catalog.cs b/Mono.Posix/Mono.Posix/Catalog.cs new file mode 100644 index 0000000..ea3c104 --- /dev/null +++ b/Mono.Posix/Mono.Posix/Catalog.cs @@ -0,0 +1,86 @@ +// +// Mono.Posix.Catalog.cs: Wrappers for the libintl library. +// +// Author: +// Edd Dumbill (edd@usefulinc.com) +// +// (C) 2004 Edd Dumbill +// +// This file implements the low-level syscall interface to the POSIX +// subsystem. +// +// This file tries to stay close to the low-level API as much as possible +// using enumerations, structures and in a few cases, using existing .NET +// data types. +// +// Implementation notes: +// +// Since the values for the various constants on the API changes +// from system to system (even Linux on different architectures will +// have different values), we define our own set of values, and we +// use a set of C helper routines to map from the constants we define +// to the values of the native OS. +// +// Bitfields are flagged with the [Map] attribute, and a helper program +// generates a set of map_XXXX routines that we can call to convert +// from our value definitions to the value definitions expected by the +// OS. +// +// Methods that require tuning are bound as `internal syscal_NAME' methods +// and then a `NAME' method is exposed. +// + +using System; +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; + } + + } +} diff --git a/Mono.Posix/Mono.Posix/PeerCred.cs b/Mono.Posix/Mono.Posix/PeerCred.cs new file mode 100644 index 0000000..c647db1 --- /dev/null +++ b/Mono.Posix/Mono.Posix/PeerCred.cs @@ -0,0 +1,81 @@ +// +// Mono.Posix.PeerCred: Peer credentials class for AF_UNIX sockets +// +// Authors: +// Dick Porter (dick@ximian.com) +// +// (C) 2004 Novell, Inc (http://www.novell.com) +// + +// +// 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.Net.Sockets; + +namespace Mono.Posix +{ +#pragma warning disable 649 + internal struct PeerCredData { + public int pid; + public int uid; + public int 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); + } + } + } +} + diff --git a/Mono.Posix/Mono.Posix/Syscall.cs b/Mono.Posix/Mono.Posix/Syscall.cs new file mode 100644 index 0000000..33bc8d8 --- /dev/null +++ b/Mono.Posix/Mono.Posix/Syscall.cs @@ -0,0 +1,641 @@ +// +// Mono.Posix.Syscall.cs: System calls to Posix subsystem features +// +// Author: +// Miguel de Icaza (miguel@novell.com) +// +// (C) 2003 Novell, Inc. +// +// This file implements the low-level syscall interface to the POSIX +// subsystem. +// +// This file tries to stay close to the low-level API as much as possible +// using enumerations, structures and in a few cases, using existing .NET +// data types. +// +// Implementation notes: +// +// Since the values for the various constants on the API changes +// from system to system (even Linux on different architectures will +// have different values), we define our own set of values, and we +// use a set of C helper routines to map from the constants we define +// to the values of the native OS. +// +// Bitfields were flagged with the [Map] attribute, and a helper program +// generates a set of map_XXXX routines that we can call to convert +// from our value definitions to the value definitions expected by the +// OS. +// +// Methods that require tuning are bound as `internal syscal_NAME' methods +// and then a `NAME' method is exposed. +// +// Deprecated Warning: +// +// This class is deprecated, and exists only for backward compatibility. +// Please use and maintain Mono.Unix.Native.Syscall. +// +// The [Map] attributes have been removed. The naming and methodology of +// the mapping routines has changed. The old map functions still exist in +// MonoPosixHelper, but they will not be updated any further. +// Consequently, there is little point in maintaining the [Map] attributes +// in this file, as they would only bloat MonoPosixHelper. +// + +// +// 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.Text; +using System.Runtime.InteropServices; + +namespace Mono.Posix { + + [Flags] + [CLSCompliant (false)] + [Obsolete ("Use Mono.Unix.Native.OpenFlags")] + public enum OpenFlags { + // + // One of these + // + O_RDONLY = 0, + O_WRONLY = 1, + O_RDWR = 2, + + // + // Or-ed with zero or more of these + // + O_CREAT = 4, + O_EXCL = 8, + O_NOCTTY = 16, + O_TRUNC = 32, + O_APPEND = 64, + O_NONBLOCK = 128, + O_SYNC = 256, + + // + // These are non-Posix, think of a way of exposing + // this for Linux users. + // + + // O_NOFOLLOW = 512, + // O_DIRECTORY = 1024, + // O_DIRECT = 2048, + // O_ASYNC = 4096, + // O_LARGEFILE = 8192 + } + + [Flags] + [CLSCompliant (false)] + [Obsolete ("Use Mono.Unix.Native.FilePermissions")] + public enum FileMode { + S_ISUID = 2048, + S_ISGID = 1024, + S_ISVTX = 512, + S_IRUSR = 256, + S_IWUSR = 128, + S_IXUSR = 64, + S_IRGRP = 32, + S_IWGRP = 16, + S_IXGRP = 8, + S_IROTH = 4, + S_IWOTH = 2, + S_IXOTH = 1 + } + + [Flags] + [CLSCompliant (false)] + [Obsolete ("Use Mono.Unix.Native.WaitOptions")] + public enum WaitOptions { + WNOHANG, + WUNTRACED + } + + [Flags] + [CLSCompliant (false)] + [Obsolete ("Use Mono.Unix.Native.AccessModes")] + public enum AccessMode { + R_OK = 1, + W_OK = 2, + X_OK = 4, + F_OK = 8 + } + + + [CLSCompliant (false)] + [Obsolete ("Use Mono.Unix.Native.Signum")] + public enum Signals { + SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, + SIGFPE, SIGKILL, SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, + SIGALRM, SIGTERM, SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, + SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM, + SIGPROF, SIGWINCH, SIGIO, + + // SIGPWR, + SIGSYS, + // SIGRTMIN + } + + [CLSCompliant (false)] + [Obsolete ("Use Mono.Unix.Native.Syscall.")] + public class Syscall { + [DllImport ("libc", SetLastError=true)] + public static extern int exit (int status); + + [DllImport ("libc", SetLastError=true)] + public static extern int fork (); + + [DllImport ("libc", SetLastError=true)] + public unsafe static extern IntPtr read (int fileDescriptor, void *buf, IntPtr count); + + [DllImport ("libc", SetLastError=true)] + public unsafe static extern IntPtr write (int fileDescriptor, void *buf, IntPtr count); + + [DllImport ("libc", EntryPoint="open", SetLastError=true)] + internal static extern int syscall_open (string pathname, int flags, int mode); + + [DllImport ("MonoPosixHelper")] + internal extern static int map_Mono_Posix_OpenFlags (OpenFlags flags); + [DllImport ("MonoPosixHelper")] + internal extern static int map_Mono_Posix_FileMode (FileMode mode); + + public static int open (string pathname, OpenFlags flags) + { + if ((flags & OpenFlags.O_CREAT) != 0) + throw new ArgumentException ("If you pass O_CREAT, you must call the method with the mode flag"); + + int posix_flags = map_Mono_Posix_OpenFlags (flags); + return syscall_open (pathname, posix_flags, 0); + } + + public static int open (string pathname, OpenFlags flags, FileMode mode) + { + int posix_flags = map_Mono_Posix_OpenFlags (flags); + int posix_mode = map_Mono_Posix_FileMode (mode); + + return syscall_open (pathname, posix_flags, posix_mode); + } + + + [DllImport ("libc", SetLastError=true)] + public static extern int close (int fileDescriptor); + + [DllImport ("libc", EntryPoint="waitpid", SetLastError=true)] + unsafe internal static extern int syscall_waitpid (int pid, int * status, int options); + + [DllImport ("MonoPosixHelper")] + internal extern static int map_Mono_Posix_WaitOptions (WaitOptions wait_options); + + public static int waitpid (int pid, out int status, WaitOptions options) + { + unsafe { + int s = 0; + int r = syscall_waitpid (pid, &s, map_Mono_Posix_WaitOptions (options)); + status = s; + return r; + } + } + + public static int waitpid (int pid, WaitOptions options) + { + unsafe { + return syscall_waitpid (pid, null, map_Mono_Posix_WaitOptions (options)); + } + } + + [DllImport ("MonoPosixHelper", EntryPoint="wifexited")] + public static extern int WIFEXITED (int status); + [DllImport ("MonoPosixHelper", EntryPoint="wexitstatus")] + public static extern int WEXITSTATUS (int status); + [DllImport ("MonoPosixHelper", EntryPoint="wifsignaled")] + public static extern int WIFSIGNALED (int status); + [DllImport ("MonoPosixHelper", EntryPoint="wtermsig")] + public static extern int WTERMSIG (int status); + [DllImport ("MonoPosixHelper", EntryPoint="wifstopped")] + public static extern int WIFSTOPPED (int status); + [DllImport ("MonoPosixHelper", EntryPoint="wstopsig")] + public static extern int WSTOPSIG (int status); + + [DllImport ("libc", EntryPoint="creat", SetLastError=true)] + internal static extern int syscall_creat (string pathname, int flags); + + public static int creat (string pathname, FileMode flags) + { + return syscall_creat (pathname, map_Mono_Posix_FileMode (flags)); + } + + [DllImport ("libc", SetLastError=true)] + public static extern int link (string oldPath, string newPath); + + [DllImport ("libc", SetLastError=true)] + public static extern int unlink (string path); + + [DllImport ("libc", SetLastError=true)] + public static extern int symlink (string oldpath, string newpath); + + // TODO: execve + + [DllImport ("libc", SetLastError=true)] + public static extern int chdir (string path); + + // TODO: time + // TODO: mknod + + + [DllImport ("libc", EntryPoint="chmod", SetLastError=true)] + internal static extern int syscall_chmod (string path, int mode); + + public static int chmod (string path, FileMode mode) + { + return syscall_chmod (path, map_Mono_Posix_FileMode (mode)); + } + + [DllImport ("libc", SetLastError=true)] + public static extern int chown (string path, int owner, int group); + [DllImport ("libc", SetLastError=true)] + public static extern int lchown (string path, int owner, int group); + + [DllImport ("libc", SetLastError=true)] + public static extern int lseek (int fileDescriptor, int offset, int whence); + + [DllImport ("libc", SetLastError=true)] + public static extern int getpid (); + + // TODO: mount + // TODO: umount + + [DllImport ("libc", SetLastError=true)] + public static extern int setuid (int uid); + + [DllImport ("libc", SetLastError=true)] + public static extern int getuid (); + + // TODO: stime + // TODO: ptrace + + [DllImport ("libc")] + public static extern uint alarm (uint seconds); + + [DllImport ("libc", SetLastError=true)] + public static extern int pause (); + + // TODO: utime + + [DllImport ("libc", EntryPoint="access", SetLastError=true)] + internal extern static int syscall_access (string pathname, int mode); + + [DllImport ("MonoPosixHelper")] + internal extern static int map_Mono_Posix_AccessMode (AccessMode mode); + + public static int access (string pathname, AccessMode mode) + { + return syscall_access (pathname, map_Mono_Posix_AccessMode (mode)); + } + + [DllImport ("libc", SetLastError=true)] + public static extern int nice (int increment); + + // TODO: ftime + + [DllImport ("libc")] + public static extern void sync (); + + [DllImport ("libc", SetLastError=true)] + public static extern void kill (int pid, int sig); + + [DllImport ("libc", SetLastError=true)] + public static extern int rename (string oldPath, string newPath); + + [DllImport ("libc", EntryPoint="mkdir", SetLastError=true)] + internal extern static int syscall_mkdir (string pathname, int mode); + + public static int mkdir (string pathname, FileMode mode) + { + return syscall_mkdir (pathname, map_Mono_Posix_FileMode (mode)); + } + + [DllImport ("libc", SetLastError=true)] + public static extern int rmdir (string path); + + [DllImport ("libc", SetLastError=true)] + public static extern int dup (int fileDescriptor); + + // TODO: pipe + // TODO: times + + [DllImport ("libc", SetLastError=true)] + public static extern int setgid (int gid); + [DllImport ("libc", SetLastError=true)] + public static extern int getgid (); + + + public delegate void sighandler_t (int v); + + [DllImport ("libc", SetLastError=true)] + public static extern int signal (int signum, sighandler_t handler); + + [DllImport ("libc", SetLastError=true)] + public static extern int geteuid (); + + [DllImport ("libc", SetLastError=true)] + public static extern int getegid (); + + // TODO: fcntl + + [DllImport ("libc", SetLastError=true)] + public static extern int setpgid (int pid, int pgid); + + // TODO: ulimit + + [DllImport ("libc")] + public static extern int umask (int umask); + + [DllImport ("libc", SetLastError=true)] + public static extern int chroot (string path); + + [DllImport ("libc", SetLastError=true)] + public static extern int dup2 (int oldFileDescriptor, int newFileDescriptor); + + [DllImport ("libc", SetLastError=true)] + public static extern int getppid (); + + [DllImport ("libc", SetLastError=true)] + public static extern int getpgrp (); + + [DllImport ("libc", SetLastError=true)] + public static extern int setsid (); + + // TODO: sigaction + + [DllImport ("libc", SetLastError=true)] + public static extern int setreuid (int ruid, int euid); + + [DllImport ("libc", SetLastError=true)] + public static extern int setregid (int rgid, int egid); + + // these don't exactly match POSIX, but it's a nice way to get user/group names + + [DllImport ("MonoPosixHelper", SetLastError=true)] + private static extern string helper_Mono_Posix_GetUserName (int uid); + + [DllImport ("MonoPosixHelper", SetLastError=true)] + private static extern string helper_Mono_Posix_GetGroupName (int gid); + + public static string getusername(int uid) { return helper_Mono_Posix_GetUserName(uid); } + public static string getgroupname(int gid) { return helper_Mono_Posix_GetGroupName(gid); } + + // TODO: sigsuspend + // TODO: sigpending + // TODO: setrlimit + // TODO: getrlimit + // TODO: getrusage + // TODO: gettimeofday + // TODO: settimeofday + + [DllImport ("libc", EntryPoint="gethostname", SetLastError=true)] + static extern int syscall_gethostname (byte[] p, int len); + + public static string GetHostName () + { + byte [] buf = new byte [256]; + int res = syscall_gethostname (buf, buf.Length); + if (res == -1) + return "localhost"; + for (res = 0; res < buf.Length; ++res) { + if (buf [res] == 0) + break; + } + + return Encoding.UTF8.GetString (buf, 0, res); + } + + [CLSCompliant (false)] + public static string gethostname () + { + return GetHostName (); + } + + + [DllImport ("libc", EntryPoint="isatty")] + static extern int syscall_isatty (int desc); + + public static bool isatty (int desc) + { + int res = syscall_isatty (desc); + if (res == 1) + return true; + else + return false; + } + + + [DllImport ("MonoPosixHelper")] + internal extern static int helper_Mono_Posix_Stat (string filename, bool dereference, + out int device, out int inode, out int mode, + out int nlinks, out int uid, out int gid, + out int rdev, out long size, out long blksize, out long blocks, + out long atime, out long mtime, out long ctime); + + private static int stat2(string filename, bool dereference, out Stat stat) { + int device, inode, mode; + int nlinks, uid, gid, rdev; + long size, blksize, blocks; + long atime, mtime, ctime; + + int ret = helper_Mono_Posix_Stat(filename, dereference, + out device, out inode, out mode, + out nlinks, out uid, out gid, + out rdev, out size, out blksize, out blocks, + out atime, out mtime, out ctime); + + stat = new Stat( + device, inode, mode, + nlinks, uid, gid, + rdev, size, blksize, blocks, + atime, mtime, ctime); + + if (ret != 0) return ret; + + return 0; + } + + public static int stat(string filename, out Stat stat) { + return stat2(filename, false, out stat); + } + + public static int lstat(string filename, out Stat stat) { + return stat2(filename, true, out stat); + } + + [DllImport ("libc")] + private static extern int readlink(string path, byte[] buffer, int buflen); + + public static string readlink(string path) { + byte[] buf = new byte[512]; + int ret = readlink(path, buf, buf.Length); + if (ret == -1) return null; + char[] cbuf = new char[512]; + int chars = System.Text.Encoding.Default.GetChars(buf, 0, ret, cbuf, 0); + return new String(cbuf, 0, chars); + } + + [DllImport ("libc", EntryPoint="strerror")] + static extern IntPtr _strerror(int errnum); + + public static string strerror (int errnum) + { + return Marshal.PtrToStringAnsi (_strerror (errnum)); + } + + [DllImport ("libc")] + public static extern IntPtr opendir(string path); + + [DllImport ("libc")] + public static extern int closedir(IntPtr dir); + + [DllImport ("MonoPosixHelper", EntryPoint="helper_Mono_Posix_readdir")] + public static extern string readdir(IntPtr dir); + + } + + [Obsolete ("Use Mono.Unix.Native.FilePermissions")] + public enum StatModeMasks { + [Obsolete ("Use Mono.Unix.Native.FilePermissions.S_IFMT")] + TypeMask = 0xF000, // bitmask for the file type bitfields + [Obsolete ("Use Mono.Unix.Native.FilePermissions.S_RWXU")] + OwnerMask = 0x1C0, // mask for file owner permissions + [Obsolete ("Use Mono.Unix.Native.FilePermissions.S_RWXG")] + GroupMask = 0x38, // mask for group permissions + [Obsolete ("Use Mono.Unix.Native.FilePermissions.S_RWXO")] + OthersMask = 0x7, // mask for permissions for others (not in group) + } + + [Flags] + [Obsolete ("Use Mono.Unix.Native.FilePermissions")] + public enum StatMode { + [Obsolete ("Use Mono.Unix.Native.FilePermissions.S_IFSOCK")] + Socket = 0xC000, // socket + [Obsolete ("Use Mono.Unix.Native.FilePermissions.S_IFLNK")] + SymLink = 0xA000, // symbolic link + [Obsolete ("Use Mono.Unix.Native.FilePermissions.S_IFREG")] + Regular = 0x8000, // regular file + [Obsolete ("Use Mono.Unix.Native.FilePermissions.S_IFBLK")] + BlockDevice = 0x6000, // block device + [Obsolete ("Use Mono.Unix.Native.FilePermissions.S_IFDIR")] + Directory = 0x4000, // directory + [Obsolete ("Use Mono.Unix.Native.FilePermissions.S_IFCHR")] + CharDevice = 0x2000, // character device + [Obsolete ("Use Mono.Unix.Native.FilePermissions.S_IFIFO")] + FIFO = 0x1000, // fifo + [Obsolete ("Use Mono.Unix.Native.FilePermissions.S_ISUID")] + SUid = 0x800, // set UID bit + [Obsolete ("Use Mono.Unix.Native.FilePermissions.S_ISGID")] + SGid = 0x400, // set GID bit + [Obsolete ("Use Mono.Unix.Native.FilePermissions.S_ISVTX")] + Sticky = 0x200, // sticky bit + [Obsolete ("Use Mono.Unix.Native.FilePermissions.S_IRUSR")] + OwnerRead = 0x100, // owner has read permission + [Obsolete ("Use Mono.Unix.Native.FilePermissions.S_IWUSR")] + OwnerWrite = 0x80, // owner has write permission + [Obsolete ("Use Mono.Unix.Native.FilePermissions.S_IXUSR")] + OwnerExecute = 0x40, // owner has execute permission + [Obsolete ("Use Mono.Unix.Native.FilePermissions.S_IRGRP")] + GroupRead = 0x20, // group has read permission + [Obsolete ("Use Mono.Unix.Native.FilePermissions.S_IWGRP")] + GroupWrite = 0x10, // group has write permission + [Obsolete ("Use Mono.Unix.Native.FilePermissions.S_IXGRP")] + GroupExecute = 0x8, // group has execute permission + [Obsolete ("Use Mono.Unix.Native.FilePermissions.S_IROTH")] + OthersRead = 0x4, // others have read permission + [Obsolete ("Use Mono.Unix.Native.FilePermissions.S_IWOTH")] + OthersWrite = 0x2, // others have write permisson + [Obsolete ("Use Mono.Unix.Native.FilePermissions.S_IXOTH")] + OthersExecute = 0x1, // others have execute permission + } + + [Obsolete ("Use Mono.Unix.Native.Stat")] + public struct Stat { + [Obsolete ("Use Mono.Unix.Native.Stat.st_dev")] + public readonly int Device; + [Obsolete ("Use Mono.Unix.Native.Stat.st_ino")] + public readonly int INode; + [Obsolete ("Use Mono.Unix.Native.Stat.st_mode")] + public readonly StatMode Mode; + [Obsolete ("Use Mono.Unix.Native.Stat.st_nlink")] + public readonly int NLinks; + [Obsolete ("Use Mono.Unix.Native.Stat.st_uid")] + public readonly int Uid; + [Obsolete ("Use Mono.Unix.Native.Stat.st_gid")] + public readonly int Gid; + [Obsolete ("Use Mono.Unix.Native.Stat.st_rdev")] + public readonly long DeviceType; + [Obsolete ("Use Mono.Unix.Native.Stat.st_size")] + public readonly long Size; + [Obsolete ("Use Mono.Unix.Native.Stat.st_blksize")] + public readonly long BlockSize; + [Obsolete ("Use Mono.Unix.Native.Stat.st_blocks")] + public readonly long Blocks; + [Obsolete ("Use Mono.Unix.Native.Stat.st_atime")] + public readonly DateTime ATime; + [Obsolete ("Use Mono.Unix.Native.Stat.st_mtime")] + public readonly DateTime MTime; + [Obsolete ("Use Mono.Unix.Native.Stat.st_ctime")] + public readonly DateTime CTime; + + [Obsolete ("Use Mono.Unix.Native.NativeConvert.LocalUnixEpoch")] + public static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1); + + [Obsolete ("Use Mono.Unix.Native.NativeConvert.ToDateTime")] + public static DateTime UnixToDateTime(long unix) { + return UnixEpoch.Add(TimeSpan.FromSeconds(unix)).ToLocalTime(); + } + + internal Stat( + int device, int inode, int mode, + int nlinks, int uid, int gid, + int rdev, long size, long blksize, long blocks, + long atime, long mtime, long ctime) { + Device = device; + INode = inode; + Mode = (StatMode)mode; + NLinks = nlinks; + Uid = uid; + Gid = gid; + DeviceType = rdev; + Size = size; + BlockSize = blksize; + Blocks = blocks; + if (atime != 0) + ATime = UnixToDateTime(atime); + else + ATime = new DateTime(); + if (mtime != 0) + MTime = UnixToDateTime(mtime); + else + MTime = new DateTime(); + if (ctime != 0) + CTime = UnixToDateTime(ctime); + else + CTime = new DateTime(); + } + } + + +} diff --git a/Mono.Posix/Mono.Posix/UnixEndPoint.cs b/Mono.Posix/Mono.Posix/UnixEndPoint.cs new file mode 100644 index 0000000..710a5ad --- /dev/null +++ b/Mono.Posix/Mono.Posix/UnixEndPoint.cs @@ -0,0 +1,118 @@ +// +// Mono.Posix.UnixEndPoint: EndPoint derived class for AF_UNIX family sockets. +// +// Authors: +// Gonzalo Paniagua Javier (gonzalo@ximian.com) +// +// (C) 2003 Ximian, Inc (http://www.ximian.com) +// + +// +// 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.Net; +using System.Net.Sockets; +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"); + + if (filename == "") + throw new ArgumentException ("Cannot be empty.", "filename"); + this.filename = filename; + } + + public string Filename { + get { + return(filename); + } + set { + filename=value; + } + } + + 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); + } + } +} + diff --git a/Mono.Posix/Mono.Remoting.Channels.Unix/.gitattributes b/Mono.Posix/Mono.Remoting.Channels.Unix/.gitattributes new file mode 100644 index 0000000..cdcaaf5 --- /dev/null +++ b/Mono.Posix/Mono.Remoting.Channels.Unix/.gitattributes @@ -0,0 +1 @@ +/UnixConnectionPool.cs -crlf diff --git a/Mono.Posix/Mono.Remoting.Channels.Unix/UnixBinaryClientFormatterSink.cs b/Mono.Posix/Mono.Remoting.Channels.Unix/UnixBinaryClientFormatterSink.cs new file mode 100644 index 0000000..2a6f812 --- /dev/null +++ b/Mono.Posix/Mono.Remoting.Channels.Unix/UnixBinaryClientFormatterSink.cs @@ -0,0 +1,167 @@ +// +// Mono.Remoting.Channels.Unix.UnixBinaryClientFormatterSink.cs +// +// Author: Rodrigo Moya (rodrigo@ximian.com) +// Dietmar Maurer (dietmar@ximian.com) +// Lluis Sanchez Gual (lluis@ideary.com) +// +// 2002 (C) Copyright, Ximian, Inc. +// + +// +// 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.Collections; +using System.IO; +using System.Runtime.Remoting.Messaging; +using System.Runtime.Remoting.Channels; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; + +namespace Mono.Remoting.Channels.Unix +{ + internal class UnixBinaryClientFormatterSink : IClientFormatterSink, IMessageSink, IClientChannelSink, IChannelSinkBase + { + UnixBinaryCore _binaryCore = UnixBinaryCore.DefaultInstance; + IClientChannelSink _nextInChain; + + public UnixBinaryClientFormatterSink (IClientChannelSink nextSink) + { + _nextInChain = nextSink; + } + + internal UnixBinaryCore BinaryCore + { + get { return _binaryCore; } + set { _binaryCore = value; } + } + + public IClientChannelSink NextChannelSink + { + get { + return _nextInChain; + } + } + + 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); + } + } + } +} diff --git a/Mono.Posix/Mono.Remoting.Channels.Unix/UnixBinaryClientFormatterSinkProvider.cs b/Mono.Posix/Mono.Remoting.Channels.Unix/UnixBinaryClientFormatterSinkProvider.cs new file mode 100644 index 0000000..cbc4bdd --- /dev/null +++ b/Mono.Posix/Mono.Remoting.Channels.Unix/UnixBinaryClientFormatterSinkProvider.cs @@ -0,0 +1,80 @@ +// +// Mono.Remoting.Channels.Unix.UnixBinaryClientFormatterSinkProvider.cs +// +// Author: Rodrigo Moya (rodrigo@ximian.com) +// Lluis Sanchez Gual (lluis@ximian.com) +// +// 2002 (C) Copyright, Ximian, Inc. +// + +// +// 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.Collections; +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" }; + + 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; + } + } +} diff --git a/Mono.Posix/Mono.Remoting.Channels.Unix/UnixBinaryCore.cs b/Mono.Posix/Mono.Remoting.Channels.Unix/UnixBinaryCore.cs new file mode 100644 index 0000000..87edbbb --- /dev/null +++ b/Mono.Posix/Mono.Remoting.Channels.Unix/UnixBinaryCore.cs @@ -0,0 +1,148 @@ +// +// Mono.Remoting.Channels.Unix.BinaryCore.cs +// +// Author: Lluis Sanchez Gual (lluis@novell.com) +// +// 2005 (C) Copyright, Novell, Inc. +// + +// +// 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.Reflection; +using System.Collections; +using System.Runtime.Remoting; +using System.Runtime.Remoting.Messaging; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters; +using System.Runtime.Serialization.Formatters.Binary; + +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); + + _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); + } + } +} + diff --git a/Mono.Posix/Mono.Remoting.Channels.Unix/UnixBinaryServerFormatterSink.cs b/Mono.Posix/Mono.Remoting.Channels.Unix/UnixBinaryServerFormatterSink.cs new file mode 100644 index 0000000..cee7514 --- /dev/null +++ b/Mono.Posix/Mono.Remoting.Channels.Unix/UnixBinaryServerFormatterSink.cs @@ -0,0 +1,163 @@ +// +// Mono.Remoting.Channels.Unix.UnixBinaryServerFormatterSink.cs +// +// Author: Duncan Mak (duncan@ximian.com) +// Lluis Sanchez Gual (lluis@ideary.com) +// +// 2002 (C) Copyright, Ximian, Inc. +// + +// +// 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.Collections; +using System.IO; +using System.Runtime.Remoting.Messaging; +using System.Runtime.Remoting.Channels; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters; +using System.Runtime.Serialization.Formatters.Binary; +using System.Runtime.InteropServices; + +namespace Mono.Remoting.Channels.Unix { + + internal class UnixBinaryServerFormatterSink : IServerChannelSink, IChannelSinkBase + { + UnixBinaryCore _binaryCore = UnixBinaryCore.DefaultInstance; + + IServerChannelSink next_sink; + IChannelReceiver 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; + } + } + + public IDictionary Properties { + get { + return null; + } + } + + public void AsyncProcessResponse (IServerResponseChannelSinkStack sinkStack, object state, + IMessage message, ITransportHeaders headers, Stream stream) + { + ITransportHeaders responseHeaders = new TransportHeaders(); + + if (sinkStack != null) stream = sinkStack.GetResponseStream (message, responseHeaders); + if (stream == null) stream = new MemoryStream(); + + _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) + { + 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; + } + } +} diff --git a/Mono.Posix/Mono.Remoting.Channels.Unix/UnixBinaryServerFormatterSinkProvider.cs b/Mono.Posix/Mono.Remoting.Channels.Unix/UnixBinaryServerFormatterSinkProvider.cs new file mode 100644 index 0000000..2d5a99e --- /dev/null +++ b/Mono.Posix/Mono.Remoting.Channels.Unix/UnixBinaryServerFormatterSinkProvider.cs @@ -0,0 +1,85 @@ +// +// Mono.Remoting.Channels.Unix.UnixBinaryServerFormatterSinkProvider.cs +// +// Author: Rodrigo Moya (rodrigo@ximian.com) +// Lluis Sanchez Gual (lluis@ximian.com) +// +// 2002 (C) Copyright, Ximian, Inc. +// + +// +// 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.Collections; +using System.Runtime.Serialization.Formatters; +using System.Runtime.InteropServices; +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" }; + + public UnixBinaryServerFormatterSinkProvider () + { + _binaryCore = UnixBinaryCore.DefaultInstance; + } + + 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 + } + } +} diff --git a/Mono.Posix/Mono.Remoting.Channels.Unix/UnixChannel.cs b/Mono.Posix/Mono.Remoting.Channels.Unix/UnixChannel.cs new file mode 100644 index 0000000..b7768d3 --- /dev/null +++ b/Mono.Posix/Mono.Remoting.Channels.Unix/UnixChannel.cs @@ -0,0 +1,143 @@ +// +// Mono.Remoting.Channels.Unix.UnixChannel.cs +// +// Author: Rodrigo Moya (rodrigo@ximian.com) +// Lluis Sanchez Gual (lluis@ideary.com) +// +// Copyright (C) 2005 Novell, Inc (http://www.novell.com) +// + +// +// 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.Collections; +using System.Runtime.Remoting.Messaging; +using System.Runtime.Remoting.Channels; +using System.Text.RegularExpressions; + +namespace Mono.Remoting.Channels.Unix +{ + public class UnixChannel : IChannelReceiver, IChannel, IChannelSender + { + private UnixClientChannel _clientChannel; + private UnixServerChannel _serverChannel = null; + private string _name = "unix"; + private int _priority = 1; + + public UnixChannel (): this (null) + { + } + + public UnixChannel (string path) + { + Hashtable ht = new Hashtable(); + ht["path"] = path; + Init(ht, null, null); + } + + void Init (IDictionary properties, IClientChannelSinkProvider clientSink, IServerChannelSinkProvider serverSink) + { + _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); + } + + public void StopListening (object data) + { + if (_serverChannel != null) _serverChannel.StopListening(data); + } + + public string[] GetUrlsForUri (string uri) + { + if (_serverChannel != null) return _serverChannel.GetUrlsForUri(uri); + else return null; + } + + public object ChannelData + { + get + { + 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) + { + // 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); + } + } +} diff --git a/Mono.Posix/Mono.Remoting.Channels.Unix/UnixClientChannel.cs b/Mono.Posix/Mono.Remoting.Channels.Unix/UnixClientChannel.cs new file mode 100644 index 0000000..a259a5e --- /dev/null +++ b/Mono.Posix/Mono.Remoting.Channels.Unix/UnixClientChannel.cs @@ -0,0 +1,134 @@ +// +// Mono.Remoting.Channels.Unix.UnixClientChannel.cs +// +// Author: Dietmar Maurer (dietmar@ximian.com) +// Lluis Sanchez Gual (lluis@novell.com) +// +// Copyright (C) 2005 Novell, Inc (http://www.novell.com) +// + +// +// 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.Collections; +using System.IO; +using System.Net.Sockets; +using System.Runtime.Remoting.Messaging; +using System.Runtime.Remoting.Channels; +using System.Threading; + +namespace Mono.Remoting.Channels.Unix +{ + public class UnixClientChannel : IChannelSender, IChannel + { + int priority = 1; + string name = "unix"; + IClientChannelSinkProvider _sinkProvider; + + public UnixClientChannel () + { + _sinkProvider = new UnixBinaryClientFormatterSinkProvider (); + _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; + + // add the unix provider at the end of the chain + IClientChannelSinkProvider prov = sinkProvider; + 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 (); + } + + } + + public UnixClientChannel (string name, IClientChannelSinkProvider sinkProvider) + { + this.name = name; + _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 + { + 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) { + IChannelDataStore ds = remoteChannelData as IChannelDataStore; + 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); + } + } +} diff --git a/Mono.Posix/Mono.Remoting.Channels.Unix/UnixClientTransportSink.cs b/Mono.Posix/Mono.Remoting.Channels.Unix/UnixClientTransportSink.cs new file mode 100644 index 0000000..4b5a1aa --- /dev/null +++ b/Mono.Posix/Mono.Remoting.Channels.Unix/UnixClientTransportSink.cs @@ -0,0 +1,193 @@ +// +// Mono.Remoting.Channels.Unix.UnixClientTransportSink.cs +// +// Author: Dietmar Maurer (dietmar@ximian.com) +// Lluis Sanchez Gual (lluis@novell.com) +// +// Copyright (C) 2005 Novell, Inc (http://www.novell.com) +// + +// +// 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.Runtime.Remoting.Channels; +using System.Runtime.Remoting.Messaging; +using System.Collections; +using System.IO; +using System.Threading; +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); + } + + public IDictionary Properties + { + get + { + return null; + } + } + + public IClientChannelSink NextChannelSink + { + get + { + // we are the last one + return null; + } + } + + public void AsyncProcessRequest (IClientChannelSinkStack sinkStack, IMessage msg, + ITransportHeaders headers, Stream requestStream) + { + UnixConnection connection = null; + bool isOneWay = RemotingServices.IsOneWay (((IMethodMessage)msg).MethodBase); + + 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 + + connection = UnixConnectionPool.GetConnection (_path); + UnixMessageIO.SendMessageStream (connection.Stream, requestStream, headers, connection.Buffer); + connection.Stream.Flush (); + + 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; + } + } + + private void ReadAsyncUnixMessage(object data) + { + // This method is called by a new thread to asynchronously + // read the response to a request + + // The stack was provided as state data in QueueUserWorkItem + IClientChannelSinkStack stack = (IClientChannelSinkStack)data; + + // 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); + + try + { + ITransportHeaders responseHeaders; + + // 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 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(); + } + } + + } + + +} diff --git a/Mono.Posix/Mono.Remoting.Channels.Unix/UnixClientTransportSinkProvider.cs b/Mono.Posix/Mono.Remoting.Channels.Unix/UnixClientTransportSinkProvider.cs new file mode 100644 index 0000000..94b336a --- /dev/null +++ b/Mono.Posix/Mono.Remoting.Channels.Unix/UnixClientTransportSinkProvider.cs @@ -0,0 +1,62 @@ +// +// Mono.Remoting.Channels.Unix.UnixClientTransportSinkProvider.cs +// +// Author: Dietmar Maurer (dietmar@ximian.com) +// Lluis Sanchez (lluis@novell.com) +// +// Copyright (C) 2005 Novell, Inc (http://www.novell.com) +// + +// +// 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.Runtime.Remoting.Channels; + +namespace Mono.Remoting.Channels.Unix +{ + internal class UnixClientTransportSinkProvider : IClientChannelSinkProvider + { + public UnixClientTransportSinkProvider () + { + // 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); + } + } +} diff --git a/Mono.Posix/Mono.Remoting.Channels.Unix/UnixConnectionPool.cs b/Mono.Posix/Mono.Remoting.Channels.Unix/UnixConnectionPool.cs new file mode 100644 index 0000000..624d94a --- /dev/null +++ b/Mono.Posix/Mono.Remoting.Channels.Unix/UnixConnectionPool.cs @@ -0,0 +1,311 @@ +// +// Mono.Remoting.Channels.Unix.UnixConnectionPool.cs +// +// Author: Lluis Sanchez Gual (lluis@ideary.com) +// +// Copyright (C) 2005 Novell, Inc (http://www.novell.com) +// + +// +// 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.Collections; +using System.Threading; +using System.IO; +using System.Net.Sockets; +using System.Runtime.Remoting; +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. + + 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 Thread _poolThread; + + 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 int MaxOpenConnections + { + get { return _maxOpenConnections; } + set + { + if (value < 1) throw new RemotingException ("MaxOpenConnections must be greater than zero"); + _maxOpenConnections = value; + } + } + + public static int KeepAliveSeconds + { + get { return _keepAliveSeconds; } + set { _keepAliveSeconds = value; } + } + + public static UnixConnection GetConnection (string path) + { + HostConnectionPool hostPool; + + lock (_pools) + { + hostPool = (HostConnectionPool) _pools[path]; + if (hostPool == null) + { + hostPool = new HostConnectionPool(path); + _pools[path] = hostPool; + } + } + + return hostPool.GetConnection(); + } + + private static void ConnectionCollector () + { + while (true) + { + Thread.Sleep(3000); + lock (_pools) + { + ICollection values = _pools.Values; + foreach (HostConnectionPool pool in values) + pool.PurgeConnections(); + } + } + } + } + + 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); + } + } + } + + internal class UnixConnection + { + DateTime _controlTime; + Stream _stream; + ReusableUnixClient _client; + HostConnectionPool _pool; + byte[] _buffer; + + public UnixConnection (HostConnectionPool pool, ReusableUnixClient client) + { + _pool = pool; + _client = client; + _stream = new BufferedStream (client.GetStream()); + _controlTime = DateTime.UtcNow; + _buffer = new byte[UnixMessageIO.DefaultStreamBufferSize]; + } + + public Stream Stream + { + get { return _stream; } + } + + public DateTime ControlTime + { + get { return _controlTime; } + set { _controlTime = value; } + } + + public bool IsAlive + { + get { return _client.IsAlive; } + } + + // 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; } + } + + // Returns the connection to the pool + public void Release() + { + _pool.ReleaseConnection (this); + } + + public void Close() + { + _client.Close(); + } + } + + internal class HostConnectionPool + { + ArrayList _pool = new ArrayList(); + int _activeConnections = 0; + + string _path; + + public HostConnectionPool (string path) + { + _path = path; + } + + public UnixConnection GetConnection () + { + UnixConnection connection = null; + lock (_pool) + { + do + { + if (_pool.Count > 0) + { + // There are available connections + + connection = (UnixConnection)_pool[_pool.Count - 1]; + _pool.RemoveAt(_pool.Count - 1); + if (!connection.IsAlive) { + CancelConnection (connection); + connection = null; + continue; + } + } + + 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; + } + + // No available connections in the pool + // Wait for somewone to release one. + + if (connection == null) + { + Monitor.Wait(_pool); + } + } + while (connection == null); + } + + if (connection == null) + return CreateConnection (); + else + return connection; + } + + 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); + } + } + + public void ReleaseConnection (UnixConnection entry) + { + lock (_pool) + { + entry.ControlTime = DateTime.UtcNow; // Initialize timeout + _pool.Add (entry); + Monitor.Pulse (_pool); + } + } + + private void CancelConnection(UnixConnection entry) + { + try + { + entry.Stream.Close(); + _activeConnections--; + } + catch + { + } + } + + 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--; + } + } + } + } + + } + + +} diff --git a/Mono.Posix/Mono.Remoting.Channels.Unix/UnixMessageIO.cs b/Mono.Posix/Mono.Remoting.Channels.Unix/UnixMessageIO.cs new file mode 100644 index 0000000..833ff6e --- /dev/null +++ b/Mono.Posix/Mono.Remoting.Channels.Unix/UnixMessageIO.cs @@ -0,0 +1,283 @@ +// +// Mono.Remoting.Channels.Unix.UnixMessageIO.cs +// +// Author: Lluis Sanchez Gual (lluis@ideary.com) +// +// Copyright (C) 2005 Novell, Inc (http://www.novell.com) + +// +// 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.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; +using System.Collections; +using System.IO; +using System.Text; +using System.Net.Sockets; +using System.Runtime.Remoting.Channels; +using System.Runtime.Remoting; + +namespace Mono.Remoting.Channels.Unix +{ + 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; + + // 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; + + while (atLeastOneOnTrack) + { + atLeastOneOnTrack = false; + byte c = buffer [i]; + for (int 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 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[(int) MessageStatus.MethodMessage]; + networkStream.Write(dotnetHeader, 0, dotnetHeader.Length); + + // 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 ID + buffer [2] = (byte) 0; + + // Writes assemblyID???? + buffer [3] = (byte) 0; + + // 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); + + // 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 }; + + 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 (); + + 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]; + } + + return headers; + } + + public static Stream ReceiveMessageStream (Stream networkStream, out ITransportHeaders headers, byte[] buffer) + { + headers = null; + + 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); + + int byteCount = (buffer [4] | (buffer [5] << 8) | + (buffer [6] << 16) | (buffer [7] << 24)); + + // Reads the headers + headers = ReceiveHeaders (networkStream, buffer); + + 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); + } + + } +} diff --git a/Mono.Posix/Mono.Remoting.Channels.Unix/UnixServerChannel.cs b/Mono.Posix/Mono.Remoting.Channels.Unix/UnixServerChannel.cs new file mode 100644 index 0000000..0cbb928 --- /dev/null +++ b/Mono.Posix/Mono.Remoting.Channels.Unix/UnixServerChannel.cs @@ -0,0 +1,330 @@ +// +// Mono.Remoting.Channels.Unix.UnixServerChannel.cs +// +// Author: Rodrigo Moya (rodrigo@ximian.com) +// Lluis Sanchez Gual (lluis@ideary.com) +// +// Copyright (C) 2005 Novell, Inc (http://www.novell.com) +// + +// +// 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.Collections; +using System.Runtime.Remoting.Messaging; +using System.Text.RegularExpressions; +using System.Net.Sockets; +using System.Net; +using System.Threading; +using System.IO; +using System.Runtime.Remoting.Channels; +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; + + Thread server_thread = null; + UnixListener listener; + UnixServerTransportSink sink; + ChannelDataStore channel_data; + int _maxConcurrentConnections = 100; + ArrayList _activeConnections = new ArrayList(); + + + void Init (IServerChannelSinkProvider serverSinkProvider) + { + if (serverSinkProvider == null) + { + serverSinkProvider = new UnixBinaryServerFormatterSinkProvider (); + } + + // Gets channel data from the chain of channel providers + + channel_data = new ChannelDataStore (null); + IServerChannelSinkProvider provider = serverSinkProvider; + while (provider != null) + { + provider.GetChannelData(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); + } + + public UnixServerChannel (string path) + { + this.path = path; + Init (null); + } + + public UnixServerChannel (IDictionary properties, + IServerChannelSinkProvider serverSinkProvider) + { + foreach(DictionaryEntry property in properties) + { + switch((string)property.Key) + { + case "path": + path = property.Value as string; + break; + case "priority": + priority = Convert.ToInt32(property.Value); + break; + case "supressChannelData": + supressChannelData = Convert.ToBoolean (property.Value); + break; + } + } + Init (serverSinkProvider); + } + + public UnixServerChannel (string name, string path, + IServerChannelSinkProvider serverSinkProvider) + { + this.name = name; + this.path = path; + Init (serverSinkProvider); + } + + public UnixServerChannel (string name, string path) + { + this.name = name; + this.path = path; + Init (null); + } + + public object ChannelData + { + get { + if (supressChannelData) return null; + else return channel_data; + } + } + + public string ChannelName + { + get { + return name; + } + } + + 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 () + { + try + { + while (true) + { + Socket client = listener.AcceptSocket (); + CreateListenerConnection (client); + } + } + catch + {} + } + + internal void CreateListenerConnection (Socket client) + { + lock (_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); + Thread thread = new Thread (new ThreadStart (reader.ProcessMessages)); + thread.Start(); + thread.IsBackground = true; + _activeConnections.Add (thread); + } + } + + internal void ReleaseConnection (Thread thread) + { + lock (_activeConnections) + { + _activeConnections.Remove (thread); + Monitor.Pulse (_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); + + if (server_thread == null) + { + 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 (); + } + } + + public void StopListening (object data) + { + if (server_thread == null) return; + + lock (_activeConnections) + { + server_thread.Abort (); + server_thread = null; + listener.Stop (); + + foreach (Thread thread in _activeConnections) + thread.Abort(); + + _activeConnections.Clear(); + Monitor.PulseAll (_activeConnections); + } + } + } + + class ClientConnection + { + Socket _client; + UnixServerTransportSink _sink; + Stream _stream; + 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)); + + try + { + bool end = false; + while (!end) + { + MessageStatus type = UnixMessageIO.ReceiveMessageStatus (_stream, buffer); + + switch (type) + { + case MessageStatus.MethodMessage: + _sink.InternalProcessMessage (this, _stream); + break; + + case MessageStatus.Unknown: + case MessageStatus.CancelSignal: + end = true; + break; + } + } + } + catch (Exception) + { + // Console.WriteLine (ex); + } + finally + { + try { + _serverChannel.ReleaseConnection (Thread.CurrentThread); + _stream.Close(); + _client.Close (); + } catch { + } + } + } + + public bool IsLocal + { + get + { + return true; + } + } + } +} diff --git a/Mono.Posix/Mono.Remoting.Channels.Unix/UnixServerTransportSink.cs b/Mono.Posix/Mono.Remoting.Channels.Unix/UnixServerTransportSink.cs new file mode 100644 index 0000000..6f91096 --- /dev/null +++ b/Mono.Posix/Mono.Remoting.Channels.Unix/UnixServerTransportSink.cs @@ -0,0 +1,136 @@ +// +// Mono.Remoting.Channels.Unix.UnixServerTransportSink.cs +// +// Author: Rodrigo Moya (rodrigo@ximian.com) +// Lluis Sanchez Gual (lsg@ctv.es) +// +// Copyright (C) 2005 Novell, Inc (http://www.novell.com) +// + +// +// 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.Net.Sockets; +using System.Collections; +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; + } + } + } +} + diff --git a/Mono.Posix/Mono.Unix.Native/CdeclFunction.cs b/Mono.Posix/Mono.Unix.Native/CdeclFunction.cs new file mode 100644 index 0000000..d60e4ce --- /dev/null +++ b/Mono.Posix/Mono.Unix.Native/CdeclFunction.cs @@ -0,0 +1,188 @@ +// +// Mono.Unix/CdeclFunction.cs +// +// Authors: +// Jonathan Pryor (jonpryor@vt.edu) +// +// (C) 2004 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.Collections; +using System.Reflection; +using System.Reflection.Emit; +using System.Runtime.InteropServices; +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; + + private Hashtable overloads; + + 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 object Invoke (object[] parameters) + { + Type[] parameterTypes = GetParameterTypes (parameters); + MethodInfo m = CreateMethod (parameterTypes); + return m.Invoke (null, parameters); + } + + private MethodInfo CreateMethod (Type[] parameterTypes) + { + string typeName = GetTypeName (parameterTypes); + + lock (overloads) { + MethodInfo mi = (MethodInfo) overloads [typeName]; + + 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; + } + } + + private TypeBuilder CreateType (string typeName) + { + return moduleBuilder.DefineType (typeName, TypeAttributes.Public); + } + + private static Type GetMarshalType (Type t) + { + switch (Type.GetTypeCode (t)) { + // types < sizeof(int) are marshaled as ints + case TypeCode.Boolean: case TypeCode.Char: case TypeCode.SByte: + case TypeCode.Int16: case TypeCode.Int32: + return typeof(int); + case TypeCode.Byte: case TypeCode.UInt16: case TypeCode.UInt32: + return typeof(uint); + case TypeCode.Int64: + return typeof(long); + case TypeCode.UInt64: + return typeof(ulong); + case TypeCode.Single: case TypeCode.Double: + return typeof(double); + default: + return t; + } + } + + private string GetTypeName (Type[] parameterTypes) + { + StringBuilder sb = new StringBuilder (); + + 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; + } + } +} + diff --git a/Mono.Posix/Mono.Unix.Native/FileNameMarshaler.cs b/Mono.Posix/Mono.Unix.Native/FileNameMarshaler.cs new file mode 100644 index 0000000..e2093b3 --- /dev/null +++ b/Mono.Posix/Mono.Unix.Native/FileNameMarshaler.cs @@ -0,0 +1,79 @@ +// +// Mono.Unix/FileNameMarshaler.cs +// +// Authors: +// Jonathan Pryor (jonpryor@vt.edu) +// +// (C) 2005 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.Runtime.InteropServices; +using Mono.Unix; + +namespace Mono.Unix.Native { + + class FileNameMarshaler : ICustomMarshaler { + + private static FileNameMarshaler Instance = new FileNameMarshaler (); + + 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; + } + } +} + +// vim: noexpandtab diff --git a/Mono.Posix/Mono.Unix.Native/MapAttribute.cs b/Mono.Posix/Mono.Unix.Native/MapAttribute.cs new file mode 100644 index 0000000..e659975 --- /dev/null +++ b/Mono.Posix/Mono.Unix.Native/MapAttribute.cs @@ -0,0 +1,60 @@ +// +// MapAttribute.cs +// +// Author: +// Miguel de Icaza (miguel@gnome.org) +// +// (C) Novell, Inc. +// + +// +// 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; + +[AttributeUsage ( + AttributeTargets.Class | + AttributeTargets.Delegate | + AttributeTargets.Enum | + AttributeTargets.Field | + AttributeTargets.Struct)] +internal class MapAttribute : Attribute { + private string nativeType; + private string suppressFlags; + + public MapAttribute () + { + } + + public MapAttribute (string nativeType) + { + this.nativeType = nativeType; + } + + public string NativeType { + get {return nativeType;} + } + + public string SuppressFlags { + get {return suppressFlags;} + set {suppressFlags = value;} + } +} + diff --git a/Mono.Posix/Mono.Unix.Native/NativeConvert.cs b/Mono.Posix/Mono.Unix.Native/NativeConvert.cs new file mode 100644 index 0000000..810e13a --- /dev/null +++ b/Mono.Posix/Mono.Unix.Native/NativeConvert.cs @@ -0,0 +1,488 @@ +/* + * This file was automatically generated by make-map from Mono.Posix.dll. + * + * DO NOT MODIFY. + */ + +using System; +using System.IO; +using System.Runtime.InteropServices; +using Mono.Unix.Native; +#if MONODROID +using Mono.Unix.Android; +#endif + +namespace Mono.Unix.Native { + + [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); + + 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); +#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 an offset to an rt signum + public static RealTimeSignum ToRealTimeSignum (int offset) + { + return new RealTimeSignum (offset); + } + + // convert from octal representation. + public static FilePermissions FromOctalPermissionString (string value) + { + uint n = Convert.ToUInt32 (value, 8); + return ToFilePermissions (n); + } + + public static string ToOctalPermissionString (FilePermissions value) + { + string s = Convert.ToString ((int) (value & ~FilePermissions.S_IFMT), 8); + return new string ('0', 4-s.Length) + s; + } + + 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"); + + int i = 0; + FilePermissions perms = new FilePermissions (); + + if (value.Length == 10) { + perms |= GetUnixPermissionDevice (value [i]); + ++i; + } + + perms |= GetUnixPermissionGroup ( + value [i++], FilePermissions.S_IRUSR, + value [i++], FilePermissions.S_IWUSR, + value [i++], FilePermissions.S_IXUSR, + 's', 'S', FilePermissions.S_ISUID); + + perms |= GetUnixPermissionGroup ( + value [i++], FilePermissions.S_IRGRP, + value [i++], FilePermissions.S_IWGRP, + value [i++], FilePermissions.S_IXGRP, + 's', 'S', FilePermissions.S_ISGID); + + perms |= GetUnixPermissionGroup ( + value [i++], FilePermissions.S_IROTH, + value [i++], FilePermissions.S_IWOTH, + value [i++], FilePermissions.S_IXOTH, + 't', 'T', FilePermissions.S_ISVTX); + + return perms; + } + + 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 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; + } + + // Create ls(1) drwxrwxrwx permissions display + public static string ToUnixPermissionString (FilePermissions value) + { + char [] access = new char[] { + '-', // device + '-', '-', '-', // owner + '-', '-', '-', // group + '-', '-', '-', // other + }; + bool have_device = true; + switch (value & FilePermissions.S_IFMT) { + case FilePermissions.S_IFDIR: access [0] = 'd'; break; + case FilePermissions.S_IFCHR: access [0] = 'c'; break; + case FilePermissions.S_IFBLK: access [0] = 'b'; break; + case FilePermissions.S_IFREG: access [0] = '-'; break; + case FilePermissions.S_IFIFO: access [0] = 'p'; break; + case FilePermissions.S_IFLNK: access [0] = 'l'; break; + case FilePermissions.S_IFSOCK: access [0] = 's'; break; + default: have_device = false; break; + } + SetUnixPermissionGroup (value, access, 1, + FilePermissions.S_IRUSR, FilePermissions.S_IWUSR, FilePermissions.S_IXUSR, + 's', 'S', FilePermissions.S_ISUID); + SetUnixPermissionGroup (value, access, 4, + FilePermissions.S_IRGRP, FilePermissions.S_IWGRP, FilePermissions.S_IXGRP, + 's', 'S', FilePermissions.S_ISGID); + SetUnixPermissionGroup (value, access, 7, + FilePermissions.S_IROTH, FilePermissions.S_IWOTH, FilePermissions.S_IXOTH, + 't', 'T', FilePermissions.S_ISVTX); + return have_device + ? new string (access) + : new string (access, 1, 9); + } + + private static 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); + } + + // 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 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 (long time) + { + return FromTimeT (time); + } + + public static DateTime ToDateTime (long time, long nanoTime) + { + return FromTimeT (time).AddMilliseconds (nanoTime / 1000); + } + + public static long FromDateTime (DateTime time) + { + return ToTimeT (time); + } + + public static DateTime FromTimeT (long time) + { + return UnixEpoch.AddSeconds (time).ToLocalTime (); + } + + 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"); + + if (time.Kind == DateTimeKind.Local) + time = time.ToUniversalTime (); + + return (long) (time - UnixEpoch).TotalSeconds; + } + + 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? + int _v; + if (TryFromOpenFlags (OpenFlags.O_LARGEFILE, out _v)) + 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"); + } + + 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; + } + } + } +} + +// vim: noexpandtab +// Local Variables: +// tab-width: 4 +// c-basic-offset: 4 +// indent-tabs-mode: t +// End: diff --git a/Mono.Posix/Mono.Unix.Native/NativeConvert.generated.cs b/Mono.Posix/Mono.Unix.Native/NativeConvert.generated.cs new file mode 100644 index 0000000..d980bbf --- /dev/null +++ b/Mono.Posix/Mono.Unix.Native/NativeConvert.generated.cs @@ -0,0 +1,1451 @@ +/* + * This file was automatically generated by create-native-map from ./../../class/lib/net_4_x/Mono.Posix.dll. + * + * DO NOT MODIFY. + */ + +using System; +using System.Runtime.InteropServices; +using Mono.Unix.Native; + +namespace Mono.Unix.Native { + + public sealed /* static */ partial class NativeConvert + { + private NativeConvert () {} + + private const string LIB = "MonoPosixHelper"; + + private static void ThrowArgumentException (object value) + { + throw new ArgumentOutOfRangeException ("value", value, + Locale.GetText ("Current platform doesn't support this value.")); + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromAccessModes")] + private static extern int FromAccessModes (AccessModes value, out Int32 rval); + + public static bool TryFromAccessModes (AccessModes value, out Int32 rval) + { + return FromAccessModes (value, out rval) == 0; + } + + public static Int32 FromAccessModes (AccessModes value) + { + Int32 rval; + if (FromAccessModes (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToAccessModes")] + private static extern int ToAccessModes (Int32 value, out AccessModes rval); + + public static bool TryToAccessModes (Int32 value, out AccessModes rval) + { + return ToAccessModes (value, out rval) == 0; + } + + public static AccessModes ToAccessModes (Int32 value) + { + AccessModes rval; + if (ToAccessModes (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromAtFlags")] + private static extern int FromAtFlags (AtFlags value, out Int32 rval); + + public static bool TryFromAtFlags (AtFlags value, out Int32 rval) + { + return FromAtFlags (value, out rval) == 0; + } + + public static Int32 FromAtFlags (AtFlags value) + { + Int32 rval; + if (FromAtFlags (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToAtFlags")] + private static extern int ToAtFlags (Int32 value, out AtFlags rval); + + public static bool TryToAtFlags (Int32 value, out AtFlags rval) + { + return ToAtFlags (value, out rval) == 0; + } + + public static AtFlags ToAtFlags (Int32 value) + { + AtFlags rval; + if (ToAtFlags (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromCmsghdr")] + private static extern int FromCmsghdr (ref Cmsghdr source, IntPtr destination); + + public static bool TryCopy (ref Cmsghdr source, IntPtr destination) + { + return FromCmsghdr (ref source, destination) == 0; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToCmsghdr")] + private static extern int ToCmsghdr (IntPtr source, out Cmsghdr destination); + + public static bool TryCopy (IntPtr source, out Cmsghdr destination) + { + return ToCmsghdr (source, out destination) == 0; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromConfstrName")] + private static extern int FromConfstrName (ConfstrName value, out Int32 rval); + + public static bool TryFromConfstrName (ConfstrName value, out Int32 rval) + { + return FromConfstrName (value, out rval) == 0; + } + + public static Int32 FromConfstrName (ConfstrName value) + { + Int32 rval; + if (FromConfstrName (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToConfstrName")] + private static extern int ToConfstrName (Int32 value, out ConfstrName rval); + + public static bool TryToConfstrName (Int32 value, out ConfstrName rval) + { + return ToConfstrName (value, out rval) == 0; + } + + public static ConfstrName ToConfstrName (Int32 value) + { + ConfstrName rval; + if (ToConfstrName (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromDirectoryNotifyFlags")] + private static extern int FromDirectoryNotifyFlags (DirectoryNotifyFlags value, out Int32 rval); + + public static bool TryFromDirectoryNotifyFlags (DirectoryNotifyFlags value, out Int32 rval) + { + return FromDirectoryNotifyFlags (value, out rval) == 0; + } + + public static Int32 FromDirectoryNotifyFlags (DirectoryNotifyFlags value) + { + Int32 rval; + if (FromDirectoryNotifyFlags (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToDirectoryNotifyFlags")] + private static extern int ToDirectoryNotifyFlags (Int32 value, out DirectoryNotifyFlags rval); + + public static bool TryToDirectoryNotifyFlags (Int32 value, out DirectoryNotifyFlags rval) + { + return ToDirectoryNotifyFlags (value, out rval) == 0; + } + + public static DirectoryNotifyFlags ToDirectoryNotifyFlags (Int32 value) + { + DirectoryNotifyFlags rval; + if (ToDirectoryNotifyFlags (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromEpollEvents")] + private static extern int FromEpollEvents (EpollEvents value, out UInt32 rval); + + public static bool TryFromEpollEvents (EpollEvents value, out UInt32 rval) + { + return FromEpollEvents (value, out rval) == 0; + } + + public static UInt32 FromEpollEvents (EpollEvents value) + { + UInt32 rval; + if (FromEpollEvents (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToEpollEvents")] + private static extern int ToEpollEvents (UInt32 value, out EpollEvents rval); + + public static bool TryToEpollEvents (UInt32 value, out EpollEvents rval) + { + return ToEpollEvents (value, out rval) == 0; + } + + public static EpollEvents ToEpollEvents (UInt32 value) + { + EpollEvents rval; + if (ToEpollEvents (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromEpollFlags")] + private static extern int FromEpollFlags (EpollFlags value, out Int32 rval); + + public static bool TryFromEpollFlags (EpollFlags value, out Int32 rval) + { + return FromEpollFlags (value, out rval) == 0; + } + + public static Int32 FromEpollFlags (EpollFlags value) + { + Int32 rval; + if (FromEpollFlags (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToEpollFlags")] + private static extern int ToEpollFlags (Int32 value, out EpollFlags rval); + + public static bool TryToEpollFlags (Int32 value, out EpollFlags rval) + { + return ToEpollFlags (value, out rval) == 0; + } + + public static EpollFlags ToEpollFlags (Int32 value) + { + EpollFlags rval; + if (ToEpollFlags (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromErrno")] + private static extern int FromErrno (Errno value, out Int32 rval); + + public static bool TryFromErrno (Errno value, out Int32 rval) + { + return FromErrno (value, out rval) == 0; + } + + public static Int32 FromErrno (Errno value) + { + Int32 rval; + if (FromErrno (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToErrno")] + private static extern int ToErrno (Int32 value, out Errno rval); + + public static bool TryToErrno (Int32 value, out Errno rval) + { + return ToErrno (value, out rval) == 0; + } + + public static Errno ToErrno (Int32 value) + { + Errno rval; + if (ToErrno (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromFcntlCommand")] + private static extern int FromFcntlCommand (FcntlCommand value, out Int32 rval); + + public static bool TryFromFcntlCommand (FcntlCommand value, out Int32 rval) + { + return FromFcntlCommand (value, out rval) == 0; + } + + public static Int32 FromFcntlCommand (FcntlCommand value) + { + Int32 rval; + if (FromFcntlCommand (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToFcntlCommand")] + private static extern int ToFcntlCommand (Int32 value, out FcntlCommand rval); + + public static bool TryToFcntlCommand (Int32 value, out FcntlCommand rval) + { + return ToFcntlCommand (value, out rval) == 0; + } + + public static FcntlCommand ToFcntlCommand (Int32 value) + { + FcntlCommand rval; + if (ToFcntlCommand (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromFilePermissions")] + private static extern int FromFilePermissions (FilePermissions value, out UInt32 rval); + + public static bool TryFromFilePermissions (FilePermissions value, out UInt32 rval) + { + return FromFilePermissions (value, out rval) == 0; + } + + public static UInt32 FromFilePermissions (FilePermissions value) + { + UInt32 rval; + if (FromFilePermissions (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToFilePermissions")] + private static extern int ToFilePermissions (UInt32 value, out FilePermissions rval); + + public static bool TryToFilePermissions (UInt32 value, out FilePermissions rval) + { + return ToFilePermissions (value, out rval) == 0; + } + + public static FilePermissions ToFilePermissions (UInt32 value) + { + FilePermissions rval; + if (ToFilePermissions (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromFlock")] + private static extern int FromFlock (ref Flock source, IntPtr destination); + + public static bool TryCopy (ref Flock source, IntPtr destination) + { + return FromFlock (ref source, destination) == 0; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToFlock")] + private static extern int ToFlock (IntPtr source, out Flock destination); + + public static bool TryCopy (IntPtr source, out Flock destination) + { + return ToFlock (source, out destination) == 0; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromIovec")] + private static extern int FromIovec (ref Iovec source, IntPtr destination); + + public static bool TryCopy (ref Iovec source, IntPtr destination) + { + return FromIovec (ref source, destination) == 0; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToIovec")] + private static extern int ToIovec (IntPtr source, out Iovec destination); + + public static bool TryCopy (IntPtr source, out Iovec destination) + { + return ToIovec (source, out destination) == 0; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromLinger")] + private static extern int FromLinger (ref Linger source, IntPtr destination); + + public static bool TryCopy (ref Linger source, IntPtr destination) + { + return FromLinger (ref source, destination) == 0; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToLinger")] + private static extern int ToLinger (IntPtr source, out Linger destination); + + public static bool TryCopy (IntPtr source, out Linger destination) + { + return ToLinger (source, out destination) == 0; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromLockType")] + private static extern int FromLockType (LockType value, out Int16 rval); + + public static bool TryFromLockType (LockType value, out Int16 rval) + { + return FromLockType (value, out rval) == 0; + } + + public static Int16 FromLockType (LockType value) + { + Int16 rval; + if (FromLockType (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToLockType")] + private static extern int ToLockType (Int16 value, out LockType rval); + + public static bool TryToLockType (Int16 value, out LockType rval) + { + return ToLockType (value, out rval) == 0; + } + + public static LockType ToLockType (Int16 value) + { + LockType rval; + if (ToLockType (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromLockfCommand")] + private static extern int FromLockfCommand (LockfCommand value, out Int32 rval); + + public static bool TryFromLockfCommand (LockfCommand value, out Int32 rval) + { + return FromLockfCommand (value, out rval) == 0; + } + + public static Int32 FromLockfCommand (LockfCommand value) + { + Int32 rval; + if (FromLockfCommand (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToLockfCommand")] + private static extern int ToLockfCommand (Int32 value, out LockfCommand rval); + + public static bool TryToLockfCommand (Int32 value, out LockfCommand rval) + { + return ToLockfCommand (value, out rval) == 0; + } + + public static LockfCommand ToLockfCommand (Int32 value) + { + LockfCommand rval; + if (ToLockfCommand (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromMessageFlags")] + private static extern int FromMessageFlags (MessageFlags value, out Int32 rval); + + public static bool TryFromMessageFlags (MessageFlags value, out Int32 rval) + { + return FromMessageFlags (value, out rval) == 0; + } + + public static Int32 FromMessageFlags (MessageFlags value) + { + Int32 rval; + if (FromMessageFlags (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToMessageFlags")] + private static extern int ToMessageFlags (Int32 value, out MessageFlags rval); + + public static bool TryToMessageFlags (Int32 value, out MessageFlags rval) + { + return ToMessageFlags (value, out rval) == 0; + } + + public static MessageFlags ToMessageFlags (Int32 value) + { + MessageFlags rval; + if (ToMessageFlags (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromMlockallFlags")] + private static extern int FromMlockallFlags (MlockallFlags value, out Int32 rval); + + public static bool TryFromMlockallFlags (MlockallFlags value, out Int32 rval) + { + return FromMlockallFlags (value, out rval) == 0; + } + + public static Int32 FromMlockallFlags (MlockallFlags value) + { + Int32 rval; + if (FromMlockallFlags (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToMlockallFlags")] + private static extern int ToMlockallFlags (Int32 value, out MlockallFlags rval); + + public static bool TryToMlockallFlags (Int32 value, out MlockallFlags rval) + { + return ToMlockallFlags (value, out rval) == 0; + } + + public static MlockallFlags ToMlockallFlags (Int32 value) + { + MlockallFlags rval; + if (ToMlockallFlags (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromMmapFlags")] + private static extern int FromMmapFlags (MmapFlags value, out Int32 rval); + + public static bool TryFromMmapFlags (MmapFlags value, out Int32 rval) + { + return FromMmapFlags (value, out rval) == 0; + } + + public static Int32 FromMmapFlags (MmapFlags value) + { + Int32 rval; + if (FromMmapFlags (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToMmapFlags")] + private static extern int ToMmapFlags (Int32 value, out MmapFlags rval); + + public static bool TryToMmapFlags (Int32 value, out MmapFlags rval) + { + return ToMmapFlags (value, out rval) == 0; + } + + public static MmapFlags ToMmapFlags (Int32 value) + { + MmapFlags rval; + if (ToMmapFlags (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromMmapProts")] + private static extern int FromMmapProts (MmapProts value, out Int32 rval); + + public static bool TryFromMmapProts (MmapProts value, out Int32 rval) + { + return FromMmapProts (value, out rval) == 0; + } + + public static Int32 FromMmapProts (MmapProts value) + { + Int32 rval; + if (FromMmapProts (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToMmapProts")] + private static extern int ToMmapProts (Int32 value, out MmapProts rval); + + public static bool TryToMmapProts (Int32 value, out MmapProts rval) + { + return ToMmapProts (value, out rval) == 0; + } + + public static MmapProts ToMmapProts (Int32 value) + { + MmapProts rval; + if (ToMmapProts (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromMountFlags")] + private static extern int FromMountFlags (MountFlags value, out UInt64 rval); + + public static bool TryFromMountFlags (MountFlags value, out UInt64 rval) + { + return FromMountFlags (value, out rval) == 0; + } + + public static UInt64 FromMountFlags (MountFlags value) + { + UInt64 rval; + if (FromMountFlags (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToMountFlags")] + private static extern int ToMountFlags (UInt64 value, out MountFlags rval); + + public static bool TryToMountFlags (UInt64 value, out MountFlags rval) + { + return ToMountFlags (value, out rval) == 0; + } + + public static MountFlags ToMountFlags (UInt64 value) + { + MountFlags rval; + if (ToMountFlags (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromMremapFlags")] + private static extern int FromMremapFlags (MremapFlags value, out UInt64 rval); + + public static bool TryFromMremapFlags (MremapFlags value, out UInt64 rval) + { + return FromMremapFlags (value, out rval) == 0; + } + + public static UInt64 FromMremapFlags (MremapFlags value) + { + UInt64 rval; + if (FromMremapFlags (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToMremapFlags")] + private static extern int ToMremapFlags (UInt64 value, out MremapFlags rval); + + public static bool TryToMremapFlags (UInt64 value, out MremapFlags rval) + { + return ToMremapFlags (value, out rval) == 0; + } + + public static MremapFlags ToMremapFlags (UInt64 value) + { + MremapFlags rval; + if (ToMremapFlags (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromMsyncFlags")] + private static extern int FromMsyncFlags (MsyncFlags value, out Int32 rval); + + public static bool TryFromMsyncFlags (MsyncFlags value, out Int32 rval) + { + return FromMsyncFlags (value, out rval) == 0; + } + + public static Int32 FromMsyncFlags (MsyncFlags value) + { + Int32 rval; + if (FromMsyncFlags (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToMsyncFlags")] + private static extern int ToMsyncFlags (Int32 value, out MsyncFlags rval); + + public static bool TryToMsyncFlags (Int32 value, out MsyncFlags rval) + { + return ToMsyncFlags (value, out rval) == 0; + } + + public static MsyncFlags ToMsyncFlags (Int32 value) + { + MsyncFlags rval; + if (ToMsyncFlags (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromOpenFlags")] + private static extern int FromOpenFlags (OpenFlags value, out Int32 rval); + + public static bool TryFromOpenFlags (OpenFlags value, out Int32 rval) + { + return FromOpenFlags (value, out rval) == 0; + } + + public static Int32 FromOpenFlags (OpenFlags value) + { + Int32 rval; + if (FromOpenFlags (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToOpenFlags")] + private static extern int ToOpenFlags (Int32 value, out OpenFlags rval); + + public static bool TryToOpenFlags (Int32 value, out OpenFlags rval) + { + return ToOpenFlags (value, out rval) == 0; + } + + public static OpenFlags ToOpenFlags (Int32 value) + { + OpenFlags rval; + if (ToOpenFlags (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromPathconfName")] + private static extern int FromPathconfName (PathconfName value, out Int32 rval); + + public static bool TryFromPathconfName (PathconfName value, out Int32 rval) + { + return FromPathconfName (value, out rval) == 0; + } + + public static Int32 FromPathconfName (PathconfName value) + { + Int32 rval; + if (FromPathconfName (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToPathconfName")] + private static extern int ToPathconfName (Int32 value, out PathconfName rval); + + public static bool TryToPathconfName (Int32 value, out PathconfName rval) + { + return ToPathconfName (value, out rval) == 0; + } + + public static PathconfName ToPathconfName (Int32 value) + { + PathconfName rval; + if (ToPathconfName (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromPollEvents")] + private static extern int FromPollEvents (PollEvents value, out Int16 rval); + + public static bool TryFromPollEvents (PollEvents value, out Int16 rval) + { + return FromPollEvents (value, out rval) == 0; + } + + public static Int16 FromPollEvents (PollEvents value) + { + Int16 rval; + if (FromPollEvents (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToPollEvents")] + private static extern int ToPollEvents (Int16 value, out PollEvents rval); + + public static bool TryToPollEvents (Int16 value, out PollEvents rval) + { + return ToPollEvents (value, out rval) == 0; + } + + public static PollEvents ToPollEvents (Int16 value) + { + PollEvents rval; + if (ToPollEvents (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromPollfd")] + private static extern int FromPollfd (ref Pollfd source, IntPtr destination); + + public static bool TryCopy (ref Pollfd source, IntPtr destination) + { + return FromPollfd (ref source, destination) == 0; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToPollfd")] + private static extern int ToPollfd (IntPtr source, out Pollfd destination); + + public static bool TryCopy (IntPtr source, out Pollfd destination) + { + return ToPollfd (source, out destination) == 0; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromPosixFadviseAdvice")] + private static extern int FromPosixFadviseAdvice (PosixFadviseAdvice value, out Int32 rval); + + public static bool TryFromPosixFadviseAdvice (PosixFadviseAdvice value, out Int32 rval) + { + return FromPosixFadviseAdvice (value, out rval) == 0; + } + + public static Int32 FromPosixFadviseAdvice (PosixFadviseAdvice value) + { + Int32 rval; + if (FromPosixFadviseAdvice (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToPosixFadviseAdvice")] + private static extern int ToPosixFadviseAdvice (Int32 value, out PosixFadviseAdvice rval); + + public static bool TryToPosixFadviseAdvice (Int32 value, out PosixFadviseAdvice rval) + { + return ToPosixFadviseAdvice (value, out rval) == 0; + } + + public static PosixFadviseAdvice ToPosixFadviseAdvice (Int32 value) + { + PosixFadviseAdvice rval; + if (ToPosixFadviseAdvice (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromPosixMadviseAdvice")] + private static extern int FromPosixMadviseAdvice (PosixMadviseAdvice value, out Int32 rval); + + public static bool TryFromPosixMadviseAdvice (PosixMadviseAdvice value, out Int32 rval) + { + return FromPosixMadviseAdvice (value, out rval) == 0; + } + + public static Int32 FromPosixMadviseAdvice (PosixMadviseAdvice value) + { + Int32 rval; + if (FromPosixMadviseAdvice (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToPosixMadviseAdvice")] + private static extern int ToPosixMadviseAdvice (Int32 value, out PosixMadviseAdvice rval); + + public static bool TryToPosixMadviseAdvice (Int32 value, out PosixMadviseAdvice rval) + { + return ToPosixMadviseAdvice (value, out rval) == 0; + } + + public static PosixMadviseAdvice ToPosixMadviseAdvice (Int32 value) + { + PosixMadviseAdvice rval; + if (ToPosixMadviseAdvice (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromSeekFlags")] + private static extern int FromSeekFlags (SeekFlags value, out Int16 rval); + + public static bool TryFromSeekFlags (SeekFlags value, out Int16 rval) + { + return FromSeekFlags (value, out rval) == 0; + } + + public static Int16 FromSeekFlags (SeekFlags value) + { + Int16 rval; + if (FromSeekFlags (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToSeekFlags")] + private static extern int ToSeekFlags (Int16 value, out SeekFlags rval); + + public static bool TryToSeekFlags (Int16 value, out SeekFlags rval) + { + return ToSeekFlags (value, out rval) == 0; + } + + public static SeekFlags ToSeekFlags (Int16 value) + { + SeekFlags rval; + if (ToSeekFlags (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromShutdownOption")] + private static extern int FromShutdownOption (ShutdownOption value, out Int32 rval); + + public static bool TryFromShutdownOption (ShutdownOption value, out Int32 rval) + { + return FromShutdownOption (value, out rval) == 0; + } + + public static Int32 FromShutdownOption (ShutdownOption value) + { + Int32 rval; + if (FromShutdownOption (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToShutdownOption")] + private static extern int ToShutdownOption (Int32 value, out ShutdownOption rval); + + public static bool TryToShutdownOption (Int32 value, out ShutdownOption rval) + { + return ToShutdownOption (value, out rval) == 0; + } + + public static ShutdownOption ToShutdownOption (Int32 value) + { + ShutdownOption rval; + if (ToShutdownOption (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromSignum")] + private static extern int FromSignum (Signum value, out Int32 rval); + + public static bool TryFromSignum (Signum value, out Int32 rval) + { + return FromSignum (value, out rval) == 0; + } + + public static Int32 FromSignum (Signum value) + { + Int32 rval; + if (FromSignum (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToSignum")] + private static extern int ToSignum (Int32 value, out Signum rval); + + public static bool TryToSignum (Int32 value, out Signum rval) + { + return ToSignum (value, out rval) == 0; + } + + public static Signum ToSignum (Int32 value) + { + Signum rval; + if (ToSignum (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromSockaddrIn")] + private static extern int FromSockaddrIn (SockaddrIn source, IntPtr destination); + + public static bool TryCopy (SockaddrIn source, IntPtr destination) + { + return FromSockaddrIn (source, destination) == 0; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToSockaddrIn")] + private static extern int ToSockaddrIn (IntPtr source, SockaddrIn destination); + + public static bool TryCopy (IntPtr source, SockaddrIn destination) + { + return ToSockaddrIn (source, destination) == 0; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromSockaddrIn6")] + private static extern int FromSockaddrIn6 (SockaddrIn6 source, IntPtr destination); + + public static bool TryCopy (SockaddrIn6 source, IntPtr destination) + { + return FromSockaddrIn6 (source, destination) == 0; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToSockaddrIn6")] + private static extern int ToSockaddrIn6 (IntPtr source, SockaddrIn6 destination); + + public static bool TryCopy (IntPtr source, SockaddrIn6 destination) + { + return ToSockaddrIn6 (source, destination) == 0; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromSockaddrType")] + private static extern int FromSockaddrType (SockaddrType value, out Int32 rval); + + internal static bool TryFromSockaddrType (SockaddrType value, out Int32 rval) + { + return FromSockaddrType (value, out rval) == 0; + } + + internal static Int32 FromSockaddrType (SockaddrType value) + { + Int32 rval; + if (FromSockaddrType (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToSockaddrType")] + private static extern int ToSockaddrType (Int32 value, out SockaddrType rval); + + internal static bool TryToSockaddrType (Int32 value, out SockaddrType rval) + { + return ToSockaddrType (value, out rval) == 0; + } + + internal static SockaddrType ToSockaddrType (Int32 value) + { + SockaddrType rval; + if (ToSockaddrType (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromSysconfName")] + private static extern int FromSysconfName (SysconfName value, out Int32 rval); + + public static bool TryFromSysconfName (SysconfName value, out Int32 rval) + { + return FromSysconfName (value, out rval) == 0; + } + + public static Int32 FromSysconfName (SysconfName value) + { + Int32 rval; + if (FromSysconfName (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToSysconfName")] + private static extern int ToSysconfName (Int32 value, out SysconfName rval); + + public static bool TryToSysconfName (Int32 value, out SysconfName rval) + { + return ToSysconfName (value, out rval) == 0; + } + + public static SysconfName ToSysconfName (Int32 value) + { + SysconfName rval; + if (ToSysconfName (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromSyslogFacility")] + private static extern int FromSyslogFacility (SyslogFacility value, out Int32 rval); + + public static bool TryFromSyslogFacility (SyslogFacility value, out Int32 rval) + { + return FromSyslogFacility (value, out rval) == 0; + } + + public static Int32 FromSyslogFacility (SyslogFacility value) + { + Int32 rval; + if (FromSyslogFacility (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToSyslogFacility")] + private static extern int ToSyslogFacility (Int32 value, out SyslogFacility rval); + + public static bool TryToSyslogFacility (Int32 value, out SyslogFacility rval) + { + return ToSyslogFacility (value, out rval) == 0; + } + + public static SyslogFacility ToSyslogFacility (Int32 value) + { + SyslogFacility rval; + if (ToSyslogFacility (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromSyslogLevel")] + private static extern int FromSyslogLevel (SyslogLevel value, out Int32 rval); + + public static bool TryFromSyslogLevel (SyslogLevel value, out Int32 rval) + { + return FromSyslogLevel (value, out rval) == 0; + } + + public static Int32 FromSyslogLevel (SyslogLevel value) + { + Int32 rval; + if (FromSyslogLevel (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToSyslogLevel")] + private static extern int ToSyslogLevel (Int32 value, out SyslogLevel rval); + + public static bool TryToSyslogLevel (Int32 value, out SyslogLevel rval) + { + return ToSyslogLevel (value, out rval) == 0; + } + + public static SyslogLevel ToSyslogLevel (Int32 value) + { + SyslogLevel rval; + if (ToSyslogLevel (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromSyslogOptions")] + private static extern int FromSyslogOptions (SyslogOptions value, out Int32 rval); + + public static bool TryFromSyslogOptions (SyslogOptions value, out Int32 rval) + { + return FromSyslogOptions (value, out rval) == 0; + } + + public static Int32 FromSyslogOptions (SyslogOptions value) + { + Int32 rval; + if (FromSyslogOptions (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToSyslogOptions")] + private static extern int ToSyslogOptions (Int32 value, out SyslogOptions rval); + + public static bool TryToSyslogOptions (Int32 value, out SyslogOptions rval) + { + return ToSyslogOptions (value, out rval) == 0; + } + + public static SyslogOptions ToSyslogOptions (Int32 value) + { + SyslogOptions rval; + if (ToSyslogOptions (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromTimespec")] + private static extern int FromTimespec (ref Timespec source, IntPtr destination); + + public static bool TryCopy (ref Timespec source, IntPtr destination) + { + return FromTimespec (ref source, destination) == 0; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToTimespec")] + private static extern int ToTimespec (IntPtr source, out Timespec destination); + + public static bool TryCopy (IntPtr source, out Timespec destination) + { + return ToTimespec (source, out destination) == 0; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromTimeval")] + private static extern int FromTimeval (ref Timeval source, IntPtr destination); + + public static bool TryCopy (ref Timeval source, IntPtr destination) + { + return FromTimeval (ref source, destination) == 0; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToTimeval")] + private static extern int ToTimeval (IntPtr source, out Timeval destination); + + public static bool TryCopy (IntPtr source, out Timeval destination) + { + return ToTimeval (source, out destination) == 0; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromTimezone")] + private static extern int FromTimezone (ref Timezone source, IntPtr destination); + + public static bool TryCopy (ref Timezone source, IntPtr destination) + { + return FromTimezone (ref source, destination) == 0; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToTimezone")] + private static extern int ToTimezone (IntPtr source, out Timezone destination); + + public static bool TryCopy (IntPtr source, out Timezone destination) + { + return ToTimezone (source, out destination) == 0; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromUnixAddressFamily")] + private static extern int FromUnixAddressFamily (UnixAddressFamily value, out Int32 rval); + + public static bool TryFromUnixAddressFamily (UnixAddressFamily value, out Int32 rval) + { + return FromUnixAddressFamily (value, out rval) == 0; + } + + public static Int32 FromUnixAddressFamily (UnixAddressFamily value) + { + Int32 rval; + if (FromUnixAddressFamily (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToUnixAddressFamily")] + private static extern int ToUnixAddressFamily (Int32 value, out UnixAddressFamily rval); + + public static bool TryToUnixAddressFamily (Int32 value, out UnixAddressFamily rval) + { + return ToUnixAddressFamily (value, out rval) == 0; + } + + public static UnixAddressFamily ToUnixAddressFamily (Int32 value) + { + UnixAddressFamily rval; + if (ToUnixAddressFamily (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromUnixSocketControlMessage")] + private static extern int FromUnixSocketControlMessage (UnixSocketControlMessage value, out Int32 rval); + + public static bool TryFromUnixSocketControlMessage (UnixSocketControlMessage value, out Int32 rval) + { + return FromUnixSocketControlMessage (value, out rval) == 0; + } + + public static Int32 FromUnixSocketControlMessage (UnixSocketControlMessage value) + { + Int32 rval; + if (FromUnixSocketControlMessage (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToUnixSocketControlMessage")] + private static extern int ToUnixSocketControlMessage (Int32 value, out UnixSocketControlMessage rval); + + public static bool TryToUnixSocketControlMessage (Int32 value, out UnixSocketControlMessage rval) + { + return ToUnixSocketControlMessage (value, out rval) == 0; + } + + public static UnixSocketControlMessage ToUnixSocketControlMessage (Int32 value) + { + UnixSocketControlMessage rval; + if (ToUnixSocketControlMessage (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromUnixSocketFlags")] + private static extern int FromUnixSocketFlags (UnixSocketFlags value, out Int32 rval); + + public static bool TryFromUnixSocketFlags (UnixSocketFlags value, out Int32 rval) + { + return FromUnixSocketFlags (value, out rval) == 0; + } + + public static Int32 FromUnixSocketFlags (UnixSocketFlags value) + { + Int32 rval; + if (FromUnixSocketFlags (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToUnixSocketFlags")] + private static extern int ToUnixSocketFlags (Int32 value, out UnixSocketFlags rval); + + public static bool TryToUnixSocketFlags (Int32 value, out UnixSocketFlags rval) + { + return ToUnixSocketFlags (value, out rval) == 0; + } + + public static UnixSocketFlags ToUnixSocketFlags (Int32 value) + { + UnixSocketFlags rval; + if (ToUnixSocketFlags (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromUnixSocketOptionName")] + private static extern int FromUnixSocketOptionName (UnixSocketOptionName value, out Int32 rval); + + public static bool TryFromUnixSocketOptionName (UnixSocketOptionName value, out Int32 rval) + { + return FromUnixSocketOptionName (value, out rval) == 0; + } + + public static Int32 FromUnixSocketOptionName (UnixSocketOptionName value) + { + Int32 rval; + if (FromUnixSocketOptionName (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToUnixSocketOptionName")] + private static extern int ToUnixSocketOptionName (Int32 value, out UnixSocketOptionName rval); + + public static bool TryToUnixSocketOptionName (Int32 value, out UnixSocketOptionName rval) + { + return ToUnixSocketOptionName (value, out rval) == 0; + } + + public static UnixSocketOptionName ToUnixSocketOptionName (Int32 value) + { + UnixSocketOptionName rval; + if (ToUnixSocketOptionName (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromUnixSocketProtocol")] + private static extern int FromUnixSocketProtocol (UnixSocketProtocol value, out Int32 rval); + + public static bool TryFromUnixSocketProtocol (UnixSocketProtocol value, out Int32 rval) + { + return FromUnixSocketProtocol (value, out rval) == 0; + } + + public static Int32 FromUnixSocketProtocol (UnixSocketProtocol value) + { + Int32 rval; + if (FromUnixSocketProtocol (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToUnixSocketProtocol")] + private static extern int ToUnixSocketProtocol (Int32 value, out UnixSocketProtocol rval); + + public static bool TryToUnixSocketProtocol (Int32 value, out UnixSocketProtocol rval) + { + return ToUnixSocketProtocol (value, out rval) == 0; + } + + public static UnixSocketProtocol ToUnixSocketProtocol (Int32 value) + { + UnixSocketProtocol rval; + if (ToUnixSocketProtocol (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromUnixSocketType")] + private static extern int FromUnixSocketType (UnixSocketType value, out Int32 rval); + + public static bool TryFromUnixSocketType (UnixSocketType value, out Int32 rval) + { + return FromUnixSocketType (value, out rval) == 0; + } + + public static Int32 FromUnixSocketType (UnixSocketType value) + { + Int32 rval; + if (FromUnixSocketType (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToUnixSocketType")] + private static extern int ToUnixSocketType (Int32 value, out UnixSocketType rval); + + public static bool TryToUnixSocketType (Int32 value, out UnixSocketType rval) + { + return ToUnixSocketType (value, out rval) == 0; + } + + public static UnixSocketType ToUnixSocketType (Int32 value) + { + UnixSocketType rval; + if (ToUnixSocketType (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromUtimbuf")] + private static extern int FromUtimbuf (ref Utimbuf source, IntPtr destination); + + public static bool TryCopy (ref Utimbuf source, IntPtr destination) + { + return FromUtimbuf (ref source, destination) == 0; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToUtimbuf")] + private static extern int ToUtimbuf (IntPtr source, out Utimbuf destination); + + public static bool TryCopy (IntPtr source, out Utimbuf destination) + { + return ToUtimbuf (source, out destination) == 0; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromWaitOptions")] + private static extern int FromWaitOptions (WaitOptions value, out Int32 rval); + + public static bool TryFromWaitOptions (WaitOptions value, out Int32 rval) + { + return FromWaitOptions (value, out rval) == 0; + } + + public static Int32 FromWaitOptions (WaitOptions value) + { + Int32 rval; + if (FromWaitOptions (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToWaitOptions")] + private static extern int ToWaitOptions (Int32 value, out WaitOptions rval); + + public static bool TryToWaitOptions (Int32 value, out WaitOptions rval) + { + return ToWaitOptions (value, out rval) == 0; + } + + public static WaitOptions ToWaitOptions (Int32 value) + { + WaitOptions rval; + if (ToWaitOptions (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_FromXattrFlags")] + private static extern int FromXattrFlags (XattrFlags value, out Int32 rval); + + public static bool TryFromXattrFlags (XattrFlags value, out Int32 rval) + { + return FromXattrFlags (value, out rval) == 0; + } + + public static Int32 FromXattrFlags (XattrFlags value) + { + Int32 rval; + if (FromXattrFlags (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + [DllImport (LIB, EntryPoint="Mono_Posix_ToXattrFlags")] + private static extern int ToXattrFlags (Int32 value, out XattrFlags rval); + + public static bool TryToXattrFlags (Int32 value, out XattrFlags rval) + { + return ToXattrFlags (value, out rval) == 0; + } + + public static XattrFlags ToXattrFlags (Int32 value) + { + XattrFlags rval; + if (ToXattrFlags (value, out rval) == -1) + ThrowArgumentException (value); + return rval; + } + + } +} + diff --git a/Mono.Posix/Mono.Unix.Native/RealTimeSignum.cs b/Mono.Posix/Mono.Unix.Native/RealTimeSignum.cs new file mode 100644 index 0000000..3e53e78 --- /dev/null +++ b/Mono.Posix/Mono.Unix.Native/RealTimeSignum.cs @@ -0,0 +1,81 @@ +// +// Authors: +// Tim Jenks (tim.jenks@realtimeworlds.com) +// +// (C) 2008 Realtime Worlds Ltd +// +// 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.Runtime.InteropServices; +using System.Threading; + +namespace Mono.Unix.Native { + + public struct RealTimeSignum + : IEquatable + { + 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 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 int Offset { + get { return rt_offset; } + } + + public override int GetHashCode () + { + return rt_offset.GetHashCode (); + } + + public override bool Equals (object obj) + { + if ((obj == null) || (obj.GetType () != GetType ())) + return false; + return Equals ((RealTimeSignum)obj); + } + + public bool Equals (RealTimeSignum value) + { + return Offset == value.Offset; + } + + public static bool operator== (RealTimeSignum lhs, RealTimeSignum rhs) + { + return lhs.Equals (rhs); + } + + public static bool operator!= (RealTimeSignum lhs, RealTimeSignum rhs) + { + return !lhs.Equals (rhs); + } + } +} diff --git a/Mono.Posix/Mono.Unix.Native/Stdlib.cs b/Mono.Posix/Mono.Unix.Native/Stdlib.cs new file mode 100644 index 0000000..59b66ca --- /dev/null +++ b/Mono.Posix/Mono.Unix.Native/Stdlib.cs @@ -0,0 +1,1171 @@ +// +// Mono.Unix/Stdlib.cs +// +// Authors: +// Jonathan Pryor (jonpryor@vt.edu) +// +// (C) 2004-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.Collections; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; +using Mono.Unix.Native; + +namespace Mono.Unix.Native { + + #region Enumerations + + [Map] + public enum Errno : int { + // errors & their values liberally copied from + // FC2 /usr/include/asm/errno.h + + EPERM = 1, // Operation not permitted + ENOENT = 2, // No such file or directory + ESRCH = 3, // No such process + EINTR = 4, // Interrupted system call + EIO = 5, // I/O error + ENXIO = 6, // No such device or address + E2BIG = 7, // Arg list too long + ENOEXEC = 8, // Exec format error + EBADF = 9, // Bad file number + ECHILD = 10, // No child processes + EAGAIN = 11, // Try again + ENOMEM = 12, // Out of memory + EACCES = 13, // Permission denied + EFAULT = 14, // Bad address + ENOTBLK = 15, // Block device required + EBUSY = 16, // Device or resource busy + EEXIST = 17, // File exists + EXDEV = 18, // Cross-device link + ENODEV = 19, // No such device + ENOTDIR = 20, // Not a directory + EISDIR = 21, // Is a directory + EINVAL = 22, // Invalid argument + ENFILE = 23, // File table overflow + EMFILE = 24, // Too many open files + ENOTTY = 25, // Not a typewriter + ETXTBSY = 26, // Text file busy + EFBIG = 27, // File too large + ENOSPC = 28, // No space left on device + ESPIPE = 29, // Illegal seek + EROFS = 30, // Read-only file system + EMLINK = 31, // Too many links + EPIPE = 32, // Broken pipe + EDOM = 33, // Math argument out of domain of func + ERANGE = 34, // Math result not representable + EDEADLK = 35, // Resource deadlock would occur + ENAMETOOLONG = 36, // File name too long + ENOLCK = 37, // No record locks available + ENOSYS = 38, // Function not implemented + ENOTEMPTY = 39, // Directory not empty + ELOOP = 40, // Too many symbolic links encountered + EWOULDBLOCK = EAGAIN, // Operation would block + ENOMSG = 42, // No message of desired type + EIDRM = 43, // Identifier removed + ECHRNG = 44, // Channel number out of range + EL2NSYNC = 45, // Level 2 not synchronized + EL3HLT = 46, // Level 3 halted + EL3RST = 47, // Level 3 reset + ELNRNG = 48, // Link number out of range + EUNATCH = 49, // Protocol driver not attached + ENOCSI = 50, // No CSI structure available + EL2HLT = 51, // Level 2 halted + EBADE = 52, // Invalid exchange + EBADR = 53, // Invalid request descriptor + EXFULL = 54, // Exchange full + ENOANO = 55, // No anode + EBADRQC = 56, // Invalid request code + EBADSLT = 57, // Invalid slot + + EDEADLOCK = EDEADLK, + + EBFONT = 59, // Bad font file format + ENOSTR = 60, // Device not a stream + ENODATA = 61, // No data available + ETIME = 62, // Timer expired + ENOSR = 63, // Out of streams resources + ENONET = 64, // Machine is not on the network + ENOPKG = 65, // Package not installed + EREMOTE = 66, // Object is remote + ENOLINK = 67, // Link has been severed + EADV = 68, // Advertise error + ESRMNT = 69, // Srmount error + ECOMM = 70, // Communication error on send + EPROTO = 71, // Protocol error + EMULTIHOP = 72, // Multihop attempted + EDOTDOT = 73, // RFS specific error + EBADMSG = 74, // Not a data message + EOVERFLOW = 75, // Value too large for defined data type + ENOTUNIQ = 76, // Name not unique on network + EBADFD = 77, // File descriptor in bad state + EREMCHG = 78, // Remote address changed + ELIBACC = 79, // Can not access a needed shared library + ELIBBAD = 80, // Accessing a corrupted shared library + ELIBSCN = 81, // .lib section in a.out corrupted + ELIBMAX = 82, // Attempting to link in too many shared libraries + ELIBEXEC = 83, // Cannot exec a shared library directly + EILSEQ = 84, // Illegal byte sequence + ERESTART = 85, // Interrupted system call should be restarted + ESTRPIPE = 86, // Streams pipe error + EUSERS = 87, // Too many users + ENOTSOCK = 88, // Socket operation on non-socket + EDESTADDRREQ = 89, // Destination address required + EMSGSIZE = 90, // Message too long + EPROTOTYPE = 91, // Protocol wrong type for socket + ENOPROTOOPT = 92, // Protocol not available + EPROTONOSUPPORT = 93, // Protocol not supported + ESOCKTNOSUPPORT = 94, // Socket type not supported + EOPNOTSUPP = 95, // Operation not supported on transport endpoint + EPFNOSUPPORT = 96, // Protocol family not supported + EAFNOSUPPORT = 97, // Address family not supported by protocol + EADDRINUSE = 98, // Address already in use + EADDRNOTAVAIL = 99, // Cannot assign requested address + ENETDOWN = 100, // Network is down + ENETUNREACH = 101, // Network is unreachable + ENETRESET = 102, // Network dropped connection because of reset + ECONNABORTED = 103, // Software caused connection abort + ECONNRESET = 104, // Connection reset by peer + ENOBUFS = 105, // No buffer space available + EISCONN = 106, // Transport endpoint is already connected + ENOTCONN = 107, // Transport endpoint is not connected + ESHUTDOWN = 108, // Cannot send after transport endpoint shutdown + ETOOMANYREFS = 109, // Too many references: cannot splice + ETIMEDOUT = 110, // Connection timed out + ECONNREFUSED = 111, // Connection refused + EHOSTDOWN = 112, // Host is down + EHOSTUNREACH = 113, // No route to host + EALREADY = 114, // Operation already in progress + EINPROGRESS = 115, // Operation now in progress + ESTALE = 116, // Stale NFS file handle + EUCLEAN = 117, // Structure needs cleaning + ENOTNAM = 118, // Not a XENIX named type file + ENAVAIL = 119, // No XENIX semaphores available + EISNAM = 120, // Is a named type file + EREMOTEIO = 121, // Remote I/O error + EDQUOT = 122, // Quota exceeded + + ENOMEDIUM = 123, // No medium found + EMEDIUMTYPE = 124, // Wrong medium type + + ECANCELED = 125, + ENOKEY = 126, + EKEYEXPIRED = 127, + EKEYREVOKED = 128, + EKEYREJECTED = 129, + + EOWNERDEAD = 130, + ENOTRECOVERABLE = 131, + + // OS X-specific values: OS X value + 1000 + EPROCLIM = 1067, // Too many processes + EBADRPC = 1072, // RPC struct is bad + ERPCMISMATCH = 1073, // RPC version wrong + EPROGUNAVAIL = 1074, // RPC prog. not avail + EPROGMISMATCH = 1075, // Program version wrong + EPROCUNAVAIL = 1076, // Bad procedure for program + EFTYPE = 1079, // Inappropriate file type or format + EAUTH = 1080, // Authentication error + ENEEDAUTH = 1081, // Need authenticator + EPWROFF = 1082, // Device power is off + EDEVERR = 1083, // Device error, e.g. paper out + EBADEXEC = 1085, // Bad executable + EBADARCH = 1086, // Bad CPU type in executable + ESHLIBVERS = 1087, // Shared library version mismatch + EBADMACHO = 1088, // Malformed Macho file + ENOATTR = 1093, // Attribute not found + ENOPOLICY = 1103, // No such policy registered + } + + #endregion + + #region Classes + + public sealed class FilePosition : MarshalByRefObject, IDisposable + , IEquatable + { + + private static readonly int FilePositionDumpSize = + Stdlib.DumpFilePosition (null, new HandleRef (null, IntPtr.Zero), 0); + + private HandleRef pos; + + public FilePosition () + { + IntPtr p = Stdlib.CreateFilePosition (); + if (p == IntPtr.Zero) + throw new OutOfMemoryException ("Unable to malloc fpos_t!"); + pos = new HandleRef (this, p); + } + + internal HandleRef Handle { + get {return pos;} + } + + public void Dispose () + { + Cleanup (); + GC.SuppressFinalize (this); + } + + private void Cleanup () + { + if (pos.Handle != IntPtr.Zero) { + Stdlib.free (pos.Handle); + pos = new HandleRef (this, IntPtr.Zero); + } + } + + public override string ToString () + { + return "(" + base.ToString () + " " + GetDump () + ")"; + } + + private string GetDump () + { + if (FilePositionDumpSize <= 0) + return "internal error"; + + StringBuilder buf = new StringBuilder (FilePositionDumpSize+1); + + if (Stdlib.DumpFilePosition (buf, Handle, FilePositionDumpSize+1) <= 0) + return "internal error dumping fpos_t"; + + return buf.ToString (); + } + + public override bool Equals (object obj) + { + FilePosition fp = obj as FilePosition; + if (obj == null || fp == null) + return false; + return ToString().Equals (obj.ToString()); + } + + public bool Equals (FilePosition value) + { + if (object.ReferenceEquals (this, value)) + return true; + return ToString().Equals (value.ToString()); + } + + public override int GetHashCode () + { + return ToString ().GetHashCode (); + } + + ~FilePosition () + { + Cleanup (); + } + + public static bool operator== (FilePosition lhs, FilePosition rhs) + { + return Object.Equals (lhs, rhs); + } + + public static bool operator!= (FilePosition lhs, FilePosition rhs) + { + return !Object.Equals (lhs, rhs); + } + } + + + public enum SignalAction { + Default, + Ignore, + Error + } + + // + // Right now using this attribute gives an assert because it + // isn't implemented. + // +#if UNMANAGED_FN_PTR_SUPPORT_FIXED + [UnmanagedFunctionPointer (CallingConvention.Cdecl)] +#endif + public delegate void SignalHandler (int signal); + + +#if !NETSTANDARD2_0 + internal class XPrintfFunctions + { + internal delegate object XPrintf (object[] parameters); + + internal static XPrintf printf; + internal static XPrintf fprintf; + internal static XPrintf snprintf; + internal static XPrintf syslog; + + static XPrintfFunctions () + { + CdeclFunction _printf = new CdeclFunction (Stdlib.LIBC, "printf", typeof(int)); + printf = new XPrintf (_printf.Invoke); + + CdeclFunction _fprintf = new CdeclFunction (Stdlib.LIBC, "fprintf", typeof(int)); + fprintf = new XPrintf (_fprintf.Invoke); + + CdeclFunction _snprintf = new CdeclFunction (Stdlib.MPH, + "Mono_Posix_Stdlib_snprintf", typeof(int)); + snprintf = new XPrintf (_snprintf.Invoke); + + CdeclFunction _syslog = new CdeclFunction (Syscall.MPH, + "Mono_Posix_Stdlib_syslog2", typeof(int)); + syslog = new XPrintf (_syslog.Invoke); + } + } +#endif + + // + // Convention: Functions that are part of the C standard library go here. + // + // For example, the man page should say something similar to: + // + // CONFORMING TO + // ISO 9899 (''ANSI C'') + // + // The intent is that members of this class should be portable to any system + // supporting the C runtime (read: non-Unix, including Windows). Using + // anything from Syscall is non-portable, but restricting yourself to just + // Stdlib is intended to be portable. + // + // The only methods in here should be: + // (1) low-level functions (as defined above). + // (2) "Trivial" function overloads. For example, if the parameters to a + // function are related (e.g. fwrite(3)) + // (3) The return type SHOULD NOT be changed. If you want to provide a + // convenience function with a nicer return type, place it into one of + // the Mono.Unix.Std* wrapper classes, and give it a .NET-styled name. + // - EXCEPTION: No public functions should have a `void' return type. + // `void' return types should be replaced with `int'. + // Rationality: `void'-return functions typically require a + // complicated call sequence, such as clear errno, then call, then + // check errno to see if any errors occurred. This sequence can't + // be done safely in managed code, as errno may change as part of + // the P/Invoke mechanism. + // Instead, add a MonoPosixHelper export which does: + // errno = 0; + // INVOKE SYSCALL; + // return errno == 0 ? 0 : -1; + // This lets managed code check the return value in the usual manner. + // (4) Exceptions SHOULD NOT be thrown. EXCEPTIONS: + // - If you're wrapping *broken* methods which make assumptions about + // input data, such as that an argument refers to N bytes of data. + // This is currently limited to cuserid(3) and encrypt(3). + // - If you call functions which themselves generate exceptions. + // This is the case for using NativeConvert, which will throw an + // exception if an invalid/unsupported value is used. + // + public class Stdlib + { +#if FORCE_USE_LIBC_NOT_MSVC + internal const string LIBC = "c"; +#else + internal const string LIBC = "msvcrt"; +#endif + internal const string MPH = "MonoPosixHelper"; + + // It is possible for Mono.Posix and MonoPosixHelper to get out of sync, + // for example if NuGet does something weird. To mitigate this, anyone + // editing Mono.Posix needs to observe two rules: + // 1. When introducing C-interface changes to MonoPosixHelper, update + // the version strings in VersionCheck below and also + // Mono_Unix_VersionString in the C sources. + // 2. Any class which performs a DllImport on Stdlib.MPH needs to call + // Stdlib.VersionCheck in its static constructor. + + [DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl, + EntryPoint="Mono_Unix_VersionString")] + private static extern IntPtr VersionStringPtr (); + private static bool versionCheckPerformed = false; + internal static void VersionCheck () + { + if (versionCheckPerformed) + return; + + // This string is arbitrary; it matters only that it is unique. + string assemblyVersion = "MonoProject-2015-12-1"; + string nativeVersion = Marshal.PtrToStringAnsi (VersionStringPtr ()); + if (assemblyVersion != nativeVersion) + { + throw new Exception ("Mono.Posix assembly loaded with a different version (\"" + + assemblyVersion + "\") than MonoPosixHelper (\"" + nativeVersion + + "\"). You may need to reinstall Mono.Posix."); + } + + versionCheckPerformed = true; + } + + static Stdlib () + { + VersionCheck (); + } + + internal Stdlib () {} + + #region Declarations + // + // -- COMPLETE + // + + public static Errno GetLastError () + { + // Always call Marshal.GetLastWin32Error() before the OS check, + // even on Windows where we don't use the return value. If we do + // the OS check first Environment.OSVersion (if it happens to be + // the first ever access) will clobber Marshal.GetLastWin32Error() + // and we won't get the desired errno value on non-Windows platforms. + int errno = Marshal.GetLastWin32Error (); + if (Environment.OSVersion.Platform != PlatformID.Unix) { + // On Windows Marshal.GetLastWin32Error() doesn't take errno + // into account so we need to call Mono_Posix_Stdlib_GetLastError() + // which returns the value of errno in the C runtime + // libMonoPosixHelper.dll was linked against. + errno = _GetLastError (); + } + return NativeConvert.ToErrno (errno); + } + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + EntryPoint="Mono_Posix_Stdlib_GetLastError")] + private static extern int _GetLastError (); + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + EntryPoint="Mono_Posix_Stdlib_SetLastError")] + private static extern void SetLastError (int error); + + protected static void SetLastError (Errno error) + { + int _error = NativeConvert.FromErrno (error); + SetLastError (_error); + } + + #endregion + + // + // + // + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + EntryPoint="Mono_Posix_Stdlib_InvokeSignalHandler")] + internal static extern void InvokeSignalHandler (int signum, IntPtr handler); + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + EntryPoint="Mono_Posix_Stdlib_SIG_DFL")] + private static extern IntPtr GetDefaultSignal (); + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + EntryPoint="Mono_Posix_Stdlib_SIG_ERR")] + private static extern IntPtr GetErrorSignal (); + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + EntryPoint="Mono_Posix_Stdlib_SIG_IGN")] + private static extern IntPtr GetIgnoreSignal (); + + private static readonly IntPtr _SIG_DFL = GetDefaultSignal (); + private static readonly IntPtr _SIG_ERR = GetErrorSignal (); + private static readonly IntPtr _SIG_IGN = GetIgnoreSignal (); + + private static void _ErrorHandler (int signum) + { + Console.Error.WriteLine ("Error handler invoked for signum " + + signum + ". Don't do that."); + } + + private static void _DefaultHandler (int signum) + { + Console.Error.WriteLine ("Default handler invoked for signum " + + signum + ". Don't do that."); + } + + private static void _IgnoreHandler (int signum) + { + Console.Error.WriteLine ("Ignore handler invoked for signum " + + signum + ". Don't do that."); + } + + [CLSCompliant (false)] + public static readonly SignalHandler SIG_DFL = new SignalHandler (_DefaultHandler); + [CLSCompliant (false)] + public static readonly SignalHandler SIG_ERR = new SignalHandler (_ErrorHandler); + [CLSCompliant (false)] + public static readonly SignalHandler SIG_IGN = new SignalHandler (_IgnoreHandler); + + [DllImport (LIBC, CallingConvention=CallingConvention.Cdecl, + SetLastError=true, EntryPoint="signal")] + private static extern IntPtr sys_signal (int signum, SignalHandler handler); + + [DllImport (LIBC, CallingConvention=CallingConvention.Cdecl, + SetLastError=true, EntryPoint="signal")] + private static extern IntPtr sys_signal (int signum, IntPtr handler); + + [CLSCompliant (false)] + [Obsolete ("This is not safe; " + + "use Mono.Unix.UnixSignal for signal delivery or SetSignalAction()")] + public static SignalHandler signal (Signum signum, SignalHandler handler) + { + int _sig = NativeConvert.FromSignum (signum); + + Delegate[] handlers = handler.GetInvocationList (); + for (int i = 0; i < handlers.Length; ++i) { + Marshal.Prelink (handlers [i].Method); + } + + IntPtr r; + if (handler == SIG_DFL) + r = sys_signal (_sig, _SIG_DFL); + else if (handler == SIG_ERR) + r = sys_signal (_sig, _SIG_ERR); + else if (handler == SIG_IGN) + r = sys_signal (_sig, _SIG_IGN); + else + r = sys_signal (_sig, handler); + return TranslateHandler (r); + } + + private static SignalHandler TranslateHandler (IntPtr handler) + { + if (handler == _SIG_DFL) + return SIG_DFL; + if (handler == _SIG_ERR) + return SIG_ERR; + if (handler == _SIG_IGN) + return SIG_IGN; + return (SignalHandler) Marshal.GetDelegateForFunctionPointer (handler, typeof(SignalHandler)); + } + + public static int SetSignalAction (Signum signal, SignalAction action) + { + return SetSignalAction (NativeConvert.FromSignum (signal), action); + } + + public static int SetSignalAction (RealTimeSignum rts, SignalAction action) + { + return SetSignalAction (NativeConvert.FromRealTimeSignum (rts), action); + } + + private static int SetSignalAction (int signum, SignalAction action) + { + IntPtr handler = IntPtr.Zero; + switch (action) { + case SignalAction.Default: + handler = _SIG_DFL; + break; + case SignalAction.Ignore: + handler = _SIG_IGN; + break; + case SignalAction.Error: + handler = _SIG_ERR; + break; + default: + throw new ArgumentException ("Invalid action value.", "action"); + } + IntPtr r = sys_signal (signum, handler); + if (r == _SIG_ERR) + return -1; + return 0; + } + + [DllImport (LIBC, CallingConvention=CallingConvention.Cdecl, EntryPoint="raise")] + private static extern int sys_raise (int sig); + + [CLSCompliant (false)] + public static int raise (Signum sig) + { + return sys_raise (NativeConvert.FromSignum (sig)); + } + + public static int raise (RealTimeSignum rts) + { + return sys_raise (NativeConvert.FromRealTimeSignum (rts)); + } + + // + // -- COMPLETE except for : + // - the scanf(3) family . + // - vararg functions. + // - Horribly unsafe functions (gets(3)). + // + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + EntryPoint="Mono_Posix_Stdlib__IOFBF")] + private static extern int GetFullyBuffered (); + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + EntryPoint="Mono_Posix_Stdlib__IOLBF")] + private static extern int GetLineBuffered (); + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + EntryPoint="Mono_Posix_Stdlib__IONBF")] + private static extern int GetNonBuffered (); + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + EntryPoint="Mono_Posix_Stdlib_BUFSIZ")] + private static extern int GetBufferSize (); + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + EntryPoint="Mono_Posix_Stdlib_CreateFilePosition")] + internal static extern IntPtr CreateFilePosition (); + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + EntryPoint="Mono_Posix_Stdlib_DumpFilePosition")] + internal static extern int DumpFilePosition (StringBuilder buf, HandleRef handle, int len); + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + EntryPoint="Mono_Posix_Stdlib_EOF")] + private static extern int GetEOF (); + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + EntryPoint="Mono_Posix_Stdlib_FILENAME_MAX")] + private static extern int GetFilenameMax (); + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + EntryPoint="Mono_Posix_Stdlib_FOPEN_MAX")] + private static extern int GetFopenMax (); + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + EntryPoint="Mono_Posix_Stdlib_L_tmpnam")] + private static extern int GetTmpnamLength (); + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + EntryPoint="Mono_Posix_Stdlib_stdin")] + private static extern IntPtr GetStandardInput (); + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + EntryPoint="Mono_Posix_Stdlib_stdout")] + private static extern IntPtr GetStandardOutput (); + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + EntryPoint="Mono_Posix_Stdlib_stderr")] + private static extern IntPtr GetStandardError (); + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + EntryPoint="Mono_Posix_Stdlib_TMP_MAX")] + private static extern int GetTmpMax (); + + [CLSCompliant (false)] + public static readonly int _IOFBF = GetFullyBuffered (); + [CLSCompliant (false)] + public static readonly int _IOLBF = GetLineBuffered (); + [CLSCompliant (false)] + public static readonly int _IONBF = GetNonBuffered (); + [CLSCompliant (false)] + public static readonly int BUFSIZ = GetBufferSize (); + [CLSCompliant (false)] + public static readonly int EOF = GetEOF (); + [CLSCompliant (false)] + public static readonly int FOPEN_MAX = GetFopenMax (); + [CLSCompliant (false)] + public static readonly int FILENAME_MAX = GetFilenameMax (); + [CLSCompliant (false)] + public static readonly int L_tmpnam = GetTmpnamLength (); + public static readonly IntPtr stderr = GetStandardError (); + public static readonly IntPtr stdin = GetStandardInput (); + public static readonly IntPtr stdout = GetStandardOutput (); + [CLSCompliant (false)] + public static readonly int TMP_MAX = GetTmpMax (); + + [DllImport (LIBC, CallingConvention=CallingConvention.Cdecl, SetLastError=true)] + public static extern int remove ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string filename); + + [DllImport (LIBC, CallingConvention=CallingConvention.Cdecl, SetLastError=true)] + public static extern int rename ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string oldpath, + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string newpath); + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + SetLastError=true, EntryPoint="Mono_Posix_Stdlib_tmpfile")] + public static extern IntPtr tmpfile (); + + private static object tmpnam_lock = new object (); + + [DllImport (LIBC, CallingConvention=CallingConvention.Cdecl, + SetLastError=true, EntryPoint="tmpnam")] + private static extern IntPtr sys_tmpnam (StringBuilder s); + + [Obsolete ("Syscall.mkstemp() should be preferred.")] + public static string tmpnam (StringBuilder s) + { + if (s != null && s.Capacity < L_tmpnam) + throw new ArgumentOutOfRangeException ("s", "s.Capacity < L_tmpnam"); + lock (tmpnam_lock) { + IntPtr r = sys_tmpnam (s); + return UnixMarshal.PtrToString (r); + } + } + + [Obsolete ("Syscall.mkstemp() should be preferred.")] + public static string tmpnam () + { + lock (tmpnam_lock) { + IntPtr r = sys_tmpnam (null); + return UnixMarshal.PtrToString (r); + } + } + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + SetLastError=true, EntryPoint="Mono_Posix_Stdlib_fclose")] + public static extern int fclose (IntPtr stream); + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + SetLastError=true, EntryPoint="Mono_Posix_Stdlib_fflush")] + public static extern int fflush (IntPtr stream); + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + SetLastError=true, EntryPoint="Mono_Posix_Stdlib_fopen")] + public static extern IntPtr fopen ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string path, string mode); + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + SetLastError=true, EntryPoint="Mono_Posix_Stdlib_freopen")] + public static extern IntPtr freopen ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string path, string mode, IntPtr stream); + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + SetLastError=true, EntryPoint="Mono_Posix_Stdlib_setbuf")] + public static extern int setbuf (IntPtr stream, IntPtr buf); + + [CLSCompliant (false)] + public static unsafe int setbuf (IntPtr stream, byte* buf) + { + return setbuf (stream, (IntPtr) buf); + } + + [CLSCompliant (false)] + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + SetLastError=true, EntryPoint="Mono_Posix_Stdlib_setvbuf")] + public static extern int setvbuf (IntPtr stream, IntPtr buf, int mode, ulong size); + + [CLSCompliant (false)] + public static unsafe int setvbuf (IntPtr stream, byte* buf, int mode, ulong size) + { + return setvbuf (stream, (IntPtr) buf, mode, size); + } + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + EntryPoint="Mono_Posix_Stdlib_fprintf")] + private static extern int sys_fprintf (IntPtr stream, string format, string message); + + public static int fprintf (IntPtr stream, string message) + { + return sys_fprintf (stream, "%s", message); + } + +#if !NETSTANDARD2_0 + [Obsolete ("Not necessarily portable due to cdecl restrictions.\n" + + "Use fprintf (IntPtr, string) instead.")] + public static int fprintf (IntPtr stream, string format, params object[] parameters) + { + object[] _parameters = new object[checked(parameters.Length+2)]; + _parameters [0] = stream; + _parameters [1] = format; + Array.Copy (parameters, 0, _parameters, 2, parameters.Length); + return (int) XPrintfFunctions.fprintf (_parameters); + } +#endif + + /* SKIP: fscanf(3) */ + + [DllImport (LIBC, CallingConvention=CallingConvention.Cdecl, + EntryPoint="printf")] + private static extern int sys_printf (string format, string message); + + public static int printf (string message) + { + return sys_printf ("%s", message); + } + +#if !NETSTANDARD2_0 + [Obsolete ("Not necessarily portable due to cdecl restrictions.\n" + + "Use printf (string) instead.")] + public static int printf (string format, params object[] parameters) + { + object[] _parameters = new object[checked(parameters.Length+1)]; + _parameters [0] = format; + Array.Copy (parameters, 0, _parameters, 1, parameters.Length); + return (int) XPrintfFunctions.printf (_parameters); + } +#endif + + /* SKIP: scanf(3) */ + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + EntryPoint="Mono_Posix_Stdlib_snprintf")] + private static extern int sys_snprintf (StringBuilder s, ulong n, + string format, string message); + + [CLSCompliant (false)] + public static int snprintf (StringBuilder s, ulong n, string message) + { + if (n > (ulong) s.Capacity) + throw new ArgumentOutOfRangeException ("n", "n must be <= s.Capacity"); + return sys_snprintf (s, n, "%s", message); + } + + public static int snprintf (StringBuilder s, string message) + { + return sys_snprintf (s, (ulong) s.Capacity, "%s", message); + } + +#if !NETSTANDARD2_0 + [CLSCompliant (false)] + [Obsolete ("Not necessarily portable due to cdecl restrictions.\n" + + "Use snprintf (StringBuilder, string) instead.")] + public static int snprintf (StringBuilder s, ulong n, + string format, params object[] parameters) + { + if (n > (ulong) s.Capacity) + throw new ArgumentOutOfRangeException ("n", "n must be <= s.Capacity"); + + object[] _parameters = new object[checked(parameters.Length+3)]; + _parameters [0] = s; + _parameters [1] = n; + _parameters [2] = format; + Array.Copy (parameters, 0, _parameters, 3, parameters.Length); + return (int) XPrintfFunctions.snprintf (_parameters); + } + + [CLSCompliant (false)] + [Obsolete ("Not necessarily portable due to cdecl restrictions.\n" + + "Use snprintf (StringBuilder, string) instead.")] + public static int snprintf (StringBuilder s, + string format, params object[] parameters) + { + object[] _parameters = new object[checked(parameters.Length+3)]; + _parameters [0] = s; + _parameters [1] = (ulong) s.Capacity; + _parameters [2] = format; + Array.Copy (parameters, 0, _parameters, 3, parameters.Length); + return (int) XPrintfFunctions.snprintf (_parameters); + } +#endif + + /* + * SKIP: + * sprintf(3) + * sscanf(3) + * vfprintf(3) + * vfscanf(3) + * vprintf(3) + * vscanf(3) + * vsnprintf(3) + * vsprint(3) + * vsscanf(3) + */ + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + SetLastError=true, EntryPoint="Mono_Posix_Stdlib_fgetc")] + public static extern int fgetc (IntPtr stream); + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + SetLastError=true, EntryPoint="Mono_Posix_Stdlib_fgets")] + private static extern IntPtr sys_fgets (StringBuilder sb, int size, IntPtr stream); + + public static StringBuilder fgets (StringBuilder sb, int size, IntPtr stream) + { + IntPtr r = sys_fgets (sb, size, stream); + if (r == IntPtr.Zero) + return null; + return sb; + } + + public static StringBuilder fgets (StringBuilder sb, IntPtr stream) + { + return fgets (sb, sb.Capacity, stream); + } + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + SetLastError=true, EntryPoint="Mono_Posix_Stdlib_fputc")] + public static extern int fputc (int c, IntPtr stream); + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + SetLastError=true, EntryPoint="Mono_Posix_Stdlib_fputs")] + public static extern int fputs (string s, IntPtr stream); + + public static int getc (IntPtr stream) + { + return fgetc (stream); + } + + [DllImport (LIBC, CallingConvention=CallingConvention.Cdecl, SetLastError=true)] + public static extern int getchar (); + + /* SKIP: gets(3) */ + + public static int putc (int c, IntPtr stream) + { + return fputc (c, stream); + } + + [DllImport (LIBC, CallingConvention=CallingConvention.Cdecl, SetLastError=true)] + public static extern int putchar (int c); + + [DllImport (LIBC, CallingConvention=CallingConvention.Cdecl, SetLastError=true)] + public static extern int puts (string s); + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + SetLastError=true, EntryPoint="Mono_Posix_Stdlib_ungetc")] + public static extern int ungetc (int c, IntPtr stream); + + [CLSCompliant (false)] + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + SetLastError=true, EntryPoint="Mono_Posix_Stdlib_fread")] + public static extern ulong fread (IntPtr ptr, ulong size, ulong nmemb, IntPtr stream); + + [CLSCompliant (false)] + public static unsafe ulong fread (void* ptr, ulong size, ulong nmemb, IntPtr stream) + { + return fread ((IntPtr) ptr, size, nmemb, stream); + } + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + SetLastError=true, EntryPoint="Mono_Posix_Stdlib_fread")] + private static extern ulong sys_fread ([Out] byte[] ptr, + ulong size, ulong nmemb, IntPtr stream); + + [CLSCompliant (false)] + public static ulong fread (byte[] ptr, ulong size, ulong nmemb, IntPtr stream) + { + if ((size * nmemb) > (ulong) ptr.Length) + throw new ArgumentOutOfRangeException ("nmemb"); + return sys_fread (ptr, size, nmemb, stream); + } + + [CLSCompliant (false)] + public static ulong fread (byte[] ptr, IntPtr stream) + { + return fread (ptr, 1, (ulong) ptr.Length, stream); + } + + [CLSCompliant (false)] + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + SetLastError=true, EntryPoint="Mono_Posix_Stdlib_fwrite")] + public static extern ulong fwrite (IntPtr ptr, ulong size, ulong nmemb, IntPtr stream); + + [CLSCompliant (false)] + public static unsafe ulong fwrite (void* ptr, ulong size, ulong nmemb, IntPtr stream) + { + return fwrite ((IntPtr) ptr, size, nmemb, stream); + } + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + SetLastError=true, EntryPoint="Mono_Posix_Stdlib_fwrite")] + private static extern ulong sys_fwrite (byte[] ptr, + ulong size, ulong nmemb, IntPtr stream); + + [CLSCompliant (false)] + public static ulong fwrite (byte[] ptr, ulong size, ulong nmemb, IntPtr stream) + { + if ((size * nmemb) > (ulong) ptr.Length) + throw new ArgumentOutOfRangeException ("nmemb"); + return sys_fwrite (ptr, size, nmemb, stream); + } + + [CLSCompliant (false)] + public static ulong fwrite (byte[] ptr, IntPtr stream) + { + return fwrite (ptr, 1, (ulong) ptr.Length, stream); + } + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + SetLastError=true, EntryPoint="Mono_Posix_Stdlib_fgetpos")] + private static extern int sys_fgetpos (IntPtr stream, HandleRef pos); + + public static int fgetpos (IntPtr stream, FilePosition pos) + { + return sys_fgetpos (stream, pos.Handle); + } + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + SetLastError=true, EntryPoint="Mono_Posix_Stdlib_fseek")] + private static extern int sys_fseek (IntPtr stream, long offset, int origin); + + [CLSCompliant (false)] + public static int fseek (IntPtr stream, long offset, SeekFlags origin) + { + int _origin = NativeConvert.FromSeekFlags (origin); + return sys_fseek (stream, offset, _origin); + } + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + SetLastError=true, EntryPoint="Mono_Posix_Stdlib_fsetpos")] + private static extern int sys_fsetpos (IntPtr stream, HandleRef pos); + + public static int fsetpos (IntPtr stream, FilePosition pos) + { + return sys_fsetpos (stream, pos.Handle); + } + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + SetLastError=true, EntryPoint="Mono_Posix_Stdlib_ftell")] + public static extern long ftell (IntPtr stream); + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + SetLastError=true, EntryPoint="Mono_Posix_Stdlib_rewind")] + public static extern int rewind (IntPtr stream); + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + SetLastError=true, EntryPoint="Mono_Posix_Stdlib_clearerr")] + public static extern int clearerr (IntPtr stream); + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + SetLastError=true, EntryPoint="Mono_Posix_Stdlib_feof")] + public static extern int feof (IntPtr stream); + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + SetLastError=true, EntryPoint="Mono_Posix_Stdlib_ferror")] + public static extern int ferror (IntPtr stream); + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + SetLastError=true, EntryPoint="Mono_Posix_Stdlib_perror")] + private static extern int perror (string s, int err); + + public static int perror (string s) + { + return perror (s, Marshal.GetLastWin32Error ()); + } + + // + // + // + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + EntryPoint="Mono_Posix_Stdlib_EXIT_FAILURE")] + private static extern int GetExitFailure(); + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + EntryPoint="Mono_Posix_Stdlib_EXIT_SUCCESS")] + private static extern int GetExitSuccess (); + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + EntryPoint="Mono_Posix_Stdlib_MB_CUR_MAX")] + private static extern int GetMbCurMax (); + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + EntryPoint="Mono_Posix_Stdlib_RAND_MAX")] + private static extern int GetRandMax (); + + [CLSCompliant (false)] + public static readonly int EXIT_FAILURE = GetExitFailure (); + [CLSCompliant (false)] + public static readonly int EXIT_SUCCESS = GetExitSuccess (); + [CLSCompliant (false)] + public static readonly int MB_CUR_MAX = GetMbCurMax (); + [CLSCompliant (false)] + public static readonly int RAND_MAX = GetRandMax (); + + [DllImport (LIBC, CallingConvention=CallingConvention.Cdecl)] + public static extern int rand (); + + [CLSCompliant (false)] + [DllImport (LIBC, CallingConvention=CallingConvention.Cdecl)] + public static extern void srand (uint seed); + + // calloc(3): + // void *calloc (size_t nmemb, size_t size); + [CLSCompliant (false)] + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + SetLastError=true, EntryPoint="Mono_Posix_Stdlib_calloc")] + public static extern IntPtr calloc (ulong nmemb, ulong size); + + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + EntryPoint="Mono_Posix_Stdlib_free")] + public static extern void free (IntPtr ptr); + + // malloc(3): + // void *malloc(size_t size); + [CLSCompliant (false)] + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + SetLastError=true, EntryPoint="Mono_Posix_Stdlib_malloc")] + public static extern IntPtr malloc (ulong size); + + // realloc(3): + // void *realloc(void *ptr, size_t size); + [CLSCompliant (false)] + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + SetLastError=true, EntryPoint="Mono_Posix_Stdlib_realloc")] + public static extern IntPtr realloc (IntPtr ptr, ulong size); + + [DllImport (LIBC, CallingConvention=CallingConvention.Cdecl)] + public static extern void abort (); + + /* SKIP: atexit(3) -- the GC should have collected most references by the + * time this runs, so no delegates should exist, making it pointless. */ + + [DllImport (LIBC, CallingConvention=CallingConvention.Cdecl)] + public static extern void exit (int status); + + [CLSCompliant (false)] + [DllImport (LIBC, CallingConvention=CallingConvention.Cdecl)] + public static extern void _Exit (int status); + + [DllImport (LIBC, CallingConvention=CallingConvention.Cdecl, EntryPoint="getenv")] + private static extern IntPtr sys_getenv (string name); + + public static string getenv (string name) + { + IntPtr r = sys_getenv (name); + return UnixMarshal.PtrToString (r); + } + + [CLSCompliant (false)] + [DllImport (LIBC, CallingConvention=CallingConvention.Cdecl, SetLastError=true)] + public static extern int system (string @string); + + // + // + // + + private static object strerror_lock = new object (); + + [DllImport (LIBC, CallingConvention=CallingConvention.Cdecl, + SetLastError=true, EntryPoint="strerror")] + private static extern IntPtr sys_strerror (int errnum); + + [CLSCompliant (false)] + public static string strerror (Errno errnum) + { + int e = NativeConvert.FromErrno (errnum); + lock (strerror_lock) { + IntPtr r = sys_strerror (e); + return UnixMarshal.PtrToString (r); + } + } + + // strlen(3): + // size_t strlen(const char *s); + [CLSCompliant (false)] + [DllImport (MPH, CallingConvention=CallingConvention.Cdecl, + SetLastError=true, EntryPoint="Mono_Posix_Stdlib_strlen")] + public static extern ulong strlen (IntPtr s); + } + + #endregion // Classes +} + +// vim: noexpandtab diff --git a/Mono.Posix/Mono.Unix.Native/Syscall.cs b/Mono.Posix/Mono.Unix.Native/Syscall.cs new file mode 100644 index 0000000..a919644 --- /dev/null +++ b/Mono.Posix/Mono.Unix.Native/Syscall.cs @@ -0,0 +1,5881 @@ +// +// Mono.Unix/Syscall.cs +// +// Authors: +// Miguel de Icaza (miguel@novell.com) +// Jonathan Pryor (jonpryor@vt.edu) +// +// (C) 2003 Novell, Inc. +// (C) 2004-2006 Jonathan Pryor +// +// This file implements the low-level syscall interface to the POSIX +// subsystem. +// +// This file tries to stay close to the low-level API as much as possible +// using enumerations, structures and in a few cases, using existing .NET +// data types. +// +// Implementation notes: +// +// Since the values for the various constants on the API changes +// from system to system (even Linux on different architectures will +// have different values), we define our own set of values, and we +// use a set of C helper routines to map from the constants we define +// to the values of the native OS. +// +// Bitfields are flagged with the [Map] attribute, and a helper program +// generates a set of routines that we can call to convert from our value +// definitions to the value definitions expected by the OS; see +// NativeConvert for the conversion routines. +// +// Methods that require tuning are bound as `private sys_NAME' methods +// and then a `NAME' method is exposed. +// + +// +// 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.Collections; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Security; +using System.Text; +using Mono.Unix.Native; + +namespace Mono.Unix.Native { + + #region Enumerations + + [Flags][Map] + [CLSCompliant (false)] + public enum SyslogOptions { + LOG_PID = 0x01, // log the pid with each message + LOG_CONS = 0x02, // log on the console if errors in sending + LOG_ODELAY = 0x04, // delay open until first syslog (default) + LOG_NDELAY = 0x08, // don't delay open + LOG_NOWAIT = 0x10, // don't wait for console forks; DEPRECATED + LOG_PERROR = 0x20 // log to stderr as well + } + + [Map] + [CLSCompliant (false)] + public enum SyslogFacility { + LOG_KERN = 0 << 3, + LOG_USER = 1 << 3, + LOG_MAIL = 2 << 3, + LOG_DAEMON = 3 << 3, + LOG_AUTH = 4 << 3, + LOG_SYSLOG = 5 << 3, + LOG_LPR = 6 << 3, + LOG_NEWS = 7 << 3, + LOG_UUCP = 8 << 3, + LOG_CRON = 9 << 3, + LOG_AUTHPRIV = 10 << 3, + LOG_FTP = 11 << 3, + LOG_LOCAL0 = 16 << 3, + LOG_LOCAL1 = 17 << 3, + LOG_LOCAL2 = 18 << 3, + LOG_LOCAL3 = 19 << 3, + LOG_LOCAL4 = 20 << 3, + LOG_LOCAL5 = 21 << 3, + LOG_LOCAL6 = 22 << 3, + LOG_LOCAL7 = 23 << 3, + } + + [Map] + [CLSCompliant (false)] + public enum SyslogLevel { + LOG_EMERG = 0, // system is unusable + LOG_ALERT = 1, // action must be taken immediately + LOG_CRIT = 2, // critical conditions + LOG_ERR = 3, // warning conditions + LOG_WARNING = 4, // warning conditions + LOG_NOTICE = 5, // normal but significant condition + LOG_INFO = 6, // informational + LOG_DEBUG = 7 // debug-level messages + } + + [Map][Flags] + [CLSCompliant (false)] + public enum OpenFlags : int { + // + // One of these + // + O_RDONLY = 0x00000000, + O_WRONLY = 0x00000001, + O_RDWR = 0x00000002, + + // + // Or-ed with zero or more of these + // + O_CREAT = 0x00000040, + O_EXCL = 0x00000080, + O_NOCTTY = 0x00000100, + O_TRUNC = 0x00000200, + O_APPEND = 0x00000400, + O_NONBLOCK = 0x00000800, + O_SYNC = 0x00001000, + + // + // These are non-Posix. Using them will result in errors/exceptions on + // non-supported platforms. + // + // (For example, "C-wrapped" system calls -- calls with implementation in + // MonoPosixHelper -- will return -1 with errno=EINVAL. C#-wrapped system + // calls will generate an exception in NativeConvert, as the value can't be + // converted on the target platform.) + // + + O_NOFOLLOW = 0x00020000, + O_DIRECTORY = 0x00010000, + O_DIRECT = 0x00004000, + O_ASYNC = 0x00002000, + O_LARGEFILE = 0x00008000, + O_CLOEXEC = 0x00080000, + O_PATH = 0x00200000 + } + + [Map][Flags] + [CLSCompliant (false)] + public enum AtFlags : int { + AT_SYMLINK_NOFOLLOW = 0x00000100, + AT_REMOVEDIR = 0x00000200, + AT_SYMLINK_FOLLOW = 0x00000400, + AT_NO_AUTOMOUNT = 0x00000800, + AT_EMPTY_PATH = 0x00001000 + } + + // mode_t + [Flags][Map] + [CLSCompliant (false)] + public enum FilePermissions : uint { + S_ISUID = 0x0800, // Set user ID on execution + S_ISGID = 0x0400, // Set group ID on execution + S_ISVTX = 0x0200, // Save swapped text after use (sticky). + S_IRUSR = 0x0100, // Read by owner + S_IWUSR = 0x0080, // Write by owner + S_IXUSR = 0x0040, // Execute by owner + S_IRGRP = 0x0020, // Read by group + S_IWGRP = 0x0010, // Write by group + S_IXGRP = 0x0008, // Execute by group + S_IROTH = 0x0004, // Read by other + S_IWOTH = 0x0002, // Write by other + S_IXOTH = 0x0001, // Execute by other + + S_IRWXG = (S_IRGRP | S_IWGRP | S_IXGRP), + S_IRWXU = (S_IRUSR | S_IWUSR | S_IXUSR), + S_IRWXO = (S_IROTH | S_IWOTH | S_IXOTH), + ACCESSPERMS = (S_IRWXU | S_IRWXG | S_IRWXO), // 0777 + ALLPERMS = (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO), // 07777 + DEFFILEMODE = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH), // 0666 + + // Device types + // Why these are held in "mode_t" is beyond me... + S_IFMT = 0xF000, // Bits which determine file type + [Map(SuppressFlags="S_IFMT")] + S_IFDIR = 0x4000, // Directory + [Map(SuppressFlags="S_IFMT")] + S_IFCHR = 0x2000, // Character device + [Map(SuppressFlags="S_IFMT")] + S_IFBLK = 0x6000, // Block device + [Map(SuppressFlags="S_IFMT")] + S_IFREG = 0x8000, // Regular file + [Map(SuppressFlags="S_IFMT")] + S_IFIFO = 0x1000, // FIFO + [Map(SuppressFlags="S_IFMT")] + S_IFLNK = 0xA000, // Symbolic link + [Map(SuppressFlags="S_IFMT")] + S_IFSOCK = 0xC000, // Socket + } + + [Map] + [CLSCompliant (false)] + public enum FcntlCommand : int { + // Form /usr/include/bits/fcntl.h + F_DUPFD = 0, // Duplicate file descriptor. + F_GETFD = 1, // Get file descriptor flags. + F_SETFD = 2, // Set file descriptor flags. + F_GETFL = 3, // Get file status flags. + F_SETFL = 4, // Set file status flags. + F_GETLK = 12, // Get record locking info. [64] + F_SETLK = 13, // Set record locking info (non-blocking). [64] + F_SETLKW = 14, // Set record locking info (blocking). [64] + F_SETOWN = 8, // Set owner of socket (receiver of SIGIO). + F_GETOWN = 9, // Get owner of socket (receiver of SIGIO). + F_SETSIG = 10, // Set number of signal to be sent. + F_GETSIG = 11, // Get number of signal to be sent. + F_NOCACHE = 48, // OSX: turn data caching off/on for this fd. + F_SETLEASE = 1024, // Set a lease. + F_GETLEASE = 1025, // Enquire what lease is active. + F_NOTIFY = 1026, // Required notifications on a directory + } + + [Map] + [CLSCompliant (false)] + public enum LockType : short { + F_RDLCK = 0, // Read lock. + F_WRLCK = 1, // Write lock. + F_UNLCK = 2, // Remove lock. + } + + [Map] + [CLSCompliant (false)] + public enum SeekFlags : short { + // values liberally copied from /usr/include/unistd.h + SEEK_SET = 0, // Seek from beginning of file. + SEEK_CUR = 1, // Seek from current position. + SEEK_END = 2, // Seek from end of file. + + L_SET = SEEK_SET, // BSD alias for SEEK_SET + L_INCR = SEEK_CUR, // BSD alias for SEEK_CUR + L_XTND = SEEK_END, // BSD alias for SEEK_END + } + + [Map, Flags] + [CLSCompliant (false)] + public enum DirectoryNotifyFlags : int { + // from /usr/include/bits/fcntl.h + DN_ACCESS = 0x00000001, // File accessed. + DN_MODIFY = 0x00000002, // File modified. + DN_CREATE = 0x00000004, // File created. + DN_DELETE = 0x00000008, // File removed. + DN_RENAME = 0x00000010, // File renamed. + DN_ATTRIB = 0x00000020, // File changed attributes. + DN_MULTISHOT = unchecked ((int)0x80000000), // Don't remove notifier + } + + [Map] + [CLSCompliant (false)] + public enum PosixFadviseAdvice : int { + POSIX_FADV_NORMAL = 0, // No further special treatment. + POSIX_FADV_RANDOM = 1, // Expect random page references. + POSIX_FADV_SEQUENTIAL = 2, // Expect sequential page references. + POSIX_FADV_WILLNEED = 3, // Will need these pages. + POSIX_FADV_DONTNEED = 4, // Don't need these pages. + POSIX_FADV_NOREUSE = 5, // Data will be accessed once. + } + + [Map] + [CLSCompliant (false)] + public enum PosixMadviseAdvice : int { + POSIX_MADV_NORMAL = 0, // No further special treatment. + POSIX_MADV_RANDOM = 1, // Expect random page references. + POSIX_MADV_SEQUENTIAL = 2, // Expect sequential page references. + POSIX_MADV_WILLNEED = 3, // Will need these pages. + POSIX_MADV_DONTNEED = 4, // Don't need these pages. + } + + [Map] + public enum Signum : int { + SIGHUP = 1, // Hangup (POSIX). + SIGINT = 2, // Interrupt (ANSI). + SIGQUIT = 3, // Quit (POSIX). + SIGILL = 4, // Illegal instruction (ANSI). + SIGTRAP = 5, // Trace trap (POSIX). + SIGABRT = 6, // Abort (ANSI). + SIGIOT = 6, // IOT trap (4.2 BSD). + SIGBUS = 7, // BUS error (4.2 BSD). + SIGFPE = 8, // Floating-point exception (ANSI). + SIGKILL = 9, // Kill, unblockable (POSIX). + SIGUSR1 = 10, // User-defined signal 1 (POSIX). + SIGSEGV = 11, // Segmentation violation (ANSI). + SIGUSR2 = 12, // User-defined signal 2 (POSIX). + SIGPIPE = 13, // Broken pipe (POSIX). + SIGALRM = 14, // Alarm clock (POSIX). + SIGTERM = 15, // Termination (ANSI). + SIGSTKFLT = 16, // Stack fault. + SIGCLD = SIGCHLD, // Same as SIGCHLD (System V). + SIGCHLD = 17, // Child status has changed (POSIX). + SIGCONT = 18, // Continue (POSIX). + SIGSTOP = 19, // Stop, unblockable (POSIX). + SIGTSTP = 20, // Keyboard stop (POSIX). + SIGTTIN = 21, // Background read from tty (POSIX). + SIGTTOU = 22, // Background write to tty (POSIX). + SIGURG = 23, // Urgent condition on socket (4.2 BSD). + SIGXCPU = 24, // CPU limit exceeded (4.2 BSD). + SIGXFSZ = 25, // File size limit exceeded (4.2 BSD). + SIGVTALRM = 26, // Virtual alarm clock (4.2 BSD). + SIGPROF = 27, // Profiling alarm clock (4.2 BSD). + SIGWINCH = 28, // Window size change (4.3 BSD, Sun). + SIGPOLL = SIGIO, // Pollable event occurred (System V). + SIGIO = 29, // I/O now possible (4.2 BSD). + SIGPWR = 30, // Power failure restart (System V). + SIGSYS = 31, // Bad system call. + SIGUNUSED = 31 + } + + [Flags][Map] + public enum WaitOptions : int { + WNOHANG = 1, // Don't block waiting + WUNTRACED = 2, // Report status of stopped children + } + + [Flags][Map] + [CLSCompliant (false)] + public enum AccessModes : int { + R_OK = 1, + W_OK = 2, + X_OK = 4, + F_OK = 8, + } + + [Map] + [CLSCompliant (false)] + public enum PathconfName : int { + _PC_LINK_MAX, + _PC_MAX_CANON, + _PC_MAX_INPUT, + _PC_NAME_MAX, + _PC_PATH_MAX, + _PC_PIPE_BUF, + _PC_CHOWN_RESTRICTED, + _PC_NO_TRUNC, + _PC_VDISABLE, + _PC_SYNC_IO, + _PC_ASYNC_IO, + _PC_PRIO_IO, + _PC_SOCK_MAXBUF, + _PC_FILESIZEBITS, + _PC_REC_INCR_XFER_SIZE, + _PC_REC_MAX_XFER_SIZE, + _PC_REC_MIN_XFER_SIZE, + _PC_REC_XFER_ALIGN, + _PC_ALLOC_SIZE_MIN, + _PC_SYMLINK_MAX, + _PC_2_SYMLINKS + } + + [Map] + [CLSCompliant (false)] + public enum SysconfName : int { + _SC_ARG_MAX, + _SC_CHILD_MAX, + _SC_CLK_TCK, + _SC_NGROUPS_MAX, + _SC_OPEN_MAX, + _SC_STREAM_MAX, + _SC_TZNAME_MAX, + _SC_JOB_CONTROL, + _SC_SAVED_IDS, + _SC_REALTIME_SIGNALS, + _SC_PRIORITY_SCHEDULING, + _SC_TIMERS, + _SC_ASYNCHRONOUS_IO, + _SC_PRIORITIZED_IO, + _SC_SYNCHRONIZED_IO, + _SC_FSYNC, + _SC_MAPPED_FILES, + _SC_MEMLOCK, + _SC_MEMLOCK_RANGE, + _SC_MEMORY_PROTECTION, + _SC_MESSAGE_PASSING, + _SC_SEMAPHORES, + _SC_SHARED_MEMORY_OBJECTS, + _SC_AIO_LISTIO_MAX, + _SC_AIO_MAX, + _SC_AIO_PRIO_DELTA_MAX, + _SC_DELAYTIMER_MAX, + _SC_MQ_OPEN_MAX, + _SC_MQ_PRIO_MAX, + _SC_VERSION, + _SC_PAGESIZE, + _SC_RTSIG_MAX, + _SC_SEM_NSEMS_MAX, + _SC_SEM_VALUE_MAX, + _SC_SIGQUEUE_MAX, + _SC_TIMER_MAX, + /* Values for the argument to `sysconf' + corresponding to _POSIX2_* symbols. */ + _SC_BC_BASE_MAX, + _SC_BC_DIM_MAX, + _SC_BC_SCALE_MAX, + _SC_BC_STRING_MAX, + _SC_COLL_WEIGHTS_MAX, + _SC_EQUIV_CLASS_MAX, + _SC_EXPR_NEST_MAX, + _SC_LINE_MAX, + _SC_RE_DUP_MAX, + _SC_CHARCLASS_NAME_MAX, + _SC_2_VERSION, + _SC_2_C_BIND, + _SC_2_C_DEV, + _SC_2_FORT_DEV, + _SC_2_FORT_RUN, + _SC_2_SW_DEV, + _SC_2_LOCALEDEF, + _SC_PII, + _SC_PII_XTI, + _SC_PII_SOCKET, + _SC_PII_INTERNET, + _SC_PII_OSI, + _SC_POLL, + _SC_SELECT, + _SC_UIO_MAXIOV, + _SC_IOV_MAX = _SC_UIO_MAXIOV, + _SC_PII_INTERNET_STREAM, + _SC_PII_INTERNET_DGRAM, + _SC_PII_OSI_COTS, + _SC_PII_OSI_CLTS, + _SC_PII_OSI_M, + _SC_T_IOV_MAX, + /* Values according to POSIX 1003.1c (POSIX threads). */ + _SC_THREADS, + _SC_THREAD_SAFE_FUNCTIONS, + _SC_GETGR_R_SIZE_MAX, + _SC_GETPW_R_SIZE_MAX, + _SC_LOGIN_NAME_MAX, + _SC_TTY_NAME_MAX, + _SC_THREAD_DESTRUCTOR_ITERATIONS, + _SC_THREAD_KEYS_MAX, + _SC_THREAD_STACK_MIN, + _SC_THREAD_THREADS_MAX, + _SC_THREAD_ATTR_STACKADDR, + _SC_THREAD_ATTR_STACKSIZE, + _SC_THREAD_PRIORITY_SCHEDULING, + _SC_THREAD_PRIO_INHERIT, + _SC_THREAD_PRIO_PROTECT, + _SC_THREAD_PROCESS_SHARED, + _SC_NPROCESSORS_CONF, + _SC_NPROCESSORS_ONLN, + _SC_PHYS_PAGES, + _SC_AVPHYS_PAGES, + _SC_ATEXIT_MAX, + _SC_PASS_MAX, + _SC_XOPEN_VERSION, + _SC_XOPEN_XCU_VERSION, + _SC_XOPEN_UNIX, + _SC_XOPEN_CRYPT, + _SC_XOPEN_ENH_I18N, + _SC_XOPEN_SHM, + _SC_2_CHAR_TERM, + _SC_2_C_VERSION, + _SC_2_UPE, + _SC_XOPEN_XPG2, + _SC_XOPEN_XPG3, + _SC_XOPEN_XPG4, + _SC_CHAR_BIT, + _SC_CHAR_MAX, + _SC_CHAR_MIN, + _SC_INT_MAX, + _SC_INT_MIN, + _SC_LONG_BIT, + _SC_WORD_BIT, + _SC_MB_LEN_MAX, + _SC_NZERO, + _SC_SSIZE_MAX, + _SC_SCHAR_MAX, + _SC_SCHAR_MIN, + _SC_SHRT_MAX, + _SC_SHRT_MIN, + _SC_UCHAR_MAX, + _SC_UINT_MAX, + _SC_ULONG_MAX, + _SC_USHRT_MAX, + _SC_NL_ARGMAX, + _SC_NL_LANGMAX, + _SC_NL_MSGMAX, + _SC_NL_NMAX, + _SC_NL_SETMAX, + _SC_NL_TEXTMAX, + _SC_XBS5_ILP32_OFF32, + _SC_XBS5_ILP32_OFFBIG, + _SC_XBS5_LP64_OFF64, + _SC_XBS5_LPBIG_OFFBIG, + _SC_XOPEN_LEGACY, + _SC_XOPEN_REALTIME, + _SC_XOPEN_REALTIME_THREADS, + _SC_ADVISORY_INFO, + _SC_BARRIERS, + _SC_BASE, + _SC_C_LANG_SUPPORT, + _SC_C_LANG_SUPPORT_R, + _SC_CLOCK_SELECTION, + _SC_CPUTIME, + _SC_THREAD_CPUTIME, + _SC_DEVICE_IO, + _SC_DEVICE_SPECIFIC, + _SC_DEVICE_SPECIFIC_R, + _SC_FD_MGMT, + _SC_FIFO, + _SC_PIPE, + _SC_FILE_ATTRIBUTES, + _SC_FILE_LOCKING, + _SC_FILE_SYSTEM, + _SC_MONOTONIC_CLOCK, + _SC_MULTI_PROCESS, + _SC_SINGLE_PROCESS, + _SC_NETWORKING, + _SC_READER_WRITER_LOCKS, + _SC_SPIN_LOCKS, + _SC_REGEXP, + _SC_REGEX_VERSION, + _SC_SHELL, + _SC_SIGNALS, + _SC_SPAWN, + _SC_SPORADIC_SERVER, + _SC_THREAD_SPORADIC_SERVER, + _SC_SYSTEM_DATABASE, + _SC_SYSTEM_DATABASE_R, + _SC_TIMEOUTS, + _SC_TYPED_MEMORY_OBJECTS, + _SC_USER_GROUPS, + _SC_USER_GROUPS_R, + _SC_2_PBS, + _SC_2_PBS_ACCOUNTING, + _SC_2_PBS_LOCATE, + _SC_2_PBS_MESSAGE, + _SC_2_PBS_TRACK, + _SC_SYMLOOP_MAX, + _SC_STREAMS, + _SC_2_PBS_CHECKPOINT, + _SC_V6_ILP32_OFF32, + _SC_V6_ILP32_OFFBIG, + _SC_V6_LP64_OFF64, + _SC_V6_LPBIG_OFFBIG, + _SC_HOST_NAME_MAX, + _SC_TRACE, + _SC_TRACE_EVENT_FILTER, + _SC_TRACE_INHERIT, + _SC_TRACE_LOG, + _SC_LEVEL1_ICACHE_SIZE, + _SC_LEVEL1_ICACHE_ASSOC, + _SC_LEVEL1_ICACHE_LINESIZE, + _SC_LEVEL1_DCACHE_SIZE, + _SC_LEVEL1_DCACHE_ASSOC, + _SC_LEVEL1_DCACHE_LINESIZE, + _SC_LEVEL2_CACHE_SIZE, + _SC_LEVEL2_CACHE_ASSOC, + _SC_LEVEL2_CACHE_LINESIZE, + _SC_LEVEL3_CACHE_SIZE, + _SC_LEVEL3_CACHE_ASSOC, + _SC_LEVEL3_CACHE_LINESIZE, + _SC_LEVEL4_CACHE_SIZE, + _SC_LEVEL4_CACHE_ASSOC, + _SC_LEVEL4_CACHE_LINESIZE + } + + [Map] + [CLSCompliant (false)] + public enum ConfstrName : int { + _CS_PATH, /* The default search path. */ + _CS_V6_WIDTH_RESTRICTED_ENVS, + _CS_GNU_LIBC_VERSION, + _CS_GNU_LIBPTHREAD_VERSION, + _CS_LFS_CFLAGS = 1000, + _CS_LFS_LDFLAGS, + _CS_LFS_LIBS, + _CS_LFS_LINTFLAGS, + _CS_LFS64_CFLAGS, + _CS_LFS64_LDFLAGS, + _CS_LFS64_LIBS, + _CS_LFS64_LINTFLAGS, + _CS_XBS5_ILP32_OFF32_CFLAGS = 1100, + _CS_XBS5_ILP32_OFF32_LDFLAGS, + _CS_XBS5_ILP32_OFF32_LIBS, + _CS_XBS5_ILP32_OFF32_LINTFLAGS, + _CS_XBS5_ILP32_OFFBIG_CFLAGS, + _CS_XBS5_ILP32_OFFBIG_LDFLAGS, + _CS_XBS5_ILP32_OFFBIG_LIBS, + _CS_XBS5_ILP32_OFFBIG_LINTFLAGS, + _CS_XBS5_LP64_OFF64_CFLAGS, + _CS_XBS5_LP64_OFF64_LDFLAGS, + _CS_XBS5_LP64_OFF64_LIBS, + _CS_XBS5_LP64_OFF64_LINTFLAGS, + _CS_XBS5_LPBIG_OFFBIG_CFLAGS, + _CS_XBS5_LPBIG_OFFBIG_LDFLAGS, + _CS_XBS5_LPBIG_OFFBIG_LIBS, + _CS_XBS5_LPBIG_OFFBIG_LINTFLAGS, + _CS_POSIX_V6_ILP32_OFF32_CFLAGS, + _CS_POSIX_V6_ILP32_OFF32_LDFLAGS, + _CS_POSIX_V6_ILP32_OFF32_LIBS, + _CS_POSIX_V6_ILP32_OFF32_LINTFLAGS, + _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS, + _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS, + _CS_POSIX_V6_ILP32_OFFBIG_LIBS, + _CS_POSIX_V6_ILP32_OFFBIG_LINTFLAGS, + _CS_POSIX_V6_LP64_OFF64_CFLAGS, + _CS_POSIX_V6_LP64_OFF64_LDFLAGS, + _CS_POSIX_V6_LP64_OFF64_LIBS, + _CS_POSIX_V6_LP64_OFF64_LINTFLAGS, + _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS, + _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS, + _CS_POSIX_V6_LPBIG_OFFBIG_LIBS, + _CS_POSIX_V6_LPBIG_OFFBIG_LINTFLAGS + } + + [Map] + [CLSCompliant (false)] + public enum LockfCommand : int { + F_ULOCK = 0, // Unlock a previously locked region. + F_LOCK = 1, // Lock a region for exclusive use. + F_TLOCK = 2, // Test and lock a region for exclusive use. + F_TEST = 3, // Test a region for other process locks. + } + + [Map][Flags] + public enum PollEvents : short { + POLLIN = 0x0001, // There is data to read + POLLPRI = 0x0002, // There is urgent data to read + POLLOUT = 0x0004, // Writing now will not block + POLLERR = 0x0008, // Error condition + POLLHUP = 0x0010, // Hung up + POLLNVAL = 0x0020, // Invalid request; fd not open + // XPG4.2 definitions (via _XOPEN_SOURCE) + POLLRDNORM = 0x0040, // Normal data may be read + POLLRDBAND = 0x0080, // Priority data may be read + POLLWRNORM = 0x0100, // Writing now will not block + POLLWRBAND = 0x0200, // Priority data may be written + } + + [Map][Flags] + [CLSCompliant (false)] + public enum XattrFlags : int { + XATTR_AUTO = 0, + XATTR_CREATE = 1, + XATTR_REPLACE = 2, + } + + [Map][Flags] + [CLSCompliant (false)] + public enum MountFlags : ulong { + ST_RDONLY = 1, // Mount read-only + ST_NOSUID = 2, // Ignore suid and sgid bits + ST_NODEV = 4, // Disallow access to device special files + ST_NOEXEC = 8, // Disallow program execution + ST_SYNCHRONOUS = 16, // Writes are synced at once + ST_REMOUNT = 32, // Alter flags of a mounted FS + ST_MANDLOCK = 64, // Allow mandatory locks on an FS + ST_WRITE = 128, // Write on file/directory/symlink + ST_APPEND = 256, // Append-only file + ST_IMMUTABLE = 512, // Immutable file + ST_NOATIME = 1024, // Do not update access times + ST_NODIRATIME = 2048, // Do not update directory access times + ST_BIND = 4096, // Bind directory at different place + } + + [Map][Flags] + [CLSCompliant (false)] + public enum MmapFlags : int { + MAP_SHARED = 0x01, // Share changes. + MAP_PRIVATE = 0x02, // Changes are private. + MAP_TYPE = 0x0f, // Mask for type of mapping. + MAP_FIXED = 0x10, // Interpret addr exactly. + MAP_FILE = 0, + MAP_ANONYMOUS = 0x20, // Don't use a file. + MAP_ANON = MAP_ANONYMOUS, + + // These are Linux-specific. + MAP_GROWSDOWN = 0x00100, // Stack-like segment. + MAP_DENYWRITE = 0x00800, // ETXTBSY + MAP_EXECUTABLE = 0x01000, // Mark it as an executable. + MAP_LOCKED = 0x02000, // Lock the mapping. + MAP_NORESERVE = 0x04000, // Don't check for reservations. + MAP_POPULATE = 0x08000, // Populate (prefault) pagetables. + MAP_NONBLOCK = 0x10000, // Do not block on IO. + } + + [Map][Flags] + [CLSCompliant (false)] + public enum MmapProts : int { + PROT_READ = 0x1, // Page can be read. + PROT_WRITE = 0x2, // Page can be written. + PROT_EXEC = 0x4, // Page can be executed. + PROT_NONE = 0x0, // Page can not be accessed. + PROT_GROWSDOWN = 0x01000000, // Extend change to start of + // growsdown vma (mprotect only). + PROT_GROWSUP = 0x02000000, // Extend change to start of + // growsup vma (mprotect only). + } + + [Map][Flags] + [CLSCompliant (false)] + public enum MsyncFlags : int { + MS_ASYNC = 0x1, // Sync memory asynchronously. + MS_SYNC = 0x4, // Synchronous memory sync. + MS_INVALIDATE = 0x2, // Invalidate the caches. + } + + [Map][Flags] + [CLSCompliant (false)] + public enum MlockallFlags : int { + MCL_CURRENT = 0x1, // Lock all currently mapped pages. + MCL_FUTURE = 0x2, // Lock all additions to address + } + + [Map][Flags] + [CLSCompliant (false)] + public enum MremapFlags : ulong { + MREMAP_MAYMOVE = 0x1, + } + + [Map] + [CLSCompliant (false)] + public enum UnixSocketType : int { + SOCK_STREAM = 1, // Byte-stream socket + SOCK_DGRAM = 2, // Datagram socket + SOCK_RAW = 3, // Raw protocol interface (linux specific) + SOCK_RDM = 4, // Reliably-delivered messages (linux specific) + SOCK_SEQPACKET = 5, // Sequenced-packet socket + SOCK_DCCP = 6, // Datagram Congestion Control Protocol (linux specific) + SOCK_PACKET = 10, // Linux specific + } + + [Map][Flags] + [CLSCompliant (false)] + public enum UnixSocketFlags : int { + SOCK_CLOEXEC = 0x80000, /* Atomically set close-on-exec flag for the new descriptor(s). */ + SOCK_NONBLOCK = 0x00800, /* Atomically mark descriptor(s) as non-blocking. */ + } + + [Map] + [CLSCompliant (false)] + public enum UnixSocketProtocol : int { + IPPROTO_ICMP = 1, /* Internet Control Message Protocol */ + IPPROTO_IGMP = 2, /* Internet Group Management Protocol */ + IPPROTO_IPIP = 4, /* IPIP tunnels (older KA9Q tunnels use 94) */ + IPPROTO_TCP = 6, /* Transmission Control Protocol */ + IPPROTO_EGP = 8, /* Exterior Gateway Protocol */ + IPPROTO_PUP = 12, /* PUP protocol */ + IPPROTO_UDP = 17, /* User Datagram Protocol */ + IPPROTO_IDP = 22, /* XNS IDP protocol */ + IPPROTO_TP = 29, /* SO Transport Protocol Class 4 */ + IPPROTO_DCCP = 33, /* Datagram Congestion Control Protocol */ + IPPROTO_IPV6 = 41, /* IPv6-in-IPv4 tunnelling */ + IPPROTO_RSVP = 46, /* RSVP Protocol */ + IPPROTO_GRE = 47, /* Cisco GRE tunnels (rfc 1701,1702) */ + IPPROTO_ESP = 50, /* Encapsulation Security Payload protocol */ + IPPROTO_AH = 51, /* Authentication Header protocol */ + IPPROTO_MTP = 92, /* Multicast Transport Protocol */ + IPPROTO_BEETPH = 94, /* IP option pseudo header for BEET */ + IPPROTO_ENCAP = 98, /* Encapsulation Header */ + IPPROTO_PIM = 103, /* Protocol Independent Multicast */ + IPPROTO_COMP = 108, /* Compression Header Protocol */ + IPPROTO_SCTP = 132, /* Stream Control Transport Protocol */ + IPPROTO_UDPLITE = 136, /* UDP-Lite (RFC 3828) */ + IPPROTO_RAW = 255, /* Raw IP packets */ + + // Number used by linux (0) has a special meaning for socket() + IPPROTO_IP = 1024, /* Dummy protocol for TCP */ + // Number used by linux (1) clashes with IPPROTO_ICMP + SOL_SOCKET = 2048, /* For setsockopt() / getsockopt(): Options to be accessed at socket level, not protocol level. */ + } + + [Map] + [CLSCompliant (false)] + public enum UnixAddressFamily : int { + AF_UNSPEC = 0, /* Unspecified. */ + AF_UNIX = 1, /* Local to host (pipes and file-domain). */ + AF_INET = 2, /* IP protocol family. */ + AF_AX25 = 3, /* Amateur Radio AX.25. */ + AF_IPX = 4, /* Novell Internet Protocol. */ + AF_APPLETALK = 5, /* Appletalk DDP. */ + AF_NETROM = 6, /* Amateur radio NetROM. */ + AF_BRIDGE = 7, /* Multiprotocol bridge. */ + AF_ATMPVC = 8, /* ATM PVCs. */ + AF_X25 = 9, /* Reserved for X.25 project. */ + AF_INET6 = 10, /* IP version 6. */ + AF_ROSE = 11, /* Amateur Radio X.25 PLP. */ + AF_DECnet = 12, /* Reserved for DECnet project. */ + AF_NETBEUI = 13, /* Reserved for 802.2LLC project. */ + AF_SECURITY = 14, /* Security callback pseudo AF. */ + AF_KEY = 15, /* PF_KEY key management API. */ + AF_NETLINK = 16, + AF_PACKET = 17, /* Packet family. */ + AF_ASH = 18, /* Ash. */ + AF_ECONET = 19, /* Acorn Econet. */ + AF_ATMSVC = 20, /* ATM SVCs. */ + AF_RDS = 21, /* RDS sockets. */ + AF_SNA = 22, /* Linux SNA Project */ + AF_IRDA = 23, /* IRDA sockets. */ + AF_PPPOX = 24, /* PPPoX sockets. */ + AF_WANPIPE = 25, /* Wanpipe API sockets. */ + AF_LLC = 26, /* Linux LLC. */ + AF_CAN = 29, /* Controller Area Network. */ + AF_TIPC = 30, /* TIPC sockets. */ + AF_BLUETOOTH = 31, /* Bluetooth sockets. */ + AF_IUCV = 32, /* IUCV sockets. */ + AF_RXRPC = 33, /* RxRPC sockets. */ + AF_ISDN = 34, /* mISDN sockets. */ + AF_PHONET = 35, /* Phonet sockets. */ + AF_IEEE802154 = 36, /* IEEE 802.15.4 sockets. */ + AF_CAIF = 37, /* CAIF sockets. */ + AF_ALG = 38, /* Algorithm sockets. */ + AF_NFC = 39, /* NFC sockets. */ + AF_VSOCK = 40, /* vSockets. */ + + // Value used when a syscall returns an unknown address family value + Unknown = 65536, + } + + [Map] + [CLSCompliant (false)] + public enum UnixSocketOptionName : int { + SO_DEBUG = 1, + SO_REUSEADDR = 2, + SO_TYPE = 3, + SO_ERROR = 4, + SO_DONTROUTE = 5, + SO_BROADCAST = 6, + SO_SNDBUF = 7, + SO_RCVBUF = 8, + SO_SNDBUFFORCE = 32, + SO_RCVBUFFORCE = 33, + SO_KEEPALIVE = 9, + SO_OOBINLINE = 10, + SO_NO_CHECK = 11, + SO_PRIORITY = 12, + SO_LINGER = 13, + SO_BSDCOMPAT = 14, + SO_REUSEPORT = 15, + SO_PASSCRED = 16, + SO_PEERCRED = 17, + SO_RCVLOWAT = 18, + SO_SNDLOWAT = 19, + SO_RCVTIMEO = 20, + SO_SNDTIMEO = 21, + SO_SECURITY_AUTHENTICATION = 22, + SO_SECURITY_ENCRYPTION_TRANSPORT = 23, + SO_SECURITY_ENCRYPTION_NETWORK = 24, + SO_BINDTODEVICE = 25, + SO_ATTACH_FILTER = 26, + SO_DETACH_FILTER = 27, + SO_PEERNAME = 28, + SO_TIMESTAMP = 29, + SO_ACCEPTCONN = 30, + SO_PEERSEC = 31, + SO_PASSSEC = 34, + SO_TIMESTAMPNS = 35, + SO_MARK = 36, + SO_TIMESTAMPING = 37, + SO_PROTOCOL = 38, + SO_DOMAIN = 39, + SO_RXQ_OVFL = 40, + SO_WIFI_STATUS = 41, + SO_PEEK_OFF = 42, + SO_NOFCS = 43, + SO_LOCK_FILTER = 44, + SO_SELECT_ERR_QUEUE = 45, + SO_BUSY_POLL = 46, + SO_MAX_PACING_RATE = 47, + } + + [Flags][Map] + [CLSCompliant (false)] + public enum MessageFlags : int { + MSG_OOB = 0x01, /* Process out-of-band data. */ + MSG_PEEK = 0x02, /* Peek at incoming messages. */ + MSG_DONTROUTE = 0x04, /* Don't use local routing. */ + MSG_CTRUNC = 0x08, /* Control data lost before delivery. */ + MSG_PROXY = 0x10, /* Supply or ask second address. */ + MSG_TRUNC = 0x20, + MSG_DONTWAIT = 0x40, /* Nonblocking IO. */ + MSG_EOR = 0x80, /* End of record. */ + MSG_WAITALL = 0x100, /* Wait for a full request. */ + MSG_FIN = 0x200, + MSG_SYN = 0x400, + MSG_CONFIRM = 0x800, /* Confirm path validity. */ + MSG_RST = 0x1000, + MSG_ERRQUEUE = 0x2000, /* Fetch message from error queue. */ + MSG_NOSIGNAL = 0x4000, /* Do not generate SIGPIPE. */ + MSG_MORE = 0x8000, /* Sender will send more. */ + MSG_WAITFORONE = 0x10000, /* Wait for at least one packet to return.*/ + MSG_FASTOPEN = 0x20000000, /* Send data in TCP SYN. */ + MSG_CMSG_CLOEXEC = 0x40000000, /* Set close_on_exit for file descriptor received through SCM_RIGHTS. */ + } + + [Map] + [CLSCompliant (false)] + public enum ShutdownOption : int { + SHUT_RD = 0x01, /* No more receptions. */ + SHUT_WR = 0x02, /* No more transmissions. */ + SHUT_RDWR = 0x03, /* No more receptions or transmissions. */ + } + + // Used by libMonoPosixHelper to distinguish between different sockaddr types + [Map] + enum SockaddrType : int { + Invalid, + SockaddrStorage, + SockaddrUn, + Sockaddr, + SockaddrIn, + SockaddrIn6, + + // Flag to indicate that this Sockaddr must be wrapped with a _SockaddrDynamic wrapper + MustBeWrapped = 0x8000, + } + + [Map] + [CLSCompliant (false)] + public enum UnixSocketControlMessage : int { + SCM_RIGHTS = 0x01, /* Transfer file descriptors. */ + SCM_CREDENTIALS = 0x02, /* Credentials passing. */ + } + + #endregion + + #region Structures + + [Map ("struct flock")] + public struct Flock + : IEquatable + { + [CLSCompliant (false)] + public LockType l_type; // Type of lock: F_RDLCK, F_WRLCK, F_UNLCK + [CLSCompliant (false)] + public SeekFlags l_whence; // How to interpret l_start + [off_t] public long l_start; // Starting offset for lock + [off_t] public long l_len; // Number of bytes to lock + [pid_t] public int l_pid; // PID of process blocking our lock (F_GETLK only) + + public override int GetHashCode () + { + return l_type.GetHashCode () ^ l_whence.GetHashCode () ^ + l_start.GetHashCode () ^ l_len.GetHashCode () ^ + l_pid.GetHashCode (); + } + + public override bool Equals (object obj) + { + if ((obj == null) || (obj.GetType () != GetType ())) + return false; + Flock value = (Flock) obj; + return l_type == value.l_type && l_whence == value.l_whence && + l_start == value.l_start && l_len == value.l_len && + l_pid == value.l_pid; + } + + public bool Equals (Flock value) + { + return l_type == value.l_type && l_whence == value.l_whence && + l_start == value.l_start && l_len == value.l_len && + l_pid == value.l_pid; + } + + public static bool operator== (Flock lhs, Flock rhs) + { + return lhs.Equals (rhs); + } + + public static bool operator!= (Flock lhs, Flock rhs) + { + return !lhs.Equals (rhs); + } + } + + [Map ("struct pollfd")] + public struct Pollfd + : IEquatable + { + public int fd; + [CLSCompliant (false)] + public PollEvents events; + [CLSCompliant (false)] + public PollEvents revents; + + public override int GetHashCode () + { + return events.GetHashCode () ^ revents.GetHashCode (); + } + + public override bool Equals (object obj) + { + if (obj == null || obj.GetType () != GetType ()) + return false; + Pollfd value = (Pollfd) obj; + return value.events == events && value.revents == revents; + } + + public bool Equals (Pollfd value) + { + return value.events == events && value.revents == revents; + } + + public static bool operator== (Pollfd lhs, Pollfd rhs) + { + return lhs.Equals (rhs); + } + + public static bool operator!= (Pollfd lhs, Pollfd rhs) + { + return !lhs.Equals (rhs); + } + } + + // Use manually written To/From methods to handle fields st_atime_nsec etc. + public struct Stat + : IEquatable + { + [CLSCompliant (false)] + [dev_t] public ulong st_dev; // device + [CLSCompliant (false)] + [ino_t] public ulong st_ino; // inode + [CLSCompliant (false)] + public FilePermissions st_mode; // protection + [NonSerialized] +#pragma warning disable 169 + private uint _padding_; // padding for structure alignment +#pragma warning restore 169 + [CLSCompliant (false)] + [nlink_t] public ulong st_nlink; // number of hard links + [CLSCompliant (false)] + [uid_t] public uint st_uid; // user ID of owner + [CLSCompliant (false)] + [gid_t] public uint st_gid; // group ID of owner + [CLSCompliant (false)] + [dev_t] public ulong st_rdev; // device type (if inode device) + [off_t] public long st_size; // total size, in bytes + [blksize_t] public long st_blksize; // blocksize for filesystem I/O + [blkcnt_t] public long st_blocks; // number of blocks allocated + [time_t] public long st_atime; // time of last access + [time_t] public long st_mtime; // time of last modification + [time_t] public long st_ctime; // time of last status change + public long st_atime_nsec; // Timespec.tv_nsec partner to st_atime + public long st_mtime_nsec; // Timespec.tv_nsec partner to st_mtime + public long st_ctime_nsec; // Timespec.tv_nsec partner to st_ctime + + public Timespec st_atim { + get { + return new Timespec { tv_sec = st_atime, tv_nsec = st_atime_nsec }; + } + set { + st_atime = value.tv_sec; + st_atime_nsec = value.tv_nsec; + } + } + + public Timespec st_mtim { + get { + return new Timespec { tv_sec = st_mtime, tv_nsec = st_mtime_nsec }; + } + set { + st_mtime = value.tv_sec; + st_mtime_nsec = value.tv_nsec; + } + } + + public Timespec st_ctim { + get { + return new Timespec { tv_sec = st_ctime, tv_nsec = st_ctime_nsec }; + } + set { + st_ctime = value.tv_sec; + st_ctime_nsec = value.tv_nsec; + } + } + + public override int GetHashCode () + { + return st_dev.GetHashCode () ^ + st_ino.GetHashCode () ^ + st_mode.GetHashCode () ^ + st_nlink.GetHashCode () ^ + st_uid.GetHashCode () ^ + st_gid.GetHashCode () ^ + st_rdev.GetHashCode () ^ + st_size.GetHashCode () ^ + st_blksize.GetHashCode () ^ + st_blocks.GetHashCode () ^ + st_atime.GetHashCode () ^ + st_mtime.GetHashCode () ^ + st_ctime.GetHashCode () ^ + st_atime_nsec.GetHashCode () ^ + st_mtime_nsec.GetHashCode () ^ + st_ctime_nsec.GetHashCode (); + } + + public override bool Equals (object obj) + { + if (obj == null || obj.GetType() != GetType ()) + return false; + Stat value = (Stat) obj; + return value.st_dev == st_dev && + value.st_ino == st_ino && + value.st_mode == st_mode && + value.st_nlink == st_nlink && + value.st_uid == st_uid && + value.st_gid == st_gid && + value.st_rdev == st_rdev && + value.st_size == st_size && + value.st_blksize == st_blksize && + value.st_blocks == st_blocks && + value.st_atime == st_atime && + value.st_mtime == st_mtime && + value.st_ctime == st_ctime && + value.st_atime_nsec == st_atime_nsec && + value.st_mtime_nsec == st_mtime_nsec && + value.st_ctime_nsec == st_ctime_nsec; + } + + public bool Equals (Stat value) + { + return value.st_dev == st_dev && + value.st_ino == st_ino && + value.st_mode == st_mode && + value.st_nlink == st_nlink && + value.st_uid == st_uid && + value.st_gid == st_gid && + value.st_rdev == st_rdev && + value.st_size == st_size && + value.st_blksize == st_blksize && + value.st_blocks == st_blocks && + value.st_atime == st_atime && + value.st_mtime == st_mtime && + value.st_ctime == st_ctime && + value.st_atime_nsec == st_atime_nsec && + value.st_mtime_nsec == st_mtime_nsec && + value.st_ctime_nsec == st_ctime_nsec; + } + + public static bool operator== (Stat lhs, Stat rhs) + { + return lhs.Equals (rhs); + } + + public static bool operator!= (Stat lhs, Stat rhs) + { + return !lhs.Equals (rhs); + } + } + + // `struct statvfs' isn't portable, so don't generate To/From methods. + [Map] + [CLSCompliant (false)] + public struct Statvfs + : IEquatable + { + public ulong f_bsize; // file system block size + public ulong f_frsize; // fragment size + [fsblkcnt_t] public ulong f_blocks; // size of fs in f_frsize units + [fsblkcnt_t] public ulong f_bfree; // # free blocks + [fsblkcnt_t] public ulong f_bavail; // # free blocks for non-root + [fsfilcnt_t] public ulong f_files; // # inodes + [fsfilcnt_t] public ulong f_ffree; // # free inodes + [fsfilcnt_t] public ulong f_favail; // # free inodes for non-root + public ulong f_fsid; // file system id + public MountFlags f_flag; // mount flags + public ulong f_namemax; // maximum filename length + + public override int GetHashCode () + { + return f_bsize.GetHashCode () ^ + f_frsize.GetHashCode () ^ + f_blocks.GetHashCode () ^ + f_bfree.GetHashCode () ^ + f_bavail.GetHashCode () ^ + f_files.GetHashCode () ^ + f_ffree.GetHashCode () ^ + f_favail.GetHashCode () ^ + f_fsid.GetHashCode () ^ + f_flag.GetHashCode () ^ + f_namemax.GetHashCode (); + } + + public override bool Equals (object obj) + { + if (obj == null || obj.GetType() != GetType ()) + return false; + Statvfs value = (Statvfs) obj; + return value.f_bsize == f_bsize && + value.f_frsize == f_frsize && + value.f_blocks == f_blocks && + value.f_bfree == f_bfree && + value.f_bavail == f_bavail && + value.f_files == f_files && + value.f_ffree == f_ffree && + value.f_favail == f_favail && + value.f_fsid == f_fsid && + value.f_flag == f_flag && + value.f_namemax == f_namemax; + } + + public bool Equals (Statvfs value) + { + return value.f_bsize == f_bsize && + value.f_frsize == f_frsize && + value.f_blocks == f_blocks && + value.f_bfree == f_bfree && + value.f_bavail == f_bavail && + value.f_files == f_files && + value.f_ffree == f_ffree && + value.f_favail == f_favail && + value.f_fsid == f_fsid && + value.f_flag == f_flag && + value.f_namemax == f_namemax; + } + + public static bool operator== (Statvfs lhs, Statvfs rhs) + { + return lhs.Equals (rhs); + } + + public static bool operator!= (Statvfs lhs, Statvfs rhs) + { + return !lhs.Equals (rhs); + } + } + + [Map ("struct timeval")] + public struct Timeval + : IEquatable + { + [time_t] public long tv_sec; // seconds + [suseconds_t] public long tv_usec; // microseconds + + public override int GetHashCode () + { + return tv_sec.GetHashCode () ^ tv_usec.GetHashCode (); + } + + public override bool Equals (object obj) + { + if (obj == null || obj.GetType () != GetType ()) + return false; + Timeval value = (Timeval) obj; + return value.tv_sec == tv_sec && value.tv_usec == tv_usec; + } + + public bool Equals (Timeval value) + { + return value.tv_sec == tv_sec && value.tv_usec == tv_usec; + } + + public static bool operator== (Timeval lhs, Timeval rhs) + { + return lhs.Equals (rhs); + } + + public static bool operator!= (Timeval lhs, Timeval rhs) + { + return !lhs.Equals (rhs); + } + } + + [Map ("struct timezone")] + public struct Timezone + : IEquatable + { + public int tz_minuteswest; // minutes W of Greenwich +#pragma warning disable 169 + private int tz_dsttime; // type of dst correction (OBSOLETE) +#pragma warning restore 169 + + public override int GetHashCode () + { + return tz_minuteswest.GetHashCode (); + } + + public override bool Equals (object obj) + { + if (obj == null || obj.GetType () != GetType ()) + return false; + Timezone value = (Timezone) obj; + return value.tz_minuteswest == tz_minuteswest; + } + + public bool Equals (Timezone value) + { + return value.tz_minuteswest == tz_minuteswest; + } + + public static bool operator== (Timezone lhs, Timezone rhs) + { + return lhs.Equals (rhs); + } + + public static bool operator!= (Timezone lhs, Timezone rhs) + { + return !lhs.Equals (rhs); + } + } + + [Map ("struct utimbuf")] + public struct Utimbuf + : IEquatable + { + [time_t] public long actime; // access time + [time_t] public long modtime; // modification time + + public override int GetHashCode () + { + return actime.GetHashCode () ^ modtime.GetHashCode (); + } + + public override bool Equals (object obj) + { + if (obj == null || obj.GetType () != GetType ()) + return false; + Utimbuf value = (Utimbuf) obj; + return value.actime == actime && value.modtime == modtime; + } + + public bool Equals (Utimbuf value) + { + return value.actime == actime && value.modtime == modtime; + } + + public static bool operator== (Utimbuf lhs, Utimbuf rhs) + { + return lhs.Equals (rhs); + } + + public static bool operator!= (Utimbuf lhs, Utimbuf rhs) + { + return !lhs.Equals (rhs); + } + } + + [Map ("struct timespec")] + public struct Timespec + : IEquatable + { + [time_t] public long tv_sec; // Seconds. + public long tv_nsec; // Nanoseconds. + + public override int GetHashCode () + { + return tv_sec.GetHashCode () ^ tv_nsec.GetHashCode (); + } + + public override bool Equals (object obj) + { + if (obj == null || obj.GetType () != GetType ()) + return false; + Timespec value = (Timespec) obj; + return value.tv_sec == tv_sec && value.tv_nsec == tv_nsec; + } + + public bool Equals (Timespec value) + { + return value.tv_sec == tv_sec && value.tv_nsec == tv_nsec; + } + + public static bool operator== (Timespec lhs, Timespec rhs) + { + return lhs.Equals (rhs); + } + + public static bool operator!= (Timespec lhs, Timespec rhs) + { + return !lhs.Equals (rhs); + } + } + + [Map ("struct iovec")] + public struct Iovec + { + public IntPtr iov_base; // Starting address + [CLSCompliant (false)] + public ulong iov_len; // Number of bytes to transfer + } + + [Flags][Map] + public enum EpollFlags { + EPOLL_CLOEXEC = 02000000, + EPOLL_NONBLOCK = 04000, + } + + [Flags][Map] + [CLSCompliant (false)] + public enum EpollEvents : uint { + EPOLLIN = 0x001, + EPOLLPRI = 0x002, + EPOLLOUT = 0x004, + EPOLLRDNORM = 0x040, + EPOLLRDBAND = 0x080, + EPOLLWRNORM = 0x100, + EPOLLWRBAND = 0x200, + EPOLLMSG = 0x400, + EPOLLERR = 0x008, + EPOLLHUP = 0x010, + EPOLLRDHUP = 0x2000, + EPOLLONESHOT = 1 << 30, + EPOLLET = unchecked ((uint) (1 << 31)) + } + + public enum EpollOp { + EPOLL_CTL_ADD = 1, + EPOLL_CTL_DEL = 2, + EPOLL_CTL_MOD = 3, + } + + [StructLayout (LayoutKind.Explicit, Size=12, Pack=1)] + [CLSCompliant (false)] + public struct EpollEvent { + [FieldOffset (0)] + public EpollEvents events; + [FieldOffset (4)] + public int fd; + [FieldOffset (4)] + public IntPtr ptr; + [FieldOffset (4)] + public uint u32; + [FieldOffset (4)] + public ulong u64; + } + + [Map ("struct linger")] + [CLSCompliant (false)] + public struct Linger { + public int l_onoff; + public int l_linger; + + public override string ToString () + { + return string.Format ("{0}, {1}", l_onoff, l_linger); + } + } + + [Map] + [StructLayout (LayoutKind.Sequential)] + [CLSCompliant (false)] + public struct InAddr : IEquatable { + public uint s_addr; + + public unsafe InAddr (byte b0, byte b1, byte b2, byte b3) + { + s_addr = 0; + fixed (uint* ptr = &s_addr) { + byte* bytePtr = (byte*) ptr; + bytePtr[0] = b0; + bytePtr[1] = b1; + bytePtr[2] = b2; + bytePtr[3] = b3; + } + } + + public unsafe InAddr (byte[] buffer) + { + if (buffer.Length != 4) + throw new ArgumentException ("buffer.Length != 4", "buffer"); + s_addr = 0; + fixed (uint* ptr = &s_addr) + Marshal.Copy (buffer, 0, (IntPtr) ptr, 4); + } + + public unsafe void CopyFrom (byte[] source, int startIndex) + { + fixed (uint* ptr = &s_addr) + Marshal.Copy (source, startIndex, (IntPtr) ptr, 4); + } + + public unsafe void CopyTo (byte[] destination, int startIndex) + { + fixed (uint* ptr = &s_addr) + Marshal.Copy ((IntPtr) ptr, destination, startIndex, 4); + } + + public unsafe byte this[int index] { + get { + if (index < 0 || index >= 4) + throw new ArgumentOutOfRangeException ("index", "index < 0 || index >= 4"); + fixed (uint* ptr = &s_addr) + return ((byte*) ptr)[index]; + } + set { + if (index < 0 || index >= 4) + throw new ArgumentOutOfRangeException ("index", "index < 0 || index >= 4"); + fixed (uint* ptr = &s_addr) + ((byte*) ptr)[index] = value; + } + } + + public override string ToString () + { + return NativeConvert.ToIPAddress (this).ToString (); + } + + public override int GetHashCode () + { + return s_addr.GetHashCode (); + } + public override bool Equals (object obj) + { + if (!(obj is InAddr)) + return false; + return Equals ((InAddr) obj); + } + public bool Equals (InAddr value) + { + return s_addr == value.s_addr; + } + } + + [Map] + [StructLayout (LayoutKind.Sequential)] + public struct In6Addr : IEquatable { + ulong addr0; + ulong addr1; + + public unsafe In6Addr (byte[] buffer) + { + if (buffer.Length != 16) + throw new ArgumentException ("buffer.Length != 16", "buffer"); + addr0 = addr1 = 0; + fixed (ulong* ptr = &addr0) + Marshal.Copy (buffer, 0, (IntPtr) ptr, 16); + } + + public unsafe void CopyFrom (byte[] source, int startIndex) + { + fixed (ulong* ptr = &addr0) + Marshal.Copy (source, startIndex, (IntPtr) ptr, 16); + } + + public unsafe void CopyTo (byte[] destination, int startIndex) + { + fixed (ulong* ptr = &addr0) + Marshal.Copy ((IntPtr) ptr, destination, startIndex, 16); + } + + public unsafe byte this[int index] { + get { + if (index < 0 || index >= 16) + throw new ArgumentOutOfRangeException ("index", "index < 0 || index >= 16"); + fixed (ulong* ptr = &addr0) + return ((byte*) ptr)[index]; + } + set { + if (index < 0 || index >= 16) + throw new ArgumentOutOfRangeException ("index", "index < 0 || index >= 16"); + fixed (ulong* ptr = &addr0) + ((byte*) ptr)[index] = value; + } + } + + public override string ToString () + { + return NativeConvert.ToIPAddress (this).ToString (); + } + + public override int GetHashCode () + { + return addr0.GetHashCode () ^ addr1.GetHashCode (); + } + public override bool Equals (object obj) + { + if (!(obj is In6Addr)) + return false; + return Equals ((In6Addr) obj); + } + public bool Equals (In6Addr value) + { + return addr0 == value.addr0 && addr1 == value.addr1; + } + } + + [Map ("struct cmsghdr")] + [CLSCompliant (false)] + public struct Cmsghdr { + public long cmsg_len; + public UnixSocketProtocol cmsg_level; + public UnixSocketControlMessage cmsg_type; + + [DllImport (Syscall.MPH, SetLastError=true, + EntryPoint="Mono_Posix_Cmsghdr_getsize")] + static extern int getsize (); + static readonly int size = getsize (); + public static int Size { + get { + return size; + } + } + + // Read a struct cmsghdr from msgh.msg_control at offset cmsg and convert it to managed Cmsghdr structure + public static unsafe Cmsghdr ReadFromBuffer (Msghdr msgh, long cmsg) + { + if (msgh == null) + throw new ArgumentNullException ("msgh"); + if (msgh.msg_control == null || msgh.msg_controllen > msgh.msg_control.Length) + throw new ArgumentException ("msgh.msg_control == null || msgh.msg_controllen > msgh.msg_control.Length", "msgh"); + if (cmsg < 0 || cmsg + Cmsghdr.Size > msgh.msg_controllen) + throw new ArgumentException ("cmsg offset pointing out of buffer", "cmsg"); + + Cmsghdr hdr; + fixed (byte* ptr = msgh.msg_control) + if (!NativeConvert.TryCopy ((IntPtr) (ptr + cmsg), out hdr)) + throw new ArgumentException ("Failed to convert from native struct", "buffer"); + // SOL_SOCKET has the same value as IPPROTO_ICMP on linux. + // Make sure that cmsg_level is set to SOL_SOCKET in this case. + if (NativeConvert.FromUnixSocketProtocol (hdr.cmsg_level) == NativeConvert.FromUnixSocketProtocol (UnixSocketProtocol.SOL_SOCKET)) + hdr.cmsg_level = UnixSocketProtocol.SOL_SOCKET; + return hdr; + } + + // Convert the Cmsghdr to a native struct cmsghdr and write it to msgh.msg_control at offset cmsg + public unsafe void WriteToBuffer (Msghdr msgh, long cmsg) + { + if (msgh == null) + throw new ArgumentNullException ("msgh"); + if (msgh.msg_control == null || msgh.msg_controllen > msgh.msg_control.Length) + throw new ArgumentException ("msgh.msg_control == null || msgh.msg_controllen > msgh.msg_control.Length", "msgh"); + if (cmsg < 0 || cmsg + Cmsghdr.Size > msgh.msg_controllen) + throw new ArgumentException ("cmsg offset pointing out of buffer", "cmsg"); + + fixed (byte* ptr = msgh.msg_control) + if (!NativeConvert.TryCopy (ref this, (IntPtr) (ptr + cmsg))) + throw new ArgumentException ("Failed to convert to native struct", "buffer"); + } + } + + #endregion + + #region Classes + + public sealed class Dirent + : IEquatable + { + [CLSCompliant (false)] + public /* ino_t */ ulong d_ino; + public /* off_t */ long d_off; + [CLSCompliant (false)] + public ushort d_reclen; + public byte d_type; + public string d_name; + + public override int GetHashCode () + { + return d_ino.GetHashCode () ^ d_off.GetHashCode () ^ + d_reclen.GetHashCode () ^ d_type.GetHashCode () ^ + d_name.GetHashCode (); + } + + public override bool Equals (object obj) + { + if (obj == null || GetType() != obj.GetType()) + return false; + Dirent d = (Dirent) obj; + return Equals (d); + } + + public bool Equals (Dirent value) + { + if (value == null) + return false; + return value.d_ino == d_ino && value.d_off == d_off && + value.d_reclen == d_reclen && value.d_type == d_type && + value.d_name == d_name; + } + + public override string ToString () + { + return d_name; + } + + public static bool operator== (Dirent lhs, Dirent rhs) + { + return Object.Equals (lhs, rhs); + } + + public static bool operator!= (Dirent lhs, Dirent rhs) + { + return !Object.Equals (lhs, rhs); + } + } + + public sealed class Fstab + : IEquatable + { + public string fs_spec; + public string fs_file; + public string fs_vfstype; + public string fs_mntops; + public string fs_type; + public int fs_freq; + public int fs_passno; + + public override int GetHashCode () + { + return fs_spec.GetHashCode () ^ fs_file.GetHashCode () ^ + fs_vfstype.GetHashCode () ^ fs_mntops.GetHashCode () ^ + fs_type.GetHashCode () ^ fs_freq ^ fs_passno; + } + + public override bool Equals (object obj) + { + if (obj == null || GetType() != obj.GetType()) + return false; + Fstab f = (Fstab) obj; + return Equals (f); + } + + public bool Equals (Fstab value) + { + if (value == null) + return false; + return value.fs_spec == fs_spec && value.fs_file == fs_file && + value.fs_vfstype == fs_vfstype && value.fs_mntops == fs_mntops && + value.fs_type == fs_type && value.fs_freq == fs_freq && + value.fs_passno == fs_passno; + } + + public override string ToString () + { + return fs_spec; + } + + public static bool operator== (Fstab lhs, Fstab rhs) + { + return Object.Equals (lhs, rhs); + } + + public static bool operator!= (Fstab lhs, Fstab rhs) + { + return !Object.Equals (lhs, rhs); + } + } + + public sealed class Group + : IEquatable + { + public string gr_name; + public string gr_passwd; + [CLSCompliant (false)] + public /* gid_t */ uint gr_gid; + public string[] gr_mem; + + public override int GetHashCode () + { + int memhc = 0; + for (int i = 0; i < gr_mem.Length; ++i) + memhc ^= gr_mem[i].GetHashCode (); + + return gr_name.GetHashCode () ^ gr_passwd.GetHashCode () ^ + gr_gid.GetHashCode () ^ memhc; + } + + public override bool Equals (object obj) + { + if (obj == null || GetType() != obj.GetType()) + return false; + Group g = (Group) obj; + return Equals (g); + } + + public bool Equals (Group value) + { + if (value == null) + return false; + if (value.gr_gid != gr_gid) + return false; + if (value.gr_gid == gr_gid && value.gr_name == gr_name && + value.gr_passwd == gr_passwd) { + if (value.gr_mem == gr_mem) + return true; + if (value.gr_mem == null || gr_mem == null) + return false; + if (value.gr_mem.Length != gr_mem.Length) + return false; + for (int i = 0; i < gr_mem.Length; ++i) + if (gr_mem[i] != value.gr_mem[i]) + return false; + return true; + } + return false; + } + + // Generate string in /etc/group format + public override string ToString () + { + StringBuilder sb = new StringBuilder (); + sb.Append (gr_name).Append (":").Append (gr_passwd).Append (":"); + sb.Append (gr_gid).Append (":"); + GetMembers (sb, gr_mem); + return sb.ToString (); + } + + private static void GetMembers (StringBuilder sb, string[] members) + { + if (members.Length > 0) + sb.Append (members[0]); + for (int i = 1; i < members.Length; ++i) { + sb.Append (","); + sb.Append (members[i]); + } + } + + public static bool operator== (Group lhs, Group rhs) + { + return Object.Equals (lhs, rhs); + } + + public static bool operator!= (Group lhs, Group rhs) + { + return !Object.Equals (lhs, rhs); + } + } + + public sealed class Passwd + : IEquatable + { + public string pw_name; + public string pw_passwd; + [CLSCompliant (false)] + public /* uid_t */ uint pw_uid; + [CLSCompliant (false)] + public /* gid_t */ uint pw_gid; + public string pw_gecos; + public string pw_dir; + public string pw_shell; + + public override int GetHashCode () + { + return pw_name.GetHashCode () ^ pw_passwd.GetHashCode () ^ + pw_uid.GetHashCode () ^ pw_gid.GetHashCode () ^ + pw_gecos.GetHashCode () ^ pw_dir.GetHashCode () ^ + pw_dir.GetHashCode () ^ pw_shell.GetHashCode (); + } + + public override bool Equals (object obj) + { + if (obj == null || GetType() != obj.GetType()) + return false; + Passwd p = (Passwd) obj; + return Equals (p); + } + + public bool Equals (Passwd value) + { + if (value == null) + return false; + return value.pw_uid == pw_uid && value.pw_gid == pw_gid && + value.pw_name == pw_name && value.pw_passwd == pw_passwd && + value.pw_gecos == pw_gecos && value.pw_dir == pw_dir && + value.pw_shell == pw_shell; + } + + // Generate string in /etc/passwd format + public override string ToString () + { + return string.Format ("{0}:{1}:{2}:{3}:{4}:{5}:{6}", + pw_name, pw_passwd, pw_uid, pw_gid, pw_gecos, pw_dir, pw_shell); + } + + public static bool operator== (Passwd lhs, Passwd rhs) + { + return Object.Equals (lhs, rhs); + } + + public static bool operator!= (Passwd lhs, Passwd rhs) + { + return !Object.Equals (lhs, rhs); + } + } + + public sealed class Utsname + : IEquatable + { + public string sysname; + public string nodename; + public string release; + public string version; + public string machine; + public string domainname; + + public override int GetHashCode () + { + return sysname.GetHashCode () ^ nodename.GetHashCode () ^ + release.GetHashCode () ^ version.GetHashCode () ^ + machine.GetHashCode () ^ domainname.GetHashCode (); + } + + public override bool Equals (object obj) + { + if (obj == null || GetType() != obj.GetType()) + return false; + Utsname u = (Utsname) obj; + return Equals (u); + } + + public bool Equals (Utsname value) + { + return value.sysname == sysname && value.nodename == nodename && + value.release == release && value.version == version && + value.machine == machine && value.domainname == domainname; + } + + // Generate string in /etc/passwd format + public override string ToString () + { + return string.Format ("{0} {1} {2} {3} {4}", + sysname, nodename, release, version, machine); + } + + public static bool operator== (Utsname lhs, Utsname rhs) + { + return Object.Equals (lhs, rhs); + } + + public static bool operator!= (Utsname lhs, Utsname rhs) + { + return !Object.Equals (lhs, rhs); + } + } + + // This struct is used by the native code. + // Its layout must be the same as the start of the Sockaddr class and the start of the _SockaddrDynamic struct + [Map] + [StructLayout (LayoutKind.Sequential)] + internal struct _SockaddrHeader { + internal SockaddrType type; + internal UnixAddressFamily sa_family; + } + + // Base class for all Sockaddr types. + // This class is not abstract, instances of this class can be used to determine the sa_family value. + // This class and all classes which are deriving from it and are passed to the native code have to be blittable. + [CLSCompliant (false)] + [StructLayout (LayoutKind.Sequential)] + public class Sockaddr { + // Note: the layout of the first members must match the layout of struct _SockaddrHeader + // 'type' must be the first field of the class as it is used to find the address of the class itself + internal SockaddrType type; + internal UnixAddressFamily _sa_family; + + public UnixAddressFamily sa_family { + get { return _sa_family; } + set { _sa_family = value; } + } + + public Sockaddr () + { + this.type = SockaddrType.Sockaddr; + this.sa_family = UnixAddressFamily.AF_UNSPEC; + } + + internal Sockaddr (SockaddrType type, UnixAddressFamily sa_family) + { + this.type = type; + this.sa_family = sa_family; + } + + [DllImport (Syscall.MPH, SetLastError=true, + EntryPoint="Mono_Posix_Sockaddr_GetNativeSize")] + static extern unsafe int GetNativeSize (_SockaddrHeader* address, out long size); + + internal unsafe long GetNativeSize () + { + long size; + fixed (SockaddrType* addr = &Sockaddr.GetAddress (this).type) + fixed (byte* data = Sockaddr.GetDynamicData (this)) { + var dyn = new _SockaddrDynamic (this, data, useMaxLength: false); + if (GetNativeSize (Sockaddr.GetNative (&dyn, addr), out size) != 0) + throw new ArgumentException ("Failed to get size of native struct", "this"); + } + return size; + } + + + // In order to create a wrapper for a syscall which accepts a "struct sockaddr" argument but does not modify it, use: + + // fixed (SockaddrType* addr = &Sockaddr.GetAddress (address).type) + // fixed (byte* data = Sockaddr.GetDynamicData (address)) { + // var dyn = new _SockaddrDynamic (address, data, useMaxLength: false); + // return sys_syscall (..., Sockaddr.GetNative (&dyn, addr)); + // } + + // For syscalls which modify the argument, use: + + // fixed (SockaddrType* addr = &Sockaddr.GetAddress (address).type) + // fixed (byte* data = Sockaddr.GetDynamicData (address)) { + // var dyn = new _SockaddrDynamic (address, data, useMaxLength: true); + // rettype r = sys_syscall (..., Sockaddr.GetNative (&dyn, addr)); + // dyn.Update (address); + // return r; + // } + + // This sequence will handle + // - normal Sockaddrs like SockaddrIn and SockaddrIn6 which will be passed directly, + // - sockaddrs like SockaddrUn and SockaddrStorage which need a wrapper and + // - null (which will be passed as null) + // without any heap memory allocations. + + + // This is a fake Sockaddr which is passed to the fixed() statement if the address was null. + // Sockaddr.GetNative() will return a null pointer for this Sockaddr. + static Sockaddr nullSockaddr = new Sockaddr (); + + internal static Sockaddr GetAddress (Sockaddr address) + { + if (address == null) + return nullSockaddr; + else + return address; + } + + internal static unsafe _SockaddrHeader* GetNative (_SockaddrDynamic* dyn, SockaddrType* addr) + { + if (dyn->data != null) { + return (_SockaddrHeader*) dyn; + } else { + fixed (SockaddrType* nullType = &nullSockaddr.type) + if (addr == nullType) + return null; + return (_SockaddrHeader*) addr; + } + } + + // Return an array containing the dynamic data (for SockaddrStorage and SockaddrUn) or null + internal static byte[] GetDynamicData (Sockaddr addr) + { + if (addr == null) + return null; + return addr.DynamicData (); + } + + // This methods is overwritten in SockaddrStorage and SockaddrUn + internal virtual byte[] DynamicData () + { + return null; + } + + // This methods should only be called for SockaddrStorage and SockaddrUn where they are overwritten + internal virtual long GetDynamicLength () + { + throw new NotImplementedException (); + } + + internal virtual void SetDynamicLength (long value) + { + throw new NotImplementedException (); + } + + public SockaddrStorage ToSockaddrStorage () + { + var storage = new SockaddrStorage ((int) GetNativeSize ()); + storage.SetTo (this); + return storage; + } + + public static Sockaddr FromSockaddrStorage (SockaddrStorage storage) + { + var ret = new Sockaddr (); + storage.CopyTo (ret); + return ret; + } + } + + // This struct is required to manually marshal Sockaddr* classes which include an array (currently SockaddrStorage and SockaddrUn). + // This is needed because the marshalling code will not work if the classes derived from Sockaddr aren't blittable. + [Map] + unsafe struct _SockaddrDynamic { + // Note: the layout of the first members must match the layout of struct _SockaddrHeader + public SockaddrType type; + public UnixAddressFamily sa_family; + public byte* data; + public long len; + + public _SockaddrDynamic (Sockaddr address, byte* data, bool useMaxLength) + { + if (data == null) { + // When data is null, no wrapper is needed. + // Initialize everything to zero, Sockaddr.GetNative() will then + // use the Sockaddr structure directly. + this = new _SockaddrDynamic (); + return; + } + + var dynData = address.DynamicData (); + + type = address.type & ~SockaddrType.MustBeWrapped; + sa_family = address.sa_family; + this.data = data; + if (useMaxLength) { + len = dynData.Length; + } else { + len = address.GetDynamicLength (); + if (len < 0 || len > dynData.Length) + throw new ArgumentException ("len < 0 || len > dynData.Length", "address"); + } + } + + public void Update (Sockaddr address) + { + // When data is null, no wrapper was needed. + if (data == null) + return; + + address.sa_family = sa_family; + address.SetDynamicLength (len); + } + }; + + // This is a class which can store arbitrary sockaddrs, even if they are not known the the Mono.Unix wrapper or the family does not have a corresponding value in the UnixAddressFamily enumeration. + [CLSCompliant (false)] + public sealed class SockaddrStorage : Sockaddr, IEquatable { + // Note: The sa_family field is ignored when passing a SockaddrStorage to a syscall (but it will be set when a SockaddrStorage is returned from a syscall). Instead of the sa_family field, the value embedded in data is used. + public byte[] data { get; set; } + public long data_len { get; set; } + + internal override byte[] DynamicData () + { + return data; + } + + internal override long GetDynamicLength () + { + return data_len; + } + + internal override void SetDynamicLength (long value) + { + data_len = value; + } + + [DllImport (Syscall.MPH, SetLastError=true, + EntryPoint="Mono_Posix_SockaddrStorage_get_size")] + static extern int get_size (); + static readonly int default_size = get_size (); + + public SockaddrStorage () + : base (SockaddrType.SockaddrStorage | SockaddrType.MustBeWrapped, UnixAddressFamily.AF_UNSPEC) + { + data = new byte[default_size]; + data_len = 0; + } + + public SockaddrStorage (int size) + : base (SockaddrType.SockaddrStorage | SockaddrType.MustBeWrapped, UnixAddressFamily.AF_UNSPEC) + { + data = new byte[size]; + data_len = 0; + } + + public unsafe void SetTo (Sockaddr address) + { + if (address == null) + throw new ArgumentNullException ("address"); + + var size = address.GetNativeSize (); + if (size > data.Length) + data = new byte[size]; + fixed (byte* ptr = data) + if (!NativeConvert.TryCopy (address, (IntPtr) ptr)) + throw new ArgumentException ("Failed to convert to native struct", "address"); + data_len = size; + sa_family = address.sa_family; + } + + public unsafe void CopyTo (Sockaddr address) + { + if (address == null) + throw new ArgumentNullException ("address"); + if (data_len < 0 || data_len > data.Length) + throw new ArgumentException ("data_len < 0 || data_len > data.Length", "this"); + + fixed (byte* ptr = data) + if (!NativeConvert.TryCopy ((IntPtr) ptr, data_len, address)) + throw new ArgumentException ("Failed to convert from native struct", "this"); + } + + public override string ToString () + { + var sb = new StringBuilder (); + sb.AppendFormat ("{{sa_family={0}, data_len={1}, data=(", sa_family, data_len); + for (int i = 0; i < data_len; i++) { + if (i != 0) + sb.Append (" "); + sb.Append (data[i].ToString ("x2")); + } + sb.Append (")"); + return sb.ToString (); + } + + public override int GetHashCode () + { + unchecked { + int hash = 0x1234; + for (int i = 0; i < data_len; i++) + hash += i ^ data[i]; + return hash; + } + } + + public override bool Equals (object obj) + { + if (!(obj is SockaddrStorage)) + return false; + return Equals ((SockaddrStorage) obj); + } + + public bool Equals (SockaddrStorage value) + { + if (value == null) + return false; + if (data_len != value.data_len) + return false; + for (int i = 0; i < data_len; i++) + if (data[i] != value.data[i]) + return false; + return true; + } + } + + [CLSCompliant (false)] + public sealed class SockaddrUn : Sockaddr, IEquatable { + public UnixAddressFamily sun_family { // AF_UNIX + get { return sa_family; } + set { sa_family = value; } + } + public byte[] sun_path { get; set; } + public long sun_path_len { get; set; } // Indicates how many bytes of sun_path are valid. Must not be larger than sun_path.Length. + + internal override byte[] DynamicData () + { + return sun_path; + } + + internal override long GetDynamicLength () + { + return sun_path_len; + } + + internal override void SetDynamicLength (long value) + { + sun_path_len = value; + } + + [DllImport (Syscall.MPH, SetLastError=true, + EntryPoint="Mono_Posix_SockaddrUn_get_sizeof_sun_path")] + static extern int get_sizeof_sun_path (); + static readonly int sizeof_sun_path = get_sizeof_sun_path (); + + public SockaddrUn () + : base (SockaddrType.SockaddrUn | SockaddrType.MustBeWrapped, UnixAddressFamily.AF_UNIX) + { + sun_path = new byte[sizeof_sun_path]; + sun_path_len = 0; + } + + public SockaddrUn (int size) + : base (SockaddrType.SockaddrUn | SockaddrType.MustBeWrapped, UnixAddressFamily.AF_UNIX) + { + sun_path = new byte[size]; + sun_path_len = 0; + } + + public SockaddrUn (string path, bool linuxAbstractNamespace = false) + : base (SockaddrType.SockaddrUn | SockaddrType.MustBeWrapped, UnixAddressFamily.AF_UNIX) + { + if (path == null) + throw new ArgumentNullException ("path"); + var bytes = UnixEncoding.Instance.GetBytes (path); + if (linuxAbstractNamespace) { + sun_path = new byte[1 + bytes.Length]; + Array.Copy (bytes, 0, sun_path, 1, bytes.Length); + } else { + sun_path = bytes; + } + sun_path_len = sun_path.Length; + } + + public bool IsLinuxAbstractNamespace { + get { + return sun_path_len > 0 && sun_path[0] == 0; + } + } + + public string Path { + get { + var offset = IsLinuxAbstractNamespace ? 1 : 0; + // Remove data after null terminator + int length; + for (length = 0; offset + length < sun_path_len; length++) + if (sun_path[offset + length] == 0) + break; + return UnixEncoding.Instance.GetString (sun_path, offset, length); + } + } + + public override string ToString () + { + return string.Format ("{{sa_family={0}, sun_path=\"{1}{2}\"}}", sa_family, IsLinuxAbstractNamespace ? "\\0" : "", Path); + } + + public static new SockaddrUn FromSockaddrStorage (SockaddrStorage storage) + { + // This will make the SockaddrUn larger than it needs to be (because + // storage.data_len includes the sun_family field), but it will be + // large enough. + var ret = new SockaddrUn ((int) storage.data_len); + storage.CopyTo (ret); + return ret; + } + + public override int GetHashCode () + { + return sun_family.GetHashCode () ^ IsLinuxAbstractNamespace.GetHashCode () ^ Path.GetHashCode (); + } + + public override bool Equals (object obj) + { + if (!(obj is SockaddrUn)) + return false; + return Equals ((SockaddrUn) obj); + } + + public bool Equals (SockaddrUn value) + { + if (value == null) + return false; + return sun_family == value.sun_family + && IsLinuxAbstractNamespace == value.IsLinuxAbstractNamespace + && Path == value.Path; + } + } + + [Map ("struct sockaddr_in")] + [CLSCompliant (false)] + [StructLayout (LayoutKind.Sequential)] + public sealed class SockaddrIn : Sockaddr, IEquatable { + public UnixAddressFamily sin_family { // AF_INET + get { return sa_family; } + set { sa_family = value; } + } + public ushort sin_port; // Port number. + public InAddr sin_addr; // IP address. + + public SockaddrIn () + : base (SockaddrType.SockaddrIn, UnixAddressFamily.AF_INET) + { + } + + public override string ToString () + { + return string.Format ("{{sin_family={0}, sin_port=htons({1}), sin_addr={2}}}", sa_family, Syscall.ntohs(sin_port), sin_addr); + } + + public static new SockaddrIn FromSockaddrStorage (SockaddrStorage storage) + { + var ret = new SockaddrIn (); + storage.CopyTo (ret); + return ret; + } + + public override int GetHashCode () + { + return sin_family.GetHashCode () ^ sin_port.GetHashCode () ^ sin_addr.GetHashCode (); + } + + public override bool Equals (object obj) + { + if (!(obj is SockaddrIn)) + return false; + return Equals ((SockaddrIn) obj); + } + + public bool Equals (SockaddrIn value) + { + if (value == null) + return false; + return sin_family == value.sin_family + && sin_port == value.sin_port + && sin_addr.Equals (value.sin_addr); + } + } + + [Map ("struct sockaddr_in6")] + [CLSCompliant (false)] + [StructLayout (LayoutKind.Sequential)] + public sealed class SockaddrIn6 : Sockaddr, IEquatable { + public UnixAddressFamily sin6_family { // AF_INET6 + get { return sa_family; } + set { sa_family = value; } + } + public ushort sin6_port; // Port number. + public uint sin6_flowinfo; // IPv6 traffic class and flow information. + public In6Addr sin6_addr; // IPv6 address. + public uint sin6_scope_id; // Set of interfaces for a scope. + + public SockaddrIn6 () + : base (SockaddrType.SockaddrIn6, UnixAddressFamily.AF_INET6) + { + } + + public override string ToString () + { + return string.Format ("{{sin6_family={0}, sin6_port=htons({1}), sin6_flowinfo={2}, sin6_addr={3}, sin6_scope_id={4}}}", sa_family, Syscall.ntohs (sin6_port), sin6_flowinfo, sin6_addr, sin6_scope_id); + } + + public static new SockaddrIn6 FromSockaddrStorage (SockaddrStorage storage) + { + var ret = new SockaddrIn6 (); + storage.CopyTo (ret); + return ret; + } + + public override int GetHashCode () + { + return sin6_family.GetHashCode () ^ sin6_port.GetHashCode () ^ sin6_flowinfo.GetHashCode () ^ sin6_addr.GetHashCode () ^ sin6_scope_id.GetHashCode (); + } + + public override bool Equals (object obj) + { + if (!(obj is SockaddrIn6)) + return false; + return Equals ((SockaddrIn6) obj); + } + + public bool Equals (SockaddrIn6 value) + { + if (value == null) + return false; + return sin6_family == value.sin6_family + && sin6_port == value.sin6_port + && sin6_flowinfo == value.sin6_flowinfo + && sin6_addr.Equals (value.sin6_addr) + && sin6_scope_id == value.sin6_scope_id; + } + } + + [CLSCompliant (false)] + public sealed class Msghdr + { + public Sockaddr msg_name; + // msg_name_len is part of the Sockaddr structure + public Iovec[] msg_iov; + public int msg_iovlen; + public byte[] msg_control; + public long msg_controllen; + public MessageFlags msg_flags; + } + + // + // Convention: Functions *not* part of the standard C library AND part of + // a POSIX and/or Unix standard (X/Open, SUS, XPG, etc.) go here. + // + // For example, the man page should be similar to: + // + // CONFORMING TO (or CONFORMS TO) + // XPG2, SUSv2, POSIX, etc. + // + // BSD- and GNU-specific exports can also be placed here. + // + // Non-POSIX/XPG/etc. functions can also be placed here if: + // (a) They'd be likely to be covered in a Steven's-like book + // (b) The functions would be present in libc.so (or equivalent). + // + // If a function has its own library, that's a STRONG indicator that the + // function should get a different binding, probably in its own assembly, + // so that package management can work sanely. (That is, we'd like to avoid + // scenarios where FooLib.dll is installed, but it requires libFooLib.so to + // run, and libFooLib.so doesn't exist. That would be confusing.) + // + // The only methods in here should be: + // (1) low-level functions + // (2) "Trivial" function overloads. For example, if the parameters to a + // function are related (e.g. getgroups(2)) + // (3) The return type SHOULD NOT be changed. If you want to provide a + // convenience function with a nicer return type, place it into one of + // the Mono.Unix.Unix* wrapper classes, and give it a .NET-styled name. + // - EXCEPTION: No public functions should have a `void' return type. + // `void' return types should be replaced with `int'. + // Rationality: `void'-return functions typically require a + // complicated call sequence, such as clear errno, then call, then + // check errno to see if any errors occurred. This sequence can't + // be done safely in managed code, as errno may change as part of + // the P/Invoke mechanism. + // Instead, add a MonoPosixHelper export which does: + // errno = 0; + // INVOKE SYSCALL; + // return errno == 0 ? 0 : -1; + // This lets managed code check the return value in the usual manner. + // (4) Exceptions SHOULD NOT be thrown. EXCEPTIONS: + // - If you're wrapping *broken* methods which make assumptions about + // input data, such as that an argument refers to N bytes of data. + // This is currently limited to cuserid(3) and encrypt(3). + // - If you call functions which themselves generate exceptions. + // This is the case for using NativeConvert, which will throw an + // exception if an invalid/unsupported value is used. + // + // Naming Conventions: + // - Syscall method names should have the same name as the function being + // wrapped (e.g. Syscall.read ==> read(2)). This allows people to + // consult the appropriate man page if necessary. + // - Methods need not have the same arguments IF this simplifies or + // permits correct usage. The current example is syslog, in which + // syslog(3)'s single `priority' argument is split into SyslogFacility + // and SyslogLevel arguments. + // - Type names (structures, classes, enumerations) are always PascalCased. + // - Enumerations are named as , and are located + // in the Mono.Unix.Native namespace. For readability, if ArgumentName + // is "cmd", use Command instead. For example, fcntl(2) takes a + // FcntlCommand argument. This naming convention is to provide an + // assocation between an enumeration and where it should be used, and + // allows a single method to accept multiple different enumerations + // (see mmap(2), which takes MmapProts and MmapFlags). + // - EXCEPTION: if an enumeration is shared between multiple different + // methods, AND/OR the "obvious" enumeration name conflicts with an + // existing .NET type, a more appropriate name should be used. + // Example: FilePermissions + // - EXCEPTION: [Flags] enumerations should get plural names to follow + // .NET name guidelines. Usually this doesn't result in a change + // (OpenFlags is the `flags' parameter for open(2)), but it can + // (mmap(2) prot ==> MmapProts, access(2) mode ==> AccessModes). + // - Enumerations should have the [Map] and (optional) [Flags] attributes. + // [Map] is required for make-map to find the type and generate the + // appropriate NativeConvert conversion functions. + // - Enumeration contents should match the original Unix names. This helps + // with documentation (the existing man pages are still useful), and is + // required for use with the make-map generation program. + // - Structure names should be the PascalCased version of the actual + // structure name (struct flock ==> Flock). Structure members should + // have the same names, or a (reasonably) portable subset (Dirent being + // the poster child for questionable members). + // - Whether the managed type should be a reference type (class) or a + // value type (struct) should be determined on a case-by-case basis: + // if you ever need to be able to use NULL for it (such as with Dirent, + // Group, Passwd, as these are method return types and `null' is used + // to signify the end), it should be a reference type; otherwise, use + // your discretion, and keep any expected usage patterns in mind. + // - Syscall should be a Single Point Of Truth (SPOT). There should be + // only ONE way to do anything. By convention, the Linux function names + // are used, but that need not always be the case (use your discretion). + // It SHOULD NOT be required that developers know what platform they're + // on, and choose among a set of similar functions. In short, anything + // that requires a platform check is BAD -- Mono.Unix is a wrapper, and + // we can afford to clean things up whenever possible. + // - Examples: + // - Syscall.statfs: Solaris/Mac OS X provide statfs(2), Linux provides + // statvfs(2). MonoPosixHelper will "thunk" between the two, + // exporting a statvfs that works across platforms. + // - Syscall.getfsent: Glibc export which Solaris lacks, while Solaris + // instead provides getvfsent(3). MonoPosixHelper provides wrappers + // to convert getvfsent(3) into Fstab data. + // - Exception: If it isn't possible to cleanly wrap platforms, then the + // method shouldn't be exported. The user will be expected to do their + // own platform check and their own DllImports. + // Examples: mount(2), umount(2), etc. + // - Note: if a platform doesn't support a function AT ALL, the + // MonoPosixHelper wrapper won't be compiled, resulting in a + // EntryPointNotFoundException. This is also consistent with a missing + // P/Invoke into libc.so. + // + [CLSCompliant (false)] + public sealed class Syscall : Stdlib + { + new internal const string LIBC = "libc"; + + private Syscall () {} + + // + // + // + + // TODO: aio_cancel(3), aio_error(3), aio_fsync(3), aio_read(3), + // aio_return(3), aio_suspend(3), aio_write(3) + // + // Then update UnixStream.BeginRead to use the aio* functions. + + + #region Declarations + // + // -- COMPLETE + // + + // setxattr(2) + // int setxattr (const char *path, const char *name, + // const void *value, size_t size, int flags); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_setxattr")] + public static extern int setxattr ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string path, + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string name, byte[] value, ulong size, XattrFlags flags); + + public static int setxattr (string path, string name, byte [] value, ulong size) + { + return setxattr (path, name, value, size, XattrFlags.XATTR_AUTO); + } + + public static int setxattr (string path, string name, byte [] value, XattrFlags flags) + { + return setxattr (path, name, value, (ulong) value.Length, flags); + } + + public static int setxattr (string path, string name, byte [] value) + { + return setxattr (path, name, value, (ulong) value.Length); + } + + // lsetxattr(2) + // int lsetxattr (const char *path, const char *name, + // const void *value, size_t size, int flags); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_lsetxattr")] + public static extern int lsetxattr ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string path, + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string name, byte[] value, ulong size, XattrFlags flags); + + public static int lsetxattr (string path, string name, byte [] value, ulong size) + { + return lsetxattr (path, name, value, size, XattrFlags.XATTR_AUTO); + } + + public static int lsetxattr (string path, string name, byte [] value, XattrFlags flags) + { + return lsetxattr (path, name, value, (ulong) value.Length, flags); + } + + public static int lsetxattr (string path, string name, byte [] value) + { + return lsetxattr (path, name, value, (ulong) value.Length); + } + + // fsetxattr(2) + // int fsetxattr (int fd, const char *name, + // const void *value, size_t size, int flags); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_fsetxattr")] + public static extern int fsetxattr (int fd, + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string name, byte[] value, ulong size, XattrFlags flags); + + public static int fsetxattr (int fd, string name, byte [] value, ulong size) + { + return fsetxattr (fd, name, value, size, XattrFlags.XATTR_AUTO); + } + + public static int fsetxattr (int fd, string name, byte [] value, XattrFlags flags) + { + return fsetxattr (fd, name, value, (ulong) value.Length, flags); + } + + public static int fsetxattr (int fd, string name, byte [] value) + { + return fsetxattr (fd, name, value, (ulong) value.Length); + } + + // getxattr(2) + // ssize_t getxattr (const char *path, const char *name, + // void *value, size_t size); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_getxattr")] + public static extern long getxattr ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string path, + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string name, byte[] value, ulong size); + + public static long getxattr (string path, string name, byte [] value) + { + return getxattr (path, name, value, (ulong) value.Length); + } + + public static long getxattr (string path, string name, out byte [] value) + { + value = null; + long size = getxattr (path, name, value, 0); + if (size <= 0) + return size; + + value = new byte [size]; + return getxattr (path, name, value, (ulong) size); + } + + // lgetxattr(2) + // ssize_t lgetxattr (const char *path, const char *name, + // void *value, size_t size); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_lgetxattr")] + public static extern long lgetxattr ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string path, + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string name, byte[] value, ulong size); + + public static long lgetxattr (string path, string name, byte [] value) + { + return lgetxattr (path, name, value, (ulong) value.Length); + } + + public static long lgetxattr (string path, string name, out byte [] value) + { + value = null; + long size = lgetxattr (path, name, value, 0); + if (size <= 0) + return size; + + value = new byte [size]; + return lgetxattr (path, name, value, (ulong) size); + } + + // fgetxattr(2) + // ssize_t fgetxattr (int fd, const char *name, void *value, size_t size); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_fgetxattr")] + public static extern long fgetxattr (int fd, + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string name, byte[] value, ulong size); + + public static long fgetxattr (int fd, string name, byte [] value) + { + return fgetxattr (fd, name, value, (ulong) value.Length); + } + + public static long fgetxattr (int fd, string name, out byte [] value) + { + value = null; + long size = fgetxattr (fd, name, value, 0); + if (size <= 0) + return size; + + value = new byte [size]; + return fgetxattr (fd, name, value, (ulong) size); + } + + // listxattr(2) + // ssize_t listxattr (const char *path, char *list, size_t size); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_listxattr")] + public static extern long listxattr ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string path, byte[] list, ulong size); + + // Slight modification: returns 0 on success, negative on error + public static long listxattr (string path, Encoding encoding, out string [] values) + { + values = null; + long size = listxattr (path, null, 0); + if (size == 0) + values = new string [0]; + if (size <= 0) + return (int) size; + + byte[] list = new byte [size]; + long ret = listxattr (path, list, (ulong) size); + if (ret < 0) + return (int) ret; + + GetValues (list, encoding, out values); + return 0; + } + + public static long listxattr (string path, out string[] values) + { + return listxattr (path, UnixEncoding.Instance, out values); + } + + private static void GetValues (byte[] list, Encoding encoding, out string[] values) + { + int num_values = 0; + for (int i = 0; i < list.Length; ++i) + if (list [i] == 0) + ++num_values; + + values = new string [num_values]; + num_values = 0; + int str_start = 0; + for (int i = 0; i < list.Length; ++i) { + if (list [i] == 0) { + values [num_values++] = encoding.GetString (list, str_start, i - str_start); + str_start = i+1; + } + } + } + + // llistxattr(2) + // ssize_t llistxattr (const char *path, char *list, size_t size); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_llistxattr")] + public static extern long llistxattr ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string path, byte[] list, ulong size); + + // Slight modification: returns 0 on success, negative on error + public static long llistxattr (string path, Encoding encoding, out string [] values) + { + values = null; + long size = llistxattr (path, null, 0); + if (size == 0) + values = new string [0]; + if (size <= 0) + return (int) size; + + byte[] list = new byte [size]; + long ret = llistxattr (path, list, (ulong) size); + if (ret < 0) + return (int) ret; + + GetValues (list, encoding, out values); + return 0; + } + + public static long llistxattr (string path, out string[] values) + { + return llistxattr (path, UnixEncoding.Instance, out values); + } + + // flistxattr(2) + // ssize_t flistxattr (int fd, char *list, size_t size); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_flistxattr")] + public static extern long flistxattr (int fd, byte[] list, ulong size); + + // Slight modification: returns 0 on success, negative on error + public static long flistxattr (int fd, Encoding encoding, out string [] values) + { + values = null; + long size = flistxattr (fd, null, 0); + if (size == 0) + values = new string [0]; + if (size <= 0) + return (int) size; + + byte[] list = new byte [size]; + long ret = flistxattr (fd, list, (ulong) size); + if (ret < 0) + return (int) ret; + + GetValues (list, encoding, out values); + return 0; + } + + public static long flistxattr (int fd, out string[] values) + { + return flistxattr (fd, UnixEncoding.Instance, out values); + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_removexattr")] + public static extern int removexattr ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string path, + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string name); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_lremovexattr")] + public static extern int lremovexattr ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string path, + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string name); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_fremovexattr")] + public static extern int fremovexattr (int fd, + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string name); + #endregion + + #region Declarations + // + // + // + // TODO: scandir(3), alphasort(3), versionsort(3), getdirentries(3) + + [DllImport (LIBC, SetLastError=true)] + public static extern IntPtr opendir ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string name); + + [DllImport (LIBC, SetLastError=true)] + public static extern int closedir (IntPtr dir); + + // seekdir(3): + // void seekdir (DIR *dir, off_t offset); + // Slight modification. Returns -1 on error, 0 on success. + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_seekdir")] + public static extern int seekdir (IntPtr dir, long offset); + + // telldir(3) + // off_t telldir(DIR *dir); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_telldir")] + public static extern long telldir (IntPtr dir); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_rewinddir")] + public static extern int rewinddir (IntPtr dir); + + private struct _Dirent { + [ino_t] public ulong d_ino; + [off_t] public long d_off; + public ushort d_reclen; + public byte d_type; + public IntPtr d_name; + } + + private static void CopyDirent (Dirent to, ref _Dirent from) + { + try { + to.d_ino = from.d_ino; + to.d_off = from.d_off; + to.d_reclen = from.d_reclen; + to.d_type = from.d_type; + to.d_name = UnixMarshal.PtrToString (from.d_name); + } + finally { + Stdlib.free (from.d_name); + from.d_name = IntPtr.Zero; + } + } + + internal static object readdir_lock = new object (); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_readdir")] + private static extern int sys_readdir (IntPtr dir, out _Dirent dentry); + + public static Dirent readdir (IntPtr dir) + { + _Dirent dentry; + int r; + lock (readdir_lock) { + r = sys_readdir (dir, out dentry); + } + if (r != 0) + return null; + Dirent d = new Dirent (); + CopyDirent (d, ref dentry); + return d; + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_readdir_r")] + private static extern int sys_readdir_r (IntPtr dirp, out _Dirent entry, out IntPtr result); + + public static int readdir_r (IntPtr dirp, Dirent entry, out IntPtr result) + { + entry.d_ino = 0; + entry.d_off = 0; + entry.d_reclen = 0; + entry.d_type = 0; + entry.d_name = null; + + _Dirent _d; + int r = sys_readdir_r (dirp, out _d, out result); + + if (r == 0 && result != IntPtr.Zero) { + CopyDirent (entry, ref _d); + } + + return r; + } + + [DllImport (LIBC, SetLastError=true)] + public static extern int dirfd (IntPtr dir); + + [DllImport (LIBC, SetLastError=true)] + public static extern IntPtr fdopendir (int fd); + #endregion + + #region Declarations + // + // -- COMPLETE + // + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_fcntl")] + public static extern int fcntl (int fd, FcntlCommand cmd); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_fcntl_arg")] + public static extern int fcntl (int fd, FcntlCommand cmd, long arg); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_fcntl_arg_int")] + public static extern int fcntl (int fd, FcntlCommand cmd, int arg); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_fcntl_arg_ptr")] + public static extern int fcntl (int fd, FcntlCommand cmd, IntPtr ptr); + + public static int fcntl (int fd, FcntlCommand cmd, DirectoryNotifyFlags arg) + { + if (cmd != FcntlCommand.F_NOTIFY) { + SetLastError (Errno.EINVAL); + return -1; + } + long _arg = NativeConvert.FromDirectoryNotifyFlags (arg); + return fcntl (fd, FcntlCommand.F_NOTIFY, _arg); + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_fcntl_lock")] + public static extern int fcntl (int fd, FcntlCommand cmd, ref Flock @lock); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_open")] + public static extern int open ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string pathname, OpenFlags flags); + + // open(2) + // int open(const char *pathname, int flags, mode_t mode); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_open_mode")] + public static extern int open ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string pathname, OpenFlags flags, FilePermissions mode); + + // creat(2) + // int creat(const char *pathname, mode_t mode); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_creat")] + public static extern int creat ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string pathname, FilePermissions mode); + + // posix_fadvise(2) + // int posix_fadvise(int fd, off_t offset, off_t len, int advice); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_posix_fadvise")] + public static extern int posix_fadvise (int fd, long offset, + long len, PosixFadviseAdvice advice); + + // posix_fallocate(P) + // int posix_fallocate(int fd, off_t offset, size_t len); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_posix_fallocate")] + public static extern int posix_fallocate (int fd, long offset, ulong len); + + [DllImport (LIBC, SetLastError=true, + EntryPoint="openat")] + private static extern int sys_openat (int dirfd, + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string pathname, int flags); + + // openat(2) + // int openat(int dirfd, const char *pathname, int flags, mode_t mode); + [DllImport (LIBC, SetLastError=true, + EntryPoint="openat")] + private static extern int sys_openat (int dirfd, + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string pathname, int flags, uint mode); + + public static int openat (int dirfd, string pathname, OpenFlags flags) + { + int _flags = NativeConvert.FromOpenFlags (flags); + return sys_openat (dirfd, pathname, _flags); + } + + public static int openat (int dirfd, string pathname, OpenFlags flags, FilePermissions mode) + { + int _flags = NativeConvert.FromOpenFlags (flags); + uint _mode = NativeConvert.FromFilePermissions (mode); + return sys_openat (dirfd, pathname, _flags, _mode); + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_get_at_fdcwd")] + private static extern int get_at_fdcwd (); + + public static readonly int AT_FDCWD = get_at_fdcwd (); + + #endregion + + #region Declarations + // + // -- COMPLETE + // + [Map] + private struct _Fstab { + public IntPtr fs_spec; + public IntPtr fs_file; + public IntPtr fs_vfstype; + public IntPtr fs_mntops; + public IntPtr fs_type; + public int fs_freq; + public int fs_passno; + public IntPtr _fs_buf_; + } + + private static void CopyFstab (Fstab to, ref _Fstab from) + { + try { + to.fs_spec = UnixMarshal.PtrToString (from.fs_spec); + to.fs_file = UnixMarshal.PtrToString (from.fs_file); + to.fs_vfstype = UnixMarshal.PtrToString (from.fs_vfstype); + to.fs_mntops = UnixMarshal.PtrToString (from.fs_mntops); + to.fs_type = UnixMarshal.PtrToString (from.fs_type); + to.fs_freq = from.fs_freq; + to.fs_passno = from.fs_passno; + } + finally { + Stdlib.free (from._fs_buf_); + from._fs_buf_ = IntPtr.Zero; + } + } + + internal static object fstab_lock = new object (); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_endfsent")] + private static extern int sys_endfsent (); + + public static int endfsent () + { + lock (fstab_lock) { + return sys_endfsent (); + } + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_getfsent")] + private static extern int sys_getfsent (out _Fstab fs); + + public static Fstab getfsent () + { + _Fstab fsbuf; + int r; + lock (fstab_lock) { + r = sys_getfsent (out fsbuf); + } + if (r != 0) + return null; + Fstab fs = new Fstab (); + CopyFstab (fs, ref fsbuf); + return fs; + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_getfsfile")] + private static extern int sys_getfsfile ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string mount_point, out _Fstab fs); + + public static Fstab getfsfile (string mount_point) + { + _Fstab fsbuf; + int r; + lock (fstab_lock) { + r = sys_getfsfile (mount_point, out fsbuf); + } + if (r != 0) + return null; + Fstab fs = new Fstab (); + CopyFstab (fs, ref fsbuf); + return fs; + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_getfsspec")] + private static extern int sys_getfsspec ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string special_file, out _Fstab fs); + + public static Fstab getfsspec (string special_file) + { + _Fstab fsbuf; + int r; + lock (fstab_lock) { + r = sys_getfsspec (special_file, out fsbuf); + } + if (r != 0) + return null; + Fstab fs = new Fstab (); + CopyFstab (fs, ref fsbuf); + return fs; + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_setfsent")] + private static extern int sys_setfsent (); + + public static int setfsent () + { + lock (fstab_lock) { + return sys_setfsent (); + } + } + + #endregion + + #region Declarations + // + // + // + // TODO: putgrent(3), fgetgrent_r(), initgroups(3) + + // getgrouplist(2) + [DllImport (LIBC, SetLastError=true, EntryPoint="getgrouplist")] + private static extern int sys_getgrouplist (string user, uint grp, uint [] groups,ref int ngroups); + + public static Group [] getgrouplist (string username) + { + if (username == null) + throw new ArgumentNullException ("username"); + if (username.Trim () == "") + throw new ArgumentException ("Username cannot be empty", "username"); + // Syscall to getpwnam to retrieve user uid + Passwd pw = Syscall.getpwnam (username); + if (pw == null) + throw new ArgumentException (string.Format ("User {0} does not exist", username), "username"); + return getgrouplist (pw); + } + + public static Group [] getgrouplist (Passwd user) + { + if (user == null) + throw new ArgumentNullException ("user"); + // initializing ngroups by 16 to get the group count + int ngroups = 8; + int res = -1; + // allocating buffer to store group uid's + uint [] groups=null; + do { + Array.Resize (ref groups, ngroups*=2); + res = sys_getgrouplist (user.pw_name, user.pw_gid, groups, ref ngroups); + } + while (res == -1); + List result = new List (); + Group gr = null; + for (int i = 0; i < res; i++) { + gr = Syscall.getgrgid (groups [i]); + if (gr != null) + result.Add (gr); + } + return result.ToArray (); + } + + // setgroups(2) + // int setgroups (size_t size, const gid_t *list); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_setgroups")] + public static extern int setgroups (ulong size, uint[] list); + + public static int setgroups (uint [] list) + { + return setgroups ((ulong) list.Length, list); + } + + [Map] + private struct _Group + { + public IntPtr gr_name; + public IntPtr gr_passwd; + [gid_t] public uint gr_gid; + public int _gr_nmem_; + public IntPtr gr_mem; + public IntPtr _gr_buf_; + } + + private static void CopyGroup (Group to, ref _Group from) + { + try { + to.gr_gid = from.gr_gid; + to.gr_name = UnixMarshal.PtrToString (from.gr_name); + to.gr_passwd = UnixMarshal.PtrToString (from.gr_passwd); + to.gr_mem = UnixMarshal.PtrToStringArray (from._gr_nmem_, from.gr_mem); + } + finally { + Stdlib.free (from.gr_mem); + Stdlib.free (from._gr_buf_); + from.gr_mem = IntPtr.Zero; + from._gr_buf_ = IntPtr.Zero; + } + } + + internal static object grp_lock = new object (); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_getgrnam")] + private static extern int sys_getgrnam (string name, out _Group group); + + public static Group getgrnam (string name) + { + _Group group; + int r; + lock (grp_lock) { + r = sys_getgrnam (name, out group); + } + if (r != 0) + return null; + Group gr = new Group (); + CopyGroup (gr, ref group); + return gr; + } + + // getgrgid(3) + // struct group *getgrgid(gid_t gid); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_getgrgid")] + private static extern int sys_getgrgid (uint uid, out _Group group); + + public static Group getgrgid (uint uid) + { + _Group group; + int r; + lock (grp_lock) { + r = sys_getgrgid (uid, out group); + } + if (r != 0) + return null; + Group gr = new Group (); + CopyGroup (gr, ref group); + return gr; + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_getgrnam_r")] + private static extern int sys_getgrnam_r ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string name, out _Group grbuf, out IntPtr grbufp); + + public static int getgrnam_r (string name, Group grbuf, out Group grbufp) + { + grbufp = null; + _Group group; + IntPtr _grbufp; + int r = sys_getgrnam_r (name, out group, out _grbufp); + if (r == 0 && _grbufp != IntPtr.Zero) { + CopyGroup (grbuf, ref group); + grbufp = grbuf; + } + return r; + } + + // getgrgid_r(3) + // int getgrgid_r(gid_t gid, struct group *gbuf, char *buf, + // size_t buflen, struct group **gbufp); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_getgrgid_r")] + private static extern int sys_getgrgid_r (uint uid, out _Group grbuf, out IntPtr grbufp); + + public static int getgrgid_r (uint uid, Group grbuf, out Group grbufp) + { + grbufp = null; + _Group group; + IntPtr _grbufp; + int r = sys_getgrgid_r (uid, out group, out _grbufp); + if (r == 0 && _grbufp != IntPtr.Zero) { + CopyGroup (grbuf, ref group); + grbufp = grbuf; + } + return r; + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_getgrent")] + private static extern int sys_getgrent (out _Group grbuf); + + public static Group getgrent () + { + _Group group; + int r; + lock (grp_lock) { + r = sys_getgrent (out group); + } + if (r != 0) + return null; + Group gr = new Group(); + CopyGroup (gr, ref group); + return gr; + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_setgrent")] + private static extern int sys_setgrent (); + + public static int setgrent () + { + lock (grp_lock) { + return sys_setgrent (); + } + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_endgrent")] + private static extern int sys_endgrent (); + + public static int endgrent () + { + lock (grp_lock) { + return sys_endgrent (); + } + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_fgetgrent")] + private static extern int sys_fgetgrent (IntPtr stream, out _Group grbuf); + + public static Group fgetgrent (IntPtr stream) + { + _Group group; + int r; + lock (grp_lock) { + r = sys_fgetgrent (stream, out group); + } + if (r != 0) + return null; + Group gr = new Group (); + CopyGroup (gr, ref group); + return gr; + } + #endregion + + #region Declarations + // + // + // + // TODO: putpwent(3), fgetpwent_r() + // + // SKIPPING: getpw(3): it's dangerous. Use getpwuid(3) instead. + + [Map] + private struct _Passwd + { + public IntPtr pw_name; + public IntPtr pw_passwd; + [uid_t] public uint pw_uid; + [gid_t] public uint pw_gid; + public IntPtr pw_gecos; + public IntPtr pw_dir; + public IntPtr pw_shell; + public IntPtr _pw_buf_; + } + + private static void CopyPasswd (Passwd to, ref _Passwd from) + { + try { + to.pw_name = UnixMarshal.PtrToString (from.pw_name); + to.pw_passwd = UnixMarshal.PtrToString (from.pw_passwd); + to.pw_uid = from.pw_uid; + to.pw_gid = from.pw_gid; + to.pw_gecos = UnixMarshal.PtrToString (from.pw_gecos); + to.pw_dir = UnixMarshal.PtrToString (from.pw_dir); + to.pw_shell = UnixMarshal.PtrToString (from.pw_shell); + } + finally { + Stdlib.free (from._pw_buf_); + from._pw_buf_ = IntPtr.Zero; + } + } + + internal static object pwd_lock = new object (); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_getpwnam")] + private static extern int sys_getpwnam (string name, out _Passwd passwd); + + public static Passwd getpwnam (string name) + { + _Passwd passwd; + int r; + lock (pwd_lock) { + r = sys_getpwnam (name, out passwd); + } + if (r != 0) + return null; + Passwd pw = new Passwd (); + CopyPasswd (pw, ref passwd); + return pw; + } + + // getpwuid(3) + // struct passwd *getpwnuid(uid_t uid); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_getpwuid")] + private static extern int sys_getpwuid (uint uid, out _Passwd passwd); + + public static Passwd getpwuid (uint uid) + { + _Passwd passwd; + int r; + lock (pwd_lock) { + r = sys_getpwuid (uid, out passwd); + } + if (r != 0) + return null; + Passwd pw = new Passwd (); + CopyPasswd (pw, ref passwd); + return pw; + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_getpwnam_r")] + private static extern int sys_getpwnam_r ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string name, out _Passwd pwbuf, out IntPtr pwbufp); + + public static int getpwnam_r (string name, Passwd pwbuf, out Passwd pwbufp) + { + pwbufp = null; + _Passwd passwd; + IntPtr _pwbufp; + int r = sys_getpwnam_r (name, out passwd, out _pwbufp); + if (r == 0 && _pwbufp != IntPtr.Zero) { + CopyPasswd (pwbuf, ref passwd); + pwbufp = pwbuf; + } + return r; + } + + // getpwuid_r(3) + // int getpwuid_r(uid_t uid, struct passwd *pwbuf, char *buf, size_t + // buflen, struct passwd **pwbufp); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_getpwuid_r")] + private static extern int sys_getpwuid_r (uint uid, out _Passwd pwbuf, out IntPtr pwbufp); + + public static int getpwuid_r (uint uid, Passwd pwbuf, out Passwd pwbufp) + { + pwbufp = null; + _Passwd passwd; + IntPtr _pwbufp; + int r = sys_getpwuid_r (uid, out passwd, out _pwbufp); + if (r == 0 && _pwbufp != IntPtr.Zero) { + CopyPasswd (pwbuf, ref passwd); + pwbufp = pwbuf; + } + return r; + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_getpwent")] + private static extern int sys_getpwent (out _Passwd pwbuf); + + public static Passwd getpwent () + { + _Passwd passwd; + int r; + lock (pwd_lock) { + r = sys_getpwent (out passwd); + } + if (r != 0) + return null; + Passwd pw = new Passwd (); + CopyPasswd (pw, ref passwd); + return pw; + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_setpwent")] + private static extern int sys_setpwent (); + + public static int setpwent () + { + lock (pwd_lock) { + return sys_setpwent (); + } + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_endpwent")] + private static extern int sys_endpwent (); + + public static int endpwent () + { + lock (pwd_lock) { + return sys_endpwent (); + } + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_fgetpwent")] + private static extern int sys_fgetpwent (IntPtr stream, out _Passwd pwbuf); + + public static Passwd fgetpwent (IntPtr stream) + { + _Passwd passwd; + int r; + lock (pwd_lock) { + r = sys_fgetpwent (stream, out passwd); + } + if (r != 0) + return null; + Passwd pw = new Passwd (); + CopyPasswd (pw, ref passwd); + return pw; + } + #endregion + + #region Declarations + // + // + // + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_psignal")] + private static extern int psignal (int sig, string s); + + public static int psignal (Signum sig, string s) + { + int signum = NativeConvert.FromSignum (sig); + return psignal (signum, s); + } + + // kill(2) + // int kill(pid_t pid, int sig); + [DllImport (LIBC, SetLastError=true, EntryPoint="kill")] + private static extern int sys_kill (int pid, int sig); + + public static int kill (int pid, Signum sig) + { + int _sig = NativeConvert.FromSignum (sig); + return sys_kill (pid, _sig); + } + + private static object signal_lock = new object (); + + [DllImport (LIBC, SetLastError=true, EntryPoint="strsignal")] + private static extern IntPtr sys_strsignal (int sig); + + public static string strsignal (Signum sig) + { + int s = NativeConvert.FromSignum (sig); + lock (signal_lock) { + IntPtr r = sys_strsignal (s); + return UnixMarshal.PtrToString (r); + } + } + + // TODO: sigaction(2) + // TODO: sigsuspend(2) + // TODO: sigpending(2) + + #endregion + + #region Declarations + // + // + // + [DllImport (MPH, EntryPoint="Mono_Posix_Syscall_L_ctermid")] + private static extern int _L_ctermid (); + + public static readonly int L_ctermid = _L_ctermid (); + + [DllImport (MPH, EntryPoint="Mono_Posix_Syscall_L_cuserid")] + private static extern int _L_cuserid (); + + public static readonly int L_cuserid = _L_cuserid (); + + internal static object getlogin_lock = new object (); + + [DllImport (LIBC, SetLastError=true, EntryPoint="cuserid")] + private static extern IntPtr sys_cuserid ([Out] StringBuilder @string); + + [Obsolete ("\"Nobody knows precisely what cuserid() does... " + + "DO NOT USE cuserid().\n" + + "`string' must hold L_cuserid characters. Use getlogin_r instead.")] + public static string cuserid (StringBuilder @string) + { + if (@string.Capacity < L_cuserid) { + throw new ArgumentOutOfRangeException ("string", "string.Capacity < L_cuserid"); + } + lock (getlogin_lock) { + IntPtr r = sys_cuserid (@string); + return UnixMarshal.PtrToString (r); + } + } + + [DllImport (LIBC, SetLastError=true)] + public static extern int renameat (int olddirfd, + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string oldpath, int newdirfd, + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string newpath); + #endregion + + #region Declarations + // + // + // + [DllImport (LIBC, SetLastError=true)] + public static extern int mkstemp (StringBuilder template); + + [DllImport (LIBC, SetLastError=true, EntryPoint="mkdtemp")] + private static extern IntPtr sys_mkdtemp (StringBuilder template); + + public static StringBuilder mkdtemp (StringBuilder template) + { + if (sys_mkdtemp (template) == IntPtr.Zero) + return null; + return template; + } + + [DllImport (LIBC, SetLastError=true)] + public static extern int ttyslot (); + + [Obsolete ("This is insecure and should not be used", true)] + public static int setkey (string key) + { + throw new SecurityException ("crypt(3) has been broken. Use something more secure."); + } + + #endregion + + #region Declarations + // + // + // + + // strerror_r(3) + // int strerror_r(int errnum, char *buf, size_t n); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_strerror_r")] + private static extern int sys_strerror_r (int errnum, + [Out] StringBuilder buf, ulong n); + + public static int strerror_r (Errno errnum, StringBuilder buf, ulong n) + { + int e = NativeConvert.FromErrno (errnum); + return sys_strerror_r (e, buf, n); + } + + public static int strerror_r (Errno errnum, StringBuilder buf) + { + return strerror_r (errnum, buf, (ulong) buf.Capacity); + } + + #endregion + + #region Declarations + + public static int epoll_create (int size) + { + return sys_epoll_create (size); + } + + public static int epoll_create (EpollFlags flags) + { + return sys_epoll_create1 (flags); + } + + public static int epoll_ctl (int epfd, EpollOp op, int fd, EpollEvents events) + { + EpollEvent ee = new EpollEvent (); + ee.events = events; + ee.fd = fd; + + return epoll_ctl (epfd, op, fd, ref ee); + } + + public static int epoll_wait (int epfd, EpollEvent [] events, int max_events, int timeout) + { + if (events.Length < max_events) + throw new ArgumentOutOfRangeException ("events", "Must refer to at least 'max_events' elements."); + + return sys_epoll_wait (epfd, events, max_events, timeout); + } + + [DllImport (LIBC, SetLastError=true, EntryPoint="epoll_create")] + private static extern int sys_epoll_create (int size); + + [DllImport (LIBC, SetLastError=true, EntryPoint="epoll_create1")] + private static extern int sys_epoll_create1 (EpollFlags flags); + + [DllImport (LIBC, SetLastError=true, EntryPoint="epoll_ctl")] + public static extern int epoll_ctl (int epfd, EpollOp op, int fd, ref EpollEvent ee); + + [DllImport (LIBC, SetLastError=true, EntryPoint="epoll_wait")] + private static extern int sys_epoll_wait (int epfd, [In,Out] EpollEvent [] ee, int maxevents, int timeout); + #endregion + + #region Declarations + // + // + // + + // posix_madvise(P) + // int posix_madvise(void *addr, size_t len, int advice); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_posix_madvise")] + public static extern int posix_madvise (IntPtr addr, ulong len, + PosixMadviseAdvice advice); + + public static readonly IntPtr MAP_FAILED = unchecked((IntPtr)(-1)); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_mmap")] + public static extern IntPtr mmap (IntPtr start, ulong length, + MmapProts prot, MmapFlags flags, int fd, long offset); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_munmap")] + public static extern int munmap (IntPtr start, ulong length); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_mprotect")] + public static extern int mprotect (IntPtr start, ulong len, MmapProts prot); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_msync")] + public static extern int msync (IntPtr start, ulong len, MsyncFlags flags); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_mlock")] + public static extern int mlock (IntPtr start, ulong len); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_munlock")] + public static extern int munlock (IntPtr start, ulong len); + + [DllImport (LIBC, SetLastError=true, EntryPoint="mlockall")] + private static extern int sys_mlockall (int flags); + + public static int mlockall (MlockallFlags flags) + { + int _flags = NativeConvert.FromMlockallFlags (flags); + return sys_mlockall (_flags); + } + + [DllImport (LIBC, SetLastError=true)] + public static extern int munlockall (); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_mremap")] + public static extern IntPtr mremap (IntPtr old_address, ulong old_size, + ulong new_size, MremapFlags flags); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_mincore")] + public static extern int mincore (IntPtr start, ulong length, byte[] vec); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_remap_file_pages")] + public static extern int remap_file_pages (IntPtr start, ulong size, + MmapProts prot, long pgoff, MmapFlags flags); + + #endregion + + #region Declarations + // + // -- COMPLETE + // +#pragma warning disable 649 + private struct _pollfd { + public int fd; + public short events; + public short revents; + } +#pragma warning restore 649 + + [DllImport (LIBC, SetLastError=true, EntryPoint="poll")] + private static extern int sys_poll ([In,Out] _pollfd[] ufds, uint nfds, int timeout); + + public static int poll (Pollfd [] fds, uint nfds, int timeout) + { + if (fds.Length < nfds) + throw new ArgumentOutOfRangeException ("fds", "Must refer to at least `nfds' elements"); + + _pollfd[] send = new _pollfd[nfds]; + + for (int i = 0; i < send.Length; i++) { + send [i].fd = fds [i].fd; + send [i].events = NativeConvert.FromPollEvents (fds [i].events); + } + + int r = sys_poll (send, nfds, timeout); + + for (int i = 0; i < send.Length; i++) { + fds [i].revents = NativeConvert.ToPollEvents (send [i].revents); + } + + return r; + } + + public static int poll (Pollfd [] fds, int timeout) + { + return poll (fds, (uint) fds.Length, timeout); + } + + // + // + // + + // TODO: ptrace(2) + + // + // + // + + // TODO: setrlimit(2) + // TODO: getrlimit(2) + // TODO: getrusage(2) + + #endregion + + #region Declarations + // + // -- COMPLETE + // + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_sendfile")] + public static extern long sendfile (int out_fd, int in_fd, + ref long offset, ulong count); + + #endregion + + #region Declarations + // + // -- COMPLETE + // + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_stat")] + public static extern int stat ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string file_name, out Stat buf); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_fstat")] + public static extern int fstat (int filedes, out Stat buf); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_lstat")] + public static extern int lstat ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string file_name, out Stat buf); + + // TODO: + // S_ISDIR, S_ISCHR, S_ISBLK, S_ISREG, S_ISFIFO, S_ISLNK, S_ISSOCK + // All take FilePermissions + + // chmod(2) + // int chmod(const char *path, mode_t mode); + [DllImport (LIBC, SetLastError=true, EntryPoint="chmod")] + private static extern int sys_chmod ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string path, uint mode); + + public static int chmod (string path, FilePermissions mode) + { + uint _mode = NativeConvert.FromFilePermissions (mode); + return sys_chmod (path, _mode); + } + + // fchmod(2) + // int chmod(int filedes, mode_t mode); + [DllImport (LIBC, SetLastError=true, EntryPoint="fchmod")] + private static extern int sys_fchmod (int filedes, uint mode); + + public static int fchmod (int filedes, FilePermissions mode) + { + uint _mode = NativeConvert.FromFilePermissions (mode); + return sys_fchmod (filedes, _mode); + } + + // umask(2) + // mode_t umask(mode_t mask); + [DllImport (LIBC, SetLastError=true, EntryPoint="umask")] + private static extern uint sys_umask (uint mask); + + public static FilePermissions umask (FilePermissions mask) + { + uint _mask = NativeConvert.FromFilePermissions (mask); + uint r = sys_umask (_mask); + return NativeConvert.ToFilePermissions (r); + } + + // mkdir(2) + // int mkdir(const char *pathname, mode_t mode); + [DllImport (LIBC, SetLastError=true, EntryPoint="mkdir")] + private static extern int sys_mkdir ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string oldpath, uint mode); + + public static int mkdir (string oldpath, FilePermissions mode) + { + uint _mode = NativeConvert.FromFilePermissions (mode); + return sys_mkdir (oldpath, _mode); + } + + // mknod(2) + // int mknod (const char *pathname, mode_t mode, dev_t dev); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_mknod")] + public static extern int mknod ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string pathname, FilePermissions mode, ulong dev); + + // mkfifo(3) + // int mkfifo(const char *pathname, mode_t mode); + [DllImport (LIBC, SetLastError=true, EntryPoint="mkfifo")] + private static extern int sys_mkfifo ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string pathname, uint mode); + + public static int mkfifo (string pathname, FilePermissions mode) + { + uint _mode = NativeConvert.FromFilePermissions (mode); + return sys_mkfifo (pathname, _mode); + } + + // fchmodat(2) + // int fchmodat(int dirfd, const char *pathname, mode_t mode, int flags); + [DllImport (LIBC, SetLastError=true, EntryPoint="fchmodat")] + private static extern int sys_fchmodat (int dirfd, + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string pathname, uint mode, int flags); + + public static int fchmodat (int dirfd, string pathname, FilePermissions mode, AtFlags flags) + { + uint _mode = NativeConvert.FromFilePermissions (mode); + int _flags = NativeConvert.FromAtFlags (flags); + return sys_fchmodat (dirfd, pathname, _mode, _flags); + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_fstatat")] + public static extern int fstatat (int dirfd, + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string file_name, out Stat buf, AtFlags flags); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_get_utime_now")] + private static extern long get_utime_now (); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_get_utime_omit")] + private static extern long get_utime_omit (); + + public static readonly long UTIME_NOW = get_utime_now (); + + public static readonly long UTIME_OMIT = get_utime_omit (); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_futimens")] + private static extern int sys_futimens (int fd, Timespec[] times); + + public static int futimens (int fd, Timespec[] times) + { + if (times != null && times.Length != 2) { + SetLastError (Errno.EINVAL); + return -1; + } + return sys_futimens (fd, times); + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_utimensat")] + private static extern int sys_utimensat (int dirfd, + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string pathname, Timespec[] times, int flags); + + public static int utimensat (int dirfd, string pathname, Timespec[] times, AtFlags flags) + { + if (times != null && times.Length != 2) { + SetLastError (Errno.EINVAL); + return -1; + } + int _flags = NativeConvert.FromAtFlags (flags); + return sys_utimensat (dirfd, pathname, times, _flags); + } + + // mkdirat(2) + // int mkdirat(int dirfd, const char *pathname, mode_t mode); + [DllImport (LIBC, SetLastError=true, EntryPoint="mkdirat")] + private static extern int sys_mkdirat (int dirfd, + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string oldpath, uint mode); + + public static int mkdirat (int dirfd, string oldpath, FilePermissions mode) + { + uint _mode = NativeConvert.FromFilePermissions (mode); + return sys_mkdirat (dirfd, oldpath, _mode); + } + + // mknodat(2) + // int mknodat (int dirfd, const char *pathname, mode_t mode, dev_t dev); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_mknodat")] + public static extern int mknodat (int dirfd, + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string pathname, FilePermissions mode, ulong dev); + + // mkfifoat(3) + // int mkfifoat(int dirfd, const char *pathname, mode_t mode); + [DllImport (LIBC, SetLastError=true, EntryPoint="mkfifoat")] + private static extern int sys_mkfifoat (int dirfd, + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string pathname, uint mode); + + public static int mkfifoat (int dirfd, string pathname, FilePermissions mode) + { + uint _mode = NativeConvert.FromFilePermissions (mode); + return sys_mkfifoat (dirfd, pathname, _mode); + } + #endregion + + #region Declarations + // + // + // + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_statvfs")] + public static extern int statvfs ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string path, out Statvfs buf); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_fstatvfs")] + public static extern int fstatvfs (int fd, out Statvfs buf); + + #endregion + + #region Declarations + // + // + // + // TODO: adjtime(), getitimer(2), setitimer(2) + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_gettimeofday")] + public static extern int gettimeofday (out Timeval tv, out Timezone tz); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_gettimeofday")] + private static extern int gettimeofday (out Timeval tv, IntPtr ignore); + + public static int gettimeofday (out Timeval tv) + { + return gettimeofday (out tv, IntPtr.Zero); + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_gettimeofday")] + private static extern int gettimeofday (IntPtr ignore, out Timezone tz); + + public static int gettimeofday (out Timezone tz) + { + return gettimeofday (IntPtr.Zero, out tz); + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_settimeofday")] + public static extern int settimeofday (ref Timeval tv, ref Timezone tz); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_gettimeofday")] + private static extern int settimeofday (ref Timeval tv, IntPtr ignore); + + public static int settimeofday (ref Timeval tv) + { + return settimeofday (ref tv, IntPtr.Zero); + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_utimes")] + private static extern int sys_utimes ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string filename, Timeval[] tvp); + + public static int utimes (string filename, Timeval[] tvp) + { + if (tvp != null && tvp.Length != 2) { + SetLastError (Errno.EINVAL); + return -1; + } + return sys_utimes (filename, tvp); + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_lutimes")] + private static extern int sys_lutimes ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string filename, Timeval[] tvp); + + public static int lutimes (string filename, Timeval[] tvp) + { + if (tvp != null && tvp.Length != 2) { + SetLastError (Errno.EINVAL); + return -1; + } + return sys_lutimes (filename, tvp); + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_futimes")] + private static extern int sys_futimes (int fd, Timeval[] tvp); + + public static int futimes (int fd, Timeval[] tvp) + { + if (tvp != null && tvp.Length != 2) { + SetLastError (Errno.EINVAL); + return -1; + } + return sys_futimes (fd, tvp); + } + + #endregion + + // + // + // + + // TODO: ftime(3) + + // + // + // + + // TODO: times(2) + + // + // + // + + [Map] + private struct _Utsname + { + public IntPtr sysname; + public IntPtr nodename; + public IntPtr release; + public IntPtr version; + public IntPtr machine; + public IntPtr domainname; + public IntPtr _buf_; + } + + private static void CopyUtsname (ref Utsname to, ref _Utsname from) + { + try { + to = new Utsname (); + to.sysname = UnixMarshal.PtrToString (from.sysname); + to.nodename = UnixMarshal.PtrToString (from.nodename); + to.release = UnixMarshal.PtrToString (from.release); + to.version = UnixMarshal.PtrToString (from.version); + to.machine = UnixMarshal.PtrToString (from.machine); + to.domainname = UnixMarshal.PtrToString (from.domainname); + } + finally { + Stdlib.free (from._buf_); + from._buf_ = IntPtr.Zero; + } + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_uname")] + private static extern int sys_uname (out _Utsname buf); + + public static int uname (out Utsname buf) + { + _Utsname _buf; + int r = sys_uname (out _buf); + buf = new Utsname (); + if (r == 0) { + CopyUtsname (ref buf, ref _buf); + } + return r; + } + + #region Declarations + // + // + // + + // wait(2) + // pid_t wait(int *status); + [DllImport (LIBC, SetLastError=true)] + public static extern int wait (out int status); + + // waitpid(2) + // pid_t waitpid(pid_t pid, int *status, int options); + [DllImport (LIBC, SetLastError=true)] + private static extern int waitpid (int pid, out int status, int options); + + public static int waitpid (int pid, out int status, WaitOptions options) + { + int _options = NativeConvert.FromWaitOptions (options); + return waitpid (pid, out status, _options); + } + + [DllImport (MPH, EntryPoint="Mono_Posix_Syscall_WIFEXITED")] + private static extern int _WIFEXITED (int status); + + public static bool WIFEXITED (int status) + { + return _WIFEXITED (status) != 0; + } + + [DllImport (MPH, EntryPoint="Mono_Posix_Syscall_WEXITSTATUS")] + public static extern int WEXITSTATUS (int status); + + [DllImport (MPH, EntryPoint="Mono_Posix_Syscall_WIFSIGNALED")] + private static extern int _WIFSIGNALED (int status); + + public static bool WIFSIGNALED (int status) + { + return _WIFSIGNALED (status) != 0; + } + + [DllImport (MPH, EntryPoint="Mono_Posix_Syscall_WTERMSIG")] + private static extern int _WTERMSIG (int status); + + public static Signum WTERMSIG (int status) + { + int r = _WTERMSIG (status); + return NativeConvert.ToSignum (r); + } + + [DllImport (MPH, EntryPoint="Mono_Posix_Syscall_WIFSTOPPED")] + private static extern int _WIFSTOPPED (int status); + + public static bool WIFSTOPPED (int status) + { + return _WIFSTOPPED (status) != 0; + } + + [DllImport (MPH, EntryPoint="Mono_Posix_Syscall_WSTOPSIG")] + private static extern int _WSTOPSIG (int status); + + public static Signum WSTOPSIG (int status) + { + int r = _WSTOPSIG (status); + return NativeConvert.ToSignum (r); + } + + // + // + // + + #endregion + + #region Declarations + // + // + // + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_openlog")] + private static extern int sys_openlog (IntPtr ident, int option, int facility); + + public static int openlog (IntPtr ident, SyslogOptions option, + SyslogFacility defaultFacility) + { + int _option = NativeConvert.FromSyslogOptions (option); + int _facility = NativeConvert.FromSyslogFacility (defaultFacility); + + return sys_openlog (ident, _option, _facility); + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_syslog")] + private static extern int sys_syslog (int priority, string message); + + public static int syslog (SyslogFacility facility, SyslogLevel level, string message) + { + int _facility = NativeConvert.FromSyslogFacility (facility); + int _level = NativeConvert.FromSyslogLevel (level); + return sys_syslog (_facility | _level, GetSyslogMessage (message)); + } + + public static int syslog (SyslogLevel level, string message) + { + int _level = NativeConvert.FromSyslogLevel (level); + return sys_syslog (_level, GetSyslogMessage (message)); + } + + private static string GetSyslogMessage (string message) + { + return UnixMarshal.EscapeFormatString (message, new char[]{'m'}); + } + +#if !NETSTANDARD2_0 + [Obsolete ("Not necessarily portable due to cdecl restrictions.\n" + + "Use syslog(SyslogFacility, SyslogLevel, string) instead.")] + public static int syslog (SyslogFacility facility, SyslogLevel level, + string format, params object[] parameters) + { + int _facility = NativeConvert.FromSyslogFacility (facility); + int _level = NativeConvert.FromSyslogLevel (level); + + object[] _parameters = new object[checked(parameters.Length+2)]; + _parameters [0] = _facility | _level; + _parameters [1] = format; + Array.Copy (parameters, 0, _parameters, 2, parameters.Length); + return (int) XPrintfFunctions.syslog (_parameters); + } + + [Obsolete ("Not necessarily portable due to cdecl restrictions.\n" + + "Use syslog(SyslogLevel, string) instead.")] + public static int syslog (SyslogLevel level, string format, + params object[] parameters) + { + int _level = NativeConvert.FromSyslogLevel (level); + + object[] _parameters = new object[checked(parameters.Length+2)]; + _parameters [0] = _level; + _parameters [1] = format; + Array.Copy (parameters, 0, _parameters, 2, parameters.Length); + return (int) XPrintfFunctions.syslog (_parameters); + } +#endif + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_closelog")] + public static extern int closelog (); + + [DllImport (LIBC, SetLastError=true, EntryPoint="setlogmask")] + private static extern int sys_setlogmask (int mask); + + public static int setlogmask (SyslogLevel mask) + { + int _mask = NativeConvert.FromSyslogLevel (mask); + return sys_setlogmask (_mask); + } + + #endregion + + #region Declarations + + // + // + // + + // nanosleep(2) + // int nanosleep(const struct timespec *req, struct timespec *rem); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_nanosleep")] + public static extern int nanosleep (ref Timespec req, ref Timespec rem); + + // stime(2) + // int stime(time_t *t); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_stime")] + public static extern int stime (ref long t); + + // time(2) + // time_t time(time_t *t); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_time")] + public static extern long time (out long t); + + // + // + // + + // TODO: ulimit(3) + + #endregion + + #region Declarations + // + // + // + // TODO: euidaccess(), usleep(3), get_current_dir_name(), group_member(), + // other TODOs listed below. + + [DllImport (LIBC, SetLastError=true, EntryPoint="access")] + private static extern int sys_access ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string pathname, int mode); + + public static int access (string pathname, AccessModes mode) + { + int _mode = NativeConvert.FromAccessModes (mode); + return sys_access (pathname, _mode); + } + + // lseek(2) + // off_t lseek(int filedes, off_t offset, int whence); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_lseek")] + private static extern long sys_lseek (int fd, long offset, int whence); + + public static long lseek (int fd, long offset, SeekFlags whence) + { + short _whence = NativeConvert.FromSeekFlags (whence); + return sys_lseek (fd, offset, _whence); + } + + [DllImport (LIBC, SetLastError=true)] + public static extern int close (int fd); + + // read(2) + // ssize_t read(int fd, void *buf, size_t count); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_read")] + public static extern long read (int fd, IntPtr buf, ulong count); + + public static unsafe long read (int fd, void *buf, ulong count) + { + return read (fd, (IntPtr) buf, count); + } + + // write(2) + // ssize_t write(int fd, const void *buf, size_t count); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_write")] + public static extern long write (int fd, IntPtr buf, ulong count); + + public static unsafe long write (int fd, void *buf, ulong count) + { + return write (fd, (IntPtr) buf, count); + } + + // pread(2) + // ssize_t pread(int fd, void *buf, size_t count, off_t offset); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_pread")] + public static extern long pread (int fd, IntPtr buf, ulong count, long offset); + + public static unsafe long pread (int fd, void *buf, ulong count, long offset) + { + return pread (fd, (IntPtr) buf, count, offset); + } + + // pwrite(2) + // ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_pwrite")] + public static extern long pwrite (int fd, IntPtr buf, ulong count, long offset); + + public static unsafe long pwrite (int fd, void *buf, ulong count, long offset) + { + return pwrite (fd, (IntPtr) buf, count, offset); + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_pipe")] + public static extern int pipe (out int reading, out int writing); + + public static int pipe (int[] filedes) + { + if (filedes == null || filedes.Length != 2) { + // TODO: set errno + return -1; + } + int reading, writing; + int r = pipe (out reading, out writing); + filedes[0] = reading; + filedes[1] = writing; + return r; + } + + [DllImport (LIBC, SetLastError=true)] + public static extern uint alarm (uint seconds); + + [DllImport (LIBC, SetLastError=true)] + public static extern uint sleep (uint seconds); + + [DllImport (LIBC, SetLastError=true)] + public static extern uint ualarm (uint usecs, uint interval); + + [DllImport (LIBC, SetLastError=true)] + public static extern int pause (); + + // chown(2) + // int chown(const char *path, uid_t owner, gid_t group); + [DllImport (LIBC, SetLastError=true)] + public static extern int chown ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string path, uint owner, uint group); + + // fchown(2) + // int fchown(int fd, uid_t owner, gid_t group); + [DllImport (LIBC, SetLastError=true)] + public static extern int fchown (int fd, uint owner, uint group); + + // lchown(2) + // int lchown(const char *path, uid_t owner, gid_t group); + [DllImport (LIBC, SetLastError=true)] + public static extern int lchown ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string path, uint owner, uint group); + + [DllImport (LIBC, SetLastError=true)] + public static extern int chdir ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string path); + + [DllImport (LIBC, SetLastError=true)] + public static extern int fchdir (int fd); + + // getcwd(3) + // char *getcwd(char *buf, size_t size); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_getcwd")] + public static extern IntPtr getcwd ([Out] StringBuilder buf, ulong size); + + public static StringBuilder getcwd (StringBuilder buf) + { + getcwd (buf, (ulong) buf.Capacity); + return buf; + } + + // getwd(2) is deprecated; don't expose it. + + [DllImport (LIBC, SetLastError=true)] + public static extern int dup (int fd); + + [DllImport (LIBC, SetLastError=true)] + public static extern int dup2 (int fd, int fd2); + + // TODO: does Mono marshal arrays properly? + [DllImport (LIBC, SetLastError=true)] + public static extern int execve ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string path, string[] argv, string[] envp); + + [DllImport (LIBC, SetLastError=true)] + public static extern int fexecve (int fd, string[] argv, string[] envp); + + [DllImport (LIBC, SetLastError=true)] + public static extern int execv ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string path, string[] argv); + + // TODO: execle, execl, execlp + [DllImport (LIBC, SetLastError=true)] + public static extern int execvp ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string path, string[] argv); + + [DllImport (LIBC, SetLastError=true)] + public static extern int nice (int inc); + + [DllImport (LIBC, SetLastError=true)] + [CLSCompliant (false)] + public static extern int _exit (int status); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_fpathconf")] + public static extern long fpathconf (int filedes, PathconfName name, Errno defaultError); + + public static long fpathconf (int filedes, PathconfName name) + { + return fpathconf (filedes, name, (Errno) 0); + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_pathconf")] + public static extern long pathconf ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string path, PathconfName name, Errno defaultError); + + public static long pathconf (string path, PathconfName name) + { + return pathconf (path, name, (Errno) 0); + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_sysconf")] + public static extern long sysconf (SysconfName name, Errno defaultError); + + public static long sysconf (SysconfName name) + { + return sysconf (name, (Errno) 0); + } + + // confstr(3) + // size_t confstr(int name, char *buf, size_t len); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_confstr")] + public static extern ulong confstr (ConfstrName name, [Out] StringBuilder buf, ulong len); + + // getpid(2) + // pid_t getpid(void); + [DllImport (LIBC, SetLastError=true)] + public static extern int getpid (); + + // getppid(2) + // pid_t getppid(void); + [DllImport (LIBC, SetLastError=true)] + public static extern int getppid (); + + // setpgid(2) + // int setpgid(pid_t pid, pid_t pgid); + [DllImport (LIBC, SetLastError=true)] + public static extern int setpgid (int pid, int pgid); + + // getpgid(2) + // pid_t getpgid(pid_t pid); + [DllImport (LIBC, SetLastError=true)] + public static extern int getpgid (int pid); + + [DllImport (LIBC, SetLastError=true)] + public static extern int setpgrp (); + + // getpgrp(2) + // pid_t getpgrp(void); + [DllImport (LIBC, SetLastError=true)] + public static extern int getpgrp (); + + // setsid(2) + // pid_t setsid(void); + [DllImport (LIBC, SetLastError=true)] + public static extern int setsid (); + + // getsid(2) + // pid_t getsid(pid_t pid); + [DllImport (LIBC, SetLastError=true)] + public static extern int getsid (int pid); + + // getuid(2) + // uid_t getuid(void); + [DllImport (LIBC, SetLastError=true)] + public static extern uint getuid (); + + // geteuid(2) + // uid_t geteuid(void); + [DllImport (LIBC, SetLastError=true)] + public static extern uint geteuid (); + + // getgid(2) + // gid_t getgid(void); + [DllImport (LIBC, SetLastError=true)] + public static extern uint getgid (); + + // getegid(2) + // gid_t getgid(void); + [DllImport (LIBC, SetLastError=true)] + public static extern uint getegid (); + + // getgroups(2) + // int getgroups(int size, gid_t list[]); + [DllImport (LIBC, SetLastError=true)] + public static extern int getgroups (int size, uint[] list); + + public static int getgroups (uint[] list) + { + return getgroups (list.Length, list); + } + + // setuid(2) + // int setuid(uid_t uid); + [DllImport (LIBC, SetLastError=true)] + public static extern int setuid (uint uid); + + // setreuid(2) + // int setreuid(uid_t ruid, uid_t euid); + [DllImport (LIBC, SetLastError=true)] + public static extern int setreuid (uint ruid, uint euid); + + // setregid(2) + // int setregid(gid_t ruid, gid_t euid); + [DllImport (LIBC, SetLastError=true)] + public static extern int setregid (uint rgid, uint egid); + + // seteuid(2) + // int seteuid(uid_t euid); + [DllImport (LIBC, SetLastError=true)] + public static extern int seteuid (uint euid); + + // setegid(2) + // int setegid(gid_t euid); + [DllImport (LIBC, SetLastError=true)] + public static extern int setegid (uint uid); + + // setgid(2) + // int setgid(gid_t gid); + [DllImport (LIBC, SetLastError=true)] + public static extern int setgid (uint gid); + + // getresuid(2) + // int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); + [DllImport (LIBC, SetLastError=true)] + public static extern int getresuid (out uint ruid, out uint euid, out uint suid); + + // getresgid(2) + // int getresgid(gid_t *ruid, gid_t *euid, gid_t *suid); + [DllImport (LIBC, SetLastError=true)] + public static extern int getresgid (out uint rgid, out uint egid, out uint sgid); + + // setresuid(2) + // int setresuid(uid_t ruid, uid_t euid, uid_t suid); + [DllImport (LIBC, SetLastError=true)] + public static extern int setresuid (uint ruid, uint euid, uint suid); + + // setresgid(2) + // int setresgid(gid_t ruid, gid_t euid, gid_t suid); + [DllImport (LIBC, SetLastError=true)] + public static extern int setresgid (uint rgid, uint egid, uint sgid); + +#if false + // fork(2) + // pid_t fork(void); + [DllImport (LIBC, SetLastError=true)] + [Obsolete ("DO NOT directly call fork(2); it bypasses essential " + + "shutdown code.\nUse System.Diagnostics.Process instead")] + private static extern int fork (); + + // vfork(2) + // pid_t vfork(void); + [DllImport (LIBC, SetLastError=true)] + [Obsolete ("DO NOT directly call vfork(2); it bypasses essential " + + "shutdown code.\nUse System.Diagnostics.Process instead")] + private static extern int vfork (); +#endif + + private static object tty_lock = new object (); + + [DllImport (LIBC, SetLastError=true, EntryPoint="ttyname")] + private static extern IntPtr sys_ttyname (int fd); + + public static string ttyname (int fd) + { + lock (tty_lock) { + IntPtr r = sys_ttyname (fd); + return UnixMarshal.PtrToString (r); + } + } + + // ttyname_r(3) + // int ttyname_r(int fd, char *buf, size_t buflen); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_ttyname_r")] + public static extern int ttyname_r (int fd, [Out] StringBuilder buf, ulong buflen); + + public static int ttyname_r (int fd, StringBuilder buf) + { + return ttyname_r (fd, buf, (ulong) buf.Capacity); + } + + [DllImport (LIBC, EntryPoint="isatty")] + private static extern int sys_isatty (int fd); + + public static bool isatty (int fd) + { + return sys_isatty (fd) == 1; + } + + [DllImport (LIBC, SetLastError=true)] + public static extern int link ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string oldpath, + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string newpath); + + [DllImport (LIBC, SetLastError=true)] + public static extern int symlink ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string oldpath, + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string newpath); + + delegate long DoReadlinkFun (byte[] target); + + // Helper function for readlink(string, StringBuilder) and readlinkat (int, string, StringBuilder) + static int ReadlinkIntoStringBuilder (DoReadlinkFun doReadlink, [Out] StringBuilder buf, ulong bufsiz) + { + // bufsiz > int.MaxValue can't work because StringBuilder can store only int.MaxValue chars + int bufsizInt = checked ((int) bufsiz); + var target = new byte [bufsizInt]; + + var r = doReadlink (target); + if (r < 0) + return checked ((int) r); + + buf.Length = 0; + var chars = UnixEncoding.Instance.GetChars (target, 0, checked ((int) r)); + // Make sure that at more bufsiz chars are written + buf.Append (chars, 0, System.Math.Min (bufsizInt, chars.Length)); + if (r == bufsizInt) { + // may not have read full contents; fill 'buf' so that caller can properly check + buf.Append (new string ('\x00', bufsizInt - buf.Length)); + } + return buf.Length; + } + + // readlink(2) + // ssize_t readlink(const char *path, char *buf, size_t bufsize); + public static int readlink (string path, [Out] StringBuilder buf, ulong bufsiz) + { + return ReadlinkIntoStringBuilder (target => readlink (path, target), buf, bufsiz); + } + + public static int readlink (string path, [Out] StringBuilder buf) + { + return readlink (path, buf, (ulong) buf.Capacity); + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_readlink")] + private static extern long readlink ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string path, byte[] buf, ulong bufsiz); + + public static long readlink (string path, byte[] buf) + { + return readlink (path, buf, (ulong) buf.LongLength); + } + + [DllImport (LIBC, SetLastError=true)] + public static extern int unlink ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string pathname); + + [DllImport (LIBC, SetLastError=true)] + public static extern int rmdir ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string pathname); + + // tcgetpgrp(3) + // pid_t tcgetpgrp(int fd); + [DllImport (LIBC, SetLastError=true)] + public static extern int tcgetpgrp (int fd); + + // tcsetpgrp(3) + // int tcsetpgrp(int fd, pid_t pgrp); + [DllImport (LIBC, SetLastError=true)] + public static extern int tcsetpgrp (int fd, int pgrp); + + [DllImport (LIBC, SetLastError=true, EntryPoint="getlogin")] + private static extern IntPtr sys_getlogin (); + + public static string getlogin () + { + lock (getlogin_lock) { + IntPtr r = sys_getlogin (); + return UnixMarshal.PtrToString (r); + } + } + + // getlogin_r(3) + // int getlogin_r(char *buf, size_t bufsize); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_getlogin_r")] + public static extern int getlogin_r ([Out] StringBuilder name, ulong bufsize); + + public static int getlogin_r (StringBuilder name) + { + return getlogin_r (name, (ulong) name.Capacity); + } + + [DllImport (LIBC, SetLastError=true)] + public static extern int setlogin (string name); + + // gethostname(2) + // int gethostname(char *name, size_t len); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_gethostname")] + public static extern int gethostname ([Out] StringBuilder name, ulong len); + + public static int gethostname (StringBuilder name) + { + return gethostname (name, (ulong) name.Capacity); + } + + // sethostname(2) + // int gethostname(const char *name, size_t len); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_sethostname")] + public static extern int sethostname (string name, ulong len); + + public static int sethostname (string name) + { + return sethostname (name, (ulong) name.Length); + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_gethostid")] + public static extern long gethostid (); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_sethostid")] + public static extern int sethostid (long hostid); + + // getdomainname(2) + // int getdomainname(char *name, size_t len); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_getdomainname")] + public static extern int getdomainname ([Out] StringBuilder name, ulong len); + + public static int getdomainname (StringBuilder name) + { + return getdomainname (name, (ulong) name.Capacity); + } + + // setdomainname(2) + // int setdomainname(const char *name, size_t len); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_setdomainname")] + public static extern int setdomainname (string name, ulong len); + + public static int setdomainname (string name) + { + return setdomainname (name, (ulong) name.Length); + } + + [DllImport (LIBC, SetLastError=true)] + public static extern int vhangup (); + + // Revoke doesn't appear to be POSIX. Include it? + [DllImport (LIBC, SetLastError=true)] + public static extern int revoke ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string file); + + // TODO: profil? It's not POSIX. + + [DllImport (LIBC, SetLastError=true)] + public static extern int acct ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string filename); + + [DllImport (LIBC, SetLastError=true, EntryPoint="getusershell")] + private static extern IntPtr sys_getusershell (); + + internal static object usershell_lock = new object (); + + public static string getusershell () + { + lock (usershell_lock) { + IntPtr r = sys_getusershell (); + return UnixMarshal.PtrToString (r); + } + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_setusershell")] + private static extern int sys_setusershell (); + + public static int setusershell () + { + lock (usershell_lock) { + return sys_setusershell (); + } + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_endusershell")] + private static extern int sys_endusershell (); + + public static int endusershell () + { + lock (usershell_lock) { + return sys_endusershell (); + } + } + +#if false + [DllImport (LIBC, SetLastError=true)] + private static extern int daemon (int nochdir, int noclose); + + // this implicitly forks, and thus isn't safe. + private static int daemon (bool nochdir, bool noclose) + { + return daemon (nochdir ? 1 : 0, noclose ? 1 : 0); + } +#endif + + [DllImport (LIBC, SetLastError=true)] + public static extern int chroot ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string path); + + // skipping getpass(3) as the man page states: + // This function is obsolete. Do not use it. + + [DllImport (LIBC, SetLastError=true)] + public static extern int fsync (int fd); + + [DllImport (LIBC, SetLastError=true)] + public static extern int fdatasync (int fd); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_sync")] + public static extern int sync (); + + [DllImport (LIBC, SetLastError=true)] + [Obsolete ("Dropped in POSIX 1003.1-2001. " + + "Use Syscall.sysconf (SysconfName._SC_PAGESIZE).")] + public static extern int getpagesize (); + + // truncate(2) + // int truncate(const char *path, off_t length); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_truncate")] + public static extern int truncate ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string path, long length); + + // ftruncate(2) + // int ftruncate(int fd, off_t length); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_ftruncate")] + public static extern int ftruncate (int fd, long length); + + [DllImport (LIBC, SetLastError=true)] + public static extern int getdtablesize (); + + [DllImport (LIBC, SetLastError=true)] + public static extern int brk (IntPtr end_data_segment); + + [DllImport (LIBC, SetLastError=true)] + public static extern IntPtr sbrk (IntPtr increment); + + // TODO: syscall(2)? + // Probably safer to skip entirely. + + // lockf(3) + // int lockf(int fd, int cmd, off_t len); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_lockf")] + public static extern int lockf (int fd, LockfCommand cmd, long len); + + [Obsolete ("This is insecure and should not be used", true)] + public static string crypt (string key, string salt) + { + throw new SecurityException ("crypt(3) has been broken. Use something more secure."); + } + + [Obsolete ("This is insecure and should not be used", true)] + public static int encrypt (byte[] block, bool decode) + { + throw new SecurityException ("crypt(3) has been broken. Use something more secure."); + } + + // swab(3) + // void swab(const void *from, void *to, ssize_t n); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_swab")] + public static extern int swab (IntPtr from, IntPtr to, long n); + + public static unsafe void swab (void* from, void* to, long n) + { + swab ((IntPtr) from, (IntPtr) to, n); + } + + [DllImport (LIBC, SetLastError=true, EntryPoint="faccessat")] + private static extern int sys_faccessat (int dirfd, + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string pathname, int mode, int flags); + + public static int faccessat (int dirfd, string pathname, AccessModes mode, AtFlags flags) + { + int _mode = NativeConvert.FromAccessModes (mode); + int _flags = NativeConvert.FromAtFlags (flags); + return sys_faccessat (dirfd, pathname, _mode, _flags); + } + + // fchownat(2) + // int fchownat(int dirfd, const char *path, uid_t owner, gid_t group, int flags); + [DllImport (LIBC, SetLastError=true, EntryPoint="fchownat")] + private static extern int sys_fchownat (int dirfd, + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string pathname, uint owner, uint group, int flags); + + public static int fchownat (int dirfd, string pathname, uint owner, uint group, AtFlags flags) + { + int _flags = NativeConvert.FromAtFlags (flags); + return sys_fchownat (dirfd, pathname, owner, group, _flags); + } + + [DllImport (LIBC, SetLastError=true, EntryPoint="linkat")] + private static extern int sys_linkat (int olddirfd, + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string oldpath, int newdirfd, + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string newpath, int flags); + + public static int linkat (int olddirfd, string oldpath, int newdirfd, string newpath, AtFlags flags) + { + int _flags = NativeConvert.FromAtFlags (flags); + return sys_linkat (olddirfd, oldpath, newdirfd, newpath, _flags); + } + + // readlinkat(2) + // ssize_t readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsize); + public static int readlinkat (int dirfd, string pathname, [Out] StringBuilder buf, ulong bufsiz) + { + return ReadlinkIntoStringBuilder (target => readlinkat (dirfd, pathname, target), buf, bufsiz); + } + + public static int readlinkat (int dirfd, string pathname, [Out] StringBuilder buf) + { + return readlinkat (dirfd, pathname, buf, (ulong) buf.Capacity); + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_readlinkat")] + private static extern long readlinkat (int dirfd, + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string pathname, byte[] buf, ulong bufsiz); + + public static long readlinkat (int dirfd, string pathname, byte[] buf) + { + return readlinkat (dirfd, pathname, buf, (ulong) buf.LongLength); + } + + [DllImport (LIBC, SetLastError=true)] + public static extern int symlinkat ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string oldpath, int dirfd, + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string newpath); + + [DllImport (LIBC, SetLastError=true, EntryPoint="unlinkat")] + private static extern int sys_unlinkat (int dirfd, + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string pathname, int flags); + + public static int unlinkat (int dirfd, string pathname, AtFlags flags) + { + int _flags = NativeConvert.FromAtFlags (flags); + return sys_unlinkat (dirfd, pathname, _flags); + } + #endregion + + #region Declarations + // + // -- COMPLETE + // + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_utime")] + private static extern int sys_utime ( + [MarshalAs (UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(FileNameMarshaler))] + string filename, ref Utimbuf buf, int use_buf); + + public static int utime (string filename, ref Utimbuf buf) + { + return sys_utime (filename, ref buf, 1); + } + + public static int utime (string filename) + { + Utimbuf buf = new Utimbuf (); + return sys_utime (filename, ref buf, 0); + } + #endregion + + #region Declarations + // + // -- COMPLETE + // + + // readv(2) + // ssize_t readv(int fd, const struct iovec *iov, int iovcnt); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_readv")] + private static extern long sys_readv (int fd, Iovec[] iov, int iovcnt); + + public static long readv (int fd, Iovec[] iov) + { + return sys_readv (fd, iov, iov.Length); + } + + // writev(2) + // ssize_t writev(int fd, const struct iovec *iov, int iovcnt); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_writev")] + private static extern long sys_writev (int fd, Iovec[] iov, int iovcnt); + + public static long writev (int fd, Iovec[] iov) + { + return sys_writev (fd, iov, iov.Length); + } + + // preadv(2) + // ssize_t preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_preadv")] + private static extern long sys_preadv (int fd, Iovec[] iov, int iovcnt, long offset); + + public static long preadv (int fd, Iovec[] iov, long offset) + { + return sys_preadv (fd, iov, iov.Length, offset); + } + + // pwritev(2) + // ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_pwritev")] + private static extern long sys_pwritev (int fd, Iovec[] iov, int iovcnt, long offset); + + public static long pwritev (int fd, Iovec[] iov, long offset) + { + return sys_pwritev (fd, iov, iov.Length, offset); + } + #endregion + + #region Declarations + // + // + // + + // htonl(3) + // uint32_t htonl(uint32_t hostlong); + [DllImport (LIBC)] + public static extern uint htonl(uint hostlong); + + // htons(3) + // uint16_t htons(uint16_t hostshort); + [DllImport (LIBC)] + public static extern ushort htons(ushort hostshort); + + // ntohl(3) + // uint32_t ntohl(uint32_t netlong); + [DllImport (LIBC)] + public static extern uint ntohl(uint netlong); + + // ntohs(3) + // uint16_t ntohs(uint16_t netshort); + [DllImport (LIBC)] + public static extern ushort ntohs(ushort netshort); + + #endregion + + #region Declarations + // + // -- COMPLETE + // + + // socket(2) + // int socket(int domain, int type, int protocol); + [DllImport (LIBC, SetLastError=true, + EntryPoint="socket")] + static extern int sys_socket (int domain, int type, int protocol); + + public static int socket (UnixAddressFamily domain, UnixSocketType type, UnixSocketFlags flags, UnixSocketProtocol protocol) + { + var _domain = NativeConvert.FromUnixAddressFamily (domain); + var _type = NativeConvert.FromUnixSocketType (type); + var _flags = NativeConvert.FromUnixSocketFlags (flags); + // protocol == 0 is a special case (uses default protocol) + var _protocol = protocol == 0 ? 0 : NativeConvert.FromUnixSocketProtocol (protocol); + + return sys_socket (_domain, _type | _flags, _protocol); + } + + public static int socket (UnixAddressFamily domain, UnixSocketType type, UnixSocketProtocol protocol) + { + return socket (domain, type, 0, protocol); + } + + // socketpair(2) + // int socketpair(int domain, int type, int protocol, int sv[2]); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_socketpair")] + static extern int sys_socketpair (int domain, int type, int protocol, out int socket1, out int socket2); + + public static int socketpair (UnixAddressFamily domain, UnixSocketType type, UnixSocketFlags flags, UnixSocketProtocol protocol, out int socket1, out int socket2) + { + var _domain = NativeConvert.FromUnixAddressFamily (domain); + var _type = NativeConvert.FromUnixSocketType (type); + var _flags = NativeConvert.FromUnixSocketFlags (flags); + // protocol == 0 is a special case (uses default protocol) + var _protocol = protocol == 0 ? 0 : NativeConvert.FromUnixSocketProtocol (protocol); + + return sys_socketpair (_domain, _type | _flags, _protocol, out socket1, out socket2); + } + + public static int socketpair (UnixAddressFamily domain, UnixSocketType type, UnixSocketProtocol protocol, out int socket1, out int socket2) + { + return socketpair (domain, type, 0, protocol, out socket1, out socket2); + } + + // sockatmark(2) + // int sockatmark(int sockfd); + [DllImport (LIBC, SetLastError=true)] + public static extern int sockatmark (int socket); + + // listen(2) + // int listen(int sockfd, int backlog); + [DllImport (LIBC, SetLastError=true)] + public static extern int listen (int socket, int backlog); + + // getsockopt(2) + // int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_getsockopt")] + static extern unsafe int sys_getsockopt (int socket, int level, int option_name, void *option_value, ref long option_len); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_getsockopt_timeval")] + static extern unsafe int sys_getsockopt_timeval (int socket, int level, int option_name, out Timeval option_value); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_getsockopt_linger")] + static extern unsafe int sys_getsockopt_linger (int socket, int level, int option_name, out Linger option_value); + + public static unsafe int getsockopt (int socket, UnixSocketProtocol level, UnixSocketOptionName option_name, void *option_value, ref long option_len) + { + var _level = NativeConvert.FromUnixSocketProtocol (level); + var _option_name = NativeConvert.FromUnixSocketOptionName (option_name); + return sys_getsockopt (socket, _level, _option_name, option_value, ref option_len); + } + + public static unsafe int getsockopt (int socket, UnixSocketProtocol level, UnixSocketOptionName option_name, IntPtr option_value, ref long option_len) + { + return getsockopt (socket, level, option_name, (void*) option_value, ref option_len); + } + + public static unsafe int getsockopt (int socket, UnixSocketProtocol level, UnixSocketOptionName option_name, out int option_value) + { + int value; + long size = sizeof (int); + int ret = getsockopt (socket, level, option_name, &value, ref size); + if (ret != -1 && size != sizeof (int)) { + SetLastError (Errno.EINVAL); + ret = -1; + } + option_value = value; + return ret; + } + + public static unsafe int getsockopt (int socket, UnixSocketProtocol level, UnixSocketOptionName option_name, byte[] option_value, ref long option_len) + { + if (option_len > (option_value == null ? 0 : option_value.Length)) + throw new ArgumentOutOfRangeException ("option_len", "option_len > (option_value == null ? 0 : option_value.Length)"); + fixed (byte* ptr = option_value) + return getsockopt (socket, level, option_name, ptr, ref option_len); + } + + public static unsafe int getsockopt (int socket, UnixSocketProtocol level, UnixSocketOptionName option_name, out Timeval option_value) + { + var _level = NativeConvert.FromUnixSocketProtocol (level); + var _option_name = NativeConvert.FromUnixSocketOptionName (option_name); + return sys_getsockopt_timeval (socket, _level, _option_name, out option_value); + } + + public static unsafe int getsockopt (int socket, UnixSocketProtocol level, UnixSocketOptionName option_name, out Linger option_value) + { + var _level = NativeConvert.FromUnixSocketProtocol (level); + var _option_name = NativeConvert.FromUnixSocketOptionName (option_name); + return sys_getsockopt_linger (socket, _level, _option_name, out option_value); + } + + // setsockopt(2) + // int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_setsockopt")] + static extern unsafe int sys_setsockopt (int socket, int level, int option_name, void *option_value, long option_len); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_setsockopt_timeval")] + static extern unsafe int sys_setsockopt_timeval (int socket, int level, int option_name, ref Timeval option_value); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_setsockopt_linger")] + static extern unsafe int sys_setsockopt_linger (int socket, int level, int option_name, ref Linger option_value); + + public static unsafe int setsockopt (int socket, UnixSocketProtocol level, UnixSocketOptionName option_name, void *option_value, long option_len) + { + var _level = NativeConvert.FromUnixSocketProtocol (level); + var _option_name = NativeConvert.FromUnixSocketOptionName (option_name); + return sys_setsockopt (socket, _level, _option_name, option_value, option_len); + } + + public static unsafe int setsockopt (int socket, UnixSocketProtocol level, UnixSocketOptionName option_name, IntPtr option_value, long option_len) + { + return setsockopt (socket, level, option_name, (void*) option_value, option_len); + } + + public static unsafe int setsockopt (int socket, UnixSocketProtocol level, UnixSocketOptionName option_name, int option_value) + { + return setsockopt (socket, level, option_name, &option_value, sizeof (int)); + } + + public static unsafe int setsockopt (int socket, UnixSocketProtocol level, UnixSocketOptionName option_name, byte[] option_value, long option_len) + { + if (option_len > (option_value == null ? 0 : option_value.Length)) + throw new ArgumentOutOfRangeException ("option_len", "option_len > (option_value == null ? 0 : option_value.Length)"); + fixed (byte* ptr = option_value) + return setsockopt (socket, level, option_name, ptr, option_len); + } + + public static unsafe int setsockopt (int socket, UnixSocketProtocol level, UnixSocketOptionName option_name, Timeval option_value) + { + var _level = NativeConvert.FromUnixSocketProtocol (level); + var _option_name = NativeConvert.FromUnixSocketOptionName (option_name); + return sys_setsockopt_timeval (socket, _level, _option_name, ref option_value); + } + + public static unsafe int setsockopt (int socket, UnixSocketProtocol level, UnixSocketOptionName option_name, Linger option_value) + { + var _level = NativeConvert.FromUnixSocketProtocol (level); + var _option_name = NativeConvert.FromUnixSocketOptionName (option_name); + return sys_setsockopt_linger (socket, _level, _option_name, ref option_value); + } + + // shutdown(2) + // int shutdown(int sockfd, int how); + [DllImport (LIBC, SetLastError=true, + EntryPoint="shutdown")] + static extern int sys_shutdown (int socket, int how); + + public static int shutdown (int socket, ShutdownOption how) + { + var _how = NativeConvert.FromShutdownOption (how); + return sys_shutdown (socket, _how); + } + + // recv(2) + // ssize_t recv(int sockfd, void *buf, size_t len, int flags); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_recv")] + static extern unsafe long sys_recv (int socket, void *buffer, ulong length, int flags); + + public static unsafe long recv (int socket, void *buffer, ulong length, MessageFlags flags) + { + int _flags = NativeConvert.FromMessageFlags (flags); + return sys_recv (socket, buffer, length, _flags); + } + + public static unsafe long recv (int socket, IntPtr buffer, ulong length, MessageFlags flags) + { + return recv (socket, (void*) buffer, length, flags); + } + + public static unsafe long recv (int socket, byte[] buffer, ulong length, MessageFlags flags) + { + if (length > (ulong) (buffer == null ? 0 : buffer.LongLength)) + throw new ArgumentOutOfRangeException ("length", "length > (buffer == null ? 0 : buffer.LongLength)"); + fixed (byte* ptr = buffer) + return recv (socket, ptr, length, flags); + } + + // send(2) + // ssize_t send(int sockfd, const void *buf, size_t len, int flags); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_send")] + static extern unsafe long sys_send (int socket, void *message, ulong length, int flags); + + public static unsafe long send (int socket, void *message, ulong length, MessageFlags flags) + { + int _flags = NativeConvert.FromMessageFlags (flags); + return sys_send (socket, message, length, _flags); + } + + public static unsafe long send (int socket, IntPtr message, ulong length, MessageFlags flags) + { + return send (socket, (void*) message, length, flags); + } + + public static unsafe long send (int socket, byte[] message, ulong length, MessageFlags flags) + { + if (length > (ulong) (message == null ? 0 : message.LongLength)) + throw new ArgumentOutOfRangeException ("length", "length > (message == null ? 0 : message.LongLength)"); + fixed (byte* ptr = message) + return send (socket, ptr, length, flags); + } + + // bind(2) + // int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_bind")] + static extern unsafe int sys_bind (int socket, _SockaddrHeader* address); + + public static unsafe int bind (int socket, Sockaddr address) + { + fixed (SockaddrType* addr = &Sockaddr.GetAddress (address).type) + fixed (byte* data = Sockaddr.GetDynamicData (address)) { + var dyn = new _SockaddrDynamic (address, data, useMaxLength: false); + return sys_bind (socket, Sockaddr.GetNative (&dyn, addr)); + } + } + + // connect(2) + // int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_connect")] + static extern unsafe int sys_connect (int socket, _SockaddrHeader* address); + + public static unsafe int connect (int socket, Sockaddr address) + { + fixed (SockaddrType* addr = &Sockaddr.GetAddress (address).type) + fixed (byte* data = Sockaddr.GetDynamicData (address)) { + var dyn = new _SockaddrDynamic (address, data, useMaxLength: false); + return sys_connect (socket, Sockaddr.GetNative (&dyn, addr)); + } + } + + // accept(2) + // int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_accept")] + static extern unsafe int sys_accept (int socket, _SockaddrHeader* address); + + public static unsafe int accept (int socket, Sockaddr address) + { + fixed (SockaddrType* addr = &Sockaddr.GetAddress (address).type) + fixed (byte* data = Sockaddr.GetDynamicData (address)) { + var dyn = new _SockaddrDynamic (address, data, useMaxLength: true); + int r = sys_accept (socket, Sockaddr.GetNative (&dyn, addr)); + dyn.Update (address); + return r; + } + } + + // accept4(2) + // int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_accept4")] + static extern unsafe int sys_accept4 (int socket, _SockaddrHeader* address, int flags); + + public static unsafe int accept4 (int socket, Sockaddr address, UnixSocketFlags flags) + { + var _flags = NativeConvert.FromUnixSocketFlags (flags); + fixed (SockaddrType* addr = &Sockaddr.GetAddress (address).type) + fixed (byte* data = Sockaddr.GetDynamicData (address)) { + var dyn = new _SockaddrDynamic (address, data, useMaxLength: true); + int r = sys_accept4 (socket, Sockaddr.GetNative (&dyn, addr), _flags); + dyn.Update (address); + return r; + } + } + + // getpeername(2) + // int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_getpeername")] + static extern unsafe int sys_getpeername (int socket, _SockaddrHeader* address); + + public static unsafe int getpeername (int socket, Sockaddr address) + { + fixed (SockaddrType* addr = &Sockaddr.GetAddress (address).type) + fixed (byte* data = Sockaddr.GetDynamicData (address)) { + var dyn = new _SockaddrDynamic (address, data, useMaxLength: true); + int r = sys_getpeername (socket, Sockaddr.GetNative (&dyn, addr)); + dyn.Update (address); + return r; + } + } + + // getsockname(2) + // int getsockname(int sockfd, struct sockaddr *addr, socklen_t *addrlen); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_getsockname")] + static extern unsafe int sys_getsockname (int socket, _SockaddrHeader* address); + + public static unsafe int getsockname (int socket, Sockaddr address) + { + fixed (SockaddrType* addr = &Sockaddr.GetAddress (address).type) + fixed (byte* data = Sockaddr.GetDynamicData (address)) { + var dyn = new _SockaddrDynamic (address, data, useMaxLength: true); + int r = sys_getsockname (socket, Sockaddr.GetNative (&dyn, addr)); + dyn.Update (address); + return r; + } + } + + // recvfrom(2) + // ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_recvfrom")] + static extern unsafe long sys_recvfrom (int socket, void *buffer, ulong length, int flags, _SockaddrHeader* address); + + public static unsafe long recvfrom (int socket, void *buffer, ulong length, MessageFlags flags, Sockaddr address) + { + int _flags = NativeConvert.FromMessageFlags (flags); + fixed (SockaddrType* addr = &Sockaddr.GetAddress (address).type) + fixed (byte* data = Sockaddr.GetDynamicData (address)) { + var dyn = new _SockaddrDynamic (address, data, useMaxLength: true); + long r = sys_recvfrom (socket, buffer, length, _flags, Sockaddr.GetNative (&dyn, addr)); + dyn.Update (address); + return r; + } + } + + public static unsafe long recvfrom (int socket, IntPtr buffer, ulong length, MessageFlags flags, Sockaddr address) + { + return recvfrom (socket, (void*) buffer, length, flags, address); + } + + public static unsafe long recvfrom (int socket, byte[] buffer, ulong length, MessageFlags flags, Sockaddr address) + { + if (length > (ulong) buffer.LongLength) + throw new ArgumentOutOfRangeException ("length", "length > buffer.LongLength"); + fixed (byte* ptr = buffer) + return recvfrom (socket, ptr, length, flags, address); + } + + // sendto(2) + // ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_sendto")] + static extern unsafe long sys_sendto (int socket, void *message, ulong length, int flags, _SockaddrHeader* address); + + public static unsafe long sendto (int socket, void *message, ulong length, MessageFlags flags, Sockaddr address) + { + int _flags = NativeConvert.FromMessageFlags (flags); + fixed (SockaddrType* addr = &Sockaddr.GetAddress (address).type) + fixed (byte* data = Sockaddr.GetDynamicData (address)) { + var dyn = new _SockaddrDynamic (address, data, useMaxLength: false); + return sys_sendto (socket, message, length, _flags, Sockaddr.GetNative (&dyn, addr)); + } + } + + public static unsafe long sendto (int socket, IntPtr message, ulong length, MessageFlags flags, Sockaddr address) + { + return sendto (socket, (void*) message, length, flags, address); + } + + public static unsafe long sendto (int socket, byte[] message, ulong length, MessageFlags flags, Sockaddr address) + { + if (length > (ulong) message.LongLength) + throw new ArgumentOutOfRangeException ("length", "length > message.LongLength"); + fixed (byte* ptr = message) + return sendto (socket, ptr, length, flags, address); + } + + // structure for recvmsg() and sendmsg() + unsafe struct _Msghdr + { + public Iovec* msg_iov; + public int msg_iovlen; + public byte* msg_control; + public long msg_controllen; + public int msg_flags; + + public _Msghdr (Msghdr message, Iovec* ptr_msg_iov, byte* ptr_msg_control) + { + if (message.msg_iovlen > message.msg_iov.Length || message.msg_iovlen < 0) + throw new ArgumentException ("message.msg_iovlen > message.msg_iov.Length || message.msg_iovlen < 0", "message"); + msg_iov = ptr_msg_iov; + msg_iovlen = message.msg_iovlen; + + if (message.msg_control == null && message.msg_controllen != 0) + throw new ArgumentException ("message.msg_control == null && message.msg_controllen != 0", "message"); + if (message.msg_control != null && message.msg_controllen > message.msg_control.Length) + throw new ArgumentException ("message.msg_controllen > message.msg_control.Length", "message"); + msg_control = ptr_msg_control; + msg_controllen = message.msg_controllen; + + msg_flags = 0; // msg_flags is only passed out of the kernel + } + + public void Update (Msghdr message) + { + message.msg_controllen = msg_controllen; + message.msg_flags = NativeConvert.ToMessageFlags (msg_flags); + } + } + + // recvmsg(2) + // ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_recvmsg")] + static extern unsafe long sys_recvmsg (int socket, ref _Msghdr message, _SockaddrHeader* msg_name, int flags); + + public static unsafe long recvmsg (int socket, Msghdr message, MessageFlags flags) + { + var _flags = NativeConvert.FromMessageFlags (flags); + var address = message.msg_name; + fixed (byte* ptr_msg_control = message.msg_control) + fixed (Iovec* ptr_msg_iov = message.msg_iov) { + var _message = new _Msghdr (message, ptr_msg_iov, ptr_msg_control); + long r; + fixed (SockaddrType* addr = &Sockaddr.GetAddress (address).type) + fixed (byte* data = Sockaddr.GetDynamicData (address)) { + var dyn = new _SockaddrDynamic (address, data, useMaxLength: true); + r = sys_recvmsg (socket, ref _message, Sockaddr.GetNative (&dyn, addr), _flags); + dyn.Update (address); + } + _message.Update (message); + return r; + } + } + + // sendmsg(2) + // ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags); + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_sendmsg")] + static extern unsafe long sys_sendmsg (int socket, ref _Msghdr message, _SockaddrHeader* msg_name, int flags); + + public static unsafe long sendmsg (int socket, Msghdr message, MessageFlags flags) + { + var _flags = NativeConvert.FromMessageFlags (flags); + var address = message.msg_name; + fixed (byte* ptr_msg_control = message.msg_control) + fixed (Iovec* ptr_msg_iov = message.msg_iov) { + var _message = new _Msghdr (message, ptr_msg_iov, ptr_msg_control); + fixed (SockaddrType* addr = &Sockaddr.GetAddress (address).type) + fixed (byte* data = Sockaddr.GetDynamicData (address)) { + var dyn = new _SockaddrDynamic (address, data, useMaxLength: false); + return sys_sendmsg (socket, ref _message, Sockaddr.GetNative (&dyn, addr), _flags); + } + } + } + + // cmsg(3) + // struct cmsghdr *CMSG_FIRSTHDR(struct msghdr *msgh); + // struct cmsghdr *CMSG_NXTHDR(struct msghdr *msgh, struct cmsghdr *cmsg); + // size_t CMSG_ALIGN(size_t length); + // size_t CMSG_SPACE(size_t length); + // size_t CMSG_LEN(size_t length); + // unsigned char *CMSG_DATA(struct cmsghdr *cmsg); + + // Wrapper methods use long offsets into msg_control instead of a + // struct cmsghdr *cmsg pointer because pointers into a byte[] aren't + // stable when the array is not pinned. + // NULL is mapped to -1. + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_CMSG_FIRSTHDR")] + static extern unsafe long CMSG_FIRSTHDR (byte* msg_control, long msg_controllen); + + public static unsafe long CMSG_FIRSTHDR (Msghdr msgh) + { + if (msgh.msg_control == null && msgh.msg_controllen != 0) + throw new ArgumentException ("msgh.msg_control == null && msgh.msg_controllen != 0", "msgh"); + if (msgh.msg_control != null && msgh.msg_controllen > msgh.msg_control.Length) + throw new ArgumentException ("msgh.msg_controllen > msgh.msg_control.Length", "msgh"); + + fixed (byte* ptr = msgh.msg_control) + return CMSG_FIRSTHDR (ptr, msgh.msg_controllen); + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_CMSG_NXTHDR")] + static extern unsafe long CMSG_NXTHDR (byte* msg_control, long msg_controllen, long cmsg); + + public static unsafe long CMSG_NXTHDR (Msghdr msgh, long cmsg) + { + if (msgh.msg_control == null || msgh.msg_controllen > msgh.msg_control.Length) + throw new ArgumentException ("msgh.msg_control == null || msgh.msg_controllen > msgh.msg_control.Length", "msgh"); + if (cmsg < 0 || cmsg + Cmsghdr.Size > msgh.msg_controllen) + throw new ArgumentException ("cmsg offset pointing out of buffer", "cmsg"); + + fixed (byte* ptr = msgh.msg_control) + return CMSG_NXTHDR (ptr, msgh.msg_controllen, cmsg); + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_CMSG_DATA")] + static extern unsafe long CMSG_DATA (byte* msg_control, long msg_controllen, long cmsg); + + public static unsafe long CMSG_DATA (Msghdr msgh, long cmsg) + { + if (msgh.msg_control == null || msgh.msg_controllen > msgh.msg_control.Length) + throw new ArgumentException ("msgh.msg_control == null || msgh.msg_controllen > msgh.msg_control.Length", "msgh"); + if (cmsg < 0 || cmsg + Cmsghdr.Size > msgh.msg_controllen) + throw new ArgumentException ("cmsg offset pointing out of buffer", "cmsg"); + + fixed (byte* ptr = msgh.msg_control) + return CMSG_DATA (ptr, msgh.msg_controllen, cmsg); + } + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_CMSG_ALIGN")] + public static extern ulong CMSG_ALIGN (ulong length); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_CMSG_SPACE")] + public static extern ulong CMSG_SPACE (ulong length); + + [DllImport (MPH, SetLastError=true, + EntryPoint="Mono_Posix_Syscall_CMSG_LEN")] + public static extern ulong CMSG_LEN (ulong length); + + #endregion + } + + #endregion +} + +// vim: noexpandtab +// Local Variables: +// tab-width: 4 +// c-basic-offset: 4 +// indent-tabs-mode: t +// End: diff --git a/Mono.Posix/Mono.Unix.Native/TypeAttributes.cs b/Mono.Posix/Mono.Unix.Native/TypeAttributes.cs new file mode 100644 index 0000000..2fadc9a --- /dev/null +++ b/Mono.Posix/Mono.Unix.Native/TypeAttributes.cs @@ -0,0 +1,138 @@ +// +// 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") + { + } + } +} + diff --git a/Mono.Posix/Mono.Unix/AbstractUnixEndPoint.cs b/Mono.Posix/Mono.Unix/AbstractUnixEndPoint.cs new file mode 100644 index 0000000..6c1fe21 --- /dev/null +++ b/Mono.Posix/Mono.Unix/AbstractUnixEndPoint.cs @@ -0,0 +1,123 @@ +// +// Mono.Unix.AbstractUnixEndPoint: EndPoint derived class for AF_UNIX family sockets. +// +// Authors: +// Gonzalo Paniagua Javier (gonzalo@ximian.com) +// Alp Toker (alp@atoker.com) +// +// (C) 2003 Ximian, Inc (http://www.ximian.com) +// (C) 2006 Alp Toker +// + +// +// 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.Net; +using System.Net.Sockets; +using System.Text; + +namespace Mono.Unix +{ + [Serializable] + public class AbstractUnixEndPoint : EndPoint + { + string path; + + public AbstractUnixEndPoint (string path) + { + if (path == null) + throw new ArgumentNullException ("path"); + + if (path == "") + throw new ArgumentException ("Cannot be empty.", "path"); + this.path = path; + } + + public string Path { + get { + return(path); + } + set { + path=value; + } + } + + 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 - 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); + } + } +} + diff --git a/Mono.Posix/Mono.Unix/Catalog.cs b/Mono.Posix/Mono.Unix/Catalog.cs new file mode 100644 index 0000000..90bddb0 --- /dev/null +++ b/Mono.Posix/Mono.Unix/Catalog.cs @@ -0,0 +1,136 @@ +// +// Mono.Unix.Catalog.cs: Wrappers for the libintl library. +// +// Authors: +// Edd Dumbill (edd@usefulinc.com) +// Jonathan Pryor (jonpryor@vt.edu) +// +// (C) 2004 Edd Dumbill +// (C) 2005-2006 Jonathan Pryor +// +// This file implements the low-level syscall interface to the POSIX +// subsystem. +// +// This file tries to stay close to the low-level API as much as possible +// using enumerations, structures and in a few cases, using existing .NET +// data types. +// +// Implementation notes: +// +// Since the values for the various constants on the API changes +// from system to system (even Linux on different architectures will +// have different values), we define our own set of values, and we +// use a set of C helper routines to map from the constants we define +// to the values of the native OS. +// +// Bitfields are flagged with the [Map] attribute, and a helper program +// generates a set of map_XXXX routines that we can call to convert +// from our value definitions to the value definitions expected by the +// OS. +// +// Methods that require tuning are bound as `internal syscal_NAME' methods +// and then a `NAME' method is exposed. +// + +using System; +using System.Runtime.InteropServices; + +namespace Mono.Unix { + + 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); + } + } + + private static void MarshalStrings (string s1, out IntPtr p1, + string s2, out IntPtr p2, string s3, out IntPtr p3) + { + p1 = p2 = p3 = IntPtr.Zero; + + 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); + } + } + } +} + diff --git a/Mono.Posix/Mono.Unix/FileAccessPattern.cs b/Mono.Posix/Mono.Unix/FileAccessPattern.cs new file mode 100644 index 0000000..bb8ada9 --- /dev/null +++ b/Mono.Posix/Mono.Unix/FileAccessPattern.cs @@ -0,0 +1,43 @@ +// +// Mono.Unix/FileAccessPattern.cs +// +// Authors: +// Jonathan Pryor (jonpryor@vt.edu) +// +// (C) 2005 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 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, + } +} + diff --git a/Mono.Posix/Mono.Unix/FileAccessPermissions.cs b/Mono.Posix/Mono.Unix/FileAccessPermissions.cs new file mode 100644 index 0000000..8d8ae10 --- /dev/null +++ b/Mono.Posix/Mono.Unix/FileAccessPermissions.cs @@ -0,0 +1,53 @@ +// +// Mono.Unix/FileAccessPermissions.cs +// +// Authors: +// Jonathan Pryor (jonpryor@vt.edu) +// +// (C) 2005-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 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, + + DefaultPermissions = (int) Native.FilePermissions.DEFFILEMODE, + AllPermissions = (int) Native.FilePermissions.ACCESSPERMS, + } +} + diff --git a/Mono.Posix/Mono.Unix/FileHandleOperations.cs b/Mono.Posix/Mono.Unix/FileHandleOperations.cs new file mode 100644 index 0000000..89cdb2c --- /dev/null +++ b/Mono.Posix/Mono.Unix/FileHandleOperations.cs @@ -0,0 +1,82 @@ +// +// Mono.Unix/FileHandleOperations.cs +// +// Authors: +// Jonathan Pryor (jonpryor@vt.edu) +// +// (C) 2005 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.IO; +using System.Text; +using Mono.Unix; + +namespace Mono.Unix { + + 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); + } + } +} + +// vim: noexpandtab diff --git a/Mono.Posix/Mono.Unix/FileSpecialAttributes.cs b/Mono.Posix/Mono.Unix/FileSpecialAttributes.cs new file mode 100644 index 0000000..cab587c --- /dev/null +++ b/Mono.Posix/Mono.Unix/FileSpecialAttributes.cs @@ -0,0 +1,41 @@ +// +// Mono.Unix/FileSpecialAttributes.cs +// +// Authors: +// Jonathan Pryor (jonpryor@vt.edu) +// +// (C) 2005-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 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, + } +} + diff --git a/Mono.Posix/Mono.Unix/FileTypes.cs b/Mono.Posix/Mono.Unix/FileTypes.cs new file mode 100644 index 0000000..0059705 --- /dev/null +++ b/Mono.Posix/Mono.Unix/FileTypes.cs @@ -0,0 +1,44 @@ +// +// Mono.Unix/FileTypes.cs +// +// Authors: +// Jonathan Pryor (jonpryor@vt.edu) +// +// (C) 2005-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 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, + } +} + diff --git a/Mono.Posix/Mono.Unix/PeerCred.cs b/Mono.Posix/Mono.Unix/PeerCred.cs new file mode 100644 index 0000000..2f8d71e --- /dev/null +++ b/Mono.Posix/Mono.Unix/PeerCred.cs @@ -0,0 +1,81 @@ +// +// Mono.Unix.PeerCred: Peer credentials class for AF_UNIX sockets +// +// Authors: +// Dick Porter (dick@ximian.com) +// +// (C) 2004 Novell, Inc (http://www.novell.com) +// + +// +// 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.Net.Sockets; + +namespace Mono.Unix +{ +#pragma warning disable 649 + internal struct PeerCredData { + public int pid; + public int uid; + public int 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); + } + } + } +} + diff --git a/Mono.Posix/Mono.Unix/StdioFileStream.cs b/Mono.Posix/Mono.Unix/StdioFileStream.cs new file mode 100644 index 0000000..1d0ef97 --- /dev/null +++ b/Mono.Posix/Mono.Unix/StdioFileStream.cs @@ -0,0 +1,406 @@ +// +// Mono.Unix/StdioFileStream.cs +// +// Authors: +// Jonathan Pryor (jonpryor@vt.edu) +// +// (C) 2005-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.IO; +using System.Runtime.InteropServices; +using System.Text; +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 StdioFileStream (IntPtr fileStream) + : this (fileStream, true) {} + + public StdioFileStream (IntPtr fileStream, bool ownsHandle) + { + InitStream (fileStream, ownsHandle); + } + + public StdioFileStream (IntPtr fileStream, FileAccess access) + : this (fileStream, access, true) {} + + public StdioFileStream (IntPtr fileStream, FileAccess access, bool ownsHandle) + { + InitStream (fileStream, ownsHandle); + InitCanReadWrite (access); + } + + public StdioFileStream (string path) + { + if (path == null) + throw new ArgumentNullException ("path"); + InitStream (Fopen (path, "rb"), true); + } + + public StdioFileStream (string path, string mode) + { + if (path == null) + throw new ArgumentNullException ("path"); + InitStream (Fopen (path, mode), true); + } + + public StdioFileStream (string path, FileMode mode) + { + if (path == null) + throw new ArgumentNullException ("path"); + InitStream (Fopen (path, ToFopenMode (path, mode)), true); + } + + public StdioFileStream (string path, FileAccess access) + { + if (path == null) + throw new ArgumentNullException ("path"); + InitStream (Fopen (path, ToFopenMode (path, access)), true); + InitCanReadWrite (access); + } + + 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 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 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 void InitCanReadWrite (FileAccess access) + { + canRead = canRead && + (access == FileAccess.Read || access == FileAccess.ReadWrite); + canWrite = canWrite && + (access == FileAccess.Write || access == FileAccess.ReadWrite); + } + + private static string ToFopenMode (string file, FileMode mode) + { + string cmode = Native.NativeConvert.ToFopenMode (mode); + AssertFileMode (file, mode); + return cmode; + } + + private static string ToFopenMode (string file, FileAccess access) + { + return Native.NativeConvert.ToFopenMode (access); + } + + 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; + } + + 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; + } + + private static bool FileExists (string file) + { + bool found = false; + IntPtr f = Native.Stdlib.fopen (file, "r"); + found = f != IntPtr.Zero; + if (f != IntPtr.Zero) + Native.Stdlib.fclose (f); + return found; + } + + private void AssertNotDisposed () + { + if (file == InvalidFileStream) + throw new ObjectDisposedException ("Invalid File Stream"); + GC.KeepAlive (this); + } + + public IntPtr Handle { + get { + AssertNotDisposed (); + GC.KeepAlive (this); + return file; + } + } + + public override bool CanRead { + get {return canRead;} + } + + public override bool CanSeek { + get {return canSeek;} + } + + public override bool CanWrite { + get {return canWrite;} + } + + 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); + + long endPos = Native.Stdlib.ftell (file); + if (endPos == -1) + UnixMarshal.ThrowExceptionForLastError (); + + r = Native.Stdlib.fseek (file, curPos, Native.SeekFlags.SEEK_SET); + UnixMarshal.ThrowExceptionForLastErrorIf (r); + + 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; + } +} + +// vim: noexpandtab diff --git a/Mono.Posix/Mono.Unix/UnixClient.cs b/Mono.Posix/Mono.Unix/UnixClient.cs new file mode 100644 index 0000000..4e28999 --- /dev/null +++ b/Mono.Posix/Mono.Unix/UnixClient.cs @@ -0,0 +1,230 @@ +// +// UnixClient.cs +// +// Authors: +// Joe Shaw (joeshaw@novell.com) +// +// Copyright (C) 2004-2005 Novell, Inc. +// + +// +// 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.IO; +using System.Net; +using System.Net.Sockets; +using System.Runtime.InteropServices; + +namespace Mono.Unix { + + public class UnixClient : MarshalByRefObject, IDisposable { + NetworkStream stream; + Socket client; + bool disposed; + + public UnixClient () + { + if (client != null) { + client.Close (); + client = null; + } + + client = new Socket (AddressFamily.Unix, SocketType.Stream, 0); + } + + 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 LingerOption LingerState { + get { + CheckDisposed (); + return (LingerOption) client.GetSocketOption (SocketOptionLevel.Socket, + SocketOptionName.Linger); + } + + set { + CheckDisposed (); + client.SetSocketOption (SocketOptionLevel.Socket, + SocketOptionName.Linger, value); + } + } + + public int ReceiveBufferSize { + get { + CheckDisposed (); + return (int) client.GetSocketOption (SocketOptionLevel.Socket, + SocketOptionName.ReceiveBuffer); + } + + set { + CheckDisposed (); + client.SetSocketOption (SocketOptionLevel.Socket, + SocketOptionName.ReceiveBuffer, value); + } + } + + public int ReceiveTimeout { + get { + CheckDisposed (); + return (int) client.GetSocketOption (SocketOptionLevel.Socket, + SocketOptionName.ReceiveTimeout); + } + + set { + CheckDisposed (); + client.SetSocketOption (SocketOptionLevel.Socket, + SocketOptionName.ReceiveTimeout, value); + } + } + + public int SendBufferSize { + get { + CheckDisposed (); + return (int) client.GetSocketOption (SocketOptionLevel.Socket, + SocketOptionName.SendBuffer); + } + + set { + CheckDisposed (); + client.SetSocketOption (SocketOptionLevel.Socket, + SocketOptionName.SendBuffer, value); + } + } + + public int SendTimeout { + get { + CheckDisposed (); + return (int) client.GetSocketOption (SocketOptionLevel.Socket, + SocketOptionName.SendTimeout); + } + + set { + CheckDisposed (); + client.SetSocketOption (SocketOptionLevel.Socket, + SocketOptionName.SendTimeout, value); + } + } + + public void Close () + { + CheckDisposed (); + Dispose (); + } + + public void Connect (UnixEndPoint remoteEndPoint) + { + CheckDisposed (); + client.Connect (remoteEndPoint); + stream = new NetworkStream (client, true); + } + + public void Connect (string path) + { + CheckDisposed (); + Connect (new UnixEndPoint (path)); + } + + public void Dispose () + { + Dispose (true); + GC.SuppressFinalize (this); + } + + protected virtual void Dispose (bool disposing) + { + if (disposed) + return; + + if (disposing) { + // release managed resources + NetworkStream s = stream; + stream = null; + if (s != null) { + // This closes the socket as well, as the NetworkStream + // owns the socket. + s.Close(); + s = null; + } else if (client != null){ + client.Close (); + } + client = null; + } + + disposed = true; + } + + public NetworkStream GetStream () + { + CheckDisposed (); + if (stream == null) + stream = new NetworkStream (client, true); + + return stream; + } + + void CheckDisposed () + { + if (disposed) + throw new ObjectDisposedException (GetType().FullName); + } + + ~UnixClient () + { + Dispose (false); + } + } +} + diff --git a/Mono.Posix/Mono.Unix/UnixDirectoryInfo.cs b/Mono.Posix/Mono.Unix/UnixDirectoryInfo.cs new file mode 100644 index 0000000..5cc6183 --- /dev/null +++ b/Mono.Posix/Mono.Unix/UnixDirectoryInfo.cs @@ -0,0 +1,250 @@ +// +// Mono.Unix/UnixDirectoryInfo.cs +// +// Authors: +// Jonathan Pryor (jonpryor@vt.edu) +// +// (C) 2004-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.Collections; +using System.IO; +using System.Text; +using System.Text.RegularExpressions; +using Mono.Unix; + +namespace Mono.Unix { + + public sealed class UnixDirectoryInfo : UnixFileSystemInfo + { + public UnixDirectoryInfo (string path) + : base (path) + { + } + + 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 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 Root { + get { + string root = UnixPath.GetPathRoot (FullPath); + if (root == null) + return null; + return 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 (); + } + + public void Create (FileAccessPermissions mode) + { + Create ((Native.FilePermissions) mode); + } + + public void Create () + { + Mono.Unix.Native.FilePermissions mode = + Mono.Unix.Native.FilePermissions.ACCESSPERMS; + Create (mode); + } + + public override void Delete () + { + Delete (false); + } + + public void Delete (bool recursive) + { + if (recursive) { + foreach (UnixFileSystemInfo e in GetFileSystemEntries ()) { + UnixDirectoryInfo d = e as UnixDirectoryInfo; + if (d != null) + d.Delete (true); + else + e.Delete (); + } + } + int r = Native.Syscall.rmdir (FullPath); + UnixMarshal.ThrowExceptionForLastErrorIf (r); + base.Refresh (); + } + + public Native.Dirent[] GetEntries () + { + IntPtr dirp = Native.Syscall.opendir (FullPath); + if (dirp == IntPtr.Zero) + UnixMarshal.ThrowExceptionForLastError (); + + 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); + } + } + + private static Native.Dirent[] GetEntries (IntPtr dirp) + { + 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) + // 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 Native.Dirent[] GetEntries (Regex regex) + { + IntPtr dirp = Native.Syscall.opendir (FullPath); + if (dirp == IntPtr.Zero) + UnixMarshal.ThrowExceptionForLastError (); + + 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); + } + } +} + +// vim: noexpandtab diff --git a/Mono.Posix/Mono.Unix/UnixDriveInfo.cs b/Mono.Posix/Mono.Unix/UnixDriveInfo.cs new file mode 100644 index 0000000..41e932b --- /dev/null +++ b/Mono.Posix/Mono.Unix/UnixDriveInfo.cs @@ -0,0 +1,195 @@ +// +// Mono.Unix/UnixDriveInfo.cs +// +// Authors: +// Jonathan Pryor (jonpryor@vt.edu) +// +// (C) 2004-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.Collections; +using System.IO; +using Mono.Unix; + +namespace Mono.Unix { + + 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; + + 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"; + } + } + + 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); + } + + private UnixDriveInfo (Native.Fstab fstab) + { + FromFstab (fstab); + } + + public long AvailableFreeSpace { + get {Refresh (); return Convert.ToInt64 (stat.f_bavail * stat.f_frsize);} + } + + public string DriveFormat { + get {return fstype;} + } + + 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; + } + } +} + +// vim: noexpandtab diff --git a/Mono.Posix/Mono.Unix/UnixEncoding.cs b/Mono.Posix/Mono.Unix/UnixEncoding.cs new file mode 100644 index 0000000..d869b1b --- /dev/null +++ b/Mono.Posix/Mono.Unix/UnixEncoding.cs @@ -0,0 +1,856 @@ +/* + * Mono.Unix/UnixEncoding.cs + * + * Authors: + * Jonathan Pryor (jonpryor@vt.edu) + * + * Copyright (c) 2001, 2002 Southern Storm Software, Pty Ltd + * Copyright (C) 2004 Novell, Inc (http://www.novell.com) + * Copyright (C) 2005 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. + */ + +namespace Mono.Unix +{ + +using System; +using System.Text; + +[Serializable] +public class UnixEncoding : Encoding +{ + public static readonly Encoding Instance = new UnixEncoding (); + + public static readonly char EscapeByte = '\u0000'; + + // Constructors. + public UnixEncoding () + { + } + + // Internal version of "GetByteCount" which can handle a rolling + // state between multiple calls to this method. + private static int InternalGetByteCount (char[] chars, int index, int count, uint leftOver, bool flush) + { + // Validate the parameters. + if (chars == null) { + throw new ArgumentNullException ("chars"); + } + if (index < 0 || index > chars.Length) { + throw new ArgumentOutOfRangeException ("index", _("ArgRange_Array")); + } + if (count < 0 || count > (chars.Length - index)) { + throw new ArgumentOutOfRangeException ("count", _("ArgRange_Array")); + } + + // Determine the lengths of all characters. + char ch; + int length = 0; + uint pair = leftOver; + while (count > 0) { + ch = chars[index]; + if (pair == 0) { + if (ch == EscapeByte && count > 1) { + ++length; + ++index; + --count; + } else if (ch < '\u0080') { + ++length; + } else if (ch < '\u0800') { + length += 2; + } else if (ch >= '\uD800' && ch <= '\uDBFF') { + // This is the start of a surrogate pair. + pair = (uint)ch; + } else { + length += 3; + } + } else if (ch >= '\uDC00' && ch <= '\uDFFF') { + // We have a surrogate pair. + length += 4; + pair = 0; + } else { + // We have a surrogate start followed by a + // regular character. Technically, this is + // invalid, but we have to do something. + // We write out the surrogate start and then + // re-visit the current character again. + length += 3; + pair = 0; + continue; + } + ++index; + --count; + } + if (flush && pair != 0) { + // Flush the left-over surrogate pair start. + length += 3; + } + + // Return the final length to the caller. + return length; + } + + // Get the number of bytes needed to encode a character buffer. + public override int GetByteCount (char[] chars, int index, int count) + { + return InternalGetByteCount (chars, index, count, 0, true); + } + + // Convenience wrappers for "GetByteCount". + public override int GetByteCount (String s) + { + // Validate the parameters. + if (s == null) { + throw new ArgumentNullException ("s"); + } + + // Determine the lengths of all characters. + char ch; + int index = 0; + int count = s.Length; + int length = 0; + uint pair; + while (count > 0) { + ch = s[index++]; + if (ch == EscapeByte && count > 1) { + ++length; + ++index; + --count; + } else if (ch < '\u0080') { + ++length; + } else if (ch < '\u0800') { + length += 2; + } else if (ch >= '\uD800' && ch <= '\uDBFF' && count > 1) { + // This may be the start of a surrogate pair. + pair = (uint)(s[index]); + if (pair >= (uint)0xDC00 && pair <= (uint)0xDFFF) { + length += 4; + ++index; + --count; + } else { + length += 3; + } + } else { + length += 3; + } + --count; + } + + // Return the final length to the caller. + return length; + } + + // Internal version of "GetBytes" which can handle a rolling + // state between multiple calls to this method. + private static int InternalGetBytes (char[] chars, int charIndex, + int charCount, byte[] bytes, + int byteIndex, ref uint leftOver, + bool flush) + { + // Validate the parameters. + if (chars == null) { + throw new ArgumentNullException ("chars"); + } + if (bytes == null) { + throw new ArgumentNullException ("bytes"); + } + if (charIndex < 0 || charIndex > chars.Length) { + throw new ArgumentOutOfRangeException ("charIndex", _("ArgRange_Array")); + } + if (charCount < 0 || charCount > (chars.Length - charIndex)) { + throw new ArgumentOutOfRangeException ("charCount", _("ArgRange_Array")); + } + if (byteIndex < 0 || byteIndex > bytes.Length) { + throw new ArgumentOutOfRangeException ("byteIndex", _("ArgRange_Array")); + } + + // Convert the characters into bytes. + char ch; + int length = bytes.Length; + uint pair; + uint left = leftOver; + int posn = byteIndex; + while (charCount > 0) { + // Fetch the next UTF-16 character pair value. + ch = chars[charIndex++]; + --charCount; + if (left == 0) { + if (ch >= '\uD800' && ch <= '\uDBFF') { + // This is the start of a surrogate pair. + left = (uint)ch; + continue; + } else if (ch == EscapeByte) { + if (posn >= length) { + throw new ArgumentException (_("Arg_InsufficientSpace"), "bytes"); + } + if (--charCount >= 0) { + bytes[posn++] = (byte) chars [charIndex++]; + } + continue; + } else { + // This is a regular character. + pair = (uint)ch; + } + } else if (ch >= '\uDC00' && ch <= '\uDFFF') { + // We have a surrogate pair. + pair = ((left - (uint)0xD800) << 10) + + (((uint)ch) - (uint)0xDC00) + + (uint)0x10000; + left = 0; + } else { + // We have a surrogate start followed by a + // regular character. Technically, this is + // invalid, but we have to do something. + // We write out the surrogate start and then + // re-visit the current character again. + pair = (uint)left; + left = 0; + --charIndex; + ++charCount; + } + + // Encode the character pair value. + if (pair < (uint)0x0080) { + if (posn >= length) { + throw new ArgumentException (_("Arg_InsufficientSpace"), "bytes"); + } + bytes[posn++] = (byte)pair; + } else if (pair < (uint)0x0800) { + if ((posn + 2) > length) { + throw new ArgumentException (_("Arg_InsufficientSpace"), "bytes"); + } + bytes[posn++] = (byte)(0xC0 | (pair >> 6)); + bytes[posn++] = (byte)(0x80 | (pair & 0x3F)); + } else if (pair < (uint)0x10000) { + if ((posn + 3) > length) { + throw new ArgumentException (_("Arg_InsufficientSpace"), "bytes"); + } + bytes[posn++] = (byte)(0xE0 | (pair >> 12)); + bytes[posn++] = (byte)(0x80 | ((pair >> 6) & 0x3F)); + bytes[posn++] = (byte)(0x80 | (pair & 0x3F)); + } else { + if ((posn + 4) > length) { + throw new ArgumentException (_("Arg_InsufficientSpace"), "bytes"); + } + bytes[posn++] = (byte)(0xF0 | (pair >> 18)); + bytes[posn++] = (byte)(0x80 | ((pair >> 12) & 0x3F)); + bytes[posn++] = (byte)(0x80 | ((pair >> 6) & 0x3F)); + bytes[posn++] = (byte)(0x80 | (pair & 0x3F)); + } + } + if (flush && left != 0) { + // Flush the left-over surrogate pair start. + if ((posn + 3) > length) { + throw new ArgumentException (_("Arg_InsufficientSpace"), "bytes"); + } + bytes[posn++] = (byte)(0xE0 | (left >> 12)); + bytes[posn++] = (byte)(0x80 | ((left >> 6) & 0x3F)); + bytes[posn++] = (byte)(0x80 | (left & 0x3F)); + left = 0; + } + leftOver = left; + + // Return the final count to the caller. + return posn - byteIndex; + } + + // Get the bytes that result from encoding a character buffer. + public override int GetBytes (char[] chars, int charIndex, int charCount, + byte[] bytes, int byteIndex) + { + uint leftOver = 0; + return InternalGetBytes (chars, charIndex, charCount, bytes, byteIndex, ref leftOver, true); + } + + // Convenience wrappers for "GetBytes". + public override int GetBytes (String s, int charIndex, int charCount, + byte[] bytes, int byteIndex) + { + // Validate the parameters. + if (s == null) { + throw new ArgumentNullException ("s"); + } + if (bytes == null) { + throw new ArgumentNullException ("bytes"); + } + if (charIndex < 0 || charIndex > s.Length) { + throw new ArgumentOutOfRangeException ("charIndex", _("ArgRange_StringIndex")); + } + if (charCount < 0 || charCount > (s.Length - charIndex)) { + throw new ArgumentOutOfRangeException ("charCount", _("ArgRange_StringRange")); + } + if (byteIndex < 0 || byteIndex > bytes.Length) { + throw new ArgumentOutOfRangeException ("byteIndex", _("ArgRange_Array")); + } + + unsafe { + fixed (char* p = s) { + fixed (byte* b = bytes) { + return GetBytes (p + charIndex, charCount, b + byteIndex, bytes.Length - byteIndex); + } + } + } + } + + public unsafe override int GetBytes(char* chars, int charCount, byte* bytes, int byteCount) + { + if (bytes == null || chars == null) + throw new ArgumentNullException (bytes == null ? "bytes" : "chars"); + + if (charCount < 0 || byteCount < 0) + throw new ArgumentOutOfRangeException (charCount < 0 ? "charCount" : "byteCount"); + + // Convert the characters into bytes. + char ch; + int length = byteCount; + uint pair; + int posn = 0; + int charIndex = 0; + while (charCount > 0) { + // Fetch the next UTF-16 character pair value. + ch = chars [charIndex++]; + if (ch >= '\uD800' && ch <= '\uDBFF' && charCount > 1) { + // This may be the start of a surrogate pair. + pair = (uint)(chars[charIndex]); + if (pair >= (uint)0xDC00 && pair <= (uint)0xDFFF) { + pair = (pair - (uint)0xDC00) + + ((((uint)ch) - (uint)0xD800) << 10) + + (uint)0x10000; + ++charIndex; + --charCount; + } else { + pair = (uint)ch; + } + } else if (ch == EscapeByte && charCount > 1) { + if (posn >= length) { + throw new ArgumentException (_("Arg_InsufficientSpace"), "bytes"); + } + charCount -= 2; + if (charCount >= 0) { + bytes[posn++] = (byte)chars [charIndex++]; + } + continue; + } else { + pair = (uint)ch; + } + --charCount; + + // Encode the character pair value. + if (pair < (uint)0x0080) { + if (posn >= length) { + throw new ArgumentException (_("Arg_InsufficientSpace"), "bytes"); + } + bytes[posn++] = (byte)pair; + } else if (pair < (uint)0x0800) { + if ((posn + 2) > length) { + throw new ArgumentException (_("Arg_InsufficientSpace"), "bytes"); + } + bytes[posn++] = (byte)(0xC0 | (pair >> 6)); + bytes[posn++] = (byte)(0x80 | (pair & 0x3F)); + } else if (pair < (uint)0x10000) { + if ((posn + 3) > length) { + throw new ArgumentException (_("Arg_InsufficientSpace"), "bytes"); + } + bytes[posn++] = (byte)(0xE0 | (pair >> 12)); + bytes[posn++] = (byte)(0x80 | ((pair >> 6) & 0x3F)); + bytes[posn++] = (byte)(0x80 | (pair & 0x3F)); + } else { + if ((posn + 4) > length) { + throw new ArgumentException (_("Arg_InsufficientSpace"), "bytes"); + } + bytes[posn++] = (byte)(0xF0 | (pair >> 18)); + bytes[posn++] = (byte)(0x80 | ((pair >> 12) & 0x3F)); + bytes[posn++] = (byte)(0x80 | ((pair >> 6) & 0x3F)); + bytes[posn++] = (byte)(0x80 | (pair & 0x3F)); + } + } + + // Return the final count to the caller. + return posn; + } + + // Internal version of "GetCharCount" which can handle a rolling + // state between multiple calls to this method. + private static int InternalGetCharCount (byte[] bytes, int index, int count, + uint leftOverBits, + uint leftOverCount, + bool throwOnInvalid, bool flush) + { + // Validate the parameters. + if (bytes == null) { + throw new ArgumentNullException ("bytes"); + } + if (index < 0 || index > bytes.Length) { + throw new ArgumentOutOfRangeException ("index", _("ArgRange_Array")); + } + if (count < 0 || count > (bytes.Length - index)) { + throw new ArgumentOutOfRangeException ("count", _("ArgRange_Array")); + } + + // Determine the number of characters that we have. + int next_raw = 0; + uint ch; + int length = 0; + uint leftBits = leftOverBits; + uint leftSoFar = (leftOverCount & (uint)0x0F); + uint leftSize = ((leftOverCount >> 4) & (uint)0x0F); + while (count > 0) { + ch = (uint)(bytes [index++]); + ++next_raw; + --count; + if (leftSize == 0) { + // Process a UTF-8 start character. + if (ch < (uint)0x0080) { + // Single-byte UTF-8 character. + ++length; + next_raw = 0; + } else if ((ch & (uint)0xE0) == (uint)0xC0) { + // Double-byte UTF-8 character. + leftBits = (ch & (uint)0x1F); + leftSoFar = 1; + leftSize = 2; + } else if ((ch & (uint)0xF0) == (uint)0xE0) { + // Three-byte UTF-8 character. + leftBits = (ch & (uint)0x0F); + leftSoFar = 1; + leftSize = 3; + } else if ((ch & (uint)0xF8) == (uint)0xF0) { + // Four-byte UTF-8 character. + leftBits = (ch & (uint)0x07); + leftSoFar = 1; + leftSize = 4; + } else if ((ch & (uint)0xFC) == (uint)0xF8) { + // Five-byte UTF-8 character. + leftBits = (ch & (uint)0x03); + leftSoFar = 1; + leftSize = 5; + } else if ((ch & (uint)0xFE) == (uint)0xFC) { + // Six-byte UTF-8 character. + leftBits = (ch & (uint)0x03); + leftSoFar = 1; + leftSize = 6; + } else { + // Invalid UTF-8 start character. + if (throwOnInvalid) { + // throw new ArgumentException (_("Arg_InvalidUTF8"), "bytes"); + } + length += next_raw*2; + next_raw = 0; + } + } else { + // Process an extra byte in a multi-byte sequence. + if ((ch & (uint)0xC0) == (uint)0x80) { + leftBits = ((leftBits << 6) | (ch & (uint)0x3F)); + if (++leftSoFar >= leftSize) { + // We have a complete character now. + if (leftBits < (uint)0x10000) { + // is it an overlong ? + bool overlong = false; + switch (leftSize) { + case 2: + overlong = (leftBits <= 0x7F); + break; + case 3: + overlong = (leftBits <= 0x07FF); + break; + case 4: + overlong = (leftBits <= 0xFFFF); + break; + case 5: + overlong = (leftBits <= 0x1FFFFF); + break; + case 6: + overlong = (leftBits <= 0x03FFFFFF); + break; + } + if (overlong) { + // if (throwOnInvalid) + // throw new ArgumentException (_("Overlong"), leftBits.ToString ()); + length += next_raw*2; + } + else + ++length; + } else if (leftBits < (uint)0x110000) { + length += 2; + } else if (throwOnInvalid) { + // ??? + // throw new ArgumentException (_("Arg_InvalidUTF8"), "bytes"); + length += next_raw*2; + } + leftSize = 0; + next_raw = 0; + } + } else { + // Invalid UTF-8 sequence: clear and restart. + if (throwOnInvalid) { + // throw new ArgumentException (_("Arg_InvalidUTF8"), "bytes"); + } + // don't escape the current byte, process it normally + if (ch < (uint)0x0080) { + --index; + ++count; + --next_raw; + } + length += next_raw*2; + leftSize = 0; + next_raw = 0; + } + } + } + if (flush && leftSize != 0 && throwOnInvalid) { + // We had left-over bytes that didn't make up + // a complete UTF-8 character sequence. + // throw new ArgumentException (_("Arg_InvalidUTF8"), "bytes"); + length += next_raw * 2; + } + + // Return the final length to the caller. + return length; + } + + // Get the number of characters needed to decode a byte buffer. + public override int GetCharCount (byte[] bytes, int index, int count) + { + return InternalGetCharCount (bytes, index, count, 0, 0, true, true); + } + + // Get the characters that result from decoding a byte buffer. + private static int InternalGetChars (byte[] bytes, int byteIndex, + int byteCount, char[] chars, + int charIndex, ref uint leftOverBits, + ref uint leftOverCount, + bool throwOnInvalid, bool flush) + { + // Validate the parameters. + if (bytes == null) { + throw new ArgumentNullException ("bytes"); + } + if (chars == null) { + throw new ArgumentNullException ("chars"); + } + if (byteIndex < 0 || byteIndex > bytes.Length) { + throw new ArgumentOutOfRangeException ("byteIndex", _("ArgRange_Array")); + } + if (byteCount < 0 || byteCount > (bytes.Length - byteIndex)) { + throw new ArgumentOutOfRangeException ("byteCount", _("ArgRange_Array")); + } + if (charIndex < 0 || charIndex > chars.Length) { + throw new ArgumentOutOfRangeException ("charIndex", _("ArgRange_Array")); + } + + if (charIndex == chars.Length) + return 0; + + // Convert the bytes into the output buffer. + byte[] raw = new byte[6]; + int next_raw = 0; + uint ch; + int length = chars.Length; + int posn = charIndex; + uint leftBits = leftOverBits; + uint leftSoFar = (leftOverCount & (uint)0x0F); + uint leftSize = ((leftOverCount >> 4) & (uint)0x0F); + while (byteCount > 0) { + // Fetch the next character from the byte buffer. + ch = (uint)(bytes[byteIndex++]); + raw [next_raw++] = (byte) ch; + --byteCount; + if (leftSize == 0) { + // Process a UTF-8 start character. + if (ch < (uint)0x0080) { + // Single-byte UTF-8 character. + if (posn >= length) { + throw new ArgumentException (_("Arg_InsufficientSpace"), "chars"); + } + next_raw = 0; + chars[posn++] = (char)ch; + } else if ((ch & (uint)0xE0) == (uint)0xC0) { + // Double-byte UTF-8 character. + leftBits = (ch & (uint)0x1F); + leftSoFar = 1; + leftSize = 2; + } else if ((ch & (uint)0xF0) == (uint)0xE0) { + // Three-byte UTF-8 character. + leftBits = (ch & (uint)0x0F); + leftSoFar = 1; + leftSize = 3; + } else if ((ch & (uint)0xF8) == (uint)0xF0) { + // Four-byte UTF-8 character. + leftBits = (ch & (uint)0x07); + leftSoFar = 1; + leftSize = 4; + } else if ((ch & (uint)0xFC) == (uint)0xF8) { + // Five-byte UTF-8 character. + leftBits = (ch & (uint)0x03); + leftSoFar = 1; + leftSize = 5; + } else if ((ch & (uint)0xFE) == (uint)0xFC) { + // Six-byte UTF-8 character. + leftBits = (ch & (uint)0x03); + leftSoFar = 1; + leftSize = 6; + } else { + // Invalid UTF-8 start character. + if (throwOnInvalid) { + // throw new ArgumentException (_("Arg_InvalidUTF8"), "bytes"); + } + next_raw = 0; + chars[posn++] = EscapeByte; + chars[posn++] = (char) ch; + } + } else { + // Process an extra byte in a multi-byte sequence. + if ((ch & (uint)0xC0) == (uint)0x80) { + leftBits = ((leftBits << 6) | (ch & (uint)0x3F)); + if (++leftSoFar >= leftSize) { + // We have a complete character now. + if (leftBits < (uint)0x10000) { + // is it an overlong ? + bool overlong = false; + switch (leftSize) { + case 2: + overlong = (leftBits <= 0x7F); + break; + case 3: + overlong = (leftBits <= 0x07FF); + break; + case 4: + overlong = (leftBits <= 0xFFFF); + break; + case 5: + overlong = (leftBits <= 0x1FFFFF); + break; + case 6: + overlong = (leftBits <= 0x03FFFFFF); + break; + } + if (overlong) { + // if (throwOnInvalid) + // throw new ArgumentException (_("Overlong"), leftBits.ToString ()); + CopyRaw (raw, ref next_raw, chars, ref posn, length); + } + else { + if (posn >= length) { + throw new ArgumentException + (_("Arg_InsufficientSpace"), "chars"); + } + chars[posn++] = (char)leftBits; + } + } else if (leftBits < (uint)0x110000) { + if ((posn + 2) > length) { + throw new ArgumentException + (_("Arg_InsufficientSpace"), "chars"); + } + leftBits -= (uint)0x10000; + chars[posn++] = (char)((leftBits >> 10) + + (uint)0xD800); + chars[posn++] = + (char)((leftBits & (uint)0x3FF) + (uint)0xDC00); + } else if (throwOnInvalid) { + // ??? + // throw new ArgumentException (_("Arg_InvalidUTF8"), "bytes"); + CopyRaw (raw, ref next_raw, chars, ref posn, length); + } + leftSize = 0; + next_raw = 0; + } + } else { + // Invalid UTF-8 sequence: clear and restart. + if (throwOnInvalid) { + // throw new ArgumentException (_("Arg_InvalidUTF8"), "bytes"); + } + // don't escape the current byte, process it normally + if (ch < (uint)0x0080) { + --byteIndex; + ++byteCount; + --next_raw; + } + CopyRaw (raw, ref next_raw, chars, ref posn, length); + leftSize = 0; + next_raw = 0; + } + } + } + if (flush && leftSize != 0 && throwOnInvalid) { + // We had left-over bytes that didn't make up + // a complete UTF-8 character sequence. + // throw new ArgumentException (_("Arg_InvalidUTF8"), "bytes"); + CopyRaw (raw, ref next_raw, chars, ref posn, length); + } + leftOverBits = leftBits; + leftOverCount = (leftSoFar | (leftSize << 4)); + + // Return the final length to the caller. + return posn - charIndex; + } + + private static void CopyRaw (byte[] raw, ref int next_raw, char[] chars, ref int posn, int length) + { + if (posn+(next_raw*2) > length) + throw new ArgumentException (_("Arg_InsufficientSpace"), "chars"); + + for (int i = 0; i < next_raw; ++i) { + chars[posn++] = EscapeByte; + chars[posn++] = (char) raw [i]; + } + + next_raw = 0; + } + + // Get the characters that result from decoding a byte buffer. + public override int GetChars (byte[] bytes, int byteIndex, int byteCount, + char[] chars, int charIndex) + { + uint leftOverBits = 0; + uint leftOverCount = 0; + return InternalGetChars (bytes, byteIndex, byteCount, chars, + charIndex, ref leftOverBits, ref leftOverCount, true, true); + } + + // Get the maximum number of bytes needed to encode a + // specified number of characters. + public override int GetMaxByteCount (int charCount) + { + if (charCount < 0) { + throw new ArgumentOutOfRangeException ("charCount", _("ArgRange_NonNegative")); + } + return charCount * 4; + } + + // Get the maximum number of characters needed to decode a + // specified number of bytes. + public override int GetMaxCharCount (int byteCount) + { + if (byteCount < 0) { + throw new ArgumentOutOfRangeException ("byteCount", _("ArgRange_NonNegative")); + } + return byteCount; + } + + // Get a Unix-specific decoder that is attached to this instance. + public override Decoder GetDecoder () + { + return new UnixDecoder (); + } + + // Get a Unix-specific encoder that is attached to this instance. + public override Encoder GetEncoder () + { + return new UnixEncoder (); + } + + // Get the Unix preamble. + public override byte[] GetPreamble () + { + return new byte [0]; + } + + // Determine if this object is equal to another. + public override bool Equals (Object value) + { + UnixEncoding enc = (value as UnixEncoding); + if (enc != null) { + return true; + } + else { + return false; + } + } + + // Get the hash code for this object. + public override int GetHashCode () + { + return base.GetHashCode (); + } + + public override byte [] GetBytes (String s) + { + if (s == null) + throw new ArgumentNullException ("s"); + + int length = GetByteCount (s); + byte [] bytes = new byte [length]; + GetBytes (s, 0, s.Length, bytes, 0); + return bytes; + } + + // Unix decoder implementation. + [Serializable] + private class UnixDecoder : Decoder + { + private uint leftOverBits; + private uint leftOverCount; + + // Constructor. + public UnixDecoder () + { + leftOverBits = 0; + leftOverCount = 0; + } + + // Override inherited methods. + public override int GetCharCount (byte[] bytes, int index, int count) + { + return InternalGetCharCount (bytes, index, count, + leftOverBits, leftOverCount, true, false); + } + public override int GetChars (byte[] bytes, int byteIndex, + int byteCount, char[] chars, int charIndex) + { + return InternalGetChars (bytes, byteIndex, byteCount, + chars, charIndex, ref leftOverBits, ref leftOverCount, true, false); + } + + } + + // Unix encoder implementation. + [Serializable] + private class UnixEncoder : Encoder + { + private uint leftOver; + + // Constructor. + public UnixEncoder () + { + leftOver = 0; + } + + // Override inherited methods. + public override int GetByteCount (char[] chars, int index, + int count, bool flush) + { + return InternalGetByteCount (chars, index, count, leftOver, flush); + } + public override int GetBytes (char[] chars, int charIndex, + int charCount, byte[] bytes, int byteCount, bool flush) + { + int result; + result = InternalGetBytes (chars, charIndex, charCount, bytes, byteCount, ref leftOver, flush); + return result; + } + } + + private static string _ (string arg) + { + return arg; + } +} +} + diff --git a/Mono.Posix/Mono.Unix/UnixEndPoint.cs b/Mono.Posix/Mono.Unix/UnixEndPoint.cs new file mode 100644 index 0000000..d7a7f0c --- /dev/null +++ b/Mono.Posix/Mono.Unix/UnixEndPoint.cs @@ -0,0 +1,133 @@ +// +// Mono.Unix.UnixEndPoint: EndPoint derived class for AF_UNIX family sockets. +// +// Authors: +// Gonzalo Paniagua Javier (gonzalo@ximian.com) +// +// (C) 2003 Ximian, Inc (http://www.ximian.com) +// + +// +// 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.Net; +using System.Net.Sockets; +using System.Text; + +namespace Mono.Unix +{ + [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 { + return(filename); + } + set { + filename=value; + } + } + + 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."); + */ + + 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); + } + } +} + diff --git a/Mono.Posix/Mono.Unix/UnixEnvironment.cs b/Mono.Posix/Mono.Unix/UnixEnvironment.cs new file mode 100644 index 0000000..e400aaa --- /dev/null +++ b/Mono.Posix/Mono.Unix/UnixEnvironment.cs @@ -0,0 +1,238 @@ +// +// Mono.Unix/UnixEnvironment.cs +// +// Authors: +// Jonathan Pryor (jonpryor@vt.edu) +// +// (C) 2004 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.Collections; +using System.Text; +using Mono.Unix; + +namespace Mono.Unix { + + public sealed /* static */ class UnixEnvironment + { + private UnixEnvironment () {} + + public static string CurrentDirectory { + get { + return UnixDirectoryInfo.GetCurrentDirectory (); + } + set { + UnixDirectoryInfo.SetCurrentDirectory (value); + } + } + + public static string MachineName { + get { + Native.Utsname buf; + if (Native.Syscall.uname (out buf) != 0) + throw UnixMarshal.CreateExceptionForLastError (); + return buf.nodename; + } + set { + int r = Native.Syscall.sethostname (value); + UnixMarshal.ThrowExceptionForLastErrorIf (r); + } + } + + public static string UserName { + get {return UnixUserInfo.GetRealUser ().UserName;} + } + + public static UnixGroupInfo RealGroup { + get {return new UnixGroupInfo (RealGroupId);} + // set can't be done as setgid(2) modifies effective gid as well + } + + public static long RealGroupId { + get {return Native.Syscall.getgid ();} + // set can't be done as setgid(2) modifies effective gid as well + } + + public static UnixUserInfo RealUser { + get {return new UnixUserInfo (RealUserId);} + // set can't be done as setuid(2) modifies effective uid as well + } + + public static long RealUserId { + get {return Native.Syscall.getuid ();} + // set can't be done as setuid(2) modifies effective uid as well + } + + public static UnixGroupInfo EffectiveGroup { + get {return new UnixGroupInfo (EffectiveGroupId);} + set {EffectiveGroupId = value.GroupId;} + } + + public static long EffectiveGroupId { + get {return Native.Syscall.getegid ();} + set {Native.Syscall.setegid (Convert.ToUInt32 (value));} + } + + public static UnixUserInfo EffectiveUser { + get {return new UnixUserInfo (EffectiveUserId);} + set {EffectiveUserId = value.UserId;} + } + + 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)); + } + } +} + +// vim: noexpandtab diff --git a/Mono.Posix/Mono.Unix/UnixFileInfo.cs b/Mono.Posix/Mono.Unix/UnixFileInfo.cs new file mode 100644 index 0000000..48248c1 --- /dev/null +++ b/Mono.Posix/Mono.Unix/UnixFileInfo.cs @@ -0,0 +1,147 @@ +// +// Mono.Unix/UnixFileInfo.cs +// +// Authors: +// Jonathan Pryor (jonpryor@vt.edu) +// +// (C) 2004-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.IO; +using System.Text; +using Mono.Unix; + +namespace Mono.Unix { + + public sealed class UnixFileInfo : UnixFileSystemInfo + { + public UnixFileInfo (string path) + : base (path) + { + } + + internal UnixFileInfo (string path, Native.Stat stat) + : base (path, stat) + { + } + + public override string Name { + get {return UnixPath.GetFileName (FullPath);} + } + + public string DirectoryName { + get {return UnixPath.GetDirectoryName (FullPath);} + } + + public UnixDirectoryInfo Directory { + get {return new UnixDirectoryInfo (DirectoryName);} + } + + public override void Delete () + { + int r = Native.Syscall.unlink (FullPath); + UnixMarshal.ThrowExceptionForLastErrorIf (r); + base.Refresh (); + } + + public UnixStream Create () + { + Native.FilePermissions mode = // 0644 + Native.FilePermissions.S_IRUSR | Native.FilePermissions.S_IWUSR | + Native.FilePermissions.S_IRGRP | Native.FilePermissions.S_IROTH; + return Create (mode); + } + + [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); + } + } +} + +// vim: noexpandtab diff --git a/Mono.Posix/Mono.Unix/UnixFileSystemInfo.cs b/Mono.Posix/Mono.Unix/UnixFileSystemInfo.cs new file mode 100644 index 0000000..149f79b --- /dev/null +++ b/Mono.Posix/Mono.Unix/UnixFileSystemInfo.cs @@ -0,0 +1,428 @@ +// +// Mono.Unix/UnixFileSystemInfo.cs +// +// Authors: +// Jonathan Pryor (jonpryor@vt.edu) +// +// (C) 2004-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.IO; +using System.Text; +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; + } + } +} + +// vim: noexpandtab diff --git a/Mono.Posix/Mono.Unix/UnixGroupInfo.cs b/Mono.Posix/Mono.Unix/UnixGroupInfo.cs new file mode 100644 index 0000000..c320eed --- /dev/null +++ b/Mono.Posix/Mono.Unix/UnixGroupInfo.cs @@ -0,0 +1,149 @@ +// +// Mono.Unix/UnixGroupInfo.cs +// +// Authors: +// Jonathan Pryor (jonpryor@vt.edu) +// +// (C) 2004-2005 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.Collections; +using System.Text; +using Mono.Unix; + +namespace Mono.Unix { + + public sealed class UnixGroupInfo + { + private 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 (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)); + } + } +} + +// vim: noexpandtab diff --git a/Mono.Posix/Mono.Unix/UnixIOException.cs b/Mono.Posix/Mono.Unix/UnixIOException.cs new file mode 100644 index 0000000..923e7aa --- /dev/null +++ b/Mono.Posix/Mono.Unix/UnixIOException.cs @@ -0,0 +1,104 @@ +// +// Mono.Unix/UnixIOException.cs +// +// Authors: +// Jonathan Pryor (jonpryor@vt.edu) +// +// (C) 2004-2005 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.IO; +using System.Runtime.InteropServices; +using System.Runtime.Serialization; +using Mono.Unix; + +namespace Mono.Unix { + + [Serializable] + public class UnixIOException : IOException + { + private int 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 (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 (string message) + : base (message) + { + 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); + } + } +} + +// vim: noexpandtab diff --git a/Mono.Posix/Mono.Unix/UnixListener.cs b/Mono.Posix/Mono.Unix/UnixListener.cs new file mode 100644 index 0000000..d766af6 --- /dev/null +++ b/Mono.Posix/Mono.Unix/UnixListener.cs @@ -0,0 +1,173 @@ +// +// UnixListener.cs +// +// Authors: +// Joe Shaw (joeshaw@novell.com) +// +// Copyright (C) 2004-2005 Novell, Inc. +// + +// +// 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.Net; +using System.Net.Sockets; +using System.IO; + +namespace Mono.Unix { + + public class UnixListener : MarshalByRefObject, IDisposable { + bool disposed; + bool 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); + } + + server = new Socket (AddressFamily.Unix, SocketType.Stream, 0); + server.Bind (ep); + savedEP = server.LocalEndPoint; + } + + 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 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); + } + + public bool Pending () + { + CheckDisposed (); + if (!listening) + throw new InvalidOperationException ("Socket is not listening"); + + return server.Poll (1000, SelectMode.SelectRead); + } + + 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); + } + } + +} diff --git a/Mono.Posix/Mono.Unix/UnixMarshal.cs b/Mono.Posix/Mono.Unix/UnixMarshal.cs new file mode 100644 index 0000000..7d39fd4 --- /dev/null +++ b/Mono.Posix/Mono.Unix/UnixMarshal.cs @@ -0,0 +1,496 @@ +// +// Mono.Unix/UnixMarshal.cs +// +// Authors: +// Jonathan Pryor (jonpryor@vt.edu) +// +// (C) 2004-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.IO; +using System.Net.Sockets; +using System.Runtime.InteropServices; +using System.Runtime.Serialization; +using System.Text; +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 (); + } + } +} + +// vim: noexpandtab diff --git a/Mono.Posix/Mono.Unix/UnixPath.cs b/Mono.Posix/Mono.Unix/UnixPath.cs new file mode 100644 index 0000000..e577edb --- /dev/null +++ b/Mono.Posix/Mono.Unix/UnixPath.cs @@ -0,0 +1,286 @@ +// +// Mono.Unix/UnixPath.cs +// +// Authors: +// Jonathan Pryor (jonpryor@vt.edu) +// +// (C) 2004-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.Collections; +using System.Text; +using Mono.Unix; + +namespace Mono.Unix { + + 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 = '/'; + + private static readonly char[] _InvalidPathChars = new char[]{}; + + public static char[] GetInvalidPathChars () + { + return (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"); + + 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; + } + + 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 (); + } + + 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 GetDirectoryName (string path) + { + CheckPath (path); + + int lastDir = path.LastIndexOf (DirectorySeparatorChar); + if (lastDir > 0) + return path.Substring (0, lastDir); + if (lastDir == 0) + return "/"; + return ""; + } + + public static string GetFileName (string path) + { + if (path == null || path.Length == 0) + return path; + + int lastDir = path.LastIndexOf (DirectorySeparatorChar); + if (lastDir >= 0) + return path.Substring (lastDir+1); + + return path; + } + + public static string GetFullPath (string path) + { + path = _GetFullPath (path); + return GetCanonicalPath (path); + } + + 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 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; + } + + 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 GetPathRoot (string path) + { + if (path == null) + return null; + if (!IsPathRooted (path)) + return ""; + return "/"; + } + + 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 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); + } + + // 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"); + } + } +} + +// vim: noexpandtab diff --git a/Mono.Posix/Mono.Unix/UnixPipes.cs b/Mono.Posix/Mono.Unix/UnixPipes.cs new file mode 100644 index 0000000..9128a86 --- /dev/null +++ b/Mono.Posix/Mono.Unix/UnixPipes.cs @@ -0,0 +1,88 @@ +// +// Mono.Unix/UnixPipes.cs +// +// Authors: +// Jonathan Pryor (jonpryor@vt.edu) +// +// (C) 2004-2005 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.IO; +using System.Text; +using Mono.Unix; + +namespace Mono.Unix { + + public struct UnixPipes + : IEquatable + { + public UnixPipes (UnixStream reading, UnixStream writing) + { + Reading = reading; + Writing = 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 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 bool Equals (UnixPipes value) + { + return Reading.Handle == value.Reading.Handle && + Writing.Handle == value.Writing.Handle; + } + + public override int GetHashCode () + { + return Reading.Handle.GetHashCode () ^ Writing.Handle.GetHashCode (); + } + + public static bool operator== (UnixPipes lhs, UnixPipes rhs) + { + return lhs.Equals (rhs); + } + + public static bool operator!= (UnixPipes lhs, UnixPipes rhs) + { + return !lhs.Equals (rhs); + } + } +} + +// vim: noexpandtab diff --git a/Mono.Posix/Mono.Unix/UnixProcess.cs b/Mono.Posix/Mono.Unix/UnixProcess.cs new file mode 100644 index 0000000..3360ef2 --- /dev/null +++ b/Mono.Posix/Mono.Unix/UnixProcess.cs @@ -0,0 +1,157 @@ +// +// Mono.Unix/UnixProcess.cs +// +// Authors: +// Jonathan Pryor (jonpryor@vt.edu) +// +// (C) 2004-2005 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 Mono.Unix; + +namespace Mono.Unix { + + public sealed class UnixProcess + { + private int pid; + + internal UnixProcess (int pid) + { + this.pid = pid; + } + + public int Id { + get {return pid;} + } + + public bool HasExited { + get { + int status = 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; + } + + public int ExitCode { + get { + if (!HasExited) + throw new InvalidOperationException ( + Locale.GetText ("Process hasn't exited")); + int status = GetProcessStatus (); + return Native.Syscall.WEXITSTATUS (status); + } + } + + public bool HasSignaled { + get { + int status = 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 bool HasStopped { + get { + int status = 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 int ProcessGroupId { + get {return Native.Syscall.getpgid (pid);} + set { + int r = Native.Syscall.setpgid (pid, value); + UnixMarshal.ThrowExceptionForLastErrorIf (r); + } + } + + public int SessionId { + get { + int r = Native.Syscall.getsid (pid); + UnixMarshal.ThrowExceptionForLastErrorIf (r); + return r; + } + } + + public static UnixProcess GetCurrentProcess () + { + return new UnixProcess (GetCurrentProcessId ()); + } + + public static int GetCurrentProcessId () + { + return Native.Syscall.getpid (); + } + + public void Kill () + { + Signal (Native.Signum.SIGKILL); + } + + [CLSCompliant (false)] + public void Signal (Native.Signum signal) + { + int r = Native.Syscall.kill (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); + } + } +} + +// vim: noexpandtab diff --git a/Mono.Posix/Mono.Unix/UnixSignal.cs b/Mono.Posix/Mono.Unix/UnixSignal.cs new file mode 100644 index 0000000..39d25ca --- /dev/null +++ b/Mono.Posix/Mono.Unix/UnixSignal.cs @@ -0,0 +1,227 @@ +// +// Mono.Unix/UnixSignal.cs +// +// Authors: +// Jonathan Pryor (jpryor@novell.com) +// Tim Jenks (tim.jenks@realtimeworlds.com) +// +// (C) 2008 Novell, Inc. +// +// 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.Runtime.InteropServices; +using System.Threading; + +using Mono.Unix.Native; + +namespace Mono.Unix { + + public class UnixSignal : WaitHandle { + private int signum; + private IntPtr signal_info; + + 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 (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 Signum Signum { + get { + if (IsRealTimeSignal) + throw new InvalidOperationException ("This signal is a RealTimeSignum"); + return NativeConvert.ToSignum (signum); + } + } + + public RealTimeSignum RealTimeSignum { + get { + if (!IsRealTimeSignal) + throw new InvalidOperationException ("This signal is not a RealTimeSignum"); + return NativeConvert.ToRealTimeSignum (signum-GetSIGRTMIN ()); + } + } + + public bool IsRealTimeSignal { + get { + AssertValid (); + int sigrtmin = GetSIGRTMIN (); + if (sigrtmin == -1) + return false; + return 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_uninstall")] + private static extern int 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; + } + + [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_Posix_SIGRTMIN")] + internal static extern int GetSIGRTMIN (); + + [DllImport (Stdlib.MPH, CallingConvention=CallingConvention.Cdecl, + EntryPoint="Mono_Posix_SIGRTMAX")] + internal static extern int GetSIGRTMAX (); + + private void AssertValid () + { + if (signal_info == IntPtr.Zero) + throw new ObjectDisposedException (GetType().FullName); + } + + private unsafe SignalInfo* Info { + get { + AssertValid (); + return (SignalInfo*) signal_info; + } + } + + public bool IsSet { + get { + return Count > 0; + } + } + + public unsafe bool Reset () + { + int n = Interlocked.Exchange (ref Info->count, 0); + return n != 0; + } + + public unsafe int Count { + get {return Info->count;} + set {Interlocked.Exchange (ref 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 +#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 + } +#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; + } + + public override bool WaitOne () + { + return 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 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 static int WaitAny (UnixSignal[] signals) + { + return 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 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); + } + } +} + diff --git a/Mono.Posix/Mono.Unix/UnixStream.cs b/Mono.Posix/Mono.Unix/UnixStream.cs new file mode 100644 index 0000000..8a94a7d --- /dev/null +++ b/Mono.Posix/Mono.Unix/UnixStream.cs @@ -0,0 +1,435 @@ +// +// Mono.Unix/UnixStream.cs +// +// Authors: +// Jonathan Pryor (jonpryor@vt.edu) +// +// (C) 2004-2006 Jonathan Pryor +// (C) 2007 Novell, Inc. +// +// +// 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.IO; +using System.Runtime.InteropServices; +using System.Text; +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 UnixStream (int 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; + } + + private void AssertNotDisposed () + { + if (fileDescriptor == InvalidFileDescriptor) + throw new ObjectDisposedException ("Invalid File Descriptor"); + } + + public int Handle { + get {return fileDescriptor;} + } + + public override bool CanRead { + get {return canRead;} + } + + public override bool CanSeek { + get {return canSeek;} + } + + public override bool CanWrite { + get {return 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 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); + } + } + + [CLSCompliant (false)] + public Native.FilePermissions Protection { + get { + RefreshStat (); + return stat.st_mode; + } + set { + // we can't change file type with fchmod, so clear out that portion + value &= ~Native.FilePermissions.S_IFMT; + int r = Native.Syscall.fchmod (fileDescriptor, value); + UnixMarshal.ThrowExceptionForLastErrorIf (r); + } + } + + public 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 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 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 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;} + } + + private void RefreshStat () + { + AssertNotDisposed (); + int r = Native.Syscall.fstat (fileDescriptor, out stat); + UnixMarshal.ThrowExceptionForLastErrorIf (r); + } + + public void AdviseFileAccessPattern (FileAccessPattern pattern, long offset, long len) + { + FileHandleOperations.AdviseFileAccessPattern (fileDescriptor, pattern, offset, len); + } + + public void AdviseFileAccessPattern (FileAccessPattern pattern) + { + AdviseFileAccessPattern (pattern, 0, 0); + } + + 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; + + 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, 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 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; + + 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; + } + + 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; + } + + long pos = Native.Syscall.lseek (fileDescriptor, offset, sf); + if (pos == -1) + UnixMarshal.ThrowExceptionForLastError (); + return (long) pos; + } + + 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 override unsafe void Write (byte[] buffer, int offset, int count) + { + AssertNotDisposed (); + AssertValidBuffer (buffer, offset, count); + if (!CanWrite) + throw new NotSupportedException ("File Descriptor does not support writing"); + + if (buffer.Length == 0) + return; + + 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"); + + if (buffer.Length == 0) + return; + + 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 (); + } + + public void SendTo (UnixStream output) + { + SendTo (output, (ulong) output.Length); + } + + [CLSCompliant (false)] + public void SendTo (UnixStream output, ulong count) + { + SendTo (output.Handle, count); + } + + [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 (); + + int r = Native.Syscall.fchown (fileDescriptor, + Convert.ToUInt32 (user), Convert.ToUInt32 (group)); + UnixMarshal.ThrowExceptionForLastErrorIf (r); + } + + public void SetOwner (string user, string group) + { + AssertNotDisposed (); + + long uid = new UnixUserInfo (user).UserId; + long gid = new UnixGroupInfo (group).GroupId; + SetOwner (uid, gid); + } + + 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; + } +} + +// vim: noexpandtab diff --git a/Mono.Posix/Mono.Unix/UnixSymbolicLinkInfo.cs b/Mono.Posix/Mono.Unix/UnixSymbolicLinkInfo.cs new file mode 100644 index 0000000..242a294 --- /dev/null +++ b/Mono.Posix/Mono.Unix/UnixSymbolicLinkInfo.cs @@ -0,0 +1,108 @@ +// +// Mono.Unix/UnixSymbolicLinkInfo.cs +// +// Authors: +// Jonathan Pryor (jonpryor@vt.edu) +// +// (C) 2004-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.IO; +using System.Text; +using Mono.Unix; + +namespace Mono.Unix { + + public sealed class UnixSymbolicLinkInfo : UnixFileSystemInfo + { + public UnixSymbolicLinkInfo (string path) + : base (path) + { + } + + internal UnixSymbolicLinkInfo (string path, Native.Stat stat) + : base (path, stat) + { + } + + public override string Name { + get {return UnixPath.GetFileName (FullPath);} + } + + [Obsolete ("Use GetContents()")] + public UnixFileSystemInfo Contents { + get {return GetContents ();} + } + + public string ContentsPath { + get { + return UnixPath.ReadLink (FullPath); + } + } + + public bool HasContents { + get { + return UnixPath.TryReadLink (FullPath) != null; + } + } + + public UnixFileSystemInfo GetContents () + { + return UnixFileSystemInfo.GetFileSystemEntry ( + UnixPath.Combine (UnixPath.GetDirectoryName (FullPath), + ContentsPath)); + } + + public void CreateSymbolicLinkTo (string path) + { + int r = Native.Syscall.symlink (path, FullName); + UnixMarshal.ThrowExceptionForLastErrorIf (r); + } + + public void CreateSymbolicLinkTo (UnixFileSystemInfo path) + { + int r = Native.Syscall.symlink (path.FullName, FullName); + UnixMarshal.ThrowExceptionForLastErrorIf (r); + } + + public override void Delete () + { + int r = Native.Syscall.unlink (FullPath); + UnixMarshal.ThrowExceptionForLastErrorIf (r); + base.Refresh (); + } + + public override void SetOwner (long owner, long group) + { + int r = Native.Syscall.lchown (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; + } + } +} + +// vim: noexpandtab diff --git a/Mono.Posix/Mono.Unix/UnixUserInfo.cs b/Mono.Posix/Mono.Unix/UnixUserInfo.cs new file mode 100644 index 0000000..3379ebf --- /dev/null +++ b/Mono.Posix/Mono.Unix/UnixUserInfo.cs @@ -0,0 +1,193 @@ +// +// Mono.Unix/UnixUserInfo.cs +// +// Authors: +// Jonathan Pryor (jonpryor@vt.edu) +// +// (C) 2004-2005 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.Collections; +using System.Text; +using Mono.Unix; + +namespace Mono.Unix { + + public sealed class UnixUserInfo + { + private 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"); + } + + [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"); + } + + 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 (Native.Passwd passwd) + { + this.passwd = CopyPasswd (passwd); + } + + private static Native.Passwd CopyPasswd (Native.Passwd pw) + { + Native.Passwd p = new Native.Passwd (); + + 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; + + return p; + } + + public string UserName { + get {return passwd.pw_name;} + } + + public string Password { + get {return passwd.pw_passwd;} + } + + public long UserId { + get {return passwd.pw_uid;} + } + + public UnixGroupInfo Group { + get {return new UnixGroupInfo (passwd.pw_gid);} + } + + public long GroupId { + get {return passwd.pw_gid;} + } + + public string GroupName { + get {return Group.GroupName;} + } + + public string RealName { + get {return passwd.pw_gecos;} + } + + public string HomeDirectory { + get {return passwd.pw_dir;} + } + + public string ShellProgram { + get {return passwd.pw_shell;} + } + + public override int GetHashCode () + { + return passwd.GetHashCode (); + } + + public override bool Equals (object obj) + { + if (obj == null || GetType () != obj.GetType()) + return false; + return passwd.Equals (((UnixUserInfo) obj).passwd); + } + + public override string ToString () + { + return passwd.ToString (); + } + + public static UnixUserInfo GetRealUser () + { + return new UnixUserInfo (GetRealUserId ()); + } + + public static long GetRealUserId () + { + return Native.Syscall.getuid (); + } + + // 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)); + } + } +} + +// vim: noexpandtab diff --git a/Mono.Posix/Properties/AssemblyInfo.cs b/Mono.Posix/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..0646afd --- /dev/null +++ b/Mono.Posix/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Allgemeine Informationen über eine Assembly werden über die folgenden +// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, +// die einer Assembly zugeordnet sind. +[assembly: AssemblyTitle("Mono.Posix.dll")] +[assembly: AssemblyDescription("Unix Integration Classes")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Mono development team")] +[assembly: AssemblyProduct("Mono Common Language Infrastructure")] +[assembly: AssemblyCopyright("(c) Various Mono authors")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly +// für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von +// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen. +[assembly: ComVisible(false)] + +// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird +[assembly: Guid("e2ca132e-e85c-40ad-be94-b138aa68772b")] + +// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: +// +// Hauptversion +// Nebenversion +// Buildnummer +// Revision +// +// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden, +// indem Sie "*" wie unten gezeigt eingeben: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("4.6.57.0")] +[assembly: AssemblyFileVersion("4.6.57.0")]