diff --git a/Src/Libraries/Builtins/FileOps.cs b/Src/Libraries/Builtins/FileOps.cs index 72fcbe93..6194d887 100644 --- a/Src/Libraries/Builtins/FileOps.cs +++ b/Src/Libraries/Builtins/FileOps.cs @@ -1098,7 +1098,7 @@ internal static int GetNativeFileDescriptor(RubyIO/*!*/ io) { [RubyMethod("flock", BuildConfig = "FEATURE_FILESYSTEM")] public static object FileLock(RubyFile/*!*/ self, [DefaultProtocol]int operation) { self.RequireInitialized(); - if (!Posix.IsAvailable) { + if (!Posix.IsFlockAvailable) { throw new IronRuby.Builtins.NotImplementedError("flock() function is unimplemented on this machine"); } @@ -1118,7 +1118,7 @@ public static object FileLock(RubyFile/*!*/ self, [DefaultProtocol]int operation if (Posix.Flock(fd, operation | Posix.LOCK_NB, out errno) == 0) { return 0; } - if (errno != Posix.EWOULDBLOCK) { + if (errno != Posix.EWouldBlock) { throw Posix.Error(errno, self.Path); } if (nonBlocking) { diff --git a/Src/Libraries/Builtins/Posix.cs b/Src/Libraries/Builtins/Posix.cs index 5f0195cc..197adc86 100644 --- a/Src/Libraries/Builtins/Posix.cs +++ b/Src/Libraries/Builtins/Posix.cs @@ -25,6 +25,29 @@ internal static class Posix { System.IO.Path.DirectorySeparatorChar == '/' && !RuntimeInformation.IsOSPlatform(OSPlatform.OSX); + /// + /// flock(2) is the same call with the same operation bits on every Unix, so it is + /// offered on macOS too, where the rest of this class (statx, Linux errno numbers) + /// is not. RubyGems takes a lock on every binstub it writes, so without this + /// `gem install` of anything with an executable failed on a Mac. + /// + internal static readonly bool IsFlockAvailable = System.IO.Path.DirectorySeparatorChar == '/'; + + /// + /// errno for "would block" on this platform: EAGAIN is 11 on Linux and 35 on macOS and + /// the other BSDs, whose errno numbering macOS inherited. IsFlockAvailable lets every + /// Unix in, so a BSD has to get 35 too, or a contended LOCK_NB raises instead of + /// returning false and a blocking lock never retries. + /// + internal static readonly int EWouldBlock = IsBsdErrno() ? 35 : EWOULDBLOCK; + + private static bool IsBsdErrno() { + return RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || + RuntimeInformation.IsOSPlatform(OSPlatform.FreeBSD) || + RuntimeInformation.IsOSPlatform(OSPlatform.Create("NETBSD")) || + RuntimeInformation.IsOSPlatform(OSPlatform.Create("OPENBSD")); + } + #region errno numbers internal const int EPERM = 1;