unix.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
use crate::errors::{ Error, Result }; use crate::file_ext::{ FileExt }; use errno::{ Errno, errno }; use libc::{ EAGAIN, EWOULDBLOCK, LOCK_EX, LOCK_NB, LOCK_SH, LOCK_UN, flock }; use std::fs::{ File }; use std::os::raw::{ c_int }; use std::os::fd::{ AsFd, AsRawFd, BorrowedFd }; impl FileExt for File { type LockGuard<'a> = LockGuard<'a>; fn lock_shared(&self) -> Result<Self::LockGuard<'_>> { lock(self.as_fd(), LOCK_SH) } fn lock_exclusive(&self) -> Result<Self::LockGuard<'_>> { lock(self.as_fd(), LOCK_EX) } fn try_lock_shared(&self) -> Result<Self::LockGuard<'_>> { try_lock(self.as_fd(), LOCK_SH) } fn try_lock_exclusive(&self) -> Result<Self::LockGuard<'_>> { try_lock(self.as_fd(), LOCK_EX) } } #[derive(Debug)] #[must_use = "Not retaining the guard object will result in the file being immediately unlocked"] pub struct LockGuard<'a> { fd: BorrowedFd<'a>, } impl Drop for LockGuard<'_> { fn drop(&mut self) { unsafe { flock(self.fd.as_raw_fd(), LOCK_UN); } } } fn lock(fd: BorrowedFd, mode: c_int) -> Result<LockGuard> { let status = unsafe { flock(fd.as_raw_fd(), mode) }; match status { 0 => Ok(LockGuard { fd }), _ => Err(Error::LockFailed(errno())), } } fn try_lock(fd: BorrowedFd, mode: c_int) -> Result<LockGuard> { let status = unsafe { flock(fd.as_raw_fd(), mode | LOCK_NB) }; match status { 0 => Ok(LockGuard { fd }), _ => { let e = errno(); if e == Errno(EAGAIN) || e == Errno(EWOULDBLOCK) { Err(Error::AlreadyLocked) } else { Err(Error::LockFailed(e)) } }, } }