Is there file locking in Rust?
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.
https://github.com/clucompany/cluFlock
use cluFlock::ToFlock;
use std::fs::File;
use std::io;
fn main() -> Result<(), io::Error> {
let file_lock = File::create("/tmp/1")?.wait_exclusive_lock()?;
println!("{:?}", file_lock);
drop(file_lock); //<-- unlock file
Ok( () )
}