From 572bc3ba44f8ad33ab002a31fbe5bce732e238a9 Mon Sep 17 00:00:00 2001 From: devmobasa <4170275+devmobasa@users.noreply.github.com> Date: Fri, 30 Oct 2026 19:32:16 +0100 Subject: [PATCH] refactor: take advisory locks through rustix Add rustix as a direct dependency. It is already compiled through the Wayland stack, so this adds no new crate. Use its typed flock operations for the durable, daemon protocol, and action journal locks, which removes their unsafe blocks. Deadline locks still always retry without blocking. --- Cargo.lock | 1 + Cargo.toml | 2 ++ src/daemon/protocol_v2/action.rs | 22 +++++++-------- src/daemon/protocol_v2/action/tests.rs | 16 +++-------- src/daemon/protocol_v2/command/action_link.rs | 9 ++++--- src/daemon/protocol_v2/command/claimed.rs | 12 ++++++--- src/daemon/protocol_v2/command/client.rs | 21 ++++++++++++--- src/daemon/protocol_v2/command/layout.rs | 27 ++++++++++--------- src/daemon/protocol_v2/command/owner.rs | 19 ++++++++----- src/daemon/protocol_v2/command/recovery.rs | 3 ++- src/daemon/protocol_v2/command/staging.rs | 3 ++- src/daemon/protocol_v2/command/tests.rs | 14 +++++----- src/durable_io/lock.rs | 22 +++++---------- tools/csharp/Commands/ChecksCommand.cs | 1 + 14 files changed, 96 insertions(+), 76 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2449a5d8..8d11b397 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1894,6 +1894,7 @@ dependencies = [ "pango", "pangocairo", "png", + "rustix", "schemars", "serde", "serde_ignored", diff --git a/Cargo.toml b/Cargo.toml index d871ff0d..f6b9622d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -93,6 +93,8 @@ serde = { version = "1.0", features = ["derive"] } serde_ignored = "0.1" schemars = { version = "1.2", features = ["derive"], optional = true } libc = "0.2" +# Safe wrappers for the kernel interfaces that the std library does not cover. +rustix = { version = "1", features = ["event", "fs", "net", "pipe", "process", "stdio", "termios", "thread", "time"] } # Kernel random bytes for portal handle tokens and daemon protocol identifiers. getrandom = { version = "0.4", features = ["std"] } # Securely created, self-deleting temporary files for the OCR engine handoff. diff --git a/src/daemon/protocol_v2/action.rs b/src/daemon/protocol_v2/action.rs index ee637e91..bb378674 100644 --- a/src/daemon/protocol_v2/action.rs +++ b/src/daemon/protocol_v2/action.rs @@ -2,7 +2,6 @@ use std::collections::BTreeMap; use std::fs::{self, File, OpenOptions}; use std::io::{self, ErrorKind}; -use std::os::fd::AsRawFd; use std::os::unix::fs::{MetadataExt, OpenOptionsExt}; use std::path::{Path, PathBuf}; #[cfg(test)] @@ -11,6 +10,7 @@ use std::sync::LazyLock; use std::sync::Mutex; use anyhow::{Context, Result, anyhow, bail}; +use rustix::fs::{self as rustix_fs, FlockOperation}; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; @@ -224,10 +224,13 @@ fn try_open_journal_lock(root: &Path, nonblocking: bool) -> Result> if !file.metadata()?.is_file() { bail!("action journal lock is not a regular file"); } - let operation = libc::LOCK_EX | if nonblocking { libc::LOCK_NB } else { 0 }; - // SAFETY: file owns the descriptor; flock retains no pointer. - if unsafe { libc::flock(file.as_raw_fd(), operation) } != 0 { - let error = io::Error::last_os_error(); + let operation = if nonblocking { + FlockOperation::NonBlockingLockExclusive + } else { + FlockOperation::LockExclusive + }; + if let Err(errno) = rustix_fs::flock(&file, operation) { + let error = io::Error::from(errno); if nonblocking && error.kind() == ErrorKind::WouldBlock { return Ok(None); } @@ -237,12 +240,9 @@ fn try_open_journal_lock(root: &Path, nonblocking: bool) -> Result> } fn unlock(file: &File) -> Result<()> { - // SAFETY: file owns the descriptor; flock retains no pointer. - if unsafe { libc::flock(file.as_raw_fd(), libc::LOCK_UN) } == 0 { - Ok(()) - } else { - Err(io::Error::last_os_error()).context("failed to unlock action journal") - } + rustix_fs::flock(file, FlockOperation::Unlock) + .map_err(io::Error::from) + .context("failed to unlock action journal") } fn write_record(path: &Path, value: &T) -> Result<()> { diff --git a/src/daemon/protocol_v2/action/tests.rs b/src/daemon/protocol_v2/action/tests.rs index 8ba46acb..181ebeb3 100644 --- a/src/daemon/protocol_v2/action/tests.rs +++ b/src/daemon/protocol_v2/action/tests.rs @@ -1,5 +1,7 @@ use std::{env, thread}; +use rustix::fs::{self as rustix_fs, FlockOperation}; + use crate::{test_env, test_temp}; use super::*; @@ -179,21 +181,11 @@ fn event_loop_claim_and_finish_defer_instead_of_waiting_for_locks() { .write(true) .open(decision_path) .unwrap(); - assert_eq!( - // SAFETY: `held_decision` keeps the descriptor open for the call, - // and flock retains no pointer. - unsafe { libc::flock(held_decision.as_raw_fd(), libc::LOCK_EX) }, - 0 - ); + rustix_fs::flock(&held_decision, FlockOperation::LockExclusive).unwrap(); let ActionFinishOutcome::Deferred(action) = action.try_finish(true, None).unwrap() else { panic!("contended command finish should defer"); }; - assert_eq!( - // SAFETY: `held_decision` keeps the descriptor open for the call, - // and flock retains no pointer. - unsafe { libc::flock(held_decision.as_raw_fd(), libc::LOCK_UN) }, - 0 - ); + rustix_fs::flock(&held_decision, FlockOperation::Unlock).unwrap(); assert!(matches!( action.try_finish(true, None).unwrap(), ActionFinishOutcome::Complete diff --git a/src/daemon/protocol_v2/command/action_link.rs b/src/daemon/protocol_v2/command/action_link.rs index f91e706f..e474792e 100644 --- a/src/daemon/protocol_v2/command/action_link.rs +++ b/src/daemon/protocol_v2/command/action_link.rs @@ -2,6 +2,7 @@ use std::io::ErrorKind; use std::time::Duration; use anyhow::{Context, Result, bail}; +use rustix::fs::FlockOperation; use super::super::BootClock; use super::super::action::PreparedAction; @@ -37,14 +38,14 @@ fn claim_command_action_inner( let path = control_path(&command_root(), command_identity); let decision = open_lock(&path.join("decision.lock"), false)?; if nonblocking { - match flock(&decision, libc::LOCK_EX | libc::LOCK_NB) { + match flock(&decision, FlockOperation::NonBlockingLockExclusive) { Ok(()) => {} Err(error) if error.kind() == ErrorKind::WouldBlock => return Ok(None), Err(error) => return Err(error).context("failed to try command-action decision lock"), } } else { let deadline = BootClock::now()?.checked_add(Duration::from_millis(200))?; - lock_until(&decision, libc::LOCK_EX, deadline)?; + lock_until(&decision, FlockOperation::LockExclusive, deadline)?; } let mut control = read_control(&path)?; let exact = |status: &ActionStatus| match status { @@ -193,14 +194,14 @@ fn finish_command_action_inner( let path = control_path(&command_root(), command_identity); let decision = open_lock(&path.join("decision.lock"), false)?; if nonblocking { - match flock(&decision, libc::LOCK_EX | libc::LOCK_NB) { + match flock(&decision, FlockOperation::NonBlockingLockExclusive) { Ok(()) => {} Err(error) if error.kind() == ErrorKind::WouldBlock => return Ok(false), Err(error) => return Err(error).context("failed to try command-action decision lock"), } } else { let deadline = BootClock::now()?.checked_add(Duration::from_millis(200))?; - lock_until(&decision, libc::LOCK_EX, deadline)?; + lock_until(&decision, FlockOperation::LockExclusive, deadline)?; } let mut control = read_control(&path)?; let applied = result == CommandActionResult::Applied; diff --git a/src/daemon/protocol_v2/command/claimed.rs b/src/daemon/protocol_v2/command/claimed.rs index 1c386649..3fb2bfd5 100644 --- a/src/daemon/protocol_v2/command/claimed.rs +++ b/src/daemon/protocol_v2/command/claimed.rs @@ -1,6 +1,7 @@ use std::time::Duration; use anyhow::{Result, anyhow, bail}; +use rustix::fs::FlockOperation; #[cfg(test)] use super::super::wire::CommandControl; @@ -61,7 +62,8 @@ impl ClaimedCommand { journal.prepare_command(&expected.identity, &expected.target_daemon_token, action)?; let deadline = BootDeadline::from_nanos(expected.submission_clock.authorization_deadline_boottime_ns); - if let Err(error) = lock_until(&self.decision_lock, libc::LOCK_EX, deadline) { + if let Err(error) = lock_until(&self.decision_lock, FlockOperation::LockExclusive, deadline) + { let _ = journal.abandon(&prepared, "command decision lock was not reacquired"); return Err(error); } @@ -71,7 +73,11 @@ impl ClaimedCommand { let reason = "command was canceled during action preparation"; journal.abandon(&prepared, reason)?; let recovery_deadline = BootClock::now()?.checked_add(Duration::from_millis(200))?; - lock_until(&self.decision_lock, libc::LOCK_EX, recovery_deadline)?; + lock_until( + &self.decision_lock, + FlockOperation::LockExclusive, + recovery_deadline, + )?; let mut latest = read_control(&self.control_path)?; if latest != current || !matches!( @@ -221,6 +227,6 @@ impl ClaimedCommand { impl Drop for ClaimedCommand { fn drop(&mut self) { - let _ = flock(&self.decision_lock, libc::LOCK_UN); + let _ = flock(&self.decision_lock, FlockOperation::Unlock); } } diff --git a/src/daemon/protocol_v2/command/client.rs b/src/daemon/protocol_v2/command/client.rs index 08ed3847..21c03c2d 100644 --- a/src/daemon/protocol_v2/command/client.rs +++ b/src/daemon/protocol_v2/command/client.rs @@ -3,6 +3,7 @@ use std::time::Duration; use std::{fs, process, thread}; use anyhow::{Context, Result, bail}; +use rustix::fs::FlockOperation; #[cfg(test)] use anyhow::anyhow; @@ -62,8 +63,16 @@ impl ClientCommand { create_private_directory(&stage)?; let decision_lock = open_lock(&stage.join("decision.lock"), true)?; let caller_lease = open_lock(&stage.join("caller.lease"), true)?; - lock_until(&caller_lease, libc::LOCK_SH, authorization_deadline)?; - lock_until(&decision_lock, libc::LOCK_EX, authorization_deadline)?; + lock_until( + &caller_lease, + FlockOperation::LockShared, + authorization_deadline, + )?; + lock_until( + &decision_lock, + FlockOperation::LockExclusive, + authorization_deadline, + )?; let mut control = CommandControl { protocol_version: DAEMON_COMMAND_PROTOCOL_VERSION, @@ -154,7 +163,7 @@ impl ClientCommand { let slice = now .checked_add(Duration::from_millis(20))? .min(self.response_deadline); - if !try_lock_until(&self.decision_lock, libc::LOCK_EX, slice)? { + if !try_lock_until(&self.decision_lock, FlockOperation::LockExclusive, slice)? { if slice < self.response_deadline { continue; } @@ -201,7 +210,11 @@ impl ClientCommand { let _ = unlock(&self.caller_lease); return Ok(TerminalCommandResult::AdmittedIndeterminate(reason)); } - lock_until(&self.decision_lock, libc::LOCK_EX, self.response_deadline)?; + lock_until( + &self.decision_lock, + FlockOperation::LockExclusive, + self.response_deadline, + )?; let mut control = read_control(&self.control_path)?; if cancel_open(&mut control)? { write_control(&self.control_path, &control)?; diff --git a/src/daemon/protocol_v2/command/layout.rs b/src/daemon/protocol_v2/command/layout.rs index 00e956c2..67efc6f9 100644 --- a/src/daemon/protocol_v2/command/layout.rs +++ b/src/daemon/protocol_v2/command/layout.rs @@ -1,13 +1,13 @@ use std::collections::BTreeSet; use std::fs::{self, File, OpenOptions}; use std::io::{self, ErrorKind}; -use std::os::fd::AsRawFd; use std::os::unix::fs::{MetadataExt, OpenOptionsExt}; use std::path::{Path, PathBuf}; use std::thread; use std::time::Duration; use anyhow::{Context, Result, anyhow, bail}; +use rustix::fs::{self as rustix_fs, FlockOperation}; use serde::de::DeserializeOwned; use crate::durable_io::AtomicWriteOptions; @@ -279,22 +279,25 @@ pub(super) fn open_lock(path: &Path, create_new: bool) -> Result { Ok(file) } -pub(super) fn flock(file: &File, operation: libc::c_int) -> io::Result<()> { - // SAFETY: file owns a valid descriptor and flock does not retain it. - if unsafe { libc::flock(file.as_raw_fd(), operation) } == 0 { - Ok(()) - } else { - Err(io::Error::last_os_error()) +pub(super) fn flock(file: &File, operation: FlockOperation) -> io::Result<()> { + rustix_fs::flock(file, operation).map_err(io::Error::from) +} + +fn nonblocking(operation: FlockOperation) -> FlockOperation { + match operation { + FlockOperation::LockShared => FlockOperation::NonBlockingLockShared, + FlockOperation::LockExclusive => FlockOperation::NonBlockingLockExclusive, + other => other, } } pub(super) fn unlock(file: &File) -> Result<()> { - flock(file, libc::LOCK_UN).context("failed to unlock protocol descriptor") + flock(file, FlockOperation::Unlock).context("failed to unlock protocol descriptor") } pub(super) fn lock_until( file: &File, - operation: libc::c_int, + operation: FlockOperation, deadline: BootDeadline, ) -> Result<()> { if try_lock_until(file, operation, deadline)? { @@ -306,11 +309,11 @@ pub(super) fn lock_until( pub(super) fn try_lock_until( file: &File, - operation: libc::c_int, + operation: FlockOperation, deadline: BootDeadline, ) -> Result { loop { - match flock(file, operation | libc::LOCK_NB) { + match flock(file, nonblocking(operation)) { Ok(()) => return Ok(true), Err(error) if error.kind() == ErrorKind::WouldBlock => { if BootClock::now()? >= deadline { @@ -341,7 +344,7 @@ pub(super) fn try_admission_lock(root: &Path, deadline: BootDeadline) -> Result< } Err(error) => return Err(error), }; - if try_lock_until(&file, libc::LOCK_EX, deadline)? { + if try_lock_until(&file, FlockOperation::LockExclusive, deadline)? { Ok(Some(file)) } else { Ok(None) diff --git a/src/daemon/protocol_v2/command/owner.rs b/src/daemon/protocol_v2/command/owner.rs index 62b0771a..07e7d001 100644 --- a/src/daemon/protocol_v2/command/owner.rs +++ b/src/daemon/protocol_v2/command/owner.rs @@ -5,6 +5,7 @@ use std::path::{Path, PathBuf}; use std::time::Duration; use anyhow::{Context, Result, bail}; +use rustix::fs::FlockOperation; use super::super::wire::{ ActionStatus, CallerDisposition, ChildReportStatus, CommandDecision, CommandResponse, @@ -191,7 +192,11 @@ impl CommandOwner { Err(error) => return Err(error), }; let retry_deadline = BootClock::now()?.checked_add(Duration::from_millis(200))?; - if !try_lock_until(&decision_lock, libc::LOCK_EX, retry_deadline)? { + if !try_lock_until( + &decision_lock, + FlockOperation::LockExclusive, + retry_deadline, + )? { return Ok(None); } let Ok(mut control) = read_control(&path) else { @@ -316,7 +321,7 @@ impl CommandOwner { Err(error) => return Err(error), }; let deadline = BootClock::now()?.checked_add(Duration::from_millis(200))?; - lock_until(&decision, libc::LOCK_EX, deadline)?; + lock_until(&decision, FlockOperation::LockExclusive, deadline)?; let mut control = read_control(&path)?; if control.identity == reference.command_identity && control.queue_order == reference.queue_order @@ -341,13 +346,13 @@ impl CommandOwner { observed: &super::super::wire::CommandControl, ) -> Result<()> { let caller_lease = open_lock(&path.join("caller.lease"), false)?; - match flock(&caller_lease, libc::LOCK_EX | libc::LOCK_NB) { + match flock(&caller_lease, FlockOperation::NonBlockingLockExclusive) { Ok(()) => {} Err(error) if error.kind() == ErrorKind::WouldBlock => return Ok(()), Err(error) => return Err(error).context("failed to inspect unqueued caller lease"), } let decision = open_lock(&path.join("decision.lock"), false)?; - match flock(&decision, libc::LOCK_EX | libc::LOCK_NB) { + match flock(&decision, FlockOperation::NonBlockingLockExclusive) { Ok(()) => {} Err(error) if error.kind() == ErrorKind::WouldBlock => { unlock(&caller_lease)?; @@ -390,7 +395,7 @@ impl CommandOwner { } let decision_lock = open_lock(&path.join("decision.lock"), false)?; let deadline = BootClock::now()?.checked_add(Duration::from_millis(200))?; - if !try_lock_until(&decision_lock, libc::LOCK_EX, deadline)? { + if !try_lock_until(&decision_lock, FlockOperation::LockExclusive, deadline)? { return Ok(None); } let mut control = read_control(&path)?; @@ -440,11 +445,11 @@ impl CommandOwner { for entry in read_dir_bounded(&controls_dir(&self.root), MAX_DIRECTORY_ENTRIES_PER_SCAN)? { let path = entry.path(); let lease = open_lock(&path.join("caller.lease"), false)?; - if flock(&lease, libc::LOCK_EX | libc::LOCK_NB).is_err() { + if flock(&lease, FlockOperation::NonBlockingLockExclusive).is_err() { continue; } let decision = open_lock(&path.join("decision.lock"), false)?; - if flock(&decision, libc::LOCK_EX | libc::LOCK_NB).is_err() { + if flock(&decision, FlockOperation::NonBlockingLockExclusive).is_err() { unlock(&lease)?; continue; } diff --git a/src/daemon/protocol_v2/command/recovery.rs b/src/daemon/protocol_v2/command/recovery.rs index d5639540..4a6f8524 100644 --- a/src/daemon/protocol_v2/command/recovery.rs +++ b/src/daemon/protocol_v2/command/recovery.rs @@ -3,6 +3,7 @@ use std::path::Path; use std::time::Duration; use anyhow::{Result, anyhow, bail}; +use rustix::fs::FlockOperation; use super::super::BootClock; use super::super::wire::{ @@ -32,7 +33,7 @@ pub(super) fn recover_previous_generation(root: &Path, daemon_token: &str) -> Re continue; }; let deadline = BootClock::now()?.checked_add(Duration::from_millis(200))?; - lock_until(&decision_lock, libc::LOCK_EX, deadline)?; + lock_until(&decision_lock, FlockOperation::LockExclusive, deadline)?; let Ok(mut control) = read_control(&path) else { unlock(&decision_lock)?; quarantine_entry(root, &path, QuarantineKind::Control)?; diff --git a/src/daemon/protocol_v2/command/staging.rs b/src/daemon/protocol_v2/command/staging.rs index 5b6cba77..48449536 100644 --- a/src/daemon/protocol_v2/command/staging.rs +++ b/src/daemon/protocol_v2/command/staging.rs @@ -3,6 +3,7 @@ use std::path::Path; use std::time::Duration; use anyhow::Result; +use rustix::fs::FlockOperation; use super::super::{BootClock, BootIdentity}; use super::MAX_COMMAND_STAGING_DIRECTORIES; @@ -24,7 +25,7 @@ pub(super) fn recover_staging(root: &Path) -> Result<()> { let _ = fs::remove_dir_all(path); continue; }; - if flock(&lease, libc::LOCK_EX | libc::LOCK_NB).is_ok() { + if flock(&lease, FlockOperation::NonBlockingLockExclusive).is_ok() { fs::remove_dir_all(path)?; } } diff --git a/src/daemon/protocol_v2/command/tests.rs b/src/daemon/protocol_v2/command/tests.rs index fdf5d264..4418c3bb 100644 --- a/src/daemon/protocol_v2/command/tests.rs +++ b/src/daemon/protocol_v2/command/tests.rs @@ -1,6 +1,8 @@ use std::env; use std::time::Duration; +use rustix::fs::FlockOperation; + use crate::{test_env, test_temp}; use super::super::BootClock; @@ -208,7 +210,7 @@ fn contended_published_command_claim_is_deferred_and_retried() { &token, ) .unwrap(); - flock(&client.decision_lock, libc::LOCK_EX).unwrap(); + flock(&client.decision_lock, FlockOperation::LockExclusive).unwrap(); assert!(owner.claim_next().unwrap().is_none()); let now = BootClock::now().unwrap(); @@ -252,7 +254,7 @@ fn contended_ref_less_recovery_is_deferred_and_retried() { &control.identity, )) .unwrap(); - flock(&client.decision_lock, libc::LOCK_EX).unwrap(); + flock(&client.decision_lock, FlockOperation::LockExclusive).unwrap(); assert!(owner.claim_next().unwrap().is_none()); unlock(&client.decision_lock).unwrap(); @@ -287,7 +289,7 @@ fn terminal_collection_defers_while_admission_is_busy() { drop(client); let admission = open_lock(&owner.root.join("admission.lock"), false).unwrap(); - flock(&admission, libc::LOCK_EX).unwrap(); + flock(&admission, FlockOperation::LockExclusive).unwrap(); assert_eq!(owner.collect_terminal().unwrap(), 0); let now = BootClock::now().unwrap(); let retry = owner @@ -715,20 +717,20 @@ fn lock_deadline_is_reported_without_parsing_error_text() { let path = root.join("structured-timeout.lock"); let held = open_lock(&path, true).unwrap(); let contender = open_lock(&path, false).unwrap(); - flock(&held, libc::LOCK_EX).unwrap(); + flock(&held, FlockOperation::LockExclusive).unwrap(); let deadline = BootClock::now() .unwrap() .checked_add(Duration::from_millis(5)) .unwrap(); - assert!(!try_lock_until(&contender, libc::LOCK_EX, deadline).unwrap()); + assert!(!try_lock_until(&contender, FlockOperation::LockExclusive, deadline).unwrap()); unlock(&held).unwrap(); let deadline = BootClock::now() .unwrap() .checked_add(Duration::from_millis(5)) .unwrap(); - assert!(try_lock_until(&contender, libc::LOCK_EX, deadline).unwrap()); + assert!(try_lock_until(&contender, FlockOperation::LockExclusive, deadline).unwrap()); unlock(&contender).unwrap(); }); } diff --git a/src/durable_io/lock.rs b/src/durable_io/lock.rs index f8dab3f7..a236e4fd 100644 --- a/src/durable_io/lock.rs +++ b/src/durable_io/lock.rs @@ -4,19 +4,11 @@ use std::fs::File; use std::io; #[cfg(unix)] -use std::os::unix::io::AsRawFd; +use rustix::fs::{self as rustix_fs, FlockOperation}; #[cfg(unix)] -fn flock(file: &File, op: libc::c_int) -> io::Result<()> { - let fd = file.as_raw_fd(); - // SAFETY: `fd` stays open for the borrowed `file`, and flock takes no - // pointers or ownership of the descriptor. - let result = unsafe { libc::flock(fd, op) }; - if result == 0 { - Ok(()) - } else { - Err(io::Error::last_os_error()) - } +fn flock(file: &File, operation: FlockOperation) -> io::Result<()> { + rustix_fs::flock(file, operation).map_err(io::Error::from) } #[cfg(not(unix))] @@ -30,7 +22,7 @@ fn flock(_file: &File, _op: i32) -> io::Result<()> { pub fn lock_shared(file: &File) -> io::Result<()> { #[cfg(unix)] { - flock(file, libc::LOCK_SH) + flock(file, FlockOperation::LockShared) } #[cfg(not(unix))] { @@ -41,7 +33,7 @@ pub fn lock_shared(file: &File) -> io::Result<()> { pub fn lock_exclusive(file: &File) -> io::Result<()> { #[cfg(unix)] { - flock(file, libc::LOCK_EX) + flock(file, FlockOperation::LockExclusive) } #[cfg(not(unix))] { @@ -52,7 +44,7 @@ pub fn lock_exclusive(file: &File) -> io::Result<()> { pub fn try_lock_exclusive(file: &File) -> io::Result<()> { #[cfg(unix)] { - flock(file, libc::LOCK_EX | libc::LOCK_NB) + flock(file, FlockOperation::NonBlockingLockExclusive) } #[cfg(not(unix))] { @@ -63,7 +55,7 @@ pub fn try_lock_exclusive(file: &File) -> io::Result<()> { pub fn unlock(file: &File) -> io::Result<()> { #[cfg(unix)] { - flock(file, libc::LOCK_UN) + flock(file, FlockOperation::Unlock) } #[cfg(not(unix))] { diff --git a/tools/csharp/Commands/ChecksCommand.cs b/tools/csharp/Commands/ChecksCommand.cs index f897b69b..e979081f 100644 --- a/tools/csharp/Commands/ChecksCommand.cs +++ b/tools/csharp/Commands/ChecksCommand.cs @@ -340,6 +340,7 @@ internal static class ChecksCommand ["pango"] = ["pango"], ["pangocairo"] = ["pango", "cairo"], ["png"] = [], + ["rustix"] = [], ["schemars"] = [], ["serde"] = [], ["serde_ignored"] = [],