]>
Commit | Line | Data |
---|---|---|
04454e1e FG |
1 | use std::fs::{File, OpenOptions}; |
2 | use std::io; | |
04454e1e FG |
3 | use std::os::windows::prelude::*; |
4 | use std::path::Path; | |
5 | ||
353b0b11 FG |
6 | use windows::{ |
7 | Win32::Foundation::{ERROR_INVALID_FUNCTION, HANDLE}, | |
8 | Win32::Storage::FileSystem::{ | |
9 | LockFileEx, FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE, LOCKFILE_EXCLUSIVE_LOCK, | |
10 | LOCKFILE_FAIL_IMMEDIATELY, LOCK_FILE_FLAGS, | |
11 | }, | |
12 | Win32::System::IO::OVERLAPPED, | |
13 | }; | |
04454e1e FG |
14 | |
15 | #[derive(Debug)] | |
16 | pub struct Lock { | |
17 | _file: File, | |
18 | } | |
19 | ||
20 | impl Lock { | |
21 | pub fn new(p: &Path, wait: bool, create: bool, exclusive: bool) -> io::Result<Lock> { | |
22 | assert!( | |
23 | p.parent().unwrap().exists(), | |
24 | "Parent directory of lock-file must exist: {}", | |
25 | p.display() | |
26 | ); | |
27 | ||
28 | let share_mode = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE; | |
29 | ||
30 | let mut open_options = OpenOptions::new(); | |
353b0b11 | 31 | open_options.read(true).share_mode(share_mode.0); |
04454e1e FG |
32 | |
33 | if create { | |
34 | open_options.create(true).write(true); | |
35 | } | |
36 | ||
37 | debug!("attempting to open lock file `{}`", p.display()); | |
38 | let file = match open_options.open(p) { | |
39 | Ok(file) => { | |
40 | debug!("lock file opened successfully"); | |
41 | file | |
42 | } | |
43 | Err(err) => { | |
44 | debug!("error opening lock file: {}", err); | |
45 | return Err(err); | |
46 | } | |
47 | }; | |
48 | ||
353b0b11 FG |
49 | let mut flags = LOCK_FILE_FLAGS::default(); |
50 | if !wait { | |
51 | flags |= LOCKFILE_FAIL_IMMEDIATELY; | |
52 | } | |
04454e1e | 53 | |
353b0b11 FG |
54 | if exclusive { |
55 | flags |= LOCKFILE_EXCLUSIVE_LOCK; | |
56 | } | |
04454e1e | 57 | |
353b0b11 | 58 | let mut overlapped = OVERLAPPED::default(); |
04454e1e | 59 | |
353b0b11 FG |
60 | debug!("attempting to acquire lock on lock file `{}`", p.display()); |
61 | ||
62 | unsafe { | |
63 | LockFileEx( | |
64 | HANDLE(file.as_raw_handle() as isize), | |
65 | flags, | |
66 | 0, | |
67 | u32::MAX, | |
68 | u32::MAX, | |
69 | &mut overlapped, | |
70 | ) | |
04454e1e | 71 | } |
353b0b11 FG |
72 | .ok() |
73 | .map_err(|e| { | |
74 | let err = io::Error::from_raw_os_error(e.code().0); | |
75 | debug!("failed acquiring file lock: {}", err); | |
76 | err | |
77 | })?; | |
78 | ||
79 | debug!("successfully acquired lock"); | |
80 | Ok(Lock { _file: file }) | |
04454e1e FG |
81 | } |
82 | ||
83 | pub fn error_unsupported(err: &io::Error) -> bool { | |
353b0b11 | 84 | err.raw_os_error() == Some(ERROR_INVALID_FUNCTION.0 as i32) |
04454e1e FG |
85 | } |
86 | } | |
87 | ||
88 | // Note that we don't need a Drop impl on Windows: The file is unlocked | |
89 | // automatically when it's closed. |