Loading Cargo.lock +0 −11 Original line number Diff line number Diff line Loading @@ -2592,21 +2592,10 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" [[package]] name = "fslock-arti-fork" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b21bd626aaab7b904b20bef6d9e06298914a0c8d9fb8b010483766b2e532791" dependencies = [ "libc", "winapi", ] [[package]] name = "fslock-guard" version = "0.6.0" dependencies = [ "fslock-arti-fork", "test-temp-dir", "thiserror 2.0.18", "winapi", Loading crates/fslock-guard/Cargo.toml +0 −1 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ default = [] full = [] [dependencies] fslock = { version = "0.2.0", package = "fslock-arti-fork" } thiserror = "2" [dev-dependencies] Loading crates/fslock-guard/src/lib.rs +39 −24 Original line number Diff line number Diff line Loading @@ -46,7 +46,7 @@ #![deny(clippy::unused_async)] //! <!-- @@ end lint list maintained by maint/add_warning @@ --> use std::path::Path; use std::{fs, path::Path}; /// A lock-file for which we hold the lock. /// Loading @@ -69,29 +69,43 @@ use std::path::Path; /// * Cross-filesystem locking is broken on Linux before 2.6.12. #[derive(Debug)] pub struct LockFileGuard { /// A locked [`fslock::LockFile`]. /// A [`File`](fs::File) with its exclusive lock held. /// /// This `LockFile` instance will remain locked for as long as this /// LockFileGuard exists. locked: fslock::LockFile, locked_file: fs::File, } impl LockFileGuard { /// Try to open `path` with options suitable for using it as a lockfile, /// creating it as necessary. fn open<P>(path: P) -> Result<fs::File, std::io::Error> where P: AsRef<Path>, { fs::OpenOptions::new() .read(true) .write(true) .create(true) .truncate(false) .open(&path) } /// Try to construct a new [`LockFileGuard`] representing a lock we hold on /// the file `path`. /// /// Blocks until we can get the lock. pub fn lock<P>(path: P) -> Result<Self, fslock::Error> pub fn lock<P>(path: P) -> Result<Self, std::io::Error> where P: AsRef<Path>, { let path = path.as_ref(); loop { let mut lockfile = fslock::LockFile::open(path)?; lockfile.lock()?; let file = Self::open(path)?; file.lock()?; if os::lockfile_has_path(&lockfile, path)? { return Ok(Self { locked: lockfile }); if os::lockfile_has_path(&file, path)? { return Ok(Self { locked_file: file }); } } } Loading @@ -100,17 +114,24 @@ impl LockFileGuard { /// the file `path`. /// /// Does not block; returns Ok(None) if somebody else holds the lock. pub fn try_lock<P>(path: P) -> Result<Option<Self>, fslock::Error> pub fn try_lock<P>(path: P) -> Result<Option<Self>, std::io::Error> where P: AsRef<Path>, { let path = path.as_ref(); let mut lockfile = fslock::LockFile::open(path)?; if lockfile.try_lock()? && os::lockfile_has_path(&lockfile, path)? { return Ok(Some(Self { locked: lockfile })); } let file = Self::open(path)?; match file.try_lock() { Ok(()) => { if os::lockfile_has_path(&file, path)? { Ok(Some(Self { locked_file: file })) } else { Ok(None) } } Err(fs::TryLockError::WouldBlock) => Ok(None), Err(fs::TryLockError::Error(e)) => Err(e), } } /// Try to delete the lock file that we hold. /// Loading @@ -120,7 +141,7 @@ impl LockFileGuard { P: AsRef<Path>, { let path = path.as_ref(); if os::lockfile_has_path(&self.locked, path)? { if os::lockfile_has_path(&self.locked_file, path)? { std::fs::remove_file(path) } else { Err(std::io::Error::other(MismatchedPathError {})) Loading @@ -136,10 +157,6 @@ impl LockFileGuard { #[error("Called delete_lock_file with a mismatched path.")] struct MismatchedPathError {} // Note: This requires AsFd and AsHandle implementations for `LockFile`. // See https://github.com/brunoczim/fslock/pull/15 // This is why we are using fslock-arti-fork in place of fslock. /// Platform module for locking protocol on Unix. /// /// ### Locking protocol on Unix Loading Loading @@ -207,14 +224,12 @@ struct MismatchedPathError {} /// and then see that they have a stale file. #[cfg(unix)] mod os { use std::{fs::File, os::fd::AsFd, os::unix::fs::MetadataExt as _, path::Path}; use std::{fs::File, os::unix::fs::MetadataExt as _, path::Path}; /// Return true if `lf` currently exists with the given `path`, and false otherwise. pub(crate) fn lockfile_has_path(lf: &fslock::LockFile, path: &Path) -> std::io::Result<bool> { pub(crate) fn lockfile_has_path(lf: &File, path: &Path) -> std::io::Result<bool> { let m1 = std::fs::metadata(path)?; // TODO: This does an unnecessary dup(). let f_dup = File::from(lf.as_fd().try_clone_to_owned()?); let m2 = f_dup.metadata()?; let m2 = lf.metadata()?; Ok(m1.ino() == m2.ino() && m1.dev() == m2.dev()) } Loading Loading @@ -265,7 +280,7 @@ mod os { use winapi::um::fileapi::{BY_HANDLE_FILE_INFORMATION as Info, GetFileInformationByHandle}; /// Return true if `lf` currently exists with the given `path`, and false otherwise. pub(crate) fn lockfile_has_path(lf: &fslock::LockFile, path: &Path) -> std::io::Result<bool> { pub(crate) fn lockfile_has_path(lf: &File, path: &Path) -> std::io::Result<bool> { let mut m1: MaybeUninit<Info> = MaybeUninit::uninit(); let mut m2: MaybeUninit<Info> = MaybeUninit::uninit(); Loading Loading
Cargo.lock +0 −11 Original line number Diff line number Diff line Loading @@ -2592,21 +2592,10 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" [[package]] name = "fslock-arti-fork" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b21bd626aaab7b904b20bef6d9e06298914a0c8d9fb8b010483766b2e532791" dependencies = [ "libc", "winapi", ] [[package]] name = "fslock-guard" version = "0.6.0" dependencies = [ "fslock-arti-fork", "test-temp-dir", "thiserror 2.0.18", "winapi", Loading
crates/fslock-guard/Cargo.toml +0 −1 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ default = [] full = [] [dependencies] fslock = { version = "0.2.0", package = "fslock-arti-fork" } thiserror = "2" [dev-dependencies] Loading
crates/fslock-guard/src/lib.rs +39 −24 Original line number Diff line number Diff line Loading @@ -46,7 +46,7 @@ #![deny(clippy::unused_async)] //! <!-- @@ end lint list maintained by maint/add_warning @@ --> use std::path::Path; use std::{fs, path::Path}; /// A lock-file for which we hold the lock. /// Loading @@ -69,29 +69,43 @@ use std::path::Path; /// * Cross-filesystem locking is broken on Linux before 2.6.12. #[derive(Debug)] pub struct LockFileGuard { /// A locked [`fslock::LockFile`]. /// A [`File`](fs::File) with its exclusive lock held. /// /// This `LockFile` instance will remain locked for as long as this /// LockFileGuard exists. locked: fslock::LockFile, locked_file: fs::File, } impl LockFileGuard { /// Try to open `path` with options suitable for using it as a lockfile, /// creating it as necessary. fn open<P>(path: P) -> Result<fs::File, std::io::Error> where P: AsRef<Path>, { fs::OpenOptions::new() .read(true) .write(true) .create(true) .truncate(false) .open(&path) } /// Try to construct a new [`LockFileGuard`] representing a lock we hold on /// the file `path`. /// /// Blocks until we can get the lock. pub fn lock<P>(path: P) -> Result<Self, fslock::Error> pub fn lock<P>(path: P) -> Result<Self, std::io::Error> where P: AsRef<Path>, { let path = path.as_ref(); loop { let mut lockfile = fslock::LockFile::open(path)?; lockfile.lock()?; let file = Self::open(path)?; file.lock()?; if os::lockfile_has_path(&lockfile, path)? { return Ok(Self { locked: lockfile }); if os::lockfile_has_path(&file, path)? { return Ok(Self { locked_file: file }); } } } Loading @@ -100,17 +114,24 @@ impl LockFileGuard { /// the file `path`. /// /// Does not block; returns Ok(None) if somebody else holds the lock. pub fn try_lock<P>(path: P) -> Result<Option<Self>, fslock::Error> pub fn try_lock<P>(path: P) -> Result<Option<Self>, std::io::Error> where P: AsRef<Path>, { let path = path.as_ref(); let mut lockfile = fslock::LockFile::open(path)?; if lockfile.try_lock()? && os::lockfile_has_path(&lockfile, path)? { return Ok(Some(Self { locked: lockfile })); } let file = Self::open(path)?; match file.try_lock() { Ok(()) => { if os::lockfile_has_path(&file, path)? { Ok(Some(Self { locked_file: file })) } else { Ok(None) } } Err(fs::TryLockError::WouldBlock) => Ok(None), Err(fs::TryLockError::Error(e)) => Err(e), } } /// Try to delete the lock file that we hold. /// Loading @@ -120,7 +141,7 @@ impl LockFileGuard { P: AsRef<Path>, { let path = path.as_ref(); if os::lockfile_has_path(&self.locked, path)? { if os::lockfile_has_path(&self.locked_file, path)? { std::fs::remove_file(path) } else { Err(std::io::Error::other(MismatchedPathError {})) Loading @@ -136,10 +157,6 @@ impl LockFileGuard { #[error("Called delete_lock_file with a mismatched path.")] struct MismatchedPathError {} // Note: This requires AsFd and AsHandle implementations for `LockFile`. // See https://github.com/brunoczim/fslock/pull/15 // This is why we are using fslock-arti-fork in place of fslock. /// Platform module for locking protocol on Unix. /// /// ### Locking protocol on Unix Loading Loading @@ -207,14 +224,12 @@ struct MismatchedPathError {} /// and then see that they have a stale file. #[cfg(unix)] mod os { use std::{fs::File, os::fd::AsFd, os::unix::fs::MetadataExt as _, path::Path}; use std::{fs::File, os::unix::fs::MetadataExt as _, path::Path}; /// Return true if `lf` currently exists with the given `path`, and false otherwise. pub(crate) fn lockfile_has_path(lf: &fslock::LockFile, path: &Path) -> std::io::Result<bool> { pub(crate) fn lockfile_has_path(lf: &File, path: &Path) -> std::io::Result<bool> { let m1 = std::fs::metadata(path)?; // TODO: This does an unnecessary dup(). let f_dup = File::from(lf.as_fd().try_clone_to_owned()?); let m2 = f_dup.metadata()?; let m2 = lf.metadata()?; Ok(m1.ino() == m2.ino() && m1.dev() == m2.dev()) } Loading Loading @@ -265,7 +280,7 @@ mod os { use winapi::um::fileapi::{BY_HANDLE_FILE_INFORMATION as Info, GetFileInformationByHandle}; /// Return true if `lf` currently exists with the given `path`, and false otherwise. pub(crate) fn lockfile_has_path(lf: &fslock::LockFile, path: &Path) -> std::io::Result<bool> { pub(crate) fn lockfile_has_path(lf: &File, path: &Path) -> std::io::Result<bool> { let mut m1: MaybeUninit<Info> = MaybeUninit::uninit(); let mut m2: MaybeUninit<Info> = MaybeUninit::uninit(); Loading