use std::fs::{File, OpenOptions};
use std::os::unix::fs::{MetadataExt, OpenOptionsExt};
use std::os::unix::io::AsRawFd;
use std::path::Path;
use crate::error::{Result, RingfireError};
pub(crate) fn create_backing_file(path: &Path, mode: u32, exclusive_lock: bool, size: u64) -> Result<File> {
crate::wait::register_producer_barrier();
if !exclusive_lock {
let file = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.truncate(true)
.mode(mode)
.open(path)?;
file.set_len(size)?;
return Ok(file);
}
for _ in 0..8 {
let file = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.truncate(false)
.mode(mode)
.open(path)?;
if unsafe { libc::flock(file.as_raw_fd(), libc::LOCK_EX | libc::LOCK_NB) } != 0 {
return Err(RingfireError::ProducerAlreadyExists);
}
let locked = file.metadata()?;
match std::fs::metadata(path) {
Ok(current) if current.dev() == locked.dev() && current.ino() == locked.ino() => {}
Ok(_) => continue,
Err(e) if e.kind() == std::io::ErrorKind::NotFound => continue,
Err(e) => return Err(e.into()),
}
if locked.len() != 0 {
std::fs::remove_file(path)?;
continue;
}
file.set_len(size)?;
return Ok(file);
}
Err(RingfireError::ProducerAlreadyExists)
}