]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | //! Simple file-locking apis for each OS. |
2 | //! | |
3 | //! This is not meant to be in the standard library, it does nothing with | |
4 | //! green/native threading. This is just a bare-bones enough solution for | |
5 | //! librustdoc, it is not production quality at all. | |
6 | ||
7 | #![allow(non_camel_case_types)] | |
b7449926 | 8 | #![allow(nonstandard_style)] |
1a4d82fc | 9 | |
f9f354fc | 10 | use std::fs::{File, OpenOptions}; |
b7449926 XL |
11 | use std::io; |
12 | use std::path::Path; | |
1a4d82fc | 13 | |
b7449926 | 14 | cfg_if! { |
f9f354fc XL |
15 | // We use `flock` rather than `fcntl` on Linux, because WSL1 does not support |
16 | // `fcntl`-style advisory locks properly (rust-lang/rust#72157). | |
17 | // | |
18 | // For other Unix targets we still use `fcntl` because it's more portable than | |
19 | // `flock`. | |
20 | if #[cfg(target_os = "linux")] { | |
b7449926 | 21 | use std::os::unix::prelude::*; |
1a4d82fc | 22 | |
b7449926 XL |
23 | #[derive(Debug)] |
24 | pub struct Lock { | |
f9f354fc | 25 | _file: File, |
b7449926 | 26 | } |
9e0c209e | 27 | |
b7449926 XL |
28 | impl Lock { |
29 | pub fn new(p: &Path, | |
30 | wait: bool, | |
31 | create: bool, | |
32 | exclusive: bool) | |
33 | -> io::Result<Lock> { | |
f9f354fc XL |
34 | let file = OpenOptions::new() |
35 | .read(true) | |
36 | .write(true) | |
37 | .create(create) | |
38 | .mode(libc::S_IRWXU as u32) | |
39 | .open(p)?; | |
b7449926 | 40 | |
f9f354fc XL |
41 | let mut operation = if exclusive { |
42 | libc::LOCK_EX | |
43 | } else { | |
44 | libc::LOCK_SH | |
b7449926 | 45 | }; |
f9f354fc XL |
46 | if !wait { |
47 | operation |= libc::LOCK_NB | |
48 | } | |
b7449926 | 49 | |
f9f354fc XL |
50 | let ret = unsafe { libc::flock(file.as_raw_fd(), operation) }; |
51 | if ret == -1 { | |
52 | Err(io::Error::last_os_error()) | |
53 | } else { | |
54 | Ok(Lock { _file: file }) | |
b7449926 | 55 | } |
f9f354fc XL |
56 | } |
57 | } | |
58 | ||
59 | // Note that we don't need a Drop impl to execute `flock(fd, LOCK_UN)`. Lock acquired by | |
60 | // `flock` is associated with the file descriptor and closing the file release it | |
61 | // automatically. | |
62 | } else if #[cfg(unix)] { | |
63 | use std::mem; | |
64 | use std::os::unix::prelude::*; | |
65 | ||
66 | #[derive(Debug)] | |
67 | pub struct Lock { | |
68 | file: File, | |
69 | } | |
70 | ||
71 | impl Lock { | |
72 | pub fn new(p: &Path, | |
73 | wait: bool, | |
74 | create: bool, | |
75 | exclusive: bool) | |
76 | -> io::Result<Lock> { | |
77 | let file = OpenOptions::new() | |
78 | .read(true) | |
79 | .write(true) | |
80 | .create(create) | |
81 | .mode(libc::S_IRWXU as u32) | |
82 | .open(p)?; | |
b7449926 XL |
83 | |
84 | let lock_type = if exclusive { | |
dfeec247 | 85 | libc::F_WRLCK |
b7449926 | 86 | } else { |
dfeec247 | 87 | libc::F_RDLCK |
b7449926 XL |
88 | }; |
89 | ||
dfeec247 XL |
90 | let mut flock: libc::flock = unsafe { mem::zeroed() }; |
91 | flock.l_type = lock_type as libc::c_short; | |
92 | flock.l_whence = libc::SEEK_SET as libc::c_short; | |
93 | flock.l_start = 0; | |
94 | flock.l_len = 0; | |
95 | ||
0731742a | 96 | let cmd = if wait { libc::F_SETLKW } else { libc::F_SETLK }; |
b7449926 | 97 | let ret = unsafe { |
f9f354fc | 98 | libc::fcntl(file.as_raw_fd(), cmd, &flock) |
b7449926 XL |
99 | }; |
100 | if ret == -1 { | |
f9f354fc | 101 | Err(io::Error::last_os_error()) |
b7449926 | 102 | } else { |
f9f354fc | 103 | Ok(Lock { file }) |
b7449926 | 104 | } |
1a4d82fc | 105 | } |
1a4d82fc | 106 | } |
1a4d82fc | 107 | |
b7449926 XL |
108 | impl Drop for Lock { |
109 | fn drop(&mut self) { | |
dfeec247 XL |
110 | let mut flock: libc::flock = unsafe { mem::zeroed() }; |
111 | flock.l_type = libc::F_UNLCK as libc::c_short; | |
112 | flock.l_whence = libc::SEEK_SET as libc::c_short; | |
113 | flock.l_start = 0; | |
114 | flock.l_len = 0; | |
115 | ||
b7449926 | 116 | unsafe { |
f9f354fc | 117 | libc::fcntl(self.file.as_raw_fd(), libc::F_SETLK, &flock); |
b7449926 | 118 | } |
1a4d82fc JJ |
119 | } |
120 | } | |
b7449926 XL |
121 | } else if #[cfg(windows)] { |
122 | use std::mem; | |
123 | use std::os::windows::prelude::*; | |
9e0c209e | 124 | |
dfeec247 XL |
125 | use winapi::um::minwinbase::{OVERLAPPED, LOCKFILE_FAIL_IMMEDIATELY, LOCKFILE_EXCLUSIVE_LOCK}; |
126 | use winapi::um::fileapi::LockFileEx; | |
127 | use winapi::um::winnt::{FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE}; | |
9e0c209e | 128 | |
b7449926 XL |
129 | #[derive(Debug)] |
130 | pub struct Lock { | |
131 | _file: File, | |
132 | } | |
9e0c209e | 133 | |
b7449926 XL |
134 | impl Lock { |
135 | pub fn new(p: &Path, | |
136 | wait: bool, | |
137 | create: bool, | |
138 | exclusive: bool) | |
139 | -> io::Result<Lock> { | |
140 | assert!(p.parent().unwrap().exists(), | |
141 | "Parent directory of lock-file must exist: {}", | |
142 | p.display()); | |
143 | ||
144 | let share_mode = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE; | |
145 | ||
146 | let mut open_options = OpenOptions::new(); | |
147 | open_options.read(true) | |
148 | .share_mode(share_mode); | |
149 | ||
150 | if create { | |
151 | open_options.create(true) | |
152 | .write(true); | |
9e0c209e SL |
153 | } |
154 | ||
416331ca | 155 | debug!("attempting to open lock file `{}`", p.display()); |
b7449926 XL |
156 | let file = match open_options.open(p) { |
157 | Ok(file) => { | |
416331ca | 158 | debug!("lock file opened successfully"); |
b7449926 XL |
159 | file |
160 | } | |
161 | Err(err) => { | |
416331ca | 162 | debug!("error opening lock file: {}", err); |
b7449926 XL |
163 | return Err(err) |
164 | } | |
165 | }; | |
166 | ||
167 | let ret = unsafe { | |
168 | let mut overlapped: OVERLAPPED = mem::zeroed(); | |
169 | ||
170 | let mut dwFlags = 0; | |
171 | if !wait { | |
172 | dwFlags |= LOCKFILE_FAIL_IMMEDIATELY; | |
173 | } | |
174 | ||
175 | if exclusive { | |
176 | dwFlags |= LOCKFILE_EXCLUSIVE_LOCK; | |
177 | } | |
178 | ||
416331ca | 179 | debug!("attempting to acquire lock on lock file `{}`", |
b7449926 XL |
180 | p.display()); |
181 | LockFileEx(file.as_raw_handle(), | |
182 | dwFlags, | |
183 | 0, | |
184 | 0xFFFF_FFFF, | |
185 | 0xFFFF_FFFF, | |
186 | &mut overlapped) | |
187 | }; | |
188 | if ret == 0 { | |
189 | let err = io::Error::last_os_error(); | |
416331ca | 190 | debug!("failed acquiring file lock: {}", err); |
b7449926 XL |
191 | Err(err) |
192 | } else { | |
416331ca | 193 | debug!("successfully acquired lock"); |
b7449926 | 194 | Ok(Lock { _file: file }) |
9e0c209e | 195 | } |
b7449926 XL |
196 | } |
197 | } | |
9e0c209e | 198 | |
b7449926 XL |
199 | // Note that we don't need a Drop impl on the Windows: The file is unlocked |
200 | // automatically when it's closed. | |
201 | } else { | |
202 | #[derive(Debug)] | |
203 | pub struct Lock(()); | |
204 | ||
205 | impl Lock { | |
206 | pub fn new(_p: &Path, _wait: bool, _create: bool, _exclusive: bool) | |
207 | -> io::Result<Lock> | |
208 | { | |
209 | let msg = "file locks not supported on this platform"; | |
210 | Err(io::Error::new(io::ErrorKind::Other, msg)) | |
1a4d82fc | 211 | } |
1a4d82fc JJ |
212 | } |
213 | } | |
9e0c209e | 214 | } |