feat(std): emulate flock for solaris via fcntl

Upstream Solaris flock emulation to libstd from cargo.

This is borrowed from
3b379fcc54/src/cargo/util/flock.rs (L502-L536)
which was implemented by an Oracle employee.
The code has been in cargo since 2022-12.

Python's `fcntl.flock` emulates like this as well:
c919d02ede/Modules/fcntlmodule.c (L337-L400)

We did the same thing in
0d0f4eac8b/compiler/rustc_data_structures/src/flock/unix.rs (L13-L39)
This commit is contained in:
Weihang Lo 2025-09-06 02:30:50 -06:00
parent 0d0f4eac8b
commit 01edb24d3c
No known key found for this signature in database
GPG key ID: D7DBF189825E82E7
2 changed files with 70 additions and 0 deletions

View file

@ -226,6 +226,7 @@ fn file_test_io_seek_and_write() {
target_os = "freebsd",
target_os = "linux",
target_os = "netbsd",
target_os = "solaris",
target_vendor = "apple",
))]
fn file_lock_multiple_shared() {
@ -249,6 +250,7 @@ fn file_lock_multiple_shared() {
target_os = "freebsd",
target_os = "linux",
target_os = "netbsd",
target_os = "solaris",
target_vendor = "apple",
))]
fn file_lock_blocking() {
@ -273,6 +275,7 @@ fn file_lock_blocking() {
target_os = "freebsd",
target_os = "linux",
target_os = "netbsd",
target_os = "solaris",
target_vendor = "apple",
))]
fn file_lock_drop() {
@ -294,6 +297,7 @@ fn file_lock_drop() {
target_os = "freebsd",
target_os = "linux",
target_os = "netbsd",
target_os = "solaris",
target_vendor = "apple",
))]
fn file_lock_dup() {

View file

@ -1293,6 +1293,15 @@ impl File {
return Ok(());
}
#[cfg(target_os = "solaris")]
pub fn lock(&self) -> io::Result<()> {
let mut flock: libc::flock = unsafe { mem::zeroed() };
flock.l_type = libc::F_WRLCK as libc::c_short;
flock.l_whence = libc::SEEK_SET as libc::c_short;
cvt(unsafe { libc::fcntl(self.as_raw_fd(), libc::F_SETLKW, &flock) })?;
Ok(())
}
#[cfg(not(any(
target_os = "freebsd",
target_os = "fuchsia",
@ -1300,6 +1309,7 @@ impl File {
target_os = "netbsd",
target_os = "openbsd",
target_os = "cygwin",
target_os = "solaris",
target_vendor = "apple",
)))]
pub fn lock(&self) -> io::Result<()> {
@ -1320,6 +1330,15 @@ impl File {
return Ok(());
}
#[cfg(target_os = "solaris")]
pub fn lock_shared(&self) -> io::Result<()> {
let mut flock: libc::flock = unsafe { mem::zeroed() };
flock.l_type = libc::F_RDLCK as libc::c_short;
flock.l_whence = libc::SEEK_SET as libc::c_short;
cvt(unsafe { libc::fcntl(self.as_raw_fd(), libc::F_SETLKW, &flock) })?;
Ok(())
}
#[cfg(not(any(
target_os = "freebsd",
target_os = "fuchsia",
@ -1327,6 +1346,7 @@ impl File {
target_os = "netbsd",
target_os = "openbsd",
target_os = "cygwin",
target_os = "solaris",
target_vendor = "apple",
)))]
pub fn lock_shared(&self) -> io::Result<()> {
@ -1355,6 +1375,23 @@ impl File {
}
}
#[cfg(target_os = "solaris")]
pub fn try_lock(&self) -> Result<(), TryLockError> {
let mut flock: libc::flock = unsafe { mem::zeroed() };
flock.l_type = libc::F_WRLCK as libc::c_short;
flock.l_whence = libc::SEEK_SET as libc::c_short;
let result = cvt(unsafe { libc::fcntl(self.as_raw_fd(), libc::F_SETLK, &flock) });
if let Err(err) = result {
if err.kind() == io::ErrorKind::WouldBlock {
Err(TryLockError::WouldBlock)
} else {
Err(TryLockError::Error(err))
}
} else {
Ok(())
}
}
#[cfg(not(any(
target_os = "freebsd",
target_os = "fuchsia",
@ -1362,6 +1399,7 @@ impl File {
target_os = "netbsd",
target_os = "openbsd",
target_os = "cygwin",
target_os = "solaris",
target_vendor = "apple",
)))]
pub fn try_lock(&self) -> Result<(), TryLockError> {
@ -1393,6 +1431,23 @@ impl File {
}
}
#[cfg(target_os = "solaris")]
pub fn try_lock_shared(&self) -> Result<(), TryLockError> {
let mut flock: libc::flock = unsafe { mem::zeroed() };
flock.l_type = libc::F_RDLCK as libc::c_short;
flock.l_whence = libc::SEEK_SET as libc::c_short;
let result = cvt(unsafe { libc::fcntl(self.as_raw_fd(), libc::F_SETLK, &flock) });
if let Err(err) = result {
if err.kind() == io::ErrorKind::WouldBlock {
Err(TryLockError::WouldBlock)
} else {
Err(TryLockError::Error(err))
}
} else {
Ok(())
}
}
#[cfg(not(any(
target_os = "freebsd",
target_os = "fuchsia",
@ -1400,6 +1455,7 @@ impl File {
target_os = "netbsd",
target_os = "openbsd",
target_os = "cygwin",
target_os = "solaris",
target_vendor = "apple",
)))]
pub fn try_lock_shared(&self) -> Result<(), TryLockError> {
@ -1423,6 +1479,15 @@ impl File {
return Ok(());
}
#[cfg(target_os = "solaris")]
pub fn unlock(&self) -> io::Result<()> {
let mut flock: libc::flock = unsafe { mem::zeroed() };
flock.l_type = libc::F_UNLCK as libc::c_short;
flock.l_whence = libc::SEEK_SET as libc::c_short;
cvt(unsafe { libc::fcntl(self.as_raw_fd(), libc::F_SETLKW, &flock) })?;
Ok(())
}
#[cfg(not(any(
target_os = "freebsd",
target_os = "fuchsia",
@ -1430,6 +1495,7 @@ impl File {
target_os = "netbsd",
target_os = "openbsd",
target_os = "cygwin",
target_os = "solaris",
target_vendor = "apple",
)))]
pub fn unlock(&self) -> io::Result<()> {