Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there file locking in Rust?

I cannot find anything resembling file locking like some programs use in Linux to prevent multiple instances from running. In Python, I'd use pylockfile.

Am I overlooking similar functionality in Rust, or should I just implement it from scratch?

I'm not lazy, just trying to reinvent as few wheels as possible.

like image 777
ayanami Avatar asked Dec 14 '14 13:12

ayanami


People also ask

Can a file be locked?

File locking is a mechanism that restricts access to a computer file. For example, applications will often create a temporary file while it is open to prevent others from editing the same file. These temporary files are usually deleted when you exit your program.

Does Git have file locking?

lock file prevents changes to your local repository from happening from outside of the currently running git process so as to ensure multiple git processes are not altering or changing the same repository internals at the same time.

What does locking a file do?

Locking a file File locking allows you to prevent other users from editing or replacing a file on which you are currently working.

How do you unlock a Lock File?

Right-click on the file. In the menu that appears, select Lock File. To unlock, right-click the file and select Unlock File.


2 Answers

For contemporary Rust (1.8+) you should use the fs2 crate. It is a cross-platform library that provides some file system functions not found in the standard library, including file locking.

fs2's file locking functions internally use flock(2) on UNIX and LockFileEx on Windows.

Example:

//! This program tries to lock a file, sleeps for N seconds, and then unlocks the file.

// cargo-deps: fs2
extern crate fs2;

use fs2::FileExt;
use std::io::Result;
use std::env::args;
use std::fs::File;
use std::time::Duration;
use std::thread::sleep;

fn main() {
    run().unwrap();
}

fn run() -> Result<()> {
    let sleep_seconds = args().nth(1).and_then(|arg| arg.parse().ok()).unwrap_or(0);
    let sleep_duration = Duration::from_secs(sleep_seconds);

    let file = File::open("file.lock")?;

    println!("{}: Preparing to lock file.", sleep_seconds);
    file.lock_exclusive()?; // block until this process can lock the file
    println!("{}: Obtained lock.", sleep_seconds);

    sleep(sleep_duration);

    println!("{}: Sleep completed", sleep_seconds);
    file.unlock()?;
    println!("{}: Released lock, returning", sleep_seconds);

    Ok(())
}

We can see that the two processes are sequenced waiting on the file lock.

$ ./a 4 & ./a 1
[1] 14894
4: Preparing to lock file.
4: Obtained lock.
1: Preparing to lock file.
4: Sleep completed
4: Released lock, returning
1: Obtained lock.
1: Sleep completed
1: Released lock, returning
[1]+  Done                    ./a 4
like image 92
kennytm Avatar answered Sep 21 '22 15:09

kennytm


In Linux you can use nix crate which wraps unix file lock.

Here is an example:

extern crate nix;

use std::fs::File;
use std::os::unix::io::AsRawFd;
use nix::fcntl::{flock, FlockArg};

fn main() {
    let file = File::open("Cargo.toml").unwrap();
    let fd = file.as_raw_fd();
    flock(fd, FlockArg::LockExclusive).unwrap();

    for rem in (1..20).rev() {
        println!("Remain: {} sec.", rem);
        std::thread::sleep(std::time::Duration::from_secs(1));
    }

    drop(file);
    println!("File unlocked!");
}

If you try to run two instances, the second will start to countdown only after first instance unlocked file. But another programs can ignore this lock:

flock(2): function places advisory locks only; given suitable permissions on a file, a process is free to ignore the use of flock() and perform I/O on the file.

like image 23
17 revs, 13 users 59% Avatar answered Sep 20 '22 15:09

17 revs, 13 users 59%