From a173b33aaf67ebc33730fae4471392a05181ce91 Mon Sep 17 00:00:00 2001 From: Caelan Sayler Date: Sun, 3 Nov 2024 11:59:51 +0000 Subject: [PATCH] Switch to using fcntl from flock on unix --- src/lib-csharp/Util/LockFile.cs | 78 +++++++++++++++++++++++++++------ src/lib-rust/src/lockfile.rs | 17 +++++-- 2 files changed, 77 insertions(+), 18 deletions(-) diff --git a/src/lib-csharp/Util/LockFile.cs b/src/lib-csharp/Util/LockFile.cs index 07281a79..aeb5b5e1 100644 --- a/src/lib-csharp/Util/LockFile.cs +++ b/src/lib-csharp/Util/LockFile.cs @@ -55,27 +55,77 @@ namespace Velopack.Util } } - - [SupportedOSPlatform("linux")] - [SupportedOSPlatform("macos")] - [DllImport("libc", SetLastError = true)] - private static extern int flock(int fd, int operation); - - private const int LOCK_SH = 1; // Shared lock - private const int LOCK_EX = 2; // Exclusive lock - private const int LOCK_NB = 4; // Non-blocking - private const int LOCK_UN = 8; // Unlock - [SupportedOSPlatform("linux")] [SupportedOSPlatform("macos")] private void UnixExclusiveLock(int fd) { - int ret = flock(fd, LOCK_EX | LOCK_NB); - if (ret != 0) { - throw new IOException("flock returned error: " + ret); + int ret; + if (VelopackRuntimeInfo.IsLinux) { + var lockOpt = new linux_flock { + l_type = F_WRLCK, + l_whence = SEEK_SET, + l_start = 0, + l_len = 0, // 0 means to lock the entire file + l_pid = 0, + }; + ret = fcntl(fd, F_SETLK, ref lockOpt); + } else if (VelopackRuntimeInfo.IsOSX) { + var lockOpt = new osx_flock { + l_start = 0, + l_len = 0, // 0 means to lock the entire file + l_pid = 0, + l_type = F_WRLCK, + l_whence = SEEK_SET, + }; + Console.WriteLine("hello"); + ret = fcntl(fd, F_SETLK, ref lockOpt); + } else { + throw new PlatformNotSupportedException(); + } + + Console.WriteLine(ret); + if (ret == -1) { + int errno = Marshal.GetLastWin32Error(); + throw new IOException($"fcntl F_SETLK failed, errno: {errno}", new Win32Exception(errno)); } } + [SupportedOSPlatform("linux")] + [DllImport("libc", SetLastError = true)] + private static extern int fcntl(int fd, int cmd, ref linux_flock linux_flock); + + [SupportedOSPlatform("macos")] + [DllImport("libc", SetLastError = true)] + private static extern int fcntl(int fd, int cmd, ref osx_flock linux_flock); + + [SupportedOSPlatform("linux")] + [StructLayout(LayoutKind.Sequential)] + private struct linux_flock + { + public short l_type; /* Type of lock: F_RDLCK, F_WRLCK, F_UNLCK */ + public short l_whence; /* How to interpret l_start: SEEK_SET, SEEK_CUR, SEEK_END */ + public long l_start; /* Starting offset for lock */ + public long l_len; /* Number of bytes to lock */ + public int l_pid; /* PID of the process blocking our lock (F_GETLK only) */ + } + + [SupportedOSPlatform("macos")] + [StructLayout(LayoutKind.Sequential)] + private struct osx_flock + { + public long l_start; /* Starting offset for lock */ + public long l_len; /* Number of bytes to lock */ + public int l_pid; /* PID of the process blocking our lock (F_GETLK only) */ + public short l_type; /* Type of lock: F_RDLCK, F_WRLCK, F_UNLCK */ + public short l_whence; /* How to interpret l_start: SEEK_SET, SEEK_CUR, SEEK_END */ + } + + private const int F_SETLK = 6; /* Non-blocking lock */ + private const short F_RDLCK = 0; /* Read lock */ + private const short F_WRLCK = 1; /* Write lock */ + private const short F_UNLCK = 2; /* Remove lock */ + private const short SEEK_SET = 0; + [SupportedOSPlatform("windows")] [DllImport("kernel32.dll", SetLastError = true)] private static extern bool LockFileEx(SafeFileHandle hFile, uint dwFlags, uint dwReserved, uint nNumberOfBytesToLockLow, uint nNumberOfBytesToLockHigh, diff --git a/src/lib-rust/src/lockfile.rs b/src/lib-rust/src/lockfile.rs index b03ab3fc..be95012b 100644 --- a/src/lib-rust/src/lockfile.rs +++ b/src/lib-rust/src/lockfile.rs @@ -35,7 +35,7 @@ impl LockFile { { use std::os::unix::io::AsRawFd; let fd = file.as_raw_fd(); - self.unix_exclusive_lock(fd)?; + lock_file.unix_exclusive_lock(fd)?; } #[cfg(target_os = "windows")] @@ -60,10 +60,19 @@ impl LockFile { /// Acquires an exclusive, non-blocking lock on Unix-like systems. #[cfg(unix)] fn unix_exclusive_lock(&self, fd: std::os::unix::io::RawFd) -> Result<()> { - use libc::{flock, LOCK_EX, LOCK_NB}; + use libc::{fcntl, F_SETLK, F_WRLCK, SEEK_SET}; - let ret = unsafe { flock(fd, LOCK_EX | LOCK_NB) }; - if ret != 0 { + let lock = libc::flock { + l_type: F_WRLCK as libc::c_short, + l_whence: SEEK_SET as libc::c_short, + l_start: 0, + l_len: 0, // 0 means to lock the entire file + l_pid: 0, + }; + + let ret = unsafe { fcntl(fd, F_SETLK, &lock) }; + + if ret == -1 { let err = Error::last_os_error(); Err(Error::new( ErrorKind::Other,