Commit ce78b7ab authored by Nick Mathewson's avatar Nick Mathewson 🤹
Browse files

fslock-guard: Remove fslock dependency.

We can do this since our msrv is now 1.89.0, where
File::lock is supported.
parent 349316cf
Loading
Loading
Loading
Loading
+0 −11
Original line number Diff line number Diff line
@@ -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",
+0 −1
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@ default = []
full = []

[dependencies]
fslock = { version = "0.2.0", package = "fslock-arti-fork" }
thiserror = "2"

[dev-dependencies]
+39 −24
Original line number Diff line number Diff line
@@ -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.
///
@@ -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 });
            }
        }
    }
@@ -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.
    ///
@@ -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 {}))
@@ -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
@@ -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())
    }
@@ -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();