windows.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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
use crate::errors::{ Error, Result }; use crate::file_ext::{ FileExt }; use errno::{ Errno, errno }; use std::fs::{ File }; use std::mem::{ self }; use std::os::raw::{ c_int, c_ulong, c_void }; use std::os::windows::io::{ AsRawHandle }; use std::os::windows::raw::{ HANDLE }; impl FileExt for File { type LockGuard = LockGuard; fn lock_shared(&self) -> Result<Self::LockGuard> { lock(self.as_raw_handle(), 0) } fn lock_exclusive(&self) -> Result<Self::LockGuard> { lock(self.as_raw_handle(), LOCKFILE_EXCLUSIVE_LOCK) } fn try_lock_shared(&self) -> Result<Self::LockGuard> { try_lock(self.as_raw_handle(), 0) } fn try_lock_exclusive(&self) -> Result<Self::LockGuard> { try_lock(self.as_raw_handle(), LOCKFILE_EXCLUSIVE_LOCK) } } #[derive(Debug)] #[must_use = "Not retaining the guard object will result in the file being immediately unlocked"] pub struct LockGuard { handle: HANDLE, } impl Drop for LockGuard { fn drop(&mut self) { unsafe { UnlockFile(self.handle, LOCK_OFFSET_LO, LOCK_OFFSET_HI, LOCK_LENGTH_LO, LOCK_LENGTH_HI); } } } fn lock(handle: HANDLE, flags: DWORD) -> Result<LockGuard> { let status = unsafe { const RESERVED: DWORD = 0; let mut overlapped = mem::zeroed::<OVERLAPPED>(); overlapped.DUMMYUNIONNAME.DUMMYSTRUCTNAME.Offset = LOCK_OFFSET_LO; overlapped.DUMMYUNIONNAME.DUMMYSTRUCTNAME.OffsetHigh = LOCK_OFFSET_HI; LockFileEx(handle, flags, RESERVED, LOCK_LENGTH_LO, LOCK_LENGTH_HI, &mut overlapped as LPOVERLAPPED) }; match status { 0 => Err(Error::LockFailed(errno())), _ => Ok(LockGuard { handle }), } } fn try_lock(handle: HANDLE, flags: DWORD) -> Result<LockGuard> { let status = unsafe { const RESERVED: DWORD = 0; let mut overlapped = mem::zeroed::<OVERLAPPED>(); overlapped.DUMMYUNIONNAME.DUMMYSTRUCTNAME.Offset = LOCK_OFFSET_LO; overlapped.DUMMYUNIONNAME.DUMMYSTRUCTNAME.OffsetHigh = LOCK_OFFSET_HI; LockFileEx(handle, flags | LOCKFILE_FAIL_IMMEDIATELY, RESERVED, LOCK_LENGTH_LO, LOCK_LENGTH_HI, &mut overlapped as LPOVERLAPPED) }; match status { 0 => { let e = errno(); if e == Errno(ERROR_LOCK_VIOLATION as i32) { Err(Error::AlreadyLocked) } else { Err(Error::LockFailed(e)) } }, _ => Ok(LockGuard { handle }), } } #[allow(non_camel_case_types, non_snake_case, clippy::upper_case_acronyms)] #[derive(Clone, Copy)] #[repr(C)] struct OVERLAPPED { Internal: ULONG_PTR, InternalHigh: ULONG_PTR, DUMMYUNIONNAME: OVERLAPPED_Union, hEvent: HANDLE, } #[allow(non_camel_case_types, non_snake_case)] #[derive(Clone, Copy)] #[repr(C)] union OVERLAPPED_Union { DUMMYSTRUCTNAME: OVERLAPPED_Offset, Pointer: PVOID, } #[allow(non_camel_case_types, non_snake_case)] #[derive(Clone, Copy)] #[repr(C)] struct OVERLAPPED_Offset { Offset: DWORD, OffsetHigh: DWORD, } #[allow(non_camel_case_types, clippy::upper_case_acronyms)] type LPOVERLAPPED = *mut OVERLAPPED; #[allow(non_camel_case_types, clippy::upper_case_acronyms)] type BOOL = c_int; #[allow(non_camel_case_types, clippy::upper_case_acronyms)] type DWORD = c_ulong; #[allow(non_camel_case_types)] type ULONG_PTR = c_ulong; #[allow(non_camel_case_types, clippy::upper_case_acronyms)] type PVOID = *mut c_void; const LOCK_OFFSET_LO: DWORD = 0; const LOCK_OFFSET_HI: DWORD = 0; const LOCK_LENGTH_LO: DWORD = !0; const LOCK_LENGTH_HI: DWORD = !0; const ERROR_LOCK_VIOLATION: DWORD = 33; const LOCKFILE_FAIL_IMMEDIATELY: DWORD = 0x00000001; const LOCKFILE_EXCLUSIVE_LOCK: DWORD = 0x00000002; extern "C" { fn LockFileEx(hFile: HANDLE, dwFlags: DWORD, dwReserved: DWORD, nNumberOfBytesToLockLow: DWORD, nNumberOfBytesToLockHigh: DWORD, lpOverlapped: LPOVERLAPPED) -> BOOL; fn UnlockFile(hFile: HANDLE, dwFileOffsetLow: DWORD, dwFileOffsetHigh: DWORD, nNumberOfBytesToUnlockLow: DWORD, nNumberOfBytesToUnlockHigh: DWORD) -> BOOL; }