Skip to main content

rustc_data_structures/
flock.rs

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
7use std::fs::{File, OpenOptions};
8use std::io;
9use std::path::Path;
10
11#[derive(#[automatically_derived]
impl ::core::fmt::Debug for Lock {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            Lock::FdLocked { _file: __self_0 } =>
                ::core::fmt::Formatter::debug_struct_field1_finish(f,
                    "FdLocked", "_file", &__self_0),
            Lock::Fallback(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "Fallback", &__self_0),
        }
    }
}Debug)]
12pub enum Lock {
13    /// A well behaved lock scoped to a single fd/handle and unlocked when closing it.
14    #[doc(hidden)]
15    FdLocked { _file: File },
16    /// A fallback implementation which may for example be scoped to an entire process,
17    /// like legacy `fcntl(F_SETLK)` on Unix. This should only be used when `flock()`
18    /// or equivalent sane locking mechanism is unsupported by the OS.
19    #[doc(hidden)]
20    Fallback(fallback::Lock),
21}
22
23impl Lock {
24    pub fn new(p: &Path, wait: bool, create: bool, exclusive: bool) -> io::Result<Lock> {
25        let mut open_options = OpenOptions::new();
26        open_options.read(true).write(true).create(create);
27        #[cfg(unix)]
28        {
29            use std::os::unix::fs::OpenOptionsExt;
30            open_options.mode(0o600);
31        }
32
33        let file = open_options.open(p)?;
34
35        let res = match (wait, exclusive) {
36            (true, true) => file.lock(),
37            (true, false) => file.lock_shared(),
38            (false, true) => file.try_lock().map_err(io::Error::from),
39            (false, false) => file.try_lock_shared().map_err(io::Error::from),
40        };
41
42        match res {
43            Ok(()) => Ok(Lock::FdLocked { _file: file }),
44            Err(err) if #[allow(non_exhaustive_omitted_patterns)] match err.kind() {
    io::ErrorKind::Unsupported => true,
    _ => false,
}matches!(err.kind(), io::ErrorKind::Unsupported) => {
45                Ok(Lock::Fallback(fallback::Lock::new(p, wait, create, exclusive)?))
46            }
47            Err(err) => Err(err),
48        }
49    }
50
51    pub fn error_unsupported(err: &io::Error) -> bool {
52        #[cfg(windows)]
53        if err.raw_os_error() == Some(windows::Win32::Foundation::ERROR_INVALID_FUNCTION.0 as i32) {
54            // Not mapped to ErrorKind::Unsupported by libstd
55            return true;
56        }
57
58        #[allow(non_exhaustive_omitted_patterns)] match err.kind() {
    io::ErrorKind::Unsupported => true,
    _ => false,
}matches!(err.kind(), io::ErrorKind::Unsupported)
59    }
60}
61
62cfg_select! {
63    unix => {
64        mod unix;
65        use unix as fallback;
66    }
67    _ => {
68        mod unsupported;
69        use unsupported as fallback;
70    }
71}