1 use libc::{LOCK_EX, LOCK_NB, LOCK_UN};
2 use std::fs::{File, OpenOptions};
3 use std::io;
4 use std::os::unix::io::{AsRawFd, RawFd};
5 use std::path::Path;
6
7 use crate::error::*;
8
9 #[derive(Debug)]
10 pub(crate) struct RawNamedLock {
11 lock_file: File,
12 }
13
14 impl RawNamedLock {
create(lock_path: &Path) -> Result<RawNamedLock>15 pub(crate) fn create(lock_path: &Path) -> Result<RawNamedLock> {
16 let lock_file = OpenOptions::new()
17 .write(true)
18 .create_new(true)
19 .open(&lock_path)
20 .or_else(|_| OpenOptions::new().write(true).open(&lock_path))
21 .map_err(Error::CreateFailed)?;
22
23 Ok(RawNamedLock {
24 lock_file,
25 })
26 }
27
try_lock(&self) -> Result<()>28 pub(crate) fn try_lock(&self) -> Result<()> {
29 unsafe { flock(self.lock_file.as_raw_fd(), LOCK_EX | LOCK_NB) }
30 }
31
lock(&self) -> Result<()>32 pub(crate) fn lock(&self) -> Result<()> {
33 unsafe { flock(self.lock_file.as_raw_fd(), LOCK_EX) }
34 }
35
unlock(&self) -> Result<()>36 pub(crate) fn unlock(&self) -> Result<()> {
37 unsafe { flock(self.lock_file.as_raw_fd(), LOCK_UN) }
38 }
39 }
40
flock(fd: RawFd, operation: i32) -> Result<()>41 unsafe fn flock(fd: RawFd, operation: i32) -> Result<()> {
42 loop {
43 let rc = libc::flock(fd, operation);
44
45 if rc < 0 {
46 let err = io::Error::last_os_error();
47
48 if err.kind() == io::ErrorKind::Interrupted {
49 continue;
50 } else if err.kind() == io::ErrorKind::WouldBlock {
51 return Err(Error::WouldBlock);
52 } else if (operation & LOCK_EX) == LOCK_EX {
53 return Err(Error::LockFailed);
54 } else if (operation & LOCK_UN) == LOCK_UN {
55 return Err(Error::UnlockFailed);
56 }
57 }
58
59 break;
60 }
61
62 Ok(())
63 }
64