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.
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.
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.
Locking a file File locking allows you to prevent other users from editing or replacing a file on which you are currently working.
Right-click on the file. In the menu that appears, select Lock File. To unlock, right-click the file and select Unlock File.
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With