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)]
15 use std::ffi::{CString, OsStr};
16 use std::os::unix::prelude::*;
18 #[cfg(any(target_os = "linux", target_os = "android"))]
22 pub l_type: libc::c_short,
23 pub l_whence: libc::c_short,
24 pub l_start: libc::off_t,
25 pub l_len: libc::off_t,
26 pub l_pid: libc::pid_t,
28 // not actually here, but brings in line with freebsd
29 pub l_sysid: libc::c_int,
33 #[cfg(target_os = "freebsd")]
37 pub l_start: libc::off_t,
38 pub l_len: libc::off_t,
39 pub l_pid: libc::pid_t,
40 pub l_type: libc::c_short,
41 pub l_whence: libc::c_short,
42 pub l_sysid: libc::c_int,
46 #[cfg(any(target_os = "dragonfly",
48 target_os = "openbsd"))]
52 pub l_start: libc::off_t,
53 pub l_len: libc::off_t,
54 pub l_pid: libc::pid_t,
55 pub l_type: libc::c_short,
56 pub l_whence: libc::c_short,
58 // not actually here, but brings in line with freebsd
59 pub l_sysid: libc::c_int,
63 #[cfg(target_os = "haiku")]
67 pub l_type: libc::c_short,
68 pub l_whence: libc::c_short,
69 pub l_start: libc::off_t,
70 pub l_len: libc::off_t,
71 pub l_pid: libc::pid_t,
73 // not actually here, but brings in line with freebsd
74 pub l_sysid: libc::c_int,
78 #[cfg(any(target_os = "macos", target_os = "ios"))]
82 pub l_start: libc::off_t,
83 pub l_len: libc::off_t,
84 pub l_pid: libc::pid_t,
85 pub l_type: libc::c_short,
86 pub l_whence: libc::c_short,
88 // not actually here, but brings in line with freebsd
89 pub l_sysid: libc::c_int,
93 #[cfg(target_os = "solaris")]
97 pub l_type: libc::c_short,
98 pub l_whence: libc::c_short,
99 pub l_start: libc::off_t,
100 pub l_len: libc::off_t,
101 pub l_sysid: libc::c_int,
102 pub l_pid: libc::pid_t,
116 -> io::Result<Lock> {
117 let os: &OsStr = p.as_ref();
118 let buf = CString::new(os.as_bytes()).unwrap();
119 let open_flags = if create {
120 libc::O_RDWR | libc::O_CREAT
126 libc::open(buf.as_ptr(), open_flags,
127 libc::S_IRWXU as libc::c_int)
131 return Err(io::Error::last_os_error());
134 let lock_type = if exclusive {
135 libc::F_WRLCK as libc::c_short
137 libc::F_RDLCK as libc::c_short
140 let flock = os::flock {
144 l_whence: libc::SEEK_SET as libc::c_short,
148 let cmd = if wait { libc::F_SETLKW } else { libc::F_SETLK };
150 libc::fcntl(fd, cmd, &flock)
153 let err = io::Error::last_os_error();
154 unsafe { libc::close(fd); }
164 let flock = os::flock {
168 l_whence: libc::SEEK_SET as libc::c_short,
169 l_type: libc::F_UNLCK as libc::c_short,
173 libc::fcntl(self.fd, libc::F_SETLK, &flock);
174 libc::close(self.fd);
178 } else if #[cfg(windows)] {
180 use std::os::windows::prelude::*;
181 use std::os::windows::raw::HANDLE;
182 use std::fs::{File, OpenOptions};
183 use std::os::raw::{c_ulong, c_int};
185 type DWORD = c_ulong;
187 type ULONG_PTR = usize;
189 type LPOVERLAPPED = *mut OVERLAPPED;
190 const LOCKFILE_EXCLUSIVE_LOCK: DWORD = 0x0000_0002;
191 const LOCKFILE_FAIL_IMMEDIATELY: DWORD = 0x0000_0001;
193 const FILE_SHARE_DELETE: DWORD = 0x4;
194 const FILE_SHARE_READ: DWORD = 0x1;
195 const FILE_SHARE_WRITE: DWORD = 0x2;
200 InternalHigh: ULONG_PTR,
207 fn LockFileEx(hFile: HANDLE,
210 nNumberOfBytesToLockLow: DWORD,
211 nNumberOfBytesToLockHigh: DWORD,
212 lpOverlapped: LPOVERLAPPED) -> BOOL;
225 -> io::Result<Lock> {
226 assert!(p.parent().unwrap().exists(),
227 "Parent directory of lock-file must exist: {}",
230 let share_mode = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE;
232 let mut open_options = OpenOptions::new();
233 open_options.read(true)
234 .share_mode(share_mode);
237 open_options.create(true)
241 debug!("Attempting to open lock file `{}`", p.display());
242 let file = match open_options.open(p) {
244 debug!("Lock file opened successfully");
248 debug!("Error opening lock file: {}", err);
254 let mut overlapped: OVERLAPPED = mem::zeroed();
258 dwFlags |= LOCKFILE_FAIL_IMMEDIATELY;
262 dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
265 debug!("Attempting to acquire lock on lock file `{}`",
267 LockFileEx(file.as_raw_handle(),
275 let err = io::Error::last_os_error();
276 debug!("Failed acquiring file lock: {}", err);
279 debug!("Successfully acquired lock.");
280 Ok(Lock { _file: file })
285 // Note that we don't need a Drop impl on the Windows: The file is unlocked
286 // automatically when it's closed.
292 pub fn new(_p: &Path, _wait: bool, _create: bool, _exclusive: bool)
295 let msg = "file locks not supported on this platform";
296 Err(io::Error::new(io::ErrorKind::Other, msg))
303 pub fn panicking_new(p: &Path,
308 Lock::new(p, wait, create, exclusive).unwrap_or_else(|err| {
309 panic!("could not lock `{}`: {}", p.display(), err);