1 //! Simple file-locking apis for each OS.
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.
7 #![allow(non_camel_case_types)]
8 #![allow(nonstandard_style)]
10 use std
::fs
::{File, OpenOptions}
;
15 // We use `flock` rather than `fcntl` on Linux, because WSL1 does not support
16 // `fcntl`-style advisory locks properly (rust-lang/rust#72157).
18 // For other Unix targets we still use `fcntl` because it's more portable than
20 if #[cfg(target_os = "linux")] {
21 use std
::os
::unix
::prelude
::*;
34 let file
= OpenOptions
::new()
38 .mode(libc
::S_IRWXU
as u32)
41 let mut operation
= if exclusive
{
47 operation
|= libc
::LOCK_NB
50 let ret
= unsafe { libc::flock(file.as_raw_fd(), operation) }
;
52 Err(io
::Error
::last_os_error())
54 Ok(Lock { _file: file }
)
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
62 } else if #[cfg(unix)] {
64 use std
::os
::unix
::prelude
::*;
77 let file
= OpenOptions
::new()
81 .mode(libc
::S_IRWXU
as u32)
84 let lock_type
= if exclusive
{
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
;
96 let cmd
= if wait { libc::F_SETLKW }
else { libc::F_SETLK }
;
98 libc
::fcntl(file
.as_raw_fd(), cmd
, &flock
)
101 Err(io
::Error
::last_os_error())
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
;
117 libc
::fcntl(self.file
.as_raw_fd(), libc
::F_SETLK
, &flock
);
121 } else if #[cfg(windows)] {
123 use std
::os
::windows
::prelude
::*;
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}
;
139 -> io
::Result
<Lock
> {
140 assert
!(p
.parent().unwrap().exists(),
141 "Parent directory of lock-file must exist: {}",
144 let share_mode
= FILE_SHARE_DELETE
| FILE_SHARE_READ
| FILE_SHARE_WRITE
;
146 let mut open_options
= OpenOptions
::new();
147 open_options
.read(true)
148 .share_mode(share_mode
);
151 open_options
.create(true)
155 debug
!("attempting to open lock file `{}`", p
.display());
156 let file
= match open_options
.open(p
) {
158 debug
!("lock file opened successfully");
162 debug
!("error opening lock file: {}", err
);
168 let mut overlapped
: OVERLAPPED
= mem
::zeroed();
172 dwFlags
|= LOCKFILE_FAIL_IMMEDIATELY
;
176 dwFlags
|= LOCKFILE_EXCLUSIVE_LOCK
;
179 debug
!("attempting to acquire lock on lock file `{}`",
181 LockFileEx(file
.as_raw_handle(),
189 let err
= io
::Error
::last_os_error();
190 debug
!("failed acquiring file lock: {}", err
);
193 debug
!("successfully acquired lock");
194 Ok(Lock { _file: file }
)
199 // Note that we don't need a Drop impl on the Windows: The file is unlocked
200 // automatically when it's closed.
206 pub fn new(_p
: &Path
, _wait
: bool
, _create
: bool
, _exclusive
: bool
)
209 let msg
= "file locks not supported on this platform";
210 Err(io
::Error
::new(io
::ErrorKind
::Other
, msg
))