diff --git a/Claunia.IO/ChangeLog b/Claunia.IO/ChangeLog index 773b77a..a70b9d3 100644 --- a/Claunia.IO/ChangeLog +++ b/Claunia.IO/ChangeLog @@ -1,3 +1,12 @@ +2015-02-12 Natalia Portillo + + * Claunia.IO.csproj: + * Tests/Interop.Apple.cs: + * Tests/Interop.DetectOS.cs: + * Interop/Interop.DetectOS.cs: + * Interop/Interop.PlatformID.cs: + Added code to detect real OS platform. + 2015-02-12 Natalia Portillo * Interop/Apple/Interop.Apple.Errors.cs: diff --git a/Claunia.IO/Claunia.IO.csproj b/Claunia.IO/Claunia.IO.csproj index 3958474..ac376e9 100644 --- a/Claunia.IO/Claunia.IO.csproj +++ b/Claunia.IO/Claunia.IO.csproj @@ -45,6 +45,9 @@ + + + diff --git a/Claunia.IO/Interop/Interop.DetectOS.cs b/Claunia.IO/Interop/Interop.DetectOS.cs new file mode 100644 index 0000000..1d030c0 --- /dev/null +++ b/Claunia.IO/Interop/Interop.DetectOS.cs @@ -0,0 +1,189 @@ +// +// Interop.DetectOS.cs +// +// Author: +// Natalia Portillo +// +// Copyright (c) 2015 © Claunia.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.InteropServices; + +internal static partial class Interop +{ + public static class DetectOS + { + /// + /// POSIX uname structure, size from OSX, big enough to handle extra fields + /// + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + struct utsname + { + /// + /// System name + /// + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public string sysname; + /// + /// Node name + /// + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public string nodename; + /// + /// Release level + /// + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public string release; + /// + /// Version level + /// + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public string version; + /// + /// Hardware level + /// + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public string machine; + } + + [DllImport("libc", SetLastError = true)] + static extern int uname(out utsname name); + + [DllImport("libc", SetLastError = true, EntryPoint = "sysctlbyname", CharSet = CharSet.Ansi)] + static extern int OSX_sysctlbyname(string name, IntPtr oldp, IntPtr oldlenp, IntPtr newp, uint newlen); + + public static Interop.PlatformID GetRealPlatformID() + { + if ((int)Environment.OSVersion.Platform < 4 || + (int)Environment.OSVersion.Platform == 5) + { + return (Interop.PlatformID)((int)Environment.OSVersion.Platform); + } + + utsname unixname; + int error = uname(out unixname); + if (error != 0) + throw new Exception(String.Format("Unhandled exception calling uname: {0}", Marshal.GetLastWin32Error())); + + switch (unixname.sysname) + { + // TODO: Differentiate Linux, Android, Tizen + case "Linux": + { + #if __ANDROID__ + return PlatformID.Android; + #else + return PlatformID.Linux; + #endif + } + case "Darwin": + { + int osx_error; + + IntPtr pLen = Marshal.AllocHGlobal(sizeof(int)); + osx_error = OSX_sysctlbyname("hw.machine", IntPtr.Zero, pLen, IntPtr.Zero, 0); + if (osx_error != 0) + { + Marshal.FreeHGlobal(pLen); + + throw new Exception(String.Format("Unhandled exception calling uname: {0}", Marshal.GetLastWin32Error())); + } + + int length = Marshal.ReadInt32(pLen); + IntPtr pStr = Marshal.AllocHGlobal(length); + osx_error = OSX_sysctlbyname("hw.machine", pStr, pLen, IntPtr.Zero, 0); + if (osx_error != 0) + { + Marshal.FreeHGlobal(pStr); + Marshal.FreeHGlobal(pLen); + + throw new Exception(String.Format("Unhandled exception calling uname: {0}", Marshal.GetLastWin32Error())); + } + + string machine = Marshal.PtrToStringAnsi(pStr); + + Marshal.FreeHGlobal(pStr); + Marshal.FreeHGlobal(pLen); + + if (machine.StartsWith("iPad", StringComparison.Ordinal) || + machine.StartsWith("iPod", StringComparison.Ordinal) || + machine.StartsWith("iPhone", StringComparison.Ordinal)) + return PlatformID.iOS; + + return PlatformID.MacOSX; + } + case "GNU": + return PlatformID.Hurd; + case "FreeBSD": + case "GNU/kFreeBSD": + return PlatformID.FreeBSD; + case "DragonFly": + return PlatformID.DragonFly; + case "Haiku": + return PlatformID.Haiku; + case "HP-UX": + return PlatformID.HPUX; + case "AIX": + return PlatformID.AIX; + case "OS400": + return PlatformID.OS400; + case "IRIX": + case "IRIX64": + return PlatformID.IRIX; + case "Minix": + return PlatformID.Minix; + case "NetBSD": + return PlatformID.NetBSD; + case "NONSTOP_KERNEL": + return PlatformID.NonStop; + case "OpenBSD": + return PlatformID.OpenBSD; + case "QNX": + return PlatformID.QNX; + case "SINIX-Y": + return PlatformID.SINIX; + case "SunOS": + return PlatformID.Solaris; + case "OSF1": + return PlatformID.Tru64; + case "ULTRIX": + return PlatformID.Ultrix; + case "SCO_SV": + return PlatformID.OpenServer; + case "UnixWare": + return PlatformID.UnixWare; + case "Interix": + case "UWIN-W7": + return PlatformID.Win32NT; + default: + { + if (unixname.sysname.StartsWith("CYGWIN_NT", StringComparison.Ordinal) || + unixname.sysname.StartsWith("MINGW32_NT", StringComparison.Ordinal) || + unixname.sysname.StartsWith("MSYS_NT", StringComparison.Ordinal) || + unixname.sysname.StartsWith("UWIN", StringComparison.Ordinal)) + return PlatformID.Win32NT; + + return PlatformID.Unknown; + } + } + } + } +} + diff --git a/Claunia.IO/Interop/Interop.PlatformID.cs b/Claunia.IO/Interop/Interop.PlatformID.cs new file mode 100644 index 0000000..585336d --- /dev/null +++ b/Claunia.IO/Interop/Interop.PlatformID.cs @@ -0,0 +1,179 @@ +// +// Interop.PlatformID.cs +// +// Author: +// Natalia Portillo +// +// Copyright (c) 2015 © Claunia.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 static partial class Interop +{ + public enum PlatformID + { + /// + /// Win32s + /// + Win32S = 0, + /// + /// Win32 (Windows 9x) + /// + Win32Windows = 1, + /// + /// Windows NT + /// + Win32NT = 2, + /// + /// Windows Mobile + /// + WinCE = 3, + /// + /// UNIX (do not use, too generic) + /// + Unix = 4, + /// + /// Xbox 360 + /// + Xbox = 5, + /// + /// OS X + /// + MacOSX = 6, + /// + /// iOS is not OS X + /// + iOS = 7, + /// + /// Linux + /// + Linux = 8, + /// + /// Sun Solaris + /// + Solaris = 9, + /// + /// NetBSD + /// + NetBSD = 10, + /// + /// OpenBSD + /// + OpenBSD = 11, + /// + /// FreeBSD + /// + FreeBSD = 12, + /// + /// DragonFly BSD + /// + DragonFly = 13, + /// + /// Nintendo Wii + /// + Wii = 14, + /// + /// Nintendo Wii U + /// + WiiU = 15, + /// + /// Sony PlayStation 3 + /// + PlayStation3 = 16, + /// + /// Sony Playstation 4 + /// + PlayStation4 = 17, + /// + /// Google Android + /// + Android = 18, + /// + /// Samsung Tizen + /// + Tizen = 19, + /// + /// Windows Phone + /// + WindowsPhone = 20, + /// + /// GNU/Hurd + /// + Hurd = 21, + /// + /// Haiku + /// + Haiku = 22, + /// + /// HP-UX + /// + HPUX = 23, + /// + /// AIX + /// + AIX = 24, + /// + /// OS/400 + /// + OS400 = 25, + /// + /// IRIX + /// + IRIX = 26, + /// + /// Minix + /// + Minix = 27, + /// + /// NonStop + /// + NonStop = 28, + /// + /// QNX + /// + QNX = 29, + /// + /// SINIX + /// + SINIX = 30, + /// + /// Tru64 UNIX + /// + Tru64 = 31, + /// + /// Ultrix + /// + Ultrix = 32, + /// + /// SCO OpenServer / SCO UNIX + /// + OpenServer = 33, + /// + /// SCO UnixWare + /// + UnixWare = 34, + /// + /// IBM z/OS + /// + zOS = 35, + Unknown = -1 + } +} + diff --git a/Claunia.IO/Tests/Interop.Apple.cs b/Claunia.IO/Tests/Interop.Apple.cs index f705841..5641979 100644 --- a/Claunia.IO/Tests/Interop.Apple.cs +++ b/Claunia.IO/Tests/Interop.Apple.cs @@ -37,7 +37,7 @@ namespace Tests public void TestStat() { // Take care, Mono returns UNIX for Mac OS X - if (Environment.OSVersion.Platform == PlatformID.MacOSX || Environment.OSVersion.Platform == PlatformID.Unix) + if (Interop.DetectOS.GetRealPlatformID() == Interop.PlatformID.MacOSX || Interop.DetectOS.GetRealPlatformID() == Interop.PlatformID.iOS) { string testFile = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "/.localized"; @@ -80,7 +80,7 @@ namespace Tests public void TestStat64() { // Take care, Mono returns UNIX for Mac OS X - if (Environment.OSVersion.Platform == PlatformID.MacOSX || Environment.OSVersion.Platform == PlatformID.Unix) + if (Interop.DetectOS.GetRealPlatformID() == Interop.PlatformID.MacOSX || Interop.DetectOS.GetRealPlatformID() == Interop.PlatformID.iOS) { string testFile = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "/.localized"; diff --git a/Claunia.IO/Tests/Interop.DetectOS.cs b/Claunia.IO/Tests/Interop.DetectOS.cs new file mode 100644 index 0000000..3201899 --- /dev/null +++ b/Claunia.IO/Tests/Interop.DetectOS.cs @@ -0,0 +1,43 @@ +// +// Interop.DetectOS.cs +// +// Author: +// Natalia Portillo +// +// Copyright (c) 2015 © Claunia.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 NUnit.Framework; + +namespace Tests +{ + [TestFixture] + public class InteropDetectOS + { + [Test] + public void DetectOS() + { + Interop.PlatformID pid = Interop.DetectOS.GetRealPlatformID(); + + Assert.AreEqual(Interop.PlatformID.MacOSX, pid, "This test only works on OS X but in the fail you'll see the detected OS"); + } + } +} +