ILRepack/LibC.cs (393 lines of code) (raw):

using System; using System.Runtime.InteropServices; namespace ILRepacking { [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "<Pending>")] internal static class LibC { [DllImport("libc", SetLastError = true)] private static extern int chmod(string path, uint mode); [DllImport("libc", SetLastError = true)] private static extern int uname(IntPtr buf); private class RuntimeInfo { public enum ProcessorArchitecture { Amd64, Arm64 } public enum OsKind { Linux, MacOs } public readonly ProcessorArchitecture Architecture; public readonly OsKind Os; private RuntimeInfo(OsKind os, ProcessorArchitecture processorArchitecture) { Os = os; Architecture = processorArchitecture; } public static readonly Lazy<RuntimeInfo> Current = new Lazy<RuntimeInfo>(() => { var buf = IntPtr.Zero; try { buf = Marshal.AllocHGlobal(8192); var rc = uname(buf); if (rc != 0) { throw new Exception("uname() from libc returned " + rc); } OsKind platform; switch (Marshal.PtrToStringAnsi(buf)) { case "Darwin": platform = OsKind.MacOs; break; case "Linux": platform = OsKind.Linux; break; default: throw new PlatformNotSupportedException(); } var isMacOs = platform == OsKind.MacOs; var nameLen = isMacOs ? 256 : 65; const int machineIndex = 4; var arch = Marshal.PtrToStringAnsi(buf + machineIndex * nameLen); if (isMacOs) { switch (arch) { case "arm64": return new RuntimeInfo(OsKind.MacOs, ProcessorArchitecture.Arm64); case "x86_64": return new RuntimeInfo(OsKind.MacOs, ProcessorArchitecture.Amd64); default: throw new PlatformNotSupportedException(); } } else { switch (arch) { case "aarch64": return new RuntimeInfo(OsKind.Linux, ProcessorArchitecture.Arm64); case "x86_64": return new RuntimeInfo(OsKind.Linux, ProcessorArchitecture.Amd64); default: throw new PlatformNotSupportedException(); } } } finally { if (buf != IntPtr.Zero) Marshal.FreeHGlobal(buf); } }); } public static int ChMod(string path, uint mode) { AssertIsUnix(); return chmod(path, mode); } public static int Stat(string path, out XPlatLayout.stat stat) { AssertIsUnix(); if (RuntimeInfo.Current.Value.Os == RuntimeInfo.OsKind.MacOs) { switch (RuntimeInfo.Current.Value.Architecture) { case RuntimeInfo.ProcessorArchitecture.Amd64: return MacOs.stat_x64(path, out stat); case RuntimeInfo.ProcessorArchitecture.Arm64: return MacOs.stat_arm64(path, out stat); default: throw new PlatformNotSupportedException(); } } switch (RuntimeInfo.Current.Value.Architecture) { case RuntimeInfo.ProcessorArchitecture.Amd64: return Linux.stat_x64(path, out stat); case RuntimeInfo.ProcessorArchitecture.Arm64: return Linux.stat_arm64(path, out stat); default: throw new PlatformNotSupportedException(); } } private static void AssertIsUnix() { if (Environment.OSVersion.Platform != PlatformID.MacOSX && Environment.OSVersion.Platform != PlatformID.Unix && Environment.Is64BitOperatingSystem) { throw new PlatformNotSupportedException(); } } public static class XPlatLayout { public struct TimeSpec { public long tv_sec; public ulong tv_nsec; } public struct stat { public ulong st_dev; public ulong st_ino; public uint st_mode; public ulong st_nlink; public uint st_uid; public uint st_gid; public ulong st_rdev; public long st_size; public TimeSpec st_atim; public TimeSpec st_mtim; public TimeSpec st_ctim; public long st_blksize; public long st_blocks; } } private static class Linux { private const string LibraryName = "libc"; private const int Ver = 1; private static class Interop { [DllImport(LibraryName, SetLastError = true)] public static extern unsafe int __xstat(int ver, string path, void* stat); } private static class Layout { public static class X64 { [StructLayout(LayoutKind.Explicit, Size = 144)] public struct stat { [FieldOffset(0)] public ulong st_dev; [FieldOffset(8)] public ulong st_ino; [FieldOffset(16)] public ulong st_nlink; [FieldOffset(24)] public uint st_mode; [FieldOffset(28)] public uint st_uid; [FieldOffset(32)] public uint st_gid; [FieldOffset(40)] public ulong st_rdev; [FieldOffset(48)] public long st_size; [FieldOffset(56)] public long st_blksize; [FieldOffset(64)] public long st_blocks; [FieldOffset(72)] public Bitness64.timespec st_atim; [FieldOffset(88)] public Bitness64.timespec st_mtim; [FieldOffset(104)] public Bitness64.timespec st_ctim; } } public static class Arm64 { [StructLayout(LayoutKind.Explicit, Size = 128)] public struct stat { [FieldOffset(0)] public ulong st_dev; [FieldOffset(8)] public ulong st_ino; [FieldOffset(16)] public uint st_mode; [FieldOffset(20)] public uint st_nlink; [FieldOffset(24)] public uint st_uid; [FieldOffset(28)] public uint st_gid; [FieldOffset(32)] public ulong st_rdev; [FieldOffset(48)] public long st_size; [FieldOffset(56)] public int st_blksize; [FieldOffset(64)] public long st_blocks; [FieldOffset(72)] public Bitness64.timespec st_atim; [FieldOffset(88)] public Bitness64.timespec st_mtim; [FieldOffset(104)] public Bitness64.timespec st_ctim; } } public static class Bitness64 { [StructLayout(LayoutKind.Explicit, Size = 16)] public struct timespec { [FieldOffset(0)] public long tv_sec; [FieldOffset(8)] public ulong tv_nsec; } } } public static unsafe int stat_x64(string path, out XPlatLayout.stat stat) { Layout.X64.stat tmp; var errno = Interop.__xstat(Ver, path, &tmp) != 0 ? Marshal.GetLastWin32Error() : 0; stat = new XPlatLayout.stat { st_dev = tmp.st_dev, st_ino = tmp.st_ino, st_mode = tmp.st_mode, st_nlink = tmp.st_nlink, st_uid = tmp.st_uid, st_gid = tmp.st_gid, st_rdev = tmp.st_rdev, st_size = tmp.st_size, st_atim = new XPlatLayout.TimeSpec { tv_sec = tmp.st_atim.tv_sec, tv_nsec = tmp.st_atim.tv_nsec, }, st_mtim = new XPlatLayout.TimeSpec { tv_sec = tmp.st_mtim.tv_sec, tv_nsec = tmp.st_mtim.tv_nsec, }, st_ctim = new XPlatLayout.TimeSpec { tv_sec = tmp.st_ctim.tv_sec, tv_nsec = tmp.st_ctim.tv_nsec, }, st_blksize = tmp.st_blksize, st_blocks = tmp.st_blocks }; return errno; } public static unsafe int stat_arm64(string path, out XPlatLayout.stat stat) { Layout.Arm64.stat tmp; var errno = Interop.__xstat(0, path, &tmp) != 0 ? Marshal.GetLastWin32Error() : 0; stat = new XPlatLayout.stat { st_dev = tmp.st_dev, st_ino = tmp.st_ino, st_mode = tmp.st_mode, st_nlink = tmp.st_nlink, st_uid = tmp.st_uid, st_gid = tmp.st_gid, st_rdev = tmp.st_rdev, st_size = tmp.st_size, st_atim = new XPlatLayout.TimeSpec { tv_sec = tmp.st_atim.tv_sec, tv_nsec = tmp.st_atim.tv_nsec, }, st_mtim = new XPlatLayout.TimeSpec { tv_sec = tmp.st_mtim.tv_sec, tv_nsec = tmp.st_mtim.tv_nsec, }, st_ctim = new XPlatLayout.TimeSpec { tv_sec = tmp.st_ctim.tv_sec, tv_nsec = tmp.st_ctim.tv_nsec, }, st_blksize = tmp.st_blksize, st_blocks = tmp.st_blocks }; return errno; } } private static class MacOs { private static class Interop { private const string LibraryName = "/usr/lib/system/libsystem_kernel.dylib"; [DllImport(LibraryName, EntryPoint = "stat$INODE64", SetLastError = true)] public static extern unsafe int stat_INODE64(string path, void* stat); [DllImport(LibraryName, SetLastError = true)] public static extern unsafe int stat(string path, void* stat); } private static class Layout { [StructLayout(LayoutKind.Explicit, Size = 144)] internal struct stat { [FieldOffset(0)] public int st_dev; [FieldOffset(4)] public ushort st_mode; [FieldOffset(6)] public ushort st_nlink; [FieldOffset(8)] public ulong st_ino; [FieldOffset(16)] public uint st_uid; [FieldOffset(20)] public uint st_gid; [FieldOffset(24)] public long st_rdev; [FieldOffset(32)] public timespec st_atimespec; [FieldOffset(48)] public timespec st_mtimespec; [FieldOffset(64)] public timespec st_ctimespec; [FieldOffset(80)] public timespec st_birthtimespec; [FieldOffset(96)] public long st_size; [FieldOffset(104)] public long st_blocks; [FieldOffset(112)] public int st_blksize; [FieldOffset(116)] public uint st_flags; [FieldOffset(120)] public uint st_gen; [FieldOffset(124)] private int st_lspare; } [StructLayout(LayoutKind.Explicit, Size = 16)] public struct timespec { [FieldOffset(0)] public long tv_sec; [FieldOffset(8)] public ulong tv_nsec; } } public static unsafe int stat_x64(string path, out XPlatLayout.stat stat) { Layout.stat tmp; var errno = Interop.stat_INODE64(path, &tmp) != 0 ? Marshal.GetLastWin32Error() : 0; stat = new XPlatLayout.stat { st_dev = (ulong)tmp.st_dev, st_ino = tmp.st_ino, st_mode = tmp.st_mode, st_nlink = tmp.st_nlink, st_uid = tmp.st_uid, st_gid = tmp.st_gid, st_rdev = (ulong)tmp.st_rdev, st_size = tmp.st_size, st_atim = new XPlatLayout.TimeSpec { tv_sec = tmp.st_atimespec.tv_sec, tv_nsec = tmp.st_atimespec.tv_nsec, }, st_mtim = new XPlatLayout.TimeSpec { tv_sec = tmp.st_mtimespec.tv_sec, tv_nsec = tmp.st_mtimespec.tv_nsec, }, st_ctim = new XPlatLayout.TimeSpec { tv_sec = tmp.st_ctimespec.tv_sec, tv_nsec = tmp.st_ctimespec.tv_nsec, }, st_blksize = tmp.st_blksize, st_blocks = tmp.st_blocks }; return errno; } public static unsafe int stat_arm64(string path, out XPlatLayout.stat stat) { Layout.stat tmp; var errno = Interop.stat(path, &tmp) != 0 ? Marshal.GetLastWin32Error() : 0; stat = new XPlatLayout.stat { st_dev = (ulong)tmp.st_dev, st_ino = tmp.st_ino, st_mode = tmp.st_mode, st_nlink = tmp.st_nlink, st_uid = tmp.st_uid, st_gid = tmp.st_gid, st_rdev = (ulong)tmp.st_rdev, st_size = tmp.st_size, st_atim = new XPlatLayout.TimeSpec { tv_sec = tmp.st_atimespec.tv_sec, tv_nsec = tmp.st_atimespec.tv_nsec, }, st_mtim = new XPlatLayout.TimeSpec { tv_sec = tmp.st_mtimespec.tv_sec, tv_nsec = tmp.st_mtimespec.tv_nsec, }, st_ctim = new XPlatLayout.TimeSpec { tv_sec = tmp.st_ctimespec.tv_sec, tv_nsec = tmp.st_ctimespec.tv_nsec, }, st_blksize = tmp.st_blksize, st_blocks = tmp.st_blocks }; return errno; } } } }