Skip to content

Commit 14af38d

Browse files
authored
Remove fs2 dependency for broader platform support (#91)
1 parent 400592f commit 14af38d

File tree

4 files changed

+135
-27
lines changed

4 files changed

+135
-27
lines changed

Cargo.lock

Lines changed: 0 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ version = "0.6.0"
1414
name = "xargo_lib"
1515

1616
[dependencies]
17-
fs2 = "0.4.1"
1817
libc = "0.2.18"
1918
rustc_version = "0.2"
2019
serde = "1.0"

src/flock.rs

Lines changed: 135 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ use std::fs::{File, OpenOptions};
55
use std::path::{Display, Path, PathBuf};
66
use std::{fs, io};
77

8-
use fs2;
9-
use fs2::FileExt;
8+
use self::sys::*;
109

1110
#[derive(PartialEq)]
1211
enum State {
@@ -107,12 +106,12 @@ impl Filesystem {
107106

108107
match state {
109108
State::Exclusive => {
110-
acquire(msg, &path, self.quiet, &|| f.try_lock_exclusive(), &|| {
111-
f.lock_exclusive()
109+
acquire(msg, &path, self.quiet, &|| try_lock_exclusive(&f), &|| {
110+
lock_exclusive(&f)
112111
})?;
113112
}
114113
State::Shared => {
115-
acquire(msg, &path, self.quiet, &|| f.try_lock_shared(), &|| f.lock_shared())?;
114+
acquire(msg, &path, self.quiet, &|| try_lock_shared(&f), &|| lock_shared(&f))?;
116115
}
117116
}
118117

@@ -129,16 +128,16 @@ impl Filesystem {
129128

130129
impl Drop for FileLock {
131130
fn drop(&mut self) {
132-
self.file.unlock().ok();
131+
unlock(&self.file).ok();
133132
}
134133
}
135134

136135
fn acquire(
137136
msg: &str,
138137
path: &Path,
139138
quiet: bool,
140-
try: &dyn Fn() -> io::Result<()>,
141-
block: &dyn Fn() -> io::Result<()>,
139+
lock_try: &dyn Fn() -> io::Result<()>,
140+
lock_block: &dyn Fn() -> io::Result<()>,
142141
) -> io::Result<()> {
143142
#[cfg(all(target_os = "linux", not(target_env = "musl")))]
144143
fn is_on_nfs_mount(path: &Path) -> bool {
@@ -168,12 +167,16 @@ fn acquire(
168167
return Ok(());
169168
}
170169

171-
match try() {
172-
Ok(_) => return Ok(()),
173-
#[cfg(target_os = "macos")]
174-
Err(ref e) if e.raw_os_error() == Some(::libc::ENOTSUP) => return Ok(()),
170+
match lock_try() {
171+
Ok(()) => return Ok(()),
172+
173+
// In addition to ignoring NFS which is commonly not working we also
174+
// just ignore locking on filesystems that look like they don't
175+
// implement file locking.
176+
Err(e) if error_unsupported(&e) => return Ok(()),
177+
175178
Err(e) => {
176-
if e.raw_os_error() != fs2::lock_contended_error().raw_os_error() {
179+
if !error_contended(&e) {
177180
return Err(e);
178181
}
179182
}
@@ -187,7 +190,125 @@ fn acquire(
187190
)
188191
}
189192

190-
block()
193+
lock_block()
194+
}
195+
196+
#[cfg(unix)]
197+
mod sys {
198+
use std::fs::File;
199+
use std::io::{Error, Result};
200+
use std::os::unix::io::AsRawFd;
201+
202+
pub(super) fn lock_shared(file: &File) -> Result<()> {
203+
flock(file, libc::LOCK_SH)
204+
}
205+
206+
pub(super) fn lock_exclusive(file: &File) -> Result<()> {
207+
flock(file, libc::LOCK_EX)
208+
}
209+
210+
pub(super) fn try_lock_shared(file: &File) -> Result<()> {
211+
flock(file, libc::LOCK_SH | libc::LOCK_NB)
212+
}
213+
214+
pub(super) fn try_lock_exclusive(file: &File) -> Result<()> {
215+
flock(file, libc::LOCK_EX | libc::LOCK_NB)
216+
}
217+
218+
pub(super) fn unlock(file: &File) -> Result<()> {
219+
flock(file, libc::LOCK_UN)
220+
}
221+
222+
pub(super) fn error_contended(err: &Error) -> bool {
223+
err.raw_os_error().map_or(false, |x| x == libc::EWOULDBLOCK)
224+
}
225+
226+
pub(super) fn error_unsupported(err: &Error) -> bool {
227+
match err.raw_os_error() {
228+
Some(libc::ENOTSUP) => true,
229+
#[cfg(target_os = "linux")]
230+
Some(libc::ENOSYS) => true,
231+
_ => false,
232+
}
233+
}
234+
235+
#[cfg(not(target_os = "solaris"))]
236+
fn flock(file: &File, flag: libc::c_int) -> Result<()> {
237+
let ret = unsafe { libc::flock(file.as_raw_fd(), flag) };
238+
if ret < 0 {
239+
Err(Error::last_os_error())
240+
} else {
241+
Ok(())
242+
}
243+
}
244+
245+
#[cfg(target_os = "solaris")]
246+
fn flock(file: &File, flag: libc::c_int) -> Result<()> {
247+
// Solaris lacks flock(), so simply succeed with a no-op
248+
Ok(())
249+
}
250+
}
251+
252+
#[cfg(windows)]
253+
mod sys {
254+
use std::fs::File;
255+
use std::io::{Error, Result};
256+
use std::mem;
257+
use std::os::windows::io::AsRawHandle;
258+
259+
use winapi::shared::minwindef::DWORD;
260+
use winapi::shared::winerror::{ERROR_INVALID_FUNCTION, ERROR_LOCK_VIOLATION};
261+
use winapi::um::fileapi::{LockFileEx, UnlockFile};
262+
use winapi::um::minwinbase::{LOCKFILE_EXCLUSIVE_LOCK, LOCKFILE_FAIL_IMMEDIATELY};
263+
264+
pub(super) fn lock_shared(file: &File) -> Result<()> {
265+
lock_file(file, 0)
266+
}
267+
268+
pub(super) fn lock_exclusive(file: &File) -> Result<()> {
269+
lock_file(file, LOCKFILE_EXCLUSIVE_LOCK)
270+
}
271+
272+
pub(super) fn try_lock_shared(file: &File) -> Result<()> {
273+
lock_file(file, LOCKFILE_FAIL_IMMEDIATELY)
274+
}
275+
276+
pub(super) fn try_lock_exclusive(file: &File) -> Result<()> {
277+
lock_file(file, LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY)
278+
}
279+
280+
pub(super) fn error_contended(err: &Error) -> bool {
281+
err.raw_os_error()
282+
.map_or(false, |x| x == ERROR_LOCK_VIOLATION as i32)
283+
}
284+
285+
pub(super) fn error_unsupported(err: &Error) -> bool {
286+
err.raw_os_error()
287+
.map_or(false, |x| x == ERROR_INVALID_FUNCTION as i32)
288+
}
289+
290+
pub(super) fn unlock(file: &File) -> Result<()> {
291+
unsafe {
292+
let ret = UnlockFile(file.as_raw_handle(), 0, 0, !0, !0);
293+
if ret == 0 {
294+
Err(Error::last_os_error())
295+
} else {
296+
Ok(())
297+
}
298+
}
299+
}
300+
301+
fn lock_file(file: &File, flags: DWORD) -> Result<()> {
302+
unsafe {
303+
let mut overlapped = mem::zeroed();
304+
let ret = LockFileEx(file.as_raw_handle(), flags, 0, !0, !0, &mut overlapped);
305+
if ret == 0 {
306+
Err(Error::last_os_error())
307+
} else {
308+
Ok(())
309+
}
310+
}
311+
}
191312
}
192313

193314
fn create_dir_all(path: &Path) -> io::Result<()> {

src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
extern crate cargo_metadata;
22
#[macro_use]
33
extern crate error_chain;
4-
extern crate fs2;
54
#[cfg(any(
65
all(target_os = "linux", not(target_env = "musl")),
76
target_os = "macos"

0 commit comments

Comments
 (0)